Implement native iPhone entry editor
This commit is contained in:
@@ -585,18 +585,36 @@ fileprivate struct FfiConverterString: FfiConverter {
|
||||
|
||||
public protocol MobileAuthenticationProtocol: AnyObject, Sendable {
|
||||
|
||||
func addEntryEditorField(editor: UInt64, kind: MobileEntryEditorFieldKind, name: String?, value: String) throws -> MobileEntryEditorPage
|
||||
|
||||
func beginCreateEntry(directory: String, name: String, passphrase: String?) throws -> MobileEntryEditorSession
|
||||
|
||||
func beginEntryEditor(path: String) throws -> MobileEntryEditorSession
|
||||
|
||||
func cancel() throws
|
||||
|
||||
func copyEntryField(path: String, field: UInt64) throws -> MobileEntryCopy
|
||||
|
||||
func discardEntryEditor(editor: UInt64) throws
|
||||
|
||||
func entryEditor(editor: UInt64) throws -> MobileEntryEditorPage
|
||||
|
||||
func entryPage(path: String) throws -> MobileEntryPage
|
||||
|
||||
func generateEntryEditorPassword(editor: UInt64, length: UInt32?, noSymbols: Bool) throws -> MobileEntryEditorPage
|
||||
|
||||
func manualLock() throws
|
||||
|
||||
func removeEntryEditorField(editor: UInt64, field: UInt64) throws -> MobileEntryEditorPage
|
||||
|
||||
func reorderEntryEditorField(editor: UInt64, field: UInt64, index: UInt32) throws -> MobileEntryEditorPage
|
||||
|
||||
func replaceEntryField(path: String, field: UInt64, value: String) throws -> MobileEntryPage
|
||||
|
||||
func revealEntryField(path: String, field: UInt64) throws -> String
|
||||
|
||||
func saveEntryEditor(editor: UInt64, fields: [MobileEntryEditorInput]) throws -> MobileEntryPage
|
||||
|
||||
func setBiometricUnlock(enabled: Bool) throws -> MobileAuthenticationState
|
||||
|
||||
func state() throws -> MobileAuthenticationState
|
||||
@@ -605,6 +623,8 @@ public protocol MobileAuthenticationProtocol: AnyObject, Sendable {
|
||||
|
||||
func unlockEntry(path: String, passphrase: String?) throws -> MobileAuthenticationState
|
||||
|
||||
func updateEntryEditor(editor: UInt64, fields: [MobileEntryEditorInput]) throws -> MobileEntryEditorPage
|
||||
|
||||
}
|
||||
open class MobileAuthentication: MobileAuthenticationProtocol, @unchecked Sendable {
|
||||
fileprivate let handle: UInt64
|
||||
@@ -659,6 +679,41 @@ open class MobileAuthentication: MobileAuthenticationProtocol, @unchecked Sendab
|
||||
|
||||
|
||||
|
||||
open func addEntryEditorField(editor: UInt64, kind: MobileEntryEditorFieldKind, name: String?, value: String)throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_add_entry_editor_field(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),
|
||||
FfiConverterTypeMobileEntryEditorFieldKind_lower(kind),
|
||||
FfiConverterOptionString.lower(name),
|
||||
FfiConverterString.lower(value),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func beginCreateEntry(directory: String, name: String, passphrase: String?)throws -> MobileEntryEditorSession {
|
||||
return try FfiConverterTypeMobileEntryEditorSession_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_begin_create_entry(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterString.lower(directory),
|
||||
FfiConverterString.lower(name),
|
||||
FfiConverterOptionString.lower(passphrase),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func beginEntryEditor(path: String)throws -> MobileEntryEditorSession {
|
||||
return try FfiConverterTypeMobileEntryEditorSession_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_begin_entry_editor(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterString.lower(path),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func cancel()throws {try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_cancel(
|
||||
@@ -678,6 +733,25 @@ open func copyEntryField(path: String, field: UInt64)throws -> MobileEntryCopy
|
||||
})
|
||||
}
|
||||
|
||||
open func discardEntryEditor(editor: UInt64)throws {try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_discard_entry_editor(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),uniffiCallStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
open func entryEditor(editor: UInt64)throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_entry_editor(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func entryPage(path: String)throws -> MobileEntryPage {
|
||||
return try FfiConverterTypeMobileEntryPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
@@ -688,6 +762,18 @@ open func entryPage(path: String)throws -> MobileEntryPage {
|
||||
})
|
||||
}
|
||||
|
||||
open func generateEntryEditorPassword(editor: UInt64, length: UInt32?, noSymbols: Bool)throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_generate_entry_editor_password(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),
|
||||
FfiConverterOptionUInt32.lower(length),
|
||||
FfiConverterBool.lower(noSymbols),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func manualLock()throws {try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_manual_lock(
|
||||
@@ -696,6 +782,29 @@ open func manualLock()throws {try rustCallWithError(FfiConverterTypeMobileAuth
|
||||
}
|
||||
}
|
||||
|
||||
open func removeEntryEditorField(editor: UInt64, field: UInt64)throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_remove_entry_editor_field(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),
|
||||
FfiConverterUInt64.lower(field),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func reorderEntryEditorField(editor: UInt64, field: UInt64, index: UInt32)throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_reorder_entry_editor_field(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),
|
||||
FfiConverterUInt64.lower(field),
|
||||
FfiConverterUInt32.lower(index),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func replaceEntryField(path: String, field: UInt64, value: String)throws -> MobileEntryPage {
|
||||
return try FfiConverterTypeMobileEntryPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
@@ -719,6 +828,17 @@ open func revealEntryField(path: String, field: UInt64)throws -> String {
|
||||
})
|
||||
}
|
||||
|
||||
open func saveEntryEditor(editor: UInt64, fields: [MobileEntryEditorInput])throws -> MobileEntryPage {
|
||||
return try FfiConverterTypeMobileEntryPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_save_entry_editor(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),
|
||||
FfiConverterSequenceTypeMobileEntryEditorInput.lower(fields),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
open func setBiometricUnlock(enabled: Bool)throws -> MobileAuthenticationState {
|
||||
return try FfiConverterTypeMobileAuthenticationState_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
@@ -757,6 +877,17 @@ open func unlockEntry(path: String, passphrase: String?)throws -> MobileAuthent
|
||||
})
|
||||
}
|
||||
|
||||
open func updateEntryEditor(editor: UInt64, fields: [MobileEntryEditorInput])throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_method_mobileauthentication_update_entry_editor(
|
||||
self.uniffiCloneHandle(),
|
||||
FfiConverterUInt64.lower(editor),
|
||||
FfiConverterSequenceTypeMobileEntryEditorInput.lower(fields),uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1239,6 +1370,290 @@ public func FfiConverterTypeMobileEntryCopy_lower(_ value: MobileEntryCopy) -> R
|
||||
}
|
||||
|
||||
|
||||
public struct MobileEntryEditorField: Equatable, Hashable {
|
||||
public var id: UInt64
|
||||
public var kind: MobileEntryEditorFieldKind
|
||||
public var name: String?
|
||||
public var label: String
|
||||
public var systemImage: String
|
||||
public var value: String?
|
||||
public var maskedValue: String
|
||||
public var diagnostic: String?
|
||||
public var sensitive: Bool
|
||||
public var multiline: Bool
|
||||
public var nameEditable: Bool
|
||||
public var removable: Bool
|
||||
public var reorderable: Bool
|
||||
|
||||
// Default memberwise initializers are never public by default, so we
|
||||
// declare one manually.
|
||||
public init(id: UInt64, kind: MobileEntryEditorFieldKind, name: String?, label: String, systemImage: String, value: String?, maskedValue: String, diagnostic: String?, sensitive: Bool, multiline: Bool, nameEditable: Bool, removable: Bool, reorderable: Bool) {
|
||||
self.id = id
|
||||
self.kind = kind
|
||||
self.name = name
|
||||
self.label = label
|
||||
self.systemImage = systemImage
|
||||
self.value = value
|
||||
self.maskedValue = maskedValue
|
||||
self.diagnostic = diagnostic
|
||||
self.sensitive = sensitive
|
||||
self.multiline = multiline
|
||||
self.nameEditable = nameEditable
|
||||
self.removable = removable
|
||||
self.reorderable = reorderable
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if compiler(>=6)
|
||||
extension MobileEntryEditorField: Sendable {}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public struct FfiConverterTypeMobileEntryEditorField: FfiConverterRustBuffer {
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileEntryEditorField {
|
||||
return
|
||||
try MobileEntryEditorField(
|
||||
id: FfiConverterUInt64.read(from: &buf),
|
||||
kind: FfiConverterTypeMobileEntryEditorFieldKind.read(from: &buf),
|
||||
name: FfiConverterOptionString.read(from: &buf),
|
||||
label: FfiConverterString.read(from: &buf),
|
||||
systemImage: FfiConverterString.read(from: &buf),
|
||||
value: FfiConverterOptionString.read(from: &buf),
|
||||
maskedValue: FfiConverterString.read(from: &buf),
|
||||
diagnostic: FfiConverterOptionString.read(from: &buf),
|
||||
sensitive: FfiConverterBool.read(from: &buf),
|
||||
multiline: FfiConverterBool.read(from: &buf),
|
||||
nameEditable: FfiConverterBool.read(from: &buf),
|
||||
removable: FfiConverterBool.read(from: &buf),
|
||||
reorderable: FfiConverterBool.read(from: &buf)
|
||||
)
|
||||
}
|
||||
|
||||
public static func write(_ value: MobileEntryEditorField, into buf: inout [UInt8]) {
|
||||
FfiConverterUInt64.write(value.id, into: &buf)
|
||||
FfiConverterTypeMobileEntryEditorFieldKind.write(value.kind, into: &buf)
|
||||
FfiConverterOptionString.write(value.name, into: &buf)
|
||||
FfiConverterString.write(value.label, into: &buf)
|
||||
FfiConverterString.write(value.systemImage, into: &buf)
|
||||
FfiConverterOptionString.write(value.value, into: &buf)
|
||||
FfiConverterString.write(value.maskedValue, into: &buf)
|
||||
FfiConverterOptionString.write(value.diagnostic, into: &buf)
|
||||
FfiConverterBool.write(value.sensitive, into: &buf)
|
||||
FfiConverterBool.write(value.multiline, into: &buf)
|
||||
FfiConverterBool.write(value.nameEditable, into: &buf)
|
||||
FfiConverterBool.write(value.removable, into: &buf)
|
||||
FfiConverterBool.write(value.reorderable, into: &buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorField_lift(_ buf: RustBuffer) throws -> MobileEntryEditorField {
|
||||
return try FfiConverterTypeMobileEntryEditorField.lift(buf)
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorField_lower(_ value: MobileEntryEditorField) -> RustBuffer {
|
||||
return FfiConverterTypeMobileEntryEditorField.lower(value)
|
||||
}
|
||||
|
||||
|
||||
public struct MobileEntryEditorInput: Equatable, Hashable {
|
||||
public var id: UInt64
|
||||
public var name: String?
|
||||
public var value: String?
|
||||
|
||||
// Default memberwise initializers are never public by default, so we
|
||||
// declare one manually.
|
||||
public init(id: UInt64, name: String?, value: String?) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.value = value
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if compiler(>=6)
|
||||
extension MobileEntryEditorInput: Sendable {}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public struct FfiConverterTypeMobileEntryEditorInput: FfiConverterRustBuffer {
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileEntryEditorInput {
|
||||
return
|
||||
try MobileEntryEditorInput(
|
||||
id: FfiConverterUInt64.read(from: &buf),
|
||||
name: FfiConverterOptionString.read(from: &buf),
|
||||
value: FfiConverterOptionString.read(from: &buf)
|
||||
)
|
||||
}
|
||||
|
||||
public static func write(_ value: MobileEntryEditorInput, into buf: inout [UInt8]) {
|
||||
FfiConverterUInt64.write(value.id, into: &buf)
|
||||
FfiConverterOptionString.write(value.name, into: &buf)
|
||||
FfiConverterOptionString.write(value.value, into: &buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorInput_lift(_ buf: RustBuffer) throws -> MobileEntryEditorInput {
|
||||
return try FfiConverterTypeMobileEntryEditorInput.lift(buf)
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorInput_lower(_ value: MobileEntryEditorInput) -> RustBuffer {
|
||||
return FfiConverterTypeMobileEntryEditorInput.lower(value)
|
||||
}
|
||||
|
||||
|
||||
public struct MobileEntryEditorPage: Equatable, Hashable {
|
||||
public var path: String
|
||||
public var title: String
|
||||
public var fields: [MobileEntryEditorField]
|
||||
public var dirty: Bool
|
||||
public var creating: Bool
|
||||
public var defaultPasswordLength: UInt32
|
||||
public var maximumPasswordLength: UInt32
|
||||
|
||||
// Default memberwise initializers are never public by default, so we
|
||||
// declare one manually.
|
||||
public init(path: String, title: String, fields: [MobileEntryEditorField], dirty: Bool, creating: Bool, defaultPasswordLength: UInt32, maximumPasswordLength: UInt32) {
|
||||
self.path = path
|
||||
self.title = title
|
||||
self.fields = fields
|
||||
self.dirty = dirty
|
||||
self.creating = creating
|
||||
self.defaultPasswordLength = defaultPasswordLength
|
||||
self.maximumPasswordLength = maximumPasswordLength
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if compiler(>=6)
|
||||
extension MobileEntryEditorPage: Sendable {}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public struct FfiConverterTypeMobileEntryEditorPage: FfiConverterRustBuffer {
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileEntryEditorPage {
|
||||
return
|
||||
try MobileEntryEditorPage(
|
||||
path: FfiConverterString.read(from: &buf),
|
||||
title: FfiConverterString.read(from: &buf),
|
||||
fields: FfiConverterSequenceTypeMobileEntryEditorField.read(from: &buf),
|
||||
dirty: FfiConverterBool.read(from: &buf),
|
||||
creating: FfiConverterBool.read(from: &buf),
|
||||
defaultPasswordLength: FfiConverterUInt32.read(from: &buf),
|
||||
maximumPasswordLength: FfiConverterUInt32.read(from: &buf)
|
||||
)
|
||||
}
|
||||
|
||||
public static func write(_ value: MobileEntryEditorPage, into buf: inout [UInt8]) {
|
||||
FfiConverterString.write(value.path, into: &buf)
|
||||
FfiConverterString.write(value.title, into: &buf)
|
||||
FfiConverterSequenceTypeMobileEntryEditorField.write(value.fields, into: &buf)
|
||||
FfiConverterBool.write(value.dirty, into: &buf)
|
||||
FfiConverterBool.write(value.creating, into: &buf)
|
||||
FfiConverterUInt32.write(value.defaultPasswordLength, into: &buf)
|
||||
FfiConverterUInt32.write(value.maximumPasswordLength, into: &buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorPage_lift(_ buf: RustBuffer) throws -> MobileEntryEditorPage {
|
||||
return try FfiConverterTypeMobileEntryEditorPage.lift(buf)
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorPage_lower(_ value: MobileEntryEditorPage) -> RustBuffer {
|
||||
return FfiConverterTypeMobileEntryEditorPage.lower(value)
|
||||
}
|
||||
|
||||
|
||||
public struct MobileEntryEditorSession: Equatable, Hashable {
|
||||
public var id: UInt64
|
||||
public var page: MobileEntryEditorPage
|
||||
|
||||
// Default memberwise initializers are never public by default, so we
|
||||
// declare one manually.
|
||||
public init(id: UInt64, page: MobileEntryEditorPage) {
|
||||
self.id = id
|
||||
self.page = page
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if compiler(>=6)
|
||||
extension MobileEntryEditorSession: Sendable {}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public struct FfiConverterTypeMobileEntryEditorSession: FfiConverterRustBuffer {
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileEntryEditorSession {
|
||||
return
|
||||
try MobileEntryEditorSession(
|
||||
id: FfiConverterUInt64.read(from: &buf),
|
||||
page: FfiConverterTypeMobileEntryEditorPage.read(from: &buf)
|
||||
)
|
||||
}
|
||||
|
||||
public static func write(_ value: MobileEntryEditorSession, into buf: inout [UInt8]) {
|
||||
FfiConverterUInt64.write(value.id, into: &buf)
|
||||
FfiConverterTypeMobileEntryEditorPage.write(value.page, into: &buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorSession_lift(_ buf: RustBuffer) throws -> MobileEntryEditorSession {
|
||||
return try FfiConverterTypeMobileEntryEditorSession.lift(buf)
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorSession_lower(_ value: MobileEntryEditorSession) -> RustBuffer {
|
||||
return FfiConverterTypeMobileEntryEditorSession.lower(value)
|
||||
}
|
||||
|
||||
|
||||
public struct MobileEntryField: Equatable, Hashable {
|
||||
public var id: UInt64
|
||||
public var label: String
|
||||
@@ -2279,6 +2694,7 @@ public enum MobileAuthenticationErrorKind: Equatable, Hashable {
|
||||
case entry
|
||||
case secureStorage
|
||||
case expired
|
||||
case conflict
|
||||
|
||||
|
||||
|
||||
@@ -2318,6 +2734,8 @@ public struct FfiConverterTypeMobileAuthenticationErrorKind: FfiConverterRustBuf
|
||||
|
||||
case 9: return .expired
|
||||
|
||||
case 10: return .conflict
|
||||
|
||||
default: throw UniffiInternalError.unexpectedEnumCase
|
||||
}
|
||||
}
|
||||
@@ -2361,6 +2779,10 @@ public struct FfiConverterTypeMobileAuthenticationErrorKind: FfiConverterRustBuf
|
||||
case .expired:
|
||||
writeInt(&buf, Int32(9))
|
||||
|
||||
|
||||
case .conflict:
|
||||
writeInt(&buf, Int32(10))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2462,6 +2884,86 @@ public func FfiConverterTypeMobileAuthenticationFfiError_lower(_ value: MobileAu
|
||||
|
||||
|
||||
|
||||
public enum MobileEntryEditorFieldKind: Equatable, Hashable {
|
||||
|
||||
case password
|
||||
case field
|
||||
case note
|
||||
case otpUri
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if compiler(>=6)
|
||||
extension MobileEntryEditorFieldKind: Sendable {}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public struct FfiConverterTypeMobileEntryEditorFieldKind: FfiConverterRustBuffer {
|
||||
typealias SwiftType = MobileEntryEditorFieldKind
|
||||
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileEntryEditorFieldKind {
|
||||
let variant: Int32 = try readInt(&buf)
|
||||
switch variant {
|
||||
|
||||
case 1: return .password
|
||||
|
||||
case 2: return .field
|
||||
|
||||
case 3: return .note
|
||||
|
||||
case 4: return .otpUri
|
||||
|
||||
default: throw UniffiInternalError.unexpectedEnumCase
|
||||
}
|
||||
}
|
||||
|
||||
public static func write(_ value: MobileEntryEditorFieldKind, into buf: inout [UInt8]) {
|
||||
switch value {
|
||||
|
||||
|
||||
case .password:
|
||||
writeInt(&buf, Int32(1))
|
||||
|
||||
|
||||
case .field:
|
||||
writeInt(&buf, Int32(2))
|
||||
|
||||
|
||||
case .note:
|
||||
writeInt(&buf, Int32(3))
|
||||
|
||||
|
||||
case .otpUri:
|
||||
writeInt(&buf, Int32(4))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorFieldKind_lift(_ buf: RustBuffer) throws -> MobileEntryEditorFieldKind {
|
||||
return try FfiConverterTypeMobileEntryEditorFieldKind.lift(buf)
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public func FfiConverterTypeMobileEntryEditorFieldKind_lower(_ value: MobileEntryEditorFieldKind) -> RustBuffer {
|
||||
return FfiConverterTypeMobileEntryEditorFieldKind.lower(value)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public enum MobileEntrySectionKind: Equatable, Hashable {
|
||||
|
||||
case password
|
||||
@@ -3809,6 +4311,30 @@ public func FfiConverterTypeMobileTab_lower(_ value: MobileTab) -> RustBuffer {
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer {
|
||||
typealias SwiftType = UInt32?
|
||||
|
||||
public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
|
||||
guard let value = value else {
|
||||
writeInt(&buf, Int8(0))
|
||||
return
|
||||
}
|
||||
writeInt(&buf, Int8(1))
|
||||
FfiConverterUInt32.write(value, into: &buf)
|
||||
}
|
||||
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
|
||||
switch try readInt(&buf) as Int8 {
|
||||
case 0: return nil
|
||||
case 1: return try FfiConverterUInt32.read(from: &buf)
|
||||
default: throw UniffiInternalError.unexpectedOptionalTag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
@@ -3906,6 +4432,56 @@ fileprivate struct FfiConverterSequenceString: FfiConverterRustBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
fileprivate struct FfiConverterSequenceTypeMobileEntryEditorField: FfiConverterRustBuffer {
|
||||
typealias SwiftType = [MobileEntryEditorField]
|
||||
|
||||
public static func write(_ value: [MobileEntryEditorField], into buf: inout [UInt8]) {
|
||||
let len = Int32(value.count)
|
||||
writeInt(&buf, len)
|
||||
for item in value {
|
||||
FfiConverterTypeMobileEntryEditorField.write(item, into: &buf)
|
||||
}
|
||||
}
|
||||
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [MobileEntryEditorField] {
|
||||
let len: Int32 = try readInt(&buf)
|
||||
var seq = [MobileEntryEditorField]()
|
||||
seq.reserveCapacity(Int(len))
|
||||
for _ in 0 ..< len {
|
||||
seq.append(try FfiConverterTypeMobileEntryEditorField.read(from: &buf))
|
||||
}
|
||||
return seq
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
fileprivate struct FfiConverterSequenceTypeMobileEntryEditorInput: FfiConverterRustBuffer {
|
||||
typealias SwiftType = [MobileEntryEditorInput]
|
||||
|
||||
public static func write(_ value: [MobileEntryEditorInput], into buf: inout [UInt8]) {
|
||||
let len = Int32(value.count)
|
||||
writeInt(&buf, len)
|
||||
for item in value {
|
||||
FfiConverterTypeMobileEntryEditorInput.write(item, into: &buf)
|
||||
}
|
||||
}
|
||||
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [MobileEntryEditorInput] {
|
||||
let len: Int32 = try readInt(&buf)
|
||||
var seq = [MobileEntryEditorInput]()
|
||||
seq.reserveCapacity(Int(len))
|
||||
for _ in 0 ..< len {
|
||||
seq.append(try FfiConverterTypeMobileEntryEditorInput.read(from: &buf))
|
||||
}
|
||||
return seq
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
@@ -4193,24 +4769,51 @@ private let initializationResult: InitializationResult = {
|
||||
if (uniffi_ironstorage_apple_checksum_func_set_selected_mobile_tab() != 65280) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_add_entry_editor_field() != 58790) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_begin_create_entry() != 21567) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_begin_entry_editor() != 63281) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_cancel() != 6512) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_copy_entry_field() != 17773) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_discard_entry_editor() != 28195) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_entry_editor() != 65179) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_entry_page() != 56594) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_generate_entry_editor_password() != 34289) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_manual_lock() != 57220) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_remove_entry_editor_field() != 12238) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_reorder_entry_editor_field() != 62124) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_replace_entry_field() != 15315) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_reveal_entry_field() != 13396) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_save_entry_editor() != 30971) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_set_biometric_unlock() != 9486) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
@@ -4223,6 +4826,9 @@ private let initializationResult: InitializationResult = {
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_unlock_entry() != 28139) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobileauthentication_update_entry_editor() != 30139) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_method_mobilehomeoperation_cached() != 32436) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
|
||||
@@ -253,6 +253,21 @@ uint64_t uniffi_ironstorage_apple_fn_clone_mobileauthentication(uint64_t handle,
|
||||
void uniffi_ironstorage_apple_fn_free_mobileauthentication(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_ADD_ENTRY_EDITOR_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_ADD_ENTRY_EDITOR_FIELD
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_add_entry_editor_field(uint64_t ptr, uint64_t editor, RustBuffer kind, RustBuffer name, RustBuffer value, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_BEGIN_CREATE_ENTRY
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_BEGIN_CREATE_ENTRY
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_begin_create_entry(uint64_t ptr, RustBuffer directory, RustBuffer name, RustBuffer passphrase, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_BEGIN_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_BEGIN_ENTRY_EDITOR
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_begin_entry_editor(uint64_t ptr, RustBuffer path, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_CANCEL
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_CANCEL
|
||||
void uniffi_ironstorage_apple_fn_method_mobileauthentication_cancel(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||
@@ -263,16 +278,41 @@ void uniffi_ironstorage_apple_fn_method_mobileauthentication_cancel(uint64_t ptr
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_copy_entry_field(uint64_t ptr, RustBuffer path, uint64_t field, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_DISCARD_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_DISCARD_ENTRY_EDITOR
|
||||
void uniffi_ironstorage_apple_fn_method_mobileauthentication_discard_entry_editor(uint64_t ptr, uint64_t editor, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_ENTRY_EDITOR
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_entry_editor(uint64_t ptr, uint64_t editor, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_ENTRY_PAGE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_ENTRY_PAGE
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_entry_page(uint64_t ptr, RustBuffer path, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_GENERATE_ENTRY_EDITOR_PASSWORD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_GENERATE_ENTRY_EDITOR_PASSWORD
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_generate_entry_editor_password(uint64_t ptr, uint64_t editor, RustBuffer length, int8_t no_symbols, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_MANUAL_LOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_MANUAL_LOCK
|
||||
void uniffi_ironstorage_apple_fn_method_mobileauthentication_manual_lock(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_REMOVE_ENTRY_EDITOR_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_REMOVE_ENTRY_EDITOR_FIELD
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_remove_entry_editor_field(uint64_t ptr, uint64_t editor, uint64_t field, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_REORDER_ENTRY_EDITOR_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_REORDER_ENTRY_EDITOR_FIELD
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_reorder_entry_editor_field(uint64_t ptr, uint64_t editor, uint64_t field, uint32_t index, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_REPLACE_ENTRY_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_REPLACE_ENTRY_FIELD
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_replace_entry_field(uint64_t ptr, RustBuffer path, uint64_t field, RustBuffer value, RustCallStatus *_Nonnull out_status
|
||||
@@ -283,6 +323,11 @@ RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_replace_entry
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_reveal_entry_field(uint64_t ptr, RustBuffer path, uint64_t field, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_SAVE_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_SAVE_ENTRY_EDITOR
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_save_entry_editor(uint64_t ptr, uint64_t editor, RustBuffer fields, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_SET_BIOMETRIC_UNLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_SET_BIOMETRIC_UNLOCK
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_set_biometric_unlock(uint64_t ptr, int8_t enabled, RustCallStatus *_Nonnull out_status
|
||||
@@ -303,6 +348,11 @@ void uniffi_ironstorage_apple_fn_method_mobileauthentication_touch_user_activity
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_unlock_entry(uint64_t ptr, RustBuffer path, RustBuffer passphrase, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_UPDATE_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_METHOD_MOBILEAUTHENTICATION_UPDATE_ENTRY_EDITOR
|
||||
RustBuffer uniffi_ironstorage_apple_fn_method_mobileauthentication_update_entry_editor(uint64_t ptr, uint64_t editor, RustBuffer fields, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_CLONE_MOBILEHOMEOPERATION
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_CLONE_MOBILEHOMEOPERATION
|
||||
uint64_t uniffi_ironstorage_apple_fn_clone_mobilehomeoperation(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
@@ -734,6 +784,24 @@ uint16_t uniffi_ironstorage_apple_checksum_func_replace_configured_mobile_applic
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_FUNC_SET_SELECTED_MOBILE_TAB
|
||||
uint16_t uniffi_ironstorage_apple_checksum_func_set_selected_mobile_tab(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_ADD_ENTRY_EDITOR_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_ADD_ENTRY_EDITOR_FIELD
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_add_entry_editor_field(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_BEGIN_CREATE_ENTRY
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_BEGIN_CREATE_ENTRY
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_begin_create_entry(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_BEGIN_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_BEGIN_ENTRY_EDITOR
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_begin_entry_editor(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_CANCEL
|
||||
@@ -746,18 +814,48 @@ uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_cancel(vo
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_COPY_ENTRY_FIELD
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_copy_entry_field(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_DISCARD_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_DISCARD_ENTRY_EDITOR
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_discard_entry_editor(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_ENTRY_EDITOR
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_entry_editor(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_ENTRY_PAGE
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_ENTRY_PAGE
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_entry_page(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_GENERATE_ENTRY_EDITOR_PASSWORD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_GENERATE_ENTRY_EDITOR_PASSWORD
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_generate_entry_editor_password(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_MANUAL_LOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_MANUAL_LOCK
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_manual_lock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_REMOVE_ENTRY_EDITOR_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_REMOVE_ENTRY_EDITOR_FIELD
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_remove_entry_editor_field(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_REORDER_ENTRY_EDITOR_FIELD
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_REORDER_ENTRY_EDITOR_FIELD
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_reorder_entry_editor_field(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_REPLACE_ENTRY_FIELD
|
||||
@@ -770,6 +868,12 @@ uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_replace_e
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_REVEAL_ENTRY_FIELD
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_reveal_entry_field(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_SAVE_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_SAVE_ENTRY_EDITOR
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_save_entry_editor(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_SET_BIOMETRIC_UNLOCK
|
||||
@@ -794,6 +898,12 @@ uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_touch_use
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_UNLOCK_ENTRY
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_unlock_entry(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_UPDATE_ENTRY_EDITOR
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEAUTHENTICATION_UPDATE_ENTRY_EDITOR
|
||||
uint16_t uniffi_ironstorage_apple_checksum_method_mobileauthentication_update_entry_editor(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_METHOD_MOBILEHOMEOPERATION_CACHED
|
||||
|
||||
@@ -896,6 +896,7 @@ private final class PasswordDirectoryViewController: UITableViewController, Mobi
|
||||
private var shellPage: MobilePage?
|
||||
private var directoryPage: MobilePasswordPage?
|
||||
private var loadTask: Task<Void, Never>?
|
||||
private var createTask: Task<Void, Never>?
|
||||
private var loadGeneration = 0
|
||||
|
||||
init(
|
||||
@@ -943,6 +944,7 @@ private final class PasswordDirectoryViewController: UITableViewController, Mobi
|
||||
|
||||
deinit {
|
||||
loadTask?.cancel()
|
||||
createTask?.cancel()
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@@ -1020,6 +1022,100 @@ private final class PasswordDirectoryViewController: UITableViewController, Mobi
|
||||
reload()
|
||||
}
|
||||
|
||||
@objc private func createRequested() {
|
||||
let alert = UIAlertController(
|
||||
title: "New Password",
|
||||
message: "Enter a name for the password entry in this folder.",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addTextField { field in
|
||||
field.placeholder = "Entry Name"
|
||||
field.autocapitalizationType = .words
|
||||
field.clearButtonMode = .whileEditing
|
||||
field.returnKeyType = .next
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "Create", style: .default) { [weak self, weak alert] _ in
|
||||
guard let name = alert?.textFields?.first?.text, !name.isEmpty else { return }
|
||||
self?.beginCreate(name: name, passphrase: nil)
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func beginCreate(name: String, passphrase: String?) {
|
||||
guard let authentication else {
|
||||
presentAuthenticationFailure(.unavailable)
|
||||
return
|
||||
}
|
||||
createTask?.cancel()
|
||||
let directory = path ?? ""
|
||||
createTask = Task { [weak self] in
|
||||
let result = await Task.detached(priority: .userInitiated) {
|
||||
do {
|
||||
return Result<MobileEntryEditorSession, AuthenticationFailure>.success(
|
||||
try authentication.beginCreateEntry(
|
||||
directory: directory,
|
||||
name: name,
|
||||
passphrase: passphrase
|
||||
)
|
||||
)
|
||||
} catch let error as MobileAuthenticationFfiError {
|
||||
return .failure(AuthenticationFailure(error))
|
||||
} catch {
|
||||
return .failure(.unexpected)
|
||||
}
|
||||
}.value
|
||||
guard !Task.isCancelled, let self else { return }
|
||||
switch result {
|
||||
case let .success(session):
|
||||
presentEditor(session, focusedField: nil)
|
||||
case let .failure(failure)
|
||||
where passphrase == nil
|
||||
&& (failure.kind == .passphraseRequired
|
||||
|| failure.kind == .biometryUnavailable):
|
||||
promptForCreationPassphrase(name: name, message: failure.detail)
|
||||
case let .failure(failure):
|
||||
presentAuthenticationFailure(failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func promptForCreationPassphrase(name: String, message: String) {
|
||||
let alert = UIAlertController(
|
||||
title: "GPG Key Passphrase",
|
||||
message: message,
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addTextField { field in
|
||||
field.isSecureTextEntry = true
|
||||
field.textContentType = .password
|
||||
field.placeholder = "Passphrase"
|
||||
field.returnKeyType = .go
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "Unlock", style: .default) { [weak self, weak alert] _ in
|
||||
guard let value = alert?.textFields?.first?.text, !value.isEmpty else { return }
|
||||
alert?.textFields?.first?.text = nil
|
||||
self?.beginCreate(name: name, passphrase: value)
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func presentEditor(_ session: MobileEntryEditorSession, focusedField: UInt64?) {
|
||||
guard let authentication else { return }
|
||||
let editor = MobileEntryEditorViewController(
|
||||
authentication: authentication,
|
||||
session: session,
|
||||
focusedField: focusedField
|
||||
) { [weak self] _ in
|
||||
NotificationCenter.default.post(name: .ironStorageLocalStoreDidChange, object: nil)
|
||||
self?.reload()
|
||||
}
|
||||
let navigation = UINavigationController(rootViewController: editor)
|
||||
navigation.modalPresentationStyle = .formSheet
|
||||
present(navigation, animated: true)
|
||||
}
|
||||
|
||||
private func reload() {
|
||||
loadGeneration += 1
|
||||
let generation = loadGeneration
|
||||
@@ -1063,6 +1159,7 @@ private final class PasswordDirectoryViewController: UITableViewController, Mobi
|
||||
title = page.title
|
||||
guard page.state == .ready else {
|
||||
directoryPage = nil
|
||||
navigationItem.rightBarButtonItem = nil
|
||||
tableView.reloadData()
|
||||
refreshControl?.endRefreshing()
|
||||
var configuration = page.state == .loading
|
||||
@@ -1088,6 +1185,12 @@ private final class PasswordDirectoryViewController: UITableViewController, Mobi
|
||||
case let .success(page):
|
||||
directoryPage = page
|
||||
title = page.title
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
barButtonSystemItem: .add,
|
||||
target: self,
|
||||
action: #selector(createRequested)
|
||||
)
|
||||
navigationItem.rightBarButtonItem?.accessibilityLabel = "Create password entry"
|
||||
contentUnavailableConfiguration = nil
|
||||
tableView.reloadData()
|
||||
if page.rows.isEmpty {
|
||||
@@ -1101,6 +1204,7 @@ private final class PasswordDirectoryViewController: UITableViewController, Mobi
|
||||
tableView.selectRow(at: IndexPath(row: row, section: 0), animated: false, scrollPosition: .none)
|
||||
}
|
||||
case let .failure(failure):
|
||||
navigationItem.rightBarButtonItem = nil
|
||||
if failure.kind == .directoryMissing, path != nil {
|
||||
UIAccessibility.post(
|
||||
notification: .announcement,
|
||||
@@ -1436,32 +1540,15 @@ private final class LockedPasswordViewController: UITableViewController {
|
||||
}
|
||||
|
||||
private func edit(_ field: MobileEntryField) {
|
||||
performFieldAction(field) { authentication, path in
|
||||
try authentication.revealEntryField(path: path, field: field.id)
|
||||
} success: { [weak self] value in
|
||||
guard let self else { return }
|
||||
let editor = MobileEntryEditorViewController(field: field, value: value) {
|
||||
[weak self] updated in self?.save(updated, for: field)
|
||||
}
|
||||
present(UINavigationController(rootViewController: editor), animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
private func save(_ value: String, for field: MobileEntryField) {
|
||||
guard let authentication else { return }
|
||||
entryTask?.cancel()
|
||||
showLoading(title: "Saving Password")
|
||||
let path = entry.path
|
||||
entryTask = Task { [weak self] in
|
||||
let result = await Task.detached(priority: .userInitiated) {
|
||||
do {
|
||||
try authentication.touchUserActivity()
|
||||
return Result<MobileEntryPage, AuthenticationFailure>.success(
|
||||
try authentication.replaceEntryField(
|
||||
path: path,
|
||||
field: field.id,
|
||||
value: value
|
||||
)
|
||||
return Result<MobileEntryEditorSession, AuthenticationFailure>.success(
|
||||
try authentication.beginEntryEditor(path: path)
|
||||
)
|
||||
} catch let error as MobileAuthenticationFfiError {
|
||||
return .failure(AuthenticationFailure(error))
|
||||
@@ -1471,13 +1558,22 @@ private final class LockedPasswordViewController: UITableViewController {
|
||||
}.value
|
||||
guard !Task.isCancelled, let self else { return }
|
||||
switch result {
|
||||
case let .success(page):
|
||||
self.page = page
|
||||
revealedValues.removeValue(forKey: field.id)
|
||||
contentUnavailableConfiguration = nil
|
||||
tableView.reloadData()
|
||||
NotificationCenter.default.post(name: .ironStorageLocalStoreDidChange, object: nil)
|
||||
showFeedback("\(field.label) saved")
|
||||
case let .success(session):
|
||||
let editor = MobileEntryEditorViewController(
|
||||
authentication: authentication,
|
||||
session: session,
|
||||
focusedField: field.id
|
||||
) { [weak self] _ in
|
||||
NotificationCenter.default.post(
|
||||
name: .ironStorageLocalStoreDidChange,
|
||||
object: nil
|
||||
)
|
||||
self?.revealedValues.removeAll(keepingCapacity: false)
|
||||
self?.loadEntry()
|
||||
}
|
||||
let navigation = UINavigationController(rootViewController: editor)
|
||||
navigation.modalPresentationStyle = .formSheet
|
||||
present(navigation, animated: true)
|
||||
case let .failure(failure):
|
||||
handle(failure)
|
||||
}
|
||||
@@ -1742,17 +1838,37 @@ private final class MobileEntryFieldCell: UITableViewCell {
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private final class MobileEntryEditorViewController: UIViewController {
|
||||
private let field: MobileEntryField
|
||||
private let valueView = UITextView()
|
||||
private let save: (String) -> Void
|
||||
private final class MobileEntryEditorViewController: UITableViewController,
|
||||
UIAdaptivePresentationControllerDelegate
|
||||
{
|
||||
private struct FieldState {
|
||||
var name: String?
|
||||
var value: String?
|
||||
}
|
||||
|
||||
init(field: MobileEntryField, value: String, save: @escaping (String) -> Void) {
|
||||
self.field = field
|
||||
self.save = save
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
valueView.text = value
|
||||
title = "Edit \(field.label)"
|
||||
private let authentication: MobileAuthentication
|
||||
private var editorID: UInt64
|
||||
private var page: MobileEntryEditorPage
|
||||
private let focusedField: UInt64?
|
||||
private let saved: (String) -> Void
|
||||
private var states: [UInt64: FieldState] = [:]
|
||||
private var localDirty = false
|
||||
private var focused = false
|
||||
private var operationTask: Task<Void, Never>?
|
||||
|
||||
init(
|
||||
authentication: MobileAuthentication,
|
||||
session: MobileEntryEditorSession,
|
||||
focusedField: UInt64?,
|
||||
saved: @escaping (String) -> Void
|
||||
) {
|
||||
self.authentication = authentication
|
||||
editorID = session.id
|
||||
page = session.page
|
||||
self.focusedField = focusedField
|
||||
self.saved = saved
|
||||
super.init(style: .insetGrouped)
|
||||
resetStates()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
@@ -1760,34 +1876,590 @@ private final class MobileEntryEditorViewController: UIViewController {
|
||||
fatalError("init(coder:) is not supported")
|
||||
}
|
||||
|
||||
deinit {
|
||||
operationTask?.cancel()
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .systemGroupedBackground
|
||||
valueView.font = .preferredFont(forTextStyle: .body)
|
||||
valueView.adjustsFontForContentSizeCategory = true
|
||||
valueView.autocorrectionType = field.sensitive ? .no : .default
|
||||
valueView.autocapitalizationType = field.sensitive ? .none : .sentences
|
||||
valueView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(valueView)
|
||||
NSLayoutConstraint.activate([
|
||||
valueView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
|
||||
valueView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
|
||||
valueView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
|
||||
valueView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor, constant: -16),
|
||||
])
|
||||
title = page.creating ? "New \(page.title)" : "Edit \(page.title)"
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
tableView.register(MobileEntryEditorCell.self, forCellReuseIdentifier: "EditorField")
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 120
|
||||
tableView.setEditing(true, animated: false)
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(
|
||||
systemItem: .cancel,
|
||||
primaryAction: UIAction { [weak self] _ in self?.dismiss(animated: true) }
|
||||
primaryAction: UIAction { [weak self] _ in self?.cancelRequested() }
|
||||
)
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
systemItem: .save,
|
||||
primaryAction: UIAction { [weak self] _ in
|
||||
guard let self else { return }
|
||||
let value = valueView.text ?? ""
|
||||
dismiss(animated: true) { self.save(value) }
|
||||
}
|
||||
primaryAction: UIAction { [weak self] _ in self?.saveRequested() }
|
||||
)
|
||||
valueView.becomeFirstResponder()
|
||||
let add = UIBarButtonItem(
|
||||
systemItem: .add,
|
||||
primaryAction: UIAction { [weak self] _ in self?.addRequested() }
|
||||
)
|
||||
add.accessibilityLabel = "Add entry field"
|
||||
let generate = UIBarButtonItem(
|
||||
title: "Generate Password",
|
||||
image: UIImage(systemName: "wand.and.stars"),
|
||||
primaryAction: UIAction { [weak self] _ in self?.generateRequested() }
|
||||
)
|
||||
toolbarItems = [
|
||||
add,
|
||||
UIBarButtonItem(systemItem: .flexibleSpace),
|
||||
generate,
|
||||
]
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(authenticationDidChange),
|
||||
name: .ironStorageAuthenticationDidChange,
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
navigationController?.setToolbarHidden(false, animated: animated)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
navigationController?.presentationController?.delegate = self
|
||||
guard !focused, let focusedField,
|
||||
let index = page.fields.firstIndex(where: { $0.id == focusedField })
|
||||
else { return }
|
||||
focused = true
|
||||
let path = IndexPath(row: index, section: 0)
|
||||
tableView.scrollToRow(at: path, at: .middle, animated: true)
|
||||
(tableView.cellForRow(at: path) as? MobileEntryEditorCell)?.focusValue()
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int { 1 }
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
page.fields.count
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
titleForHeaderInSection section: Int
|
||||
) -> String? {
|
||||
"Entry Fields"
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
titleForFooterInSection section: Int
|
||||
) -> String? {
|
||||
"Drag the reorder controls to preserve the exact field order saved by Rust."
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
cellForRowAt indexPath: IndexPath
|
||||
) -> UITableViewCell {
|
||||
guard let cell = tableView.dequeueReusableCell(
|
||||
withIdentifier: "EditorField",
|
||||
for: indexPath
|
||||
) as? MobileEntryEditorCell else { return UITableViewCell() }
|
||||
let field = page.fields[indexPath.row]
|
||||
let state = states[field.id] ?? FieldState(name: field.name, value: field.value)
|
||||
cell.configure(field: field, name: state.name, value: state.value) { [weak self] name, value in
|
||||
self?.states[field.id] = FieldState(name: name, value: value)
|
||||
self?.localDirty = true
|
||||
}
|
||||
cell.showsReorderControl = field.reorderable
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||
page.fields[indexPath.row].removable
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
||||
page.fields[indexPath.row].reorderable
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
editingStyleForRowAt indexPath: IndexPath
|
||||
) -> UITableViewCell.EditingStyle {
|
||||
page.fields[indexPath.row].removable ? .delete : .none
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
commit editingStyle: UITableViewCell.EditingStyle,
|
||||
forRowAt indexPath: IndexPath
|
||||
) {
|
||||
guard editingStyle == .delete else { return }
|
||||
do {
|
||||
try synchronizeDraft()
|
||||
page = try authentication.removeEntryEditorField(
|
||||
editor: editorID,
|
||||
field: page.fields[indexPath.row].id
|
||||
)
|
||||
resetStates()
|
||||
tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
} catch {
|
||||
presentEditorFailure(error)
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
moveRowAt sourceIndexPath: IndexPath,
|
||||
to destinationIndexPath: IndexPath
|
||||
) {
|
||||
let field = page.fields[sourceIndexPath.row]
|
||||
do {
|
||||
try synchronizeDraft()
|
||||
page = try authentication.reorderEntryEditorField(
|
||||
editor: editorID,
|
||||
field: field.id,
|
||||
index: UInt32(destinationIndexPath.row)
|
||||
)
|
||||
resetStates()
|
||||
tableView.reloadData()
|
||||
} catch {
|
||||
presentEditorFailure(error)
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
|
||||
guard isDirty else {
|
||||
try? authentication.discardEntryEditor(editor: editorID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func presentationControllerDidAttemptToDismiss(
|
||||
_ presentationController: UIPresentationController
|
||||
) {
|
||||
confirmDiscard()
|
||||
}
|
||||
|
||||
@objc private func authenticationDidChange() {
|
||||
guard (try? authentication.state().unlocked) != true else { return }
|
||||
states = states.mapValues { _ in FieldState(name: nil, value: nil) }
|
||||
tableView.visibleCells
|
||||
.compactMap { $0 as? MobileEntryEditorCell }
|
||||
.forEach { $0.clearSensitiveContent() }
|
||||
dismiss(animated: true)
|
||||
UIAccessibility.post(notification: .announcement, argument: "Entry editor locked")
|
||||
}
|
||||
|
||||
private var isDirty: Bool { localDirty || page.dirty }
|
||||
|
||||
private func resetStates() {
|
||||
states = Dictionary(uniqueKeysWithValues: page.fields.map {
|
||||
($0.id, FieldState(name: $0.name, value: $0.value))
|
||||
})
|
||||
localDirty = false
|
||||
}
|
||||
|
||||
private func inputs() -> [MobileEntryEditorInput] {
|
||||
page.fields.map { field in
|
||||
let state = states[field.id] ?? FieldState(name: field.name, value: field.value)
|
||||
return MobileEntryEditorInput(id: field.id, name: state.name, value: state.value)
|
||||
}
|
||||
}
|
||||
|
||||
private func synchronizeDraft() throws {
|
||||
view.endEditing(true)
|
||||
try authentication.touchUserActivity()
|
||||
page = try authentication.updateEntryEditor(editor: editorID, fields: inputs())
|
||||
resetStates()
|
||||
}
|
||||
|
||||
private func cancelRequested() {
|
||||
if isDirty {
|
||||
confirmDiscard()
|
||||
} else {
|
||||
discardAndDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private func confirmDiscard() {
|
||||
let sheet = UIAlertController(
|
||||
title: "Discard Changes?",
|
||||
message: "Unsaved entry changes will be lost.",
|
||||
preferredStyle: .actionSheet
|
||||
)
|
||||
sheet.addAction(UIAlertAction(title: "Discard Changes", style: .destructive) {
|
||||
[weak self] _ in self?.discardAndDismiss()
|
||||
})
|
||||
sheet.addAction(UIAlertAction(title: "Keep Editing", style: .cancel))
|
||||
sheet.popoverPresentationController?.barButtonItem = navigationItem.leftBarButtonItem
|
||||
present(sheet, animated: true)
|
||||
}
|
||||
|
||||
private func discardAndDismiss() {
|
||||
try? authentication.discardEntryEditor(editor: editorID)
|
||||
states.removeAll(keepingCapacity: false)
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
private func addRequested() {
|
||||
let sheet = UIAlertController(title: "Add Field", message: nil, preferredStyle: .actionSheet)
|
||||
sheet.addAction(UIAlertAction(title: "Named Field", style: .default) { [weak self] _ in
|
||||
self?.promptForNamedField()
|
||||
})
|
||||
sheet.addAction(UIAlertAction(title: "Notes", style: .default) { [weak self] _ in
|
||||
self?.addField(kind: .note, name: nil, value: "")
|
||||
})
|
||||
sheet.addAction(UIAlertAction(title: "OTP URI", style: .default) { [weak self] _ in
|
||||
self?.promptForOtpUri()
|
||||
})
|
||||
sheet.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
sheet.popoverPresentationController?.barButtonItem = toolbarItems?.first
|
||||
present(sheet, animated: true)
|
||||
}
|
||||
|
||||
private func promptForNamedField() {
|
||||
let alert = UIAlertController(
|
||||
title: "Named Field",
|
||||
message: "Enter a field name. You can enter its value in the form.",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addTextField { field in
|
||||
field.placeholder = "Field Name"
|
||||
field.autocapitalizationType = .none
|
||||
field.autocorrectionType = .no
|
||||
field.clearButtonMode = .whileEditing
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "Add", style: .default) { [weak self, weak alert] _ in
|
||||
guard let name = alert?.textFields?.first?.text, !name.isEmpty else { return }
|
||||
self?.addField(kind: .field, name: name, value: "")
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func promptForOtpUri() {
|
||||
let alert = UIAlertController(
|
||||
title: "OTP URI",
|
||||
message: "Enter the complete otpauth URI.",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addTextField { field in
|
||||
field.placeholder = "otpauth://…"
|
||||
field.keyboardType = .URL
|
||||
field.autocapitalizationType = .none
|
||||
field.autocorrectionType = .no
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "Add", style: .default) { [weak self, weak alert] _ in
|
||||
guard let value = alert?.textFields?.first?.text, !value.isEmpty else { return }
|
||||
self?.addField(kind: .otpUri, name: nil, value: value)
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func addField(kind: MobileEntryEditorFieldKind, name: String?, value: String) {
|
||||
do {
|
||||
try synchronizeDraft()
|
||||
page = try authentication.addEntryEditorField(
|
||||
editor: editorID,
|
||||
kind: kind,
|
||||
name: name,
|
||||
value: value
|
||||
)
|
||||
resetStates()
|
||||
tableView.reloadData()
|
||||
if !page.fields.isEmpty {
|
||||
let path = IndexPath(row: page.fields.count - 1, section: 0)
|
||||
tableView.scrollToRow(at: path, at: .bottom, animated: true)
|
||||
}
|
||||
} catch {
|
||||
presentEditorFailure(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func generateRequested() {
|
||||
let alert = UIAlertController(
|
||||
title: "Generate Password",
|
||||
message: "Choose a validated length from 1 through \(page.maximumPasswordLength).",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addTextField { [defaultLength = page.defaultPasswordLength] field in
|
||||
field.text = String(defaultLength)
|
||||
field.keyboardType = .numberPad
|
||||
field.clearButtonMode = .whileEditing
|
||||
field.accessibilityLabel = "Password length"
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "With Symbols", style: .default) { [weak self, weak alert] _ in
|
||||
self?.generate(from: alert, noSymbols: false)
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Letters & Numbers", style: .default) {
|
||||
[weak self, weak alert] _ in self?.generate(from: alert, noSymbols: true)
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func generate(from alert: UIAlertController?, noSymbols: Bool) {
|
||||
guard let text = alert?.textFields?.first?.text,
|
||||
let length = UInt32(text)
|
||||
else {
|
||||
let failure = UIAlertController(
|
||||
title: "Invalid Password Length",
|
||||
message: "Enter a whole number from 1 through \(page.maximumPasswordLength).",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
failure.addAction(UIAlertAction(title: "OK", style: .default))
|
||||
present(failure, animated: true)
|
||||
return
|
||||
}
|
||||
do {
|
||||
try synchronizeDraft()
|
||||
page = try authentication.generateEntryEditorPassword(
|
||||
editor: editorID,
|
||||
length: length,
|
||||
noSymbols: noSymbols
|
||||
)
|
||||
resetStates()
|
||||
tableView.reloadData()
|
||||
UIAccessibility.post(notification: .announcement, argument: "Password generated")
|
||||
} catch {
|
||||
presentEditorFailure(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func saveRequested() {
|
||||
view.endEditing(true)
|
||||
let fields = inputs()
|
||||
let authentication = authentication
|
||||
let editorID = editorID
|
||||
navigationItem.leftBarButtonItem?.isEnabled = false
|
||||
navigationItem.rightBarButtonItem?.isEnabled = false
|
||||
operationTask?.cancel()
|
||||
operationTask = Task { [weak self] in
|
||||
let result = await Task.detached(priority: .userInitiated) {
|
||||
do {
|
||||
try authentication.touchUserActivity()
|
||||
return Result<MobileEntryPage, AuthenticationFailure>.success(
|
||||
try authentication.saveEntryEditor(editor: editorID, fields: fields)
|
||||
)
|
||||
} catch let error as MobileAuthenticationFfiError {
|
||||
return .failure(AuthenticationFailure(error))
|
||||
} catch {
|
||||
return .failure(.unexpected)
|
||||
}
|
||||
}.value
|
||||
guard !Task.isCancelled, let self else { return }
|
||||
navigationItem.leftBarButtonItem?.isEnabled = true
|
||||
navigationItem.rightBarButtonItem?.isEnabled = true
|
||||
switch result {
|
||||
case let .success(savedPage):
|
||||
states.removeAll(keepingCapacity: false)
|
||||
dismiss(animated: true) { self.saved(savedPage.id) }
|
||||
case let .failure(failure):
|
||||
presentSaveFailure(failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func presentSaveFailure(_ failure: AuthenticationFailure) {
|
||||
let alert = UIAlertController(
|
||||
title: failure.title,
|
||||
message: failure.detail,
|
||||
preferredStyle: .alert
|
||||
)
|
||||
if failure.kind == .conflict {
|
||||
alert.addAction(UIAlertAction(title: "Reload Latest", style: .destructive) {
|
||||
[weak self] _ in self?.reloadLatest()
|
||||
})
|
||||
}
|
||||
alert.addAction(UIAlertAction(title: "Keep Editing", style: .cancel))
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
private func reloadLatest() {
|
||||
let path = page.path
|
||||
try? authentication.discardEntryEditor(editor: editorID)
|
||||
do {
|
||||
let session = try authentication.beginEntryEditor(path: path)
|
||||
editorID = session.id
|
||||
page = session.page
|
||||
resetStates()
|
||||
tableView.reloadData()
|
||||
} catch {
|
||||
presentEditorFailure(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentEditorFailure(_ error: Error) {
|
||||
let failure = (error as? MobileAuthenticationFfiError).map(AuthenticationFailure.init)
|
||||
?? .unexpected
|
||||
presentAuthenticationFailure(failure)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private final class MobileEntryEditorCell: UITableViewCell, UITextViewDelegate {
|
||||
private let iconView = UIImageView()
|
||||
private let labelView = UILabel()
|
||||
private let nameField = UITextField()
|
||||
private let valueField = UITextField()
|
||||
private let valueView = UITextView()
|
||||
private let diagnosticView = UILabel()
|
||||
private let revealButton = UIButton(type: .system)
|
||||
private var changed: ((String?, String?) -> Void)?
|
||||
private var currentName: String?
|
||||
private var currentValue: String?
|
||||
private var sensitive = false
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
selectionStyle = .none
|
||||
iconView.tintColor = .secondaryLabel
|
||||
iconView.translatesAutoresizingMaskIntoConstraints = false
|
||||
labelView.font = .preferredFont(forTextStyle: .caption1)
|
||||
labelView.textColor = .secondaryLabel
|
||||
labelView.adjustsFontForContentSizeCategory = true
|
||||
for field in [nameField, valueField] {
|
||||
field.font = .preferredFont(forTextStyle: .body)
|
||||
field.adjustsFontForContentSizeCategory = true
|
||||
field.clearButtonMode = .whileEditing
|
||||
field.addTarget(self, action: #selector(textFieldChanged(_:)), for: .editingChanged)
|
||||
}
|
||||
nameField.placeholder = "Field Name"
|
||||
nameField.autocapitalizationType = .none
|
||||
nameField.autocorrectionType = .no
|
||||
valueView.font = .preferredFont(forTextStyle: .body)
|
||||
valueView.adjustsFontForContentSizeCategory = true
|
||||
valueView.backgroundColor = .clear
|
||||
valueView.isScrollEnabled = false
|
||||
valueView.textContainerInset = .zero
|
||||
valueView.textContainer.lineFragmentPadding = 0
|
||||
valueView.delegate = self
|
||||
diagnosticView.font = .preferredFont(forTextStyle: .footnote)
|
||||
diagnosticView.textColor = .systemOrange
|
||||
diagnosticView.adjustsFontForContentSizeCategory = true
|
||||
diagnosticView.numberOfLines = 0
|
||||
revealButton.configuration = .plain()
|
||||
revealButton.configuration?.image = UIImage(systemName: "eye")
|
||||
revealButton.addAction(UIAction { [weak self] _ in self?.toggleReveal() }, for: .touchUpInside)
|
||||
let heading = UIStackView(arrangedSubviews: [labelView, nameField])
|
||||
heading.axis = .vertical
|
||||
heading.spacing = 2
|
||||
let body = UIStackView(arrangedSubviews: [heading, valueField, valueView, diagnosticView])
|
||||
body.axis = .vertical
|
||||
body.spacing = 6
|
||||
let row = UIStackView(arrangedSubviews: [iconView, body, revealButton])
|
||||
row.alignment = .top
|
||||
row.spacing = 12
|
||||
row.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(row)
|
||||
NSLayoutConstraint.activate([
|
||||
iconView.widthAnchor.constraint(equalToConstant: 24),
|
||||
iconView.heightAnchor.constraint(equalToConstant: 24),
|
||||
revealButton.widthAnchor.constraint(equalToConstant: 44),
|
||||
revealButton.heightAnchor.constraint(equalToConstant: 44),
|
||||
valueView.heightAnchor.constraint(greaterThanOrEqualToConstant: 72),
|
||||
row.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
|
||||
row.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
|
||||
row.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
|
||||
row.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) is not supported")
|
||||
}
|
||||
|
||||
func configure(
|
||||
field: MobileEntryEditorField,
|
||||
name: String?,
|
||||
value: String?,
|
||||
changed: @escaping (String?, String?) -> Void
|
||||
) {
|
||||
self.changed = changed
|
||||
currentName = name
|
||||
currentValue = value
|
||||
sensitive = field.sensitive
|
||||
iconView.image = UIImage(systemName: field.systemImage)
|
||||
labelView.text = field.label
|
||||
nameField.text = name
|
||||
nameField.isHidden = !field.nameEditable
|
||||
labelView.isHidden = field.nameEditable
|
||||
let multiline = field.multiline || field.kind == .note
|
||||
valueField.isHidden = multiline
|
||||
valueView.isHidden = !multiline
|
||||
valueField.text = value ?? field.maskedValue
|
||||
valueView.text = value ?? field.maskedValue
|
||||
let editable = value != nil
|
||||
nameField.isEnabled = editable
|
||||
valueField.isEnabled = editable
|
||||
valueView.isEditable = editable
|
||||
valueField.isSecureTextEntry = field.sensitive
|
||||
valueField.textContentType = field.kind == .password ? .password : nil
|
||||
valueField.keyboardType = field.kind == .otpUri ? .URL : .default
|
||||
valueField.autocapitalizationType = field.sensitive ? .none : .sentences
|
||||
valueField.autocorrectionType = field.sensitive ? .no : .default
|
||||
valueView.autocapitalizationType = .sentences
|
||||
diagnosticView.text = field.diagnostic
|
||||
diagnosticView.isHidden = field.diagnostic == nil
|
||||
revealButton.isHidden = !field.sensitive
|
||||
revealButton.accessibilityLabel = "Reveal \(field.label)"
|
||||
nameField.accessibilityLabel = "\(field.label) name"
|
||||
valueField.accessibilityLabel = field.label
|
||||
valueView.accessibilityLabel = field.label
|
||||
}
|
||||
|
||||
func focusValue() {
|
||||
if valueView.isHidden {
|
||||
valueField.becomeFirstResponder()
|
||||
} else {
|
||||
valueView.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
func clearSensitiveContent() {
|
||||
currentValue = nil
|
||||
valueField.text = nil
|
||||
valueView.text = nil
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
changed = nil
|
||||
currentName = nil
|
||||
currentValue = nil
|
||||
valueField.isSecureTextEntry = false
|
||||
}
|
||||
|
||||
@objc private func textFieldChanged(_ sender: UITextField) {
|
||||
if sender === nameField {
|
||||
currentName = sender.text
|
||||
} else {
|
||||
currentValue = sender.text
|
||||
}
|
||||
changed?(currentName, currentValue)
|
||||
}
|
||||
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
currentValue = textView.text
|
||||
changed?(currentName, currentValue)
|
||||
}
|
||||
|
||||
private func toggleReveal() {
|
||||
guard sensitive else { return }
|
||||
valueField.isSecureTextEntry.toggle()
|
||||
revealButton.configuration?.image = UIImage(
|
||||
systemName: valueField.isSecureTextEntry ? "eye" : "eye.slash"
|
||||
)
|
||||
revealButton.accessibilityLabel = valueField.isSecureTextEntry
|
||||
? "Reveal field"
|
||||
: "Hide field"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user