auths_cli/commands/
anchor.rs1use std::path::PathBuf;
9
10use anyhow::{Result, anyhow};
11use auths_anchor::DuplicityProof;
12use clap::{Parser, Subcommand};
13
14use crate::config::CliConfig;
15
16#[derive(Parser, Debug, Clone)]
18pub struct AnchorCommand {
19 #[command(subcommand)]
20 pub subcommand: AnchorSubcommand,
21}
22
23#[derive(Subcommand, Debug, Clone)]
25pub enum AnchorSubcommand {
26 Verify {
32 #[clap(long)]
34 proof: PathBuf,
35 },
36}
37
38pub fn handle_anchor(cmd: AnchorCommand) -> Result<()> {
48 match cmd.subcommand {
49 AnchorSubcommand::Verify { proof } => verify_duplicity(proof),
50 }
51}
52
53fn verify_duplicity(path: PathBuf) -> Result<()> {
55 let bytes = if path.as_os_str() == "-" {
56 let mut buf = Vec::new();
57 std::io::Read::read_to_end(&mut std::io::stdin(), &mut buf)
58 .map_err(|e| anyhow!("could not read the proof from stdin: {e}"))?;
59 buf
60 } else {
61 std::fs::read(&path).map_err(|e| anyhow!("could not read {}: {e}", path.display()))?
62 };
63 let proof: DuplicityProof = serde_json::from_slice(&bytes)
64 .map_err(|e| anyhow!("not a readable duplicity proof: {e}"))?;
65 match proof.verify() {
66 Ok(()) => {
67 println!(
68 "DUPLICITY PROVEN (offline, no witness contacted)\n \
69 seed {}\n index {}\n heads {} / {}\n \
70 => one party key signed two heads at one index. CHEAT PROVEN.",
71 proof.seed_id.to_hex(),
72 proof.index,
73 proof.anchor_a.head.to_hex(),
74 proof.anchor_b.head.to_hex(),
75 );
76 Ok(())
77 }
78 Err(e) => Err(anyhow!("INVALID duplicity proof: {e}")),
79 }
80}
81
82impl crate::commands::executable::ExecutableCommand for AnchorCommand {
83 fn execute(&self, _ctx: &CliConfig) -> Result<()> {
84 handle_anchor(self.clone())
85 }
86}