use cyphr_storage::load_principal_from_commits;
use super::common::{
extract_genesis_from_commits, load_key_from_keystore, parse_principal_genesis, parse_store,
};
use crate::keystore::{JsonKeyStore, KeyStore};
use crate::{Cli, OutputFormat};
pub fn run(cli: &Cli, identity: &str) -> crate::Result<()> {
let store = parse_store(&cli.store)?;
let keystore = JsonKeyStore::open(&cli.keystore)?;
let pr = parse_principal_genesis(identity)?;
let commits = store.get_commits(&pr).unwrap_or_default();
let is_implicit_genesis = keystore.get(identity).is_ok();
let principal = if commits.is_empty() {
let key = load_key_from_keystore(&keystore, identity)?;
cyphr::Principal::implicit(key)?
} else if is_implicit_genesis {
let genesis_key = load_key_from_keystore(&keystore, identity)?;
let genesis = cyphr_storage::Genesis::Implicit(genesis_key);
load_principal_from_commits(genesis, &commits)?
} else {
let genesis = extract_genesis_from_commits(&commits, None)?;
load_principal_from_commits(genesis, &commits)?
};
match cli.output {
OutputFormat::Json => {
let active_keys: Vec<_> = principal
.active_keys()
.map(|k| {
serde_json::json!({
"tmb": k.tmb.to_b64(),
"alg": k.alg,
"tag": k.tag,
"first_seen": k.first_seen,
"last_used": k.last_used,
})
})
.collect();
let output = serde_json::json!({
"pr": format_pr(&principal),
"ps": format_ps(&principal),
"ks": format_ks(&principal),
"as": format_as(&principal),
"active_keys": active_keys,
"commit_count": principal.commits().count(),
});
println!("{}", serde_json::to_string_pretty(&output)?);
},
OutputFormat::Table => {
println!("Identity: {}", format_pr(&principal));
println!();
println!("State:");
println!(" PR: {}", format_pr(&principal));
println!(" PS: {}", format_ps(&principal));
println!(" KS: {}", format_ks(&principal));
println!(" AS: {}", format_as(&principal));
println!();
let active: Vec<_> = principal.active_keys().collect();
println!("Active Keys ({}):", active.len());
for key in active {
let tag_str = key.tag.as_deref().unwrap_or("-");
println!(" {} ({}) [{}]", key.tmb.to_b64(), key.alg, tag_str);
}
println!();
println!("Commits: {}", principal.commits().count());
},
}
Ok(())
}
fn format_ks(principal: &cyphr::Principal) -> String {
use base64ct::{Base64UrlUnpadded, Encoding};
let ks = principal.key_root();
let hash_alg = principal.hash_alg();
ks.get(hash_alg)
.map(Base64UrlUnpadded::encode_string)
.unwrap_or_else(|| "<no variant>".to_string())
}
fn format_as(principal: &cyphr::Principal) -> String {
use base64ct::{Base64UrlUnpadded, Encoding};
let auth_root = principal.auth_root();
let hash_alg = principal.hash_alg();
auth_root
.get(hash_alg)
.map(Base64UrlUnpadded::encode_string)
.unwrap_or_else(|| "<no variant>".to_string())
}
fn format_ps(principal: &cyphr::Principal) -> String {
use base64ct::{Base64UrlUnpadded, Encoding};
let ps = principal.pr();
let hash_alg = principal.hash_alg();
ps.get(hash_alg)
.map(Base64UrlUnpadded::encode_string)
.unwrap_or_else(|| "<no variant>".to_string())
}
fn format_pr(principal: &cyphr::Principal) -> String {
use base64ct::{Base64UrlUnpadded, Encoding};
let hash_alg = principal.hash_alg();
principal
.pg()
.and_then(|pr| pr.get(hash_alg))
.map(Base64UrlUnpadded::encode_string)
.unwrap_or_else(|| "<none>".to_string())
}