Skip to main content

pubhubs/cli/
tools.rs

1use crate::common::elgamal::Encoding as _;
2use anyhow::Result;
3
4#[derive(clap::Args, Debug)]
5pub struct ToolsArgs {
6    #[command(subcommand)]
7    command: Commands,
8}
9
10impl ToolsArgs {
11    pub fn run(self, _spec: &mut clap::Command) -> Result<()> {
12        match self.command {
13            Commands::Generate(args) => args.run(),
14            Commands::YiviEpoch(args) => args.run(),
15        }
16    }
17}
18
19#[derive(clap::Subcommand, Debug)]
20enum Commands {
21    /// Generates identifiers and/or key material
22    Generate(generate::Args),
23
24    /// Prints information about the current Yivi epoch
25    YiviEpoch(YiviEpochArgs),
26}
27
28#[derive(clap::Args, Debug)]
29struct YiviEpochArgs {
30    /// Print information about the NUMBERth yivi epoch
31    #[arg(long, value_name = "NUMBER", conflicts_with = "at")]
32    nr: Option<u64>,
33
34    /// Print information about the yivi epoch at the given TIMESTAMP such as '2025-12-17 15:15:15'
35    #[arg(
36        long,
37        value_name = "TIMESTAMP",
38        value_parser = humantime::parse_rfc3339_weak,
39        conflicts_with = "nr"
40    )]
41    at: Option<std::time::SystemTime>,
42}
43
44impl YiviEpochArgs {
45    fn run(self) -> Result<()> {
46        let epoch = if let Some(nr) = self.nr {
47            crate::servers::yivi::Epoch::with_seqnr(nr)
48        } else if let Some(at) = self.at {
49            let nd: crate::api::NumericDate = at.into();
50            crate::servers::yivi::Epoch::from(nd)
51        } else {
52            crate::servers::yivi::Epoch::current()
53        };
54
55        print!("{}", epoch);
56
57        Ok(())
58    }
59}
60
61/// Implementation details of [`Commands::Generate`].
62mod generate {
63    use super::*;
64
65    #[derive(clap::Args, Debug)]
66    pub(super) struct Args {
67        #[command(subcommand)]
68        command: Commands,
69    }
70
71    impl Args {
72        pub(super) fn run(self) -> Result<()> {
73            match self.command {
74                Commands::Id(args) => args.run(),
75                Commands::Scalar(args) => args.run(),
76                Commands::SigningKey(args) => args.run(),
77            }
78        }
79    }
80
81    #[derive(clap::Subcommand, Debug)]
82    enum Commands {
83        /// Generate a random identifier for e.g. a hub, attribute type, ...
84        Id(IdArgs),
85
86        /// Generate a random ristretto25519 scalar to be used e.g. as elgamal private key
87        Scalar(ScalarArgs),
88
89        /// Generate a random ed25519 signing key
90        SigningKey(SigningKeyArgs),
91    }
92
93    #[derive(clap::Args, Debug)]
94    struct IdArgs {}
95
96    impl IdArgs {
97        fn run(self) -> Result<()> {
98            println!("{}", crate::id::Id::random());
99
100            Ok(())
101        }
102    }
103
104    #[derive(clap::Args, Debug)]
105    struct ScalarArgs {}
106
107    impl ScalarArgs {
108        fn run(self) -> Result<()> {
109            let pk = crate::common::elgamal::PrivateKey::random();
110
111            println!("x (private key): {}", pk.to_hex());
112            println!("xB (public key): {}", pk.public_key().to_hex());
113
114            Ok(())
115        }
116    }
117
118    #[derive(clap::Args, Debug)]
119
120    struct SigningKeyArgs {}
121
122    impl SigningKeyArgs {
123        fn run(self) -> Result<()> {
124            let sk = crate::api::SigningKey::generate();
125            let vk: crate::api::VerifyingKey = sk.verifying_key().into();
126
127            println!("  signing key: {sk}");
128            println!("verifying key: {vk}");
129
130            Ok(())
131        }
132    }
133}