Implement structured iPhone entry viewer

This commit is contained in:
2026-08-11 19:59:18 +02:00
parent 873db91204
commit 900e62e523
9 changed files with 1728 additions and 92 deletions

View File

@@ -12,6 +12,10 @@ use ironstorage::{
MobileAuthenticationError as StorageAuthenticationError,
MobileAuthenticationErrorKind as StorageAuthenticationErrorKind,
MobileAuthenticationState as StorageAuthenticationState,
MobileEntryCopy as StorageEntryCopy,
},
mobile_entry::{
MobileEntryPage as StorageEntryPage, MobileEntrySectionKind as StorageEntrySectionKind,
},
mobile_home::{
self, MobileHomeChangeKind as StorageHomeChangeKind,
@@ -532,6 +536,103 @@ pub struct MobileAuthenticationState {
pub remaining_seconds: u64,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
pub enum MobileEntrySectionKind {
Password,
Details,
OneTimePassword,
Notes,
}
impl From<StorageEntrySectionKind> for MobileEntrySectionKind {
fn from(kind: StorageEntrySectionKind) -> Self {
match kind {
StorageEntrySectionKind::Password => Self::Password,
StorageEntrySectionKind::Details => Self::Details,
StorageEntrySectionKind::OneTimePassword => Self::OneTimePassword,
StorageEntrySectionKind::Notes => Self::Notes,
}
}
}
#[derive(Clone, uniffi::Record)]
pub struct MobileEntryField {
pub id: u64,
pub label: String,
pub system_image: String,
pub value: Option<String>,
pub masked_value: String,
pub detail: Option<String>,
pub diagnostic: Option<String>,
pub sensitive: bool,
pub multiline: bool,
pub selectable: bool,
pub editable: bool,
}
#[derive(Clone, uniffi::Record)]
pub struct MobileEntrySection {
pub kind: MobileEntrySectionKind,
pub title: String,
pub fields: Vec<MobileEntryField>,
}
#[derive(Clone, uniffi::Record)]
pub struct MobileEntryPage {
pub id: String,
pub title: String,
pub sections: Vec<MobileEntrySection>,
}
impl From<StorageEntryPage> for MobileEntryPage {
fn from(page: StorageEntryPage) -> Self {
Self {
id: page.id().to_owned(),
title: page.title().to_owned(),
sections: page
.sections()
.iter()
.map(|section| MobileEntrySection {
kind: section.kind().into(),
title: section.title().to_owned(),
fields: section
.fields()
.iter()
.map(|field| MobileEntryField {
id: field.id(),
label: field.label().to_owned(),
system_image: field.system_image().to_owned(),
value: field.value().map(str::to_owned),
masked_value: field.masked_value().to_owned(),
detail: field.detail().map(str::to_owned),
diagnostic: field.diagnostic().map(str::to_owned),
sensitive: field.sensitive(),
multiline: field.multiline(),
selectable: field.selectable(),
editable: field.editable(),
})
.collect(),
})
.collect(),
}
}
}
#[derive(Clone, uniffi::Record)]
pub struct MobileEntryCopy {
pub value: String,
pub timeout_seconds: u64,
}
impl From<StorageEntryCopy> for MobileEntryCopy {
fn from(copy: StorageEntryCopy) -> Self {
Self {
value: copy.value().to_owned(),
timeout_seconds: copy.timeout_seconds(),
}
}
}
impl From<StorageAuthenticationState> for MobileAuthenticationState {
fn from(state: StorageAuthenticationState) -> Self {
Self {
@@ -616,6 +717,49 @@ impl MobileAuthentication {
.map_err(Into::into)
}
pub fn entry_page(
&self,
path: String,
) -> Result<MobileEntryPage, MobileAuthenticationFfiError> {
self.authentication
.entry_page(&path)
.map(Into::into)
.map_err(Into::into)
}
pub fn reveal_entry_field(
&self,
path: String,
field: u64,
) -> Result<String, MobileAuthenticationFfiError> {
self.authentication
.reveal_entry_field(&path, field)
.map_err(Into::into)
}
pub fn copy_entry_field(
&self,
path: String,
field: u64,
) -> Result<MobileEntryCopy, MobileAuthenticationFfiError> {
self.authentication
.copy_entry_field(&path, field)
.map(Into::into)
.map_err(Into::into)
}
pub fn replace_entry_field(
&self,
path: String,
field: u64,
value: String,
) -> Result<MobileEntryPage, MobileAuthenticationFfiError> {
self.authentication
.replace_entry_field(&path, field, value)
.map(Into::into)
.map_err(Into::into)
}
pub fn manual_lock(&self) -> Result<(), MobileAuthenticationFfiError> {
self.authentication.manual_lock().map_err(Into::into)
}