use std::path::PathBuf;
use aimo_core::keys::{MetadataV1, Scope, SecretKeyV1, Wallet};
use chrono::{Duration, Utc};
use solana_sdk::{signature::Keypair, signer::Signer};
use aimo_core::utils::id::create_keypair_from_file;
pub fn generate_secret_key(
tag: &str,
valid_for: u32,
scopes: Vec<Scope>,
usage_limit: u64,
id: Option<PathBuf>,
) -> anyhow::Result<String> {
let keypair = create_keypair_from_file(id)?;
let valid_for = Duration::days(valid_for.into()).num_milliseconds();
let created_at = Utc::now().timestamp_millis();
let metadata = MetadataV1 {
created_at,
usage_limit,
valid_for,
scopes,
};
generate_key_with(&keypair, tag, metadata)
}
fn generate_key_with(keypair: &Keypair, tag: &str, metadata: MetadataV1) -> anyhow::Result<String> {
let canonical_metadata = metadata.to_canonical_json()?;
let signature = keypair
.sign_message(canonical_metadata.as_bytes())
.to_string();
let signer = keypair.pubkey().to_string();
let payload = SecretKeyV1 {
version: 1,
wallet: Wallet::Solana,
signer,
signature,
metadata,
};
Ok(payload.into_string(tag)?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generated_valid_key() {
let keypair = Keypair::new();
let valid_for = Duration::days(30).num_milliseconds();
let created_at = Utc::now().timestamp_millis();
let scopes = vec![Scope::CompletionModel];
let metadata = MetadataV1 {
created_at,
usage_limit: 1000,
valid_for,
scopes,
};
let sk = generate_key_with(&keypair, "test", metadata.clone()).unwrap();
let (scope, key) = SecretKeyV1::decode(&sk).unwrap();
assert_eq!(scope, "test");
assert!(key.verify_signature().is_ok());
assert_eq!(key.signer, keypair.pubkey().to_string());
assert_eq!(key.metadata, metadata);
}
}