Implement OTP clipboard and QR TUI

This commit is contained in:
Hermes Agent
2026-08-10 11:11:53 +00:00
parent 1850846696
commit 71bbff934e
8 changed files with 1021 additions and 28 deletions

View File

@@ -427,6 +427,7 @@ impl OtpWriteOutcome {
pub struct OtpCodeOutcome {
code: SecretBytes,
counter: Option<u64>,
valid_until: Option<u64>,
}
impl OtpCodeOutcome {
@@ -437,6 +438,15 @@ impl OtpCodeOutcome {
pub fn counter(&self) -> Option<u64> {
self.counter
}
pub fn valid_until(&self) -> Option<u64> {
self.valid_until
}
pub fn remaining_at(&self, unix_seconds: u64) -> Option<u64> {
self.valid_until
.map(|valid_until| valid_until.saturating_sub(unix_seconds))
}
}
impl fmt::Debug for OtpCodeOutcome {
@@ -445,6 +455,7 @@ impl fmt::Debug for OtpCodeOutcome {
.debug_struct("OtpCodeOutcome")
.field("code", &"[REDACTED]")
.field("counter", &self.counter)
.field("valid_until", &self.valid_until)
.finish()
}
}
@@ -463,6 +474,10 @@ impl<'a> OtpService<'a> {
OtpUri::parse_str(encoded).map(|_| ())
}
pub fn validate_input(input: OtpInput) -> Result<(), OtpError> {
OtpUri::parse(input.into_secret()).map(|_| ())
}
pub fn prepare_insert(
&self,
request: &OtpInsertRequest,
@@ -639,9 +654,16 @@ impl<'a> OtpService<'a> {
) -> Result<OtpCodeOutcome, OtpError> {
let (path, original, plaintext, range, uri) = self.load_code_entry(entry, provider)?;
if uri.kind() == OtpKind::Totp {
let period = uri.period().ok_or(OtpError::NotTotp)?;
return Ok(OtpCodeOutcome {
code: uri.code_at(unix_seconds)?,
counter: None,
valid_until: Some(
(unix_seconds / period)
.checked_add(1)
.and_then(|counter| counter.checked_mul(period))
.ok_or(OtpError::CounterOverflow)?,
),
});
}
let entry = path.to_string();
@@ -692,6 +714,13 @@ impl<'a> OtpService<'a> {
OtpKind::Totp => Ok(OtpCodeOutcome {
code: uri.code_at(unix_seconds)?,
counter: None,
valid_until: Some({
let period = uri.period().ok_or(OtpError::NotTotp)?;
(unix_seconds / period)
.checked_add(1)
.and_then(|counter| counter.checked_mul(period))
.ok_or(OtpError::CounterOverflow)?
}),
}),
OtpKind::Hotp => {
let (counter, incremented) = uri.incremented_hotp()?;
@@ -714,6 +743,7 @@ impl<'a> OtpService<'a> {
Ok(OtpCodeOutcome {
code,
counter: Some(counter),
valid_until: None,
})
}
}