mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
feat(cli): add craftlabs-auth-cli with status/activate/check/info/release commands
This commit is contained in:
Generated
+136
@@ -46,6 +46,56 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell_polyfill",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -143,6 +193,52 @@ dependencies = [
|
|||||||
"inout",
|
"inout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-oid"
|
name = "const-oid"
|
||||||
version = "0.9.6"
|
version = "0.9.6"
|
||||||
@@ -187,6 +283,16 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "craftlabs-auth-cli"
|
||||||
|
version = "1.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"clap",
|
||||||
|
"craft-core",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -336,6 +442,12 @@ dependencies = [
|
|||||||
"polyval",
|
"polyval",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -600,6 +712,12 @@ version = "2.12.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@@ -742,6 +860,12 @@ version = "1.21.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell_polyfill"
|
||||||
|
version = "1.70.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opaque-debug"
|
name = "opaque-debug"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -1210,6 +1334,12 @@ version = "1.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
@@ -1444,6 +1574,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["craft-core"]
|
members = ["craft-core", "craftlabs-auth-cli"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ edition = "2021"
|
|||||||
description = "CraftLabs 授权核心库 — Rust 实现,导出 craft_* C ABI。目标平台:Linux(主)> Windows(次)> macOS(最低)"
|
description = "CraftLabs 授权核心库 — Rust 实现,导出 craft_* C ABI。目标平台:Linux(主)> Windows(次)> macOS(最低)"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "staticlib"]
|
crate-type = ["cdylib", "staticlib", "lib"]
|
||||||
name = "craftlabs_auth_core"
|
name = "craftlabs_auth_core"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -143,6 +143,11 @@ pub extern "C" fn craft_heartbeat(handle: *mut CraftContext) -> CraftResult {
|
|||||||
.map_or_else(fail_result, |_| ok_result())
|
.map_or_else(fail_result, |_| ok_result())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn craft_initialize_with_config(config: &str) -> *mut CraftContext {
|
||||||
|
let c_str = std::ffi::CString::new(config).unwrap_or_default();
|
||||||
|
craft_initialize(c_str.as_ptr())
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn craft_destroy(handle: *mut CraftContext) {
|
pub extern "C" fn craft_destroy(handle: *mut CraftContext) {
|
||||||
if !handle.is_null() {
|
if !handle.is_null() {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "craftlabs-auth-cli"
|
||||||
|
version = "1.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
description = "CraftLabs 授权客户端 CLI — 设备授权/查看/撤销/迁移"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "craft"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
craft-core = { path = "../craft-core" }
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
chrono = "0.4"
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
use craftlabs_auth_core::{
|
||||||
|
craft_activate, craft_check_license, craft_destroy, craft_free_license_info,
|
||||||
|
craft_get_license_info, craft_heartbeat, craft_initialize, craft_release,
|
||||||
|
};
|
||||||
|
use craftlabs_auth_core::device;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(name = "craft", version, about = "CraftLabs 授权客户端")]
|
||||||
|
struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
command: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum Commands {
|
||||||
|
/// 查看本地授权状态
|
||||||
|
Status,
|
||||||
|
/// 使用 SN 激活本机
|
||||||
|
Activate { sn: String },
|
||||||
|
/// 检查授权是否有效
|
||||||
|
Check,
|
||||||
|
/// 显示授权详情 + 功能特性
|
||||||
|
Info,
|
||||||
|
/// 撤销本机授权
|
||||||
|
Release,
|
||||||
|
/// 显示本机设备指纹
|
||||||
|
DeviceId,
|
||||||
|
/// 手动触发心跳
|
||||||
|
Heartbeat,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config_path() -> PathBuf {
|
||||||
|
let mut path = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
|
||||||
|
path.push("craftlabs-auth-config.json");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_config() -> String {
|
||||||
|
r#"{"provider":"selfhosted","schemaVersion":1,"scenario":"floating"}"#.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_or_create_config() -> String {
|
||||||
|
let path = get_config_path();
|
||||||
|
std::fs::read_to_string(&path).unwrap_or_else(|_| {
|
||||||
|
let cfg = default_config();
|
||||||
|
std::fs::write(&path, &cfg).ok();
|
||||||
|
cfg
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
let config = load_or_create_config();
|
||||||
|
let c_config = CString::new(config).unwrap();
|
||||||
|
|
||||||
|
match &cli.command {
|
||||||
|
Commands::Status => {
|
||||||
|
print_status();
|
||||||
|
}
|
||||||
|
Commands::Activate { sn } => {
|
||||||
|
let handle = craft_initialize(c_config.as_ptr());
|
||||||
|
if handle.is_null() {
|
||||||
|
eprintln!("错误: 初始化授权引擎失败");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
let c_sn = CString::new(sn.as_str()).unwrap();
|
||||||
|
let result = craft_activate(handle, c_sn.as_ptr(), std::ptr::null());
|
||||||
|
if result.success != 0 {
|
||||||
|
println!("✅ 激活成功");
|
||||||
|
save_config_with_sn(sn);
|
||||||
|
} else {
|
||||||
|
let msg = if result.message.is_null() { "未知错误" } else {
|
||||||
|
unsafe { std::ffi::CStr::from_ptr(result.message) }.to_str().unwrap_or("未知错误")
|
||||||
|
};
|
||||||
|
eprintln!("❌ 激活失败: {}", msg);
|
||||||
|
}
|
||||||
|
craft_destroy(handle);
|
||||||
|
}
|
||||||
|
Commands::Check => {
|
||||||
|
let handle = craft_initialize(c_config.as_ptr());
|
||||||
|
if handle.is_null() { eprintln!("初始化失败"); return; }
|
||||||
|
let result = craft_check_license(handle);
|
||||||
|
if result.success != 0 {
|
||||||
|
println!("✅ 授权有效");
|
||||||
|
} else {
|
||||||
|
println!("❌ 授权无效");
|
||||||
|
}
|
||||||
|
craft_destroy(handle);
|
||||||
|
}
|
||||||
|
Commands::Info => {
|
||||||
|
let handle = craft_initialize(c_config.as_ptr());
|
||||||
|
if handle.is_null() { eprintln!("初始化失败"); return; }
|
||||||
|
let info = craft_get_license_info(handle);
|
||||||
|
if !info.is_null() {
|
||||||
|
let i = unsafe { &*info };
|
||||||
|
let names = unsafe { std::slice::from_raw_parts(i.feature_names, i.feature_count as usize) };
|
||||||
|
let values = unsafe { std::slice::from_raw_parts(i.feature_values, i.feature_count as usize) };
|
||||||
|
println!("授权状态: {}", if i.is_licensed != 0 { "已授权" } else { "未授权" });
|
||||||
|
if i.expiration_date > 0 {
|
||||||
|
println!("过期时间: {}", i.expiration_date);
|
||||||
|
}
|
||||||
|
if i.feature_count > 0 {
|
||||||
|
println!("功能特性 ({}):", i.feature_count);
|
||||||
|
for idx in 0..i.feature_count as usize {
|
||||||
|
let name = if idx < names.len() && !names[idx].is_null() {
|
||||||
|
unsafe { std::ffi::CStr::from_ptr(names[idx]) }
|
||||||
|
.to_str().unwrap_or("?")
|
||||||
|
} else { "?" };
|
||||||
|
let val = if idx < values.len() { values[idx] } else { 0 };
|
||||||
|
println!(" {}: {}", name, if val != 0 { "✅" } else { "❌" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
craft_free_license_info(info);
|
||||||
|
} else {
|
||||||
|
println!("无法获取授权信息");
|
||||||
|
}
|
||||||
|
craft_destroy(handle);
|
||||||
|
}
|
||||||
|
Commands::Release => {
|
||||||
|
let handle = craft_initialize(c_config.as_ptr());
|
||||||
|
if handle.is_null() { eprintln!("初始化失败"); return; }
|
||||||
|
let result = craft_release(handle);
|
||||||
|
if result.success != 0 {
|
||||||
|
println!("✅ 授权已撤销");
|
||||||
|
} else {
|
||||||
|
println!("❌ 撤销失败");
|
||||||
|
}
|
||||||
|
craft_destroy(handle);
|
||||||
|
}
|
||||||
|
Commands::DeviceId => {
|
||||||
|
let fp = device::collect();
|
||||||
|
println!("设备指纹: {}", fp.composite_hash);
|
||||||
|
}
|
||||||
|
Commands::Heartbeat => {
|
||||||
|
let handle = craft_initialize(c_config.as_ptr());
|
||||||
|
if handle.is_null() { eprintln!("初始化失败"); return; }
|
||||||
|
let result = craft_heartbeat(handle);
|
||||||
|
if result.success != 0 {
|
||||||
|
println!("✅ 心跳成功");
|
||||||
|
} else {
|
||||||
|
println!("❌ 心跳失败");
|
||||||
|
}
|
||||||
|
craft_destroy(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_status() {
|
||||||
|
let config = load_or_create_config();
|
||||||
|
let c_config = CString::new(config).unwrap();
|
||||||
|
let handle = craft_initialize(c_config.as_ptr());
|
||||||
|
if handle.is_null() { eprintln!("初始化失败"); return; }
|
||||||
|
|
||||||
|
let check = craft_check_license(handle);
|
||||||
|
println!("授权状态: {}", if check.success != 0 { "✅ 有效" } else { "❌ 无效" });
|
||||||
|
|
||||||
|
let fp = device::collect();
|
||||||
|
println!("设备指纹: {}", fp.composite_hash);
|
||||||
|
|
||||||
|
craft_destroy(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_config_with_sn(sn: &str) {
|
||||||
|
let config = serde_json::json!({
|
||||||
|
"provider": "selfhosted",
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"scenario": "floating",
|
||||||
|
"floating": { "sn": sn }
|
||||||
|
});
|
||||||
|
let path = get_config_path();
|
||||||
|
std::fs::write(&path, serde_json::to_string_pretty(&config).unwrap()).ok();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user