Add subcommand to list local certificates
- Add `husk locals list` to list all certificates which would be used by husk, but are not introduced by another certificate. These certificates are added 'locally'. - Refcator the code so that `local` -> `locals`.
This commit is contained in:
+10
-10
@@ -25,7 +25,7 @@ pub struct CliArgs {
|
||||
pub enum HuskSubcommands {
|
||||
Daemon(DaemonCommand),
|
||||
Introducer(IntroducerCommand),
|
||||
Local(LocalCommand),
|
||||
Locals(LocalsCommand),
|
||||
}
|
||||
|
||||
// Daemon subcommands
|
||||
@@ -134,23 +134,23 @@ pub struct IntroducerRemoveCommand {
|
||||
disable_colored_help = true,
|
||||
disable_version_flag = true,
|
||||
)]
|
||||
pub struct LocalCommand {
|
||||
pub struct LocalsCommand {
|
||||
#[clap(subcommand)]
|
||||
pub subcommand: LocalSubcommand,
|
||||
pub subcommand: LocalsSubcommand,
|
||||
}
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum LocalSubcommand {
|
||||
Add(LocalAddCommand),
|
||||
Remove(LocalRemoveCommand),
|
||||
pub enum LocalsSubcommand {
|
||||
Add(LocalsAddCommand),
|
||||
Remove(LocalsRemoveCommand),
|
||||
List
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "local_add",
|
||||
name = "locals_add",
|
||||
about = "Add an authenticated certificate.",
|
||||
)]
|
||||
pub struct LocalAddCommand {
|
||||
pub struct LocalsAddCommand {
|
||||
#[clap(
|
||||
long = "cert",
|
||||
help = "Certificate to add."
|
||||
@@ -160,10 +160,10 @@ pub struct LocalAddCommand {
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "local_remove",
|
||||
name = "locals_remove",
|
||||
about = "Certificate to remove.",
|
||||
)]
|
||||
pub struct LocalRemoveCommand {
|
||||
pub struct LocalsRemoveCommand {
|
||||
#[clap(
|
||||
long = "cert",
|
||||
help = "Certificate to removed."
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ use crate::config::HuskConfigContainer;
|
||||
|
||||
pub mod daemon;
|
||||
pub mod introducer;
|
||||
pub mod local;
|
||||
pub mod locals;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum CommandError {
|
||||
@@ -31,8 +31,8 @@ pub async fn dispatch(cli: CliArgs, config: HuskConfigContainer) -> Result<()> {
|
||||
HuskSubcommands::Introducer(subcmd) => {
|
||||
commands::introducer::dispatch(subcmd, config).await?;
|
||||
},
|
||||
HuskSubcommands::Local(subcmd) => {
|
||||
commands::local::dispatch(subcmd, config).await?;
|
||||
HuskSubcommands::Locals(subcmd) => {
|
||||
commands::locals::dispatch(subcmd, config).await?;
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cli::cli_args::{LocalCommand, LocalSubcommand};
|
||||
use crate::config::HuskConfigContainer;
|
||||
|
||||
pub mod add;
|
||||
pub mod remove;
|
||||
|
||||
pub async fn dispatch(cmd: LocalCommand, config: HuskConfigContainer) -> Result<()> {
|
||||
match cmd.subcommand {
|
||||
LocalSubcommand::Add(add_cmd) => {
|
||||
add::dispatch(add_cmd, &config).await?;
|
||||
},
|
||||
LocalSubcommand::Remove(rm_cmd) => {
|
||||
remove::dispatch(rm_cmd, &config).await?;
|
||||
},
|
||||
LocalSubcommand::List => {
|
||||
println!("list");
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cli::cli_args::LocalRemoveCommand;
|
||||
use crate::config::HuskConfigContainer;
|
||||
|
||||
pub async fn dispatch(cmd: LocalRemoveCommand, _config: &HuskConfigContainer) -> Result<()> {
|
||||
println!("remove");
|
||||
println!(" {:?}", cmd.cert);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cli::cli_args::{LocalsCommand, LocalsSubcommand};
|
||||
use crate::common::crypto;
|
||||
use crate::config::HuskConfigContainer;
|
||||
use crate::types::husk_context::HuskContext;
|
||||
|
||||
pub mod add;
|
||||
pub mod remove;
|
||||
|
||||
pub async fn dispatch(cmd: LocalsCommand, config: HuskConfigContainer) -> Result<()> {
|
||||
match cmd.subcommand {
|
||||
LocalsSubcommand::Add(add_cmd) => {
|
||||
add::dispatch(add_cmd, &config).await?;
|
||||
},
|
||||
LocalsSubcommand::Remove(rm_cmd) => {
|
||||
remove::dispatch(rm_cmd, &config).await?;
|
||||
},
|
||||
LocalsSubcommand::List => {
|
||||
let context = HuskContext::new(&config.into())?;
|
||||
|
||||
println!("list locals");
|
||||
for local in crypto::get_locals(
|
||||
&context.cert_store,
|
||||
&context.policy,
|
||||
context.local_trust_root.fingerprint()) {
|
||||
|
||||
println!("{}", local);
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cli::cli_args::LocalAddCommand;
|
||||
use crate::cli::cli_args::LocalsAddCommand;
|
||||
use crate::config::HuskConfigContainer;
|
||||
|
||||
pub async fn dispatch(cmd: LocalAddCommand, _config: &HuskConfigContainer) -> Result<()> {
|
||||
pub async fn dispatch(cmd: LocalsAddCommand, _config: &HuskConfigContainer) -> Result<()> {
|
||||
println!("add");
|
||||
println!(" {:?}", cmd.cert_file);
|
||||
Ok(())
|
||||
@@ -0,0 +1,12 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cli::cli_args::LocalsRemoveCommand;
|
||||
use crate::config::HuskConfigContainer;
|
||||
|
||||
pub async fn dispatch(cmd: LocalsRemoveCommand, _config: &HuskConfigContainer) -> Result<()> {
|
||||
println!("remove");
|
||||
println!(" {:?}", cmd.cert);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+55
-1
@@ -4,6 +4,7 @@ use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
|
||||
use anyhow;
|
||||
@@ -20,7 +21,7 @@ use sequoia_openpgp::cert::raw::RawCertParser;
|
||||
use sequoia_openpgp::types::SignatureType;
|
||||
use sequoia_cert_store::{Store, CertStore, LazyCert, StoreUpdate};
|
||||
use sequoia_cert_store::store::MergePublicCollectStats;
|
||||
use sequoia_wot::{self as wot};
|
||||
use sequoia_wot::{self as wot, CertSynopsis};
|
||||
use wot::store::Store as _;
|
||||
use wot::{Depth, Path};
|
||||
|
||||
@@ -309,6 +310,59 @@ pub fn get_introducers<'c>(cert_store: &CertStore<'c>, policy: &StandardPolicy,
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns all local certificates available in cert_store.
|
||||
pub fn get_locals<'c>(cert_store: &CertStore<'c>, policy: &StandardPolicy, local_trust_root: Fingerprint) -> Vec<CertSynopsis> {
|
||||
|
||||
let mut set = HashMap::new();
|
||||
let mut introducers = HashSet::new();
|
||||
let mut targets = Vec::new();
|
||||
let local_root_fpr = local_trust_root.clone();
|
||||
|
||||
let trust_roots = vec![(local_trust_root, wot::FULLY_TRUSTED)];
|
||||
let wot_store = wot::store::CertStore::from_store(cert_store, policy, None);
|
||||
let n = wot::NetworkBuilder::rooted(&wot_store, &*trust_roots)
|
||||
.build();
|
||||
|
||||
n.certified_userids().iter().for_each(|(fpr, user_id)| {
|
||||
let paths = n.authenticate(user_id, fpr, wot::FULLY_TRUSTED);
|
||||
|
||||
paths.iter().for_each(|(path, amount)| {
|
||||
if *amount == wot::FULLY_TRUSTED {
|
||||
if path.residual_depth() == Depth::Limit(0) {
|
||||
// A leaf, which is not an introducer itself.
|
||||
targets.push(path.clone());
|
||||
} else {
|
||||
// Introducer encountered. Do not add the local trust
|
||||
// root to the introducers HashSet, otherwise all local
|
||||
// certificates would be viewed as introduced.
|
||||
if path.target().fingerprint() != local_root_fpr {
|
||||
introducers.insert(path.target().fingerprint());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
for p in targets {
|
||||
let cert_synopsis = p.target().clone();
|
||||
|
||||
match set.entry(cert_synopsis.fingerprint()) {
|
||||
Vacant(_) => {
|
||||
// Only consider non introduced certificates.
|
||||
if !p.certifications().any(|c|
|
||||
introducers.contains(&c.issuer().fingerprint())) {
|
||||
|
||||
set.insert(cert_synopsis.fingerprint(), cert_synopsis);
|
||||
}
|
||||
},
|
||||
// The target is already known, do nothing.
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
set.into_values().collect()
|
||||
}
|
||||
|
||||
|
||||
/// Checks if a message contains the OpenPGP artifacts of an encrypted message.
|
||||
pub fn is_encrypted(body: &Bytes) -> bool {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user