Implement structured Android entry viewer (#99)
Android ARM verification / rust (push) Failing after 47m18s
Android ARM verification / android (push) Failing after 8s
Dependency security audit / rustsec (push) Successful in 22s

This commit is contained in:
hugo committed 2026-10-09 17:36:38 +02:00
1 parent 647dc1bb4b
commit c0ba6d43d8
29 files changed
+1768 -78

No files matched your search

+76
View File
@@ -1006,6 +1006,7 @@ pub struct MobileEntrySection {
#[derive(Clone, uniffi::Record)]
pub struct MobileEntryPage {
pub id: String,
pub revision: String,
pub title: String,
pub sections: Vec<MobileEntrySection>,
}
@@ -1014,6 +1015,7 @@ impl From<StorageEntryPage> for MobileEntryPage {
fn from(page: StorageEntryPage) -> Self {
Self {
id: page.id().to_owned(),
revision: page.revision().to_owned(),
title: page.title().to_owned(),
sections: page
.sections()
@@ -1221,6 +1223,7 @@ pub struct MobileTotpDetail {
pub account: String,
pub code: String,
pub valid_until: u64,
pub remaining_seconds: u64,
pub period: u64,
#[cfg(feature = "watch")]
pub shared_with_watch: bool,
@@ -1237,6 +1240,7 @@ impl From<StorageTotpDetail> for MobileTotpDetail {
code: String::from_utf8(detail.code().expose().to_vec())
.expect("storage-generated TOTP codes are ASCII"),
valid_until: detail.valid_until(),
remaining_seconds: detail.remaining_seconds(),
period: detail.period(),
#[cfg(feature = "watch")]
shared_with_watch: detail.shared_with_watch(),
@@ -1831,6 +1835,78 @@ impl MobileAuthentication {
.map_err(Into::into)
}
pub fn reveal_presented_entry_field(
&self,
path: String,
field_id: u64,
revision: String,
) -> Result<String, MobileAuthenticationFfiError> {
self.authentication
.reveal_presented_entry_field(&path, field_id, &revision)
.map_err(Into::into)
}
pub fn copy_presented_entry_field(
&self,
path: String,
field_id: u64,
revision: String,
) -> Result<MobileEntryCopy, MobileAuthenticationFfiError> {
self.authentication
.copy_presented_entry_field(&path, field_id, &revision)
.map(Into::into)
.map_err(Into::into)
}
pub fn replace_presented_entry_field(
&self,
path: String,
field_id: u64,
revision: String,
value: String,
) -> Result<MobileEntryPage, MobileAuthenticationFfiError> {
self.authentication
.replace_presented_entry_field(&path, field_id, &revision, value)
.map(Into::into)
.map_err(Into::into)
}
pub fn refresh_entry_presentation(
&self,
path: String,
revision: String,
unix_seconds: u64,
) -> Result<MobileEntryPresentation, MobileAuthenticationFfiError> {
self.authentication
.refresh_entry_presentation(&path, &revision, unix_seconds)
.map(Into::into)
.map_err(Into::into)
}
pub fn copy_presented_totp_code(
&self,
path: String,
revision: String,
unix_seconds: u64,
) -> Result<MobileEntryCopy, MobileAuthenticationFfiError> {
self.authentication
.copy_presented_totp_code(&path, &revision, unix_seconds)
.map(Into::into)
.map_err(Into::into)
}
pub fn prepare_presented_entry_mutation(
&self,
path: String,
revision: String,
action: MobileMutationAction,
) -> Result<MobileMutationPlan, MobileAuthenticationFfiError> {
self.authentication
.prepare_presented_entry_mutation(&path, &revision, action.into())
.map(Into::into)
.map_err(Into::into)
}
pub fn copy_entry_field(
&self,
path: String,
+28 -8
View File
@@ -391,19 +391,39 @@ impl ClipboardBackend for ClipboardAdapter {
pub fn copy_mobile_entry(
copy: MobileEntryCopy,
clipboard: Arc<dyn MobileClipboard>,
) -> Result<MobileClipboardDisposition, MobilePlatformFfiError> {
copy_entry(copy, clipboard, false)
}
/// Android never retains or resurrects previous clipboard contents.
#[uniffi::export]
pub fn copy_mobile_entry_clearing(
copy: MobileEntryCopy,
clipboard: Arc<dyn MobileClipboard>,
) -> Result<MobileClipboardDisposition, MobilePlatformFfiError> {
copy_entry(copy, clipboard, true)
}
fn copy_entry(
copy: MobileEntryCopy,
clipboard: Arc<dyn MobileClipboard>,
clear: bool,
) -> Result<MobileClipboardDisposition, MobilePlatformFfiError> {
let timeout = presentation::ClipboardTimeout::new(Duration::from_secs(copy.timeout_seconds))
.map_err(|_| MobilePlatformFfiError::ClipboardFailed)?;
let mut manager =
presentation::ClipboardManager::new(ClipboardAdapter(Arc::clone(&clipboard)), timeout);
manager
.copy_with(
&SecretBytes::new(copy.value.into_bytes()),
|duration| match clipboard.wait_for_timeout(duration.as_millis() as u64) {
MobileClipboardWait::Elapsed => presentation::ClipboardWait::Elapsed,
MobileClipboardWait::Cancelled => presentation::ClipboardWait::Cancelled,
},
)
let wait = |duration: Duration| match clipboard.wait_for_timeout(duration.as_millis() as u64) {
MobileClipboardWait::Elapsed => presentation::ClipboardWait::Elapsed,
MobileClipboardWait::Cancelled => presentation::ClipboardWait::Cancelled,
};
let value = SecretBytes::new(copy.value.into_bytes());
let result = if clear {
manager.copy_clearing_with(&value, wait)
} else {
manager.copy_with(&value, wait)
};
result
.map(|result| match result {
presentation::ClipboardDisposition::RestoredPrevious => {
MobileClipboardDisposition::RestoredPrevious