1use std::io::BufRead;
2use std::sync::Arc;
3use std::time::Duration;
4
5use clap::Subcommand;
6
7use crate::admin;
8use crate::cli::CliError;
9use crate::config::Config;
10use crate::sqlite::db::Database;
11
12#[derive(Subcommand)]
13pub enum NonceCommand {
14 Cleanup {
16 #[arg(long = "ttl-seconds")]
17 ttl_seconds: Option<u64>,
18 },
19}
20
21pub async fn run_nonce_command(
22 command: NonceCommand,
23 yes: bool,
24 reader: &mut impl BufRead,
25 config: &Config,
26 database: Arc<Database>,
27) -> Result<(), CliError> {
28 match command {
29 NonceCommand::Cleanup { ttl_seconds } => {
30 let ttl = Duration::from_secs(ttl_seconds.unwrap_or(config.nonce.ttl_seconds));
31 match admin::confirm_cleanup_nonces(ttl, yes, reader, database).await? {
32 None => println!("Cancelled."),
33 Some(removed) => println!("Removed {removed} nonce(s)."),
34 }
35 }
36 }
37 Ok(())
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[tokio::test]
47 async fn cleanup_honours_the_configured_ttl_and_the_prompt() {
48 let database = Arc::new(
49 crate::sqlite::db::Database::connect_in_memory()
50 .await
51 .unwrap(),
52 );
53 let mut config = Config::default();
54 config.nonce.ttl_seconds = 1;
55
56 let mut declined: &[u8] = b"n\n";
57 run_nonce_command(
58 NonceCommand::Cleanup { ttl_seconds: None },
59 false,
60 &mut declined,
61 &config,
62 database.clone(),
63 )
64 .await
65 .unwrap();
66
67 let mut reader: &[u8] = &[];
68 run_nonce_command(
69 NonceCommand::Cleanup {
70 ttl_seconds: Some(60),
71 },
72 true,
73 &mut reader,
74 &config,
75 database,
76 )
77 .await
78 .unwrap();
79 }
80}