Cuica

REST API
REST APIRust

Rust

Sample code using Rust

Session-based HTTPS Request

This is an example of accessing a REST API endpoint using a session. The application requires a custom TLS certificate chain PEM file and the Cuica hostname as input arguments. Placeholders are indicated by <>.

Example Cargo.toml*
[dependencies]
clap = { version = "4.2", features = ["derive"] }
rpassword = "5.1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.12", features = ["json", "rustls-tls", "cookies"] }
tokio = { version = "1.29", features = ["rt-multi-thread", "macros"] }
*Versions may vary
Example Rust Application
use clap::Parser;
use rpassword::read_password;
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::{self, Write};
use std::path::PathBuf;
 
/// Command-line arguments
#[derive(Parser)]
struct Args {
    /// The host of the Cuica device
    #[arg(index = 1)]
    cuica_host: String,
 
    /// Path to the Root CA certificate file
    #[arg(index = 2)]
    root_ca_path: PathBuf,
}
 
/// Structure for authentication login data
#[derive(Debug, Serialize)]
pub struct AuthLogin {
    pub username: String,
    pub password: String,
}
 
/// Structure matching the expected JSON response schema
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SystemInfoResponse {
    pub version: String,
    pub build_version: String,
    pub last_commit_time: String,
    pub serial_number: String,
}
 
/// Prompt the user for a username
fn prompt_username() -> String {
    print!("\u{25e6} Username: ");
    io::stdout().flush().unwrap();
 
    let mut input = String::new();
    if let Err(e) = io::stdin().read_line(&mut input) {
        eprintln!("Error reading username: {}", e);
        std::process::exit(1);
    }
    input.trim().to_string()
}
 
/// Prompt the user for a password without echoing input
fn prompt_password() -> String {
    print!("\u{25e6} Password: ");
    io::stdout().flush().unwrap();
 
    match read_password() {
        Ok(pwd) => pwd.trim().to_string(),
        Err(e) => {
            eprintln!("Error reading password: {}", e);
            std::process::exit(1);
        }
    }
}
 
#[tokio::main]
async fn main() {
    let args = Args::parse();
 
    let username = prompt_username();
    let password = prompt_password();
 
    // Ensure the specified Root CA file exists to validate 
    // TLS connections
    if !args.root_ca_path.exists() {
        eprintln!("Error: Root CA file was not found");
        std::process::exit(1);
    }
 
    // Read and parse the Root CA certificate
    let root_ca = match fs::read(&args.root_ca_path) {
        Ok(ca) => ca,
        Err(e) => {
            eprintln!("Error reading Root CA file: {}", e);
            std::process::exit(1);
        }
    };
 
    let cert = match reqwest::Certificate::from_pem(&root_ca) {
        Ok(cert) => cert,
        Err(e) => {
            eprintln!("Error parsing Root CA certificate: {}", e);
            std::process::exit(1);
        }
    };
 
    // Build the HTTP client with the custom Root CA certificate
    let http_client = match reqwest::Client::builder()
        .cookie_store(true)
        .use_rustls_tls()
        .add_root_certificate(cert)
        .build()
    {
        Ok(client) => client,
        Err(e) => {
            eprintln!("Error building HTTP client: {}", e);
            std::process::exit(1);
        }
    };
 
    // Log into the Cuica device to get a valid session
    let login_request = AuthLogin {
        username: username.clone(),
        password: password.clone(),
    };
 
    let login_response = match http_client
        .post(format!("https://{}/login", args.cuica_host))
        .json(&login_request)
        .header(reqwest::header::CONTENT_TYPE, "application/json")
        .send()
        .await
    {
        Ok(response) => response,
        Err(e) => {
            eprintln!("Error sending login request: {}", e);
            std::process::exit(1);
        }
    };
 
    // Handle the login response
    match login_response.status() {
        reqwest::StatusCode::OK => {
            println!("Logged in successfully.");
        }
        reqwest::StatusCode::UNAUTHORIZED => {
            eprintln!("User login unsuccessful. \
                Check username and password.");
            std::process::exit(1);
        }
        reqwest::StatusCode::FORBIDDEN => {
            eprintln!(
                "Access forbidden: Max tokens reached, \
                     system setup required, \
                     or non-admin user."
            );
            std::process::exit(1);
        }
        _ => {
            // Handle all other responses
            let error_body = match login_response.text().await {
                Ok(body) => body,
                Err(e) => {
                    eprintln!("Error reading login error response: {}", e);
                    std::process::exit(1);
                }
            };
            eprintln!("Login failed: {}", error_body);
            std::process::exit(1);
        }
    }
 
    // Perform a GET request to retrieve system information
    let info_response = match http_client
        .get(format!("https://{}/v1/system/info", args.cuica_host))
        .header(reqwest::header::CONTENT_TYPE, "application/json")
        .send()
        .await
    {
        Ok(response) => response,
        Err(e) => {
            eprintln!("Error sending system info request: {}", e);
            std::process::exit(1);
        }
    };
 
    // Deserialize the response into the SystemInfoResponse struct
    let system_info = 
        match info_response.json::<SystemInfoResponse>().await {
        Ok(info) => info,
        Err(e) => {
            eprintln!("Error parsing system info response: {}", e);
            std::process::exit(1);
        }
    };
 
    // Print the retrieved system information
    println!("Version: {}", system_info.version);
    println!("Build Version: {}", system_info.build_version);
    println!("Last Commit Time: {}", system_info.last_commit_time);
    println!("Serial Number: {}", system_info.serial_number);
}
Executing Sample Rust Application
$ ./sample_code cuica-host ./my-certs.pem 
 Username: <somebody>
 Password: 
Logged in successfully.
Version: 1.2.3
Build Version: 8311830
Last Commit Time: 2025-10-26T00:37:38-04:00
Serial Number: CUIPRF-XXX
Copyright © Uatha LLC. All rights reserved.