t_rust_less_lib/service/
secrets_provider.rs

1use crate::api::{ClipboardProviding, SecretVersion, PROPERTY_TOTP_URL};
2use crate::clipboard::SelectionProvider;
3use crate::otp::OTPAuthUrl;
4use log::{error, info};
5use std::time::{SystemTime, UNIX_EPOCH};
6use zeroize::{Zeroize, Zeroizing};
7
8#[derive(Clone, Zeroize)]
9#[zeroize(drop)]
10pub struct SecretsProvider {
11  store_name: String,
12  block_id: String,
13  secret_version: SecretVersion,
14  properties_stack: Vec<String>,
15}
16
17impl SecretsProvider {
18  pub fn new(store_name: String, block_id: String, secret_version: SecretVersion, properties: &[&str]) -> Self {
19    let properties_stack = properties
20      .iter()
21      .filter(|p| secret_version.properties.has_non_empty(p))
22      .rev()
23      .map(ToString::to_string)
24      .collect();
25    SecretsProvider {
26      store_name,
27      block_id,
28      secret_version,
29      properties_stack,
30    }
31  }
32}
33
34impl SelectionProvider for SecretsProvider {
35  fn current_selection(&self) -> Option<ClipboardProviding> {
36    self
37      .properties_stack
38      .last()
39      .cloned()
40      .map(|property| ClipboardProviding {
41        store_name: self.store_name.clone(),
42        block_id: self.block_id.clone(),
43        secret_name: self.secret_version.name.clone(),
44        property,
45      })
46  }
47
48  fn get_selection_value(&self) -> Option<Zeroizing<String>> {
49    let property = self.properties_stack.last()?;
50    let value = self.secret_version.properties.get(property)?;
51
52    if property == PROPERTY_TOTP_URL {
53      info!("Providing TOTP of {}", self.secret_version.secret_id);
54      match OTPAuthUrl::parse(value) {
55        Ok(otpauth) => {
56          let (token, _) = otpauth.generate(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs());
57          Some(Zeroizing::new(token))
58        }
59        Err(error) => {
60          error!("Invalid OTPAuth url: {error}");
61          None
62        }
63      }
64    } else {
65      info!("Providing {} of {}", property, self.secret_version.secret_id);
66      Some(Zeroizing::new(value.clone()))
67    }
68  }
69
70  fn next_selection(&mut self) {
71    self.properties_stack.pop();
72  }
73}