use owo_colors::OwoColorize;
use std::fs;
use std::process::Command;
use std::env;
use std::path::Path;
use clap::Subcommand;
static ZAKOSIGN_BINARY: &[u8] = include_bytes!("../bin/macos/arm64/zakosign");
#[derive(Subcommand)]
pub enum KeyCommands {
New {
name: String,
},
}
fn get_zakosign_path() -> Result<std::path::PathBuf, Box<dyn std::error::Error>> {
let temp_dir = env::temp_dir();
let zakosign_path = temp_dir.join("zakosign");
if !zakosign_path.exists() {
fs::write(&zakosign_path, ZAKOSIGN_BINARY)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
fs::set_permissions(&zakosign_path, fs::Permissions::from_mode(0o755))?;
}
}
Ok(zakosign_path)
}
pub fn execute_sign_file(file: String) {
println!("{} {}", "📋", "对文件进行签名".cyan());
let input_path = Path::new(&file);
if !input_path.exists() {
println!("{} 文件 '{}' 不存在", "❌", file);
return;
}
let ksmm_dir = Path::new(".ksmm");
let key_dir = ksmm_dir.join("key");
if !key_dir.exists() {
println!("{} 未找到密钥目录,请先使用 'ksmm key new <name>' 创建密钥", "❌");
println!("{} 或者手动将 ED25519 类型的 .pem 文件放置在 .ksmm/key/ 目录中", "💡".blue());
return;
}
let key_files = match fs::read_dir(&key_dir) {
Ok(entries) => {
entries
.filter_map(|entry| entry.ok())
.map(|entry| entry.path())
.filter(|path| path.extension().map_or(false, |ext| ext == "pem"))
.collect::<Vec<_>>()
}
Err(e) => {
println!("{} 读取密钥目录失败: {}", "❌", e);
return;
}
};
if key_files.is_empty() {
println!("{} 未找到任何 .pem 密钥文件,请先使用 'ksmm key new <name>' 创建密钥", "❌");
return;
}
let key_path = &key_files[0];
println!("{} 使用密钥: {}", "🔑", key_path.display());
let zakosign_path = match get_zakosign_path() {
Ok(path) => path,
Err(e) => {
println!("{} 获取 zakosign 失败: {}", "❌", e);
return;
}
};
let output_file = if file.ends_with(".zip") {
file.replace(".zip", "_signed.zip")
} else {
format!("{}_signed", file)
};
let output = match Command::new(&zakosign_path)
.args(&["sign", "--key", key_path.to_str().unwrap(), "--output", &output_file, "-f", &file])
.output()
{
Ok(output) => output,
Err(e) => {
println!("{} 执行签名命令失败: {}", "❌", e);
return;
}
};
if output.status.success() {
let signed_file = format!("{}_signed.zip", file.trim_end_matches(".zip"));
println!("{} 文件签名成功", "✅");
println!("{} 输入文件: {}", "📁", file);
println!("{} 输出文件: {}", "📁", signed_file);
} else {
println!("{} 签名失败", "❌");
if let Ok(stderr) = String::from_utf8(output.stderr) {
println!("错误信息: {}", stderr);
}
}
}
pub fn execute_key_command(key_command: KeyCommands) {
match key_command {
KeyCommands::New { name } => create_new_key(name),
}
}
fn create_new_key(name: String) {
println!("{} {}", "🔑", "创建新的签名密钥".cyan());
let key_name = if name.ends_with(".pem") {
name
} else {
format!("{}.pem", name)
};
let ksmm_dir = Path::new(".ksmm");
let key_dir = ksmm_dir.join("key");
if let Err(e) = fs::create_dir_all(&key_dir) {
println!("{} 创建密钥目录失败: {}", "❌", e);
return;
}
let key_path = key_dir.join(&key_name);
if key_path.exists() {
println!("{} 密钥文件 '{}' 已存在", "⚠️".yellow(), key_path.display());
return;
}
let zakosign_path = match get_zakosign_path() {
Ok(path) => path,
Err(e) => {
println!("{} 获取 zakosign 失败: {}", "❌", e);
return;
}
};
let output = match Command::new(&zakosign_path)
.args(&["key", "new", &key_path.to_string_lossy()])
.output()
{
Ok(output) => output,
Err(e) => {
println!("{} 执行密钥创建命令失败: {}", "❌", e);
return;
}
};
if output.status.success() {
println!("{} 密钥已创建: {}", "✅", key_path.display());
println!("{} 私钥文件: {}", "🔒", key_path.display());
} else {
println!("{} 密钥创建失败", "❌");
if let Ok(stderr) = String::from_utf8(output.stderr) {
println!("错误信息: {}", stderr);
}
if let Ok(stdout) = String::from_utf8(output.stdout) {
println!("标准输出: {}", stdout);
}
}
}