Skip to main content

offline_license/
offline_license.rs

1use ai_cortex_sdk::{
2    verify_offline_license, CortexClient, CortexConfig, OfflineLicenseFile,
3};
4
5/// 演示离线许可证的拉取 + 本地验签流程:
6///   1. 从环境变量读取 server_url / pat / software_id / 可选 pinned pubkey
7///   2. 采集当前设备指纹
8///   3. fetch_offline_license 拉取许可证文件
9///   4. verify_offline_license 本地验签(Ed25519 + 公钥钉扎 + 字段 + 过期)
10///   5. 打印 payload / 有效性
11///
12/// Usage:
13///   cargo run --example offline_license -- [PAT] [SOFTWARE_ID] [PINNED_PUBKEY_HEX]
14#[tokio::main]
15async fn main() {
16    let server_url =
17        std::env::var("CORTEX_SERVER_URL").unwrap_or_else(|_| "http://localhost:40404".into());
18    let pat = std::env::args()
19        .nth(1)
20        .or_else(|| std::env::var("CORTEX_PAT").ok())
21        .unwrap_or_else(|| "REPLACE_WITH_YOUR_PAT".to_string());
22    let software_id = std::env::args()
23        .nth(2)
24        .or_else(|| std::env::var("CORTEX_SOFTWARE_ID").ok())
25        .unwrap_or_else(|| "00000000-0000-0000-0000-000000000000".to_string());
26    let pinned_pk = std::env::args().nth(3);
27
28    // 关闭心跳,避免示例对服务端产生副作用
29    let config = CortexConfig::new(&server_url, &pat, &software_id)
30        .without_heartbeat();
31    let config = if let Some(pk) = &pinned_pk {
32        config.with_software_public_key(pk)
33    } else {
34        config
35    };
36    let client = CortexClient::new(config);
37
38    // 采集设备指纹
39    let dev = ai_cortex_sdk::device::collect();
40    let fingerprint = dev.fingerprint.as_str();
41    println!("Device fingerprint: {fingerprint}");
42
43    // 1. 拉取离线许可证
44    println!("\n=== Fetch offline license ===");
45    let file: OfflineLicenseFile = match client.fetch_offline_license(fingerprint).await {
46        Ok(f) => f,
47        Err(e) => {
48            eprintln!("fetch failed: {e}");
49            return;
50        }
51    };
52    println!("public_key: {}", file.public_key);
53    println!("signature : {}", file.signature);
54    println!("payload   : {}", file.payload);
55
56    // 2. 本地验签(钉扎公钥来自参数)
57    println!("\n=== Verify offline license ===");
58    match verify_offline_license(
59        &file,
60        &software_id,
61        fingerprint,
62        pinned_pk.as_deref(),
63    ) {
64        Ok(payload) => {
65            println!("VALID. payload parsed:");
66            println!("  license_id  : {}", payload.license_id);
67            println!("  user_id     : {}", payload.user_id);
68            println!("  software_id : {}", payload.software_id);
69            println!("  fingerprint : {}", payload.fingerprint);
70            println!("  max_devices : {}", payload.max_devices);
71            println!("  issued_at   : {}", payload.issued_at);
72            println!("  expire_time : {}", payload.expire_time);
73        }
74        Err(e) => {
75            eprintln!("INVALID license: {e}");
76        }
77    }
78}