aboutsummaryrefslogtreecommitdiffstats
path: root/src/bin/rbw/commands.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/rbw/commands.rs')
-rw-r--r--src/bin/rbw/commands.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index 3180cc9..e5858b6 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -545,6 +545,40 @@ pub fn get(
Ok(())
}
+pub fn code(
+ name: &str,
+ user: Option<&str>,
+ folder: Option<&str>,
+) -> anyhow::Result<()> {
+ unlock()?;
+
+ let db = load_db()?;
+
+ let desc = format!(
+ "{}{}",
+ user.map(|s| format!("{}@", s))
+ .unwrap_or_else(|| "".to_string()),
+ name
+ );
+
+ let (_, decrypted) = find_entry(&db, name, user, folder)
+ .with_context(|| format!("couldn't find entry for '{}'", desc))?;
+
+ if let DecryptedData::Login { totp, .. } = decrypted.data {
+ if let Some(totp) = totp {
+ println!("{}", generate_totp(&totp)?)
+ } else {
+ return Err(anyhow::anyhow!(
+ "entry does not contain a totp secret"
+ ));
+ }
+ } else {
+ return Err(anyhow::anyhow!("not a login entry"));
+ }
+
+ Ok(())
+}
+
pub fn add(
name: &str,
username: Option<&str>,
@@ -1392,6 +1426,25 @@ fn remove_db() -> anyhow::Result<()> {
}
}
+fn generate_totp(secret: &str) -> anyhow::Result<String> {
+ Ok(format!(
+ "{}",
+ oath::totp_raw_now(
+ &base32::decode(
+ base32::Alphabet::RFC4648 { padding: false },
+ secret
+ )
+ .ok_or_else(|| anyhow::anyhow!(
+ "totp secret was not valid base32"
+ ))?,
+ 6,
+ 0,
+ 30,
+ &oath::HashType::SHA1,
+ )
+ ))
+}
+
#[cfg(test)]
mod test {
use super::*;