Show TOTP codes in password details (#75)

This commit is contained in:
hugo committed 2026-08-11 23:40:24 +02:00
1 parent 9759162eff
commit 2026637a0e
9 files changed
+640 -110

No files matched your search

+70 -2
View File
@@ -145,6 +145,30 @@ impl MobileEntryCopy {
}
}
pub struct MobileEntryPresentation {
page: MobileEntryPage,
totp: Option<MobileTotpDetail>,
cache_notice: Option<String>,
}
impl MobileEntryPresentation {
pub fn page(&self) -> &MobileEntryPage {
&self.page
}
pub fn totp(&self) -> Option<&MobileTotpDetail> {
self.totp.as_ref()
}
pub fn cache_notice(&self) -> Option<&str> {
self.cache_notice.as_deref()
}
pub fn into_parts(self) -> (MobileEntryPage, Option<MobileTotpDetail>, Option<String>) {
(self.page, self.totp, self.cache_notice)
}
}
impl MobileAuthenticationState {
pub fn unlocked(self) -> bool {
self.unlocked
@@ -385,9 +409,32 @@ impl MobileAuthentication {
.map_err(MobileAuthenticationError::authentication)
}
pub fn entry_page(&self, path: &str) -> Result<MobileEntryPage, MobileAuthenticationError> {
pub fn entry_page(
&self,
path: &str,
unix_seconds: u64,
) -> Result<MobileEntryPresentation, MobileAuthenticationError> {
let document = self.open_active_document(path)?;
Ok(MobileEntryPage::from_document(&document))
let ciphertext = document
.original_ciphertext()
.ok_or_else(|| entry_detail("Password Entry Is Unavailable", "entry does not exist"))?;
let shared = self.status()?.watch_shared_totp_entries.clone();
let cache_path = self.config.source().with_file_name("totp-catalog.toml");
let reconciliation = MobileTotpService::new(&self.repository, &self.keys)
.reconcile_document(
&document,
ciphertext,
Some(unix_seconds),
&shared,
&cache_path,
)
.map_err(totp_error)?;
let (totp, cache_notice) = reconciliation.into_parts();
Ok(MobileEntryPresentation {
page: MobileEntryPage::from_document(&document),
totp,
cache_notice,
})
}
pub fn reveal_entry_field(
@@ -591,6 +638,7 @@ impl MobileAuthentication {
EntryDocumentService::new(&self.repository, &self.keys)
.save_recoverable(&document, None, &mut committer)
.map_err(document_error)?;
self.reconcile_saved_document(&document);
Ok(MobileEntryPage::from_document(&document))
}
@@ -764,6 +812,7 @@ impl MobileAuthentication {
self.restore_editor(editor, draft)?;
return Err(document_error(error));
}
self.reconcile_saved_document(draft.document());
Ok(MobileEntryPage::from_document(draft.document()))
}
@@ -954,6 +1003,25 @@ impl MobileAuthentication {
.open(path, &mut provider)
.map_err(document_error)
}
fn reconcile_saved_document(&self, document: &EntryDocument) {
let Ok(ciphertext) = self.repository.read_entry(document.path()) else {
return;
};
let Ok(status) = self.status() else {
return;
};
let shared = status.watch_shared_totp_entries.clone();
drop(status);
let cache_path = self.config.source().with_file_name("totp-catalog.toml");
let _ = MobileTotpService::new(&self.repository, &self.keys).reconcile_document(
document,
&ciphertext,
None,
&shared,
&cache_path,
);
}
}
struct KeyOnlyProvider<'a> {