Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swap to using cipher list view #1124

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class CipherMatchingHelper {
/// - ciphers: The list of ciphers to filter.
/// - Returns: The list of ciphers that match the URI.
///
func ciphersMatching(uri: String?, ciphers: [CipherView]) async -> [CipherView] {
func ciphersMatching(uri: String?, ciphers: [CipherListView]) async -> [CipherListView] {
guard let uri else { return [] }

let matchURL = URL(string: uri)
Expand All @@ -66,7 +66,7 @@ class CipherMatchingHelper {
let defaultMatchType = await (try? stateService.getDefaultUriMatchType()) ?? .domain

let matchingCiphers = ciphers.reduce(
into: (exact: [CipherView], fuzzy: [CipherView])([], [])
into: (exact: [CipherListView], fuzzy: [CipherListView])([], [])
) { result, cipher in
let match = checkForCipherMatch(
cipher: cipher,
Expand Down Expand Up @@ -138,15 +138,14 @@ class CipherMatchingHelper {
/// - Returns: The result of the match for the cipher and URI.
///
private func checkForCipherMatch( // swiftlint:disable:this function_parameter_count
cipher: CipherView,
cipher: CipherListView,
defaultMatchType: UriMatchType,
isApp: Bool,
matchUri: String,
matchingDomains: Set<String>,
matchingFuzzyDomains: Set<String>
) -> MatchResult {
guard cipher.type == .login,
let login = cipher.login,
guard case let .login(login) = cipher.type,
let loginUris = login.uris,
cipher.deletedDate == nil else {
return .none
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ extension VaultFilterType {
/// - Parameter cipher: The `CipherView` to determine if it should be in the vault list.
/// - Returns: Whether the cipher should be displayed in the vault list.
///
func cipherFilter(_ cipher: CipherView) -> Bool {
func cipherFilter(_ cipher: CipherListView) -> Bool {
switch self {
case .allVaults:
true
Expand Down Expand Up @@ -82,7 +82,7 @@ extension VaultFilterType {
/// - ciphers: The `CipherView` objects used to determine if a folder is empty.
/// - Returns: Whether the folder should be displayed in the vault list.
///
func folderFilter(_ folder: FolderView, ciphers: [CipherView]) -> Bool {
func folderFilter(_ folder: FolderView, ciphers: [CipherListView]) -> Bool {
switch self {
case .allVaults:
return true
Expand Down
204 changes: 107 additions & 97 deletions BitwardenShared/Core/Vault/Repositories/VaultRepository.swift

Large diffs are not rendered by default.

227 changes: 113 additions & 114 deletions BitwardenShared/UI/Vault/Extensions/Alert+Vault.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ extension Alert {
@MainActor
static func moreOptions( // swiftlint:disable:this function_body_length function_parameter_count cyclomatic_complexity line_length
canCopyTotp: Bool,
cipherView: CipherView,
cipherView: CipherListView,
hasMasterPassword: Bool,
id: String,
showEdit: Bool,
Expand All @@ -183,119 +183,118 @@ extension Alert {
))
})
}

// Add any additional actions for the type of cipher selected.
switch cipherView.type {
case .card:
if let number = cipherView.card?.number {
alertActions.append(AlertAction(title: Localizations.copyNumber, style: .default) { _, _ in
await action(.copy(
toast: Localizations.number,
value: number,
requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
logEvent: nil,
cipherId: nil
))
})
}
if let code = cipherView.card?.code {
alertActions.append(AlertAction(title: Localizations.copySecurityCode, style: .default) { _, _ in
await action(.copy(
toast: Localizations.securityCode,
value: code,
requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
logEvent: .cipherClientCopiedCardCode,
cipherId: cipherView.id
))
})
}
case .login:
if let username = cipherView.login?.username {
alertActions.append(AlertAction(title: Localizations.copyUsername, style: .default) { _, _ in
await action(.copy(
toast: Localizations.username,
value: username,
requiresMasterPasswordReprompt: false,
logEvent: nil,
cipherId: nil
))
})
}
if let password = cipherView.login?.password,
cipherView.viewPassword {
alertActions.append(AlertAction(title: Localizations.copyPassword, style: .default) { _, _ in
await action(.copy(
toast: Localizations.password,
value: password,
requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
logEvent: .cipherClientCopiedPassword,
cipherId: cipherView.id
))
})
}
if canCopyTotp, let totp = cipherView.login?.totp {
alertActions.append(AlertAction(title: Localizations.copyTotp, style: .default) { _, _ in
await action(.copyTotp(
totpKey: TOTPKeyModel(authenticatorKey: totp),
requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword
))
})
}
if let uri = cipherView.login?.uris?.first?.uri,
let url = URL(string: uri) {
alertActions
.append(AlertAction(title: Localizations.launch, style: .default) { _, _ in
await action(.launch(url: url))
})
}
case .identity:
// No-op: no extra options beyond view and edit.
break
case .secureNote:
if let notes = cipherView.notes {
alertActions.append(AlertAction(title: Localizations.copyNotes, style: .default) { _, _ in
await action(.copy(
toast: Localizations.notes,
value: notes,
requiresMasterPasswordReprompt: false,
logEvent: nil,
cipherId: nil
))
})
}
case .sshKey:
if let sshKey = cipherView.sshKey {
alertActions.append(AlertAction(title: Localizations.copyPublicKey, style: .default) { _, _ in
await action(.copy(
toast: Localizations.publicKey,
value: sshKey.publicKey,
requiresMasterPasswordReprompt: false,
logEvent: nil,
cipherId: cipherView.id
))
})
if cipherView.viewPassword {
alertActions.append(AlertAction(title: Localizations.copyPrivateKey, style: .default) { _, _ in
await action(.copy(
toast: Localizations.privateKey,
value: sshKey.privateKey,
requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
logEvent: nil,
cipherId: cipherView.id
))
})
}
alertActions.append(AlertAction(title: Localizations.copyFingerprint, style: .default) { _, _ in
await action(.copy(
toast: Localizations.fingerprint,
value: sshKey.fingerprint,
requiresMasterPasswordReprompt: false,
logEvent: nil,
cipherId: cipherView.id
))
})
}
}
// // Add any additional actions for the type of cipher selected.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: We probably need to adjust this to be lazy vs eager, and ad-hoc decrypt items when clicking on items.

// switch cipherView.type {
// case .card:
// if let number = cipherView.card?.number {
// alertActions.append(AlertAction(title: Localizations.copyNumber, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.number,
// value: number,
// requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
// logEvent: nil,
// cipherId: nil
// ))
// })
// }
// if let code = cipherView.card?.code {
// alertActions.append(AlertAction(title: Localizations.copySecurityCode, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.securityCode,
// value: code,
// requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
// logEvent: .cipherClientCopiedCardCode,
// cipherId: cipherView.id
// ))
// })
// }
// case .login:
// if let username = cipherView.login?.username {
// alertActions.append(AlertAction(title: Localizations.copyUsername, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.username,
// value: username,
// requiresMasterPasswordReprompt: false,
// logEvent: nil,
// cipherId: nil
// ))
// })
// }
// if let password = cipherView.login?.password,
// cipherView.viewPassword {
// alertActions.append(AlertAction(title: Localizations.copyPassword, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.password,
// value: password,
// requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
// logEvent: .cipherClientCopiedPassword,
// cipherId: cipherView.id
// ))
// })
// }
// if canCopyTotp, let totp = cipherView.login?.totp {
// alertActions.append(AlertAction(title: Localizations.copyTotp, style: .default) { _, _ in
// await action(.copyTotp(
// totpKey: TOTPKeyModel(authenticatorKey: totp),
// requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword
// ))
// })
// }
// if let uri = cipherView.login?.uris?.first?.uri,
// let url = URL(string: uri) {
// alertActions
// .append(AlertAction(title: Localizations.launch, style: .default) { _, _ in
// await action(.launch(url: url))
// })
// }
// case .identity:
// // No-op: no extra options beyond view and edit.
// break
// case .secureNote:
// if let notes = cipherView.notes {
// alertActions.append(AlertAction(title: Localizations.copyNotes, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.notes,
// value: notes,
// requiresMasterPasswordReprompt: false,
// logEvent: nil,
// cipherId: nil
// ))
// })
// }
// case .sshKey:
// if let sshKey = cipherView.sshKey {
// alertActions.append(AlertAction(title: Localizations.copyPublicKey, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.publicKey,
// value: sshKey.publicKey,
// requiresMasterPasswordReprompt: false,
// logEvent: nil,
// cipherId: cipherView.id
// ))
// })
// if cipherView.viewPassword {
// alertActions.append(AlertAction(title: Localizations.copyPrivateKey, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.privateKey,
// value: sshKey.privateKey,
// requiresMasterPasswordReprompt: cipherView.reprompt == .password && hasMasterPassword,
// logEvent: nil,
// cipherId: cipherView.id
// ))
// })
// }
// alertActions.append(AlertAction(title: Localizations.copyFingerprint, style: .default) { _, _ in
// await action(.copy(
// toast: Localizations.fingerprint,
// value: sshKey.fingerprint,
// requiresMasterPasswordReprompt: false,
// logEvent: nil,
// cipherId: cipherView.id
// ))
// })
// }
// }

// Return the alert.
return Alert(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,13 @@ class DefaultVaultItemMoreOptionsHelper: VaultItemMoreOptionsHelper {
await generateAndCopyTotpCode(totpKey: totpKey, handleDisplayToast: handleDisplayToast)
}
case let .edit(cipherView, requiresMasterPasswordReprompt):
guard let id = cipherView.id else { return }
if requiresMasterPasswordReprompt {
presentMasterPasswordRepromptAlert {
self.coordinator.navigate(to: .editItem(cipherView), context: self)
self.coordinator.navigate(to: .editItemFrom(id: id), context: self)
}
} else {
coordinator.navigate(to: .editItem(cipherView), context: self)
coordinator.navigate(to: .editItemFrom(id: id), context: self)
}
case let .launch(url):
handleOpenURL(url.sanitized)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,48 @@ extension CipherView {
}
}

extension CipherListView {
static func fixture(
attachments: UInt32 = 0,
collectionIds: [String] = [],
creationDate: DateTime = Date(year: 2023, month: 11, day: 5, hour: 9, minute: 41),
deletedDate: Date? = nil,
edit: Bool = true,
favorite: Bool = false,
folderId: String? = nil,
id: String? = "1",
key: String? = nil,
name: String = "Bitwarden",
organizationId: String? = nil,
reprompt: BitwardenSdk.CipherRepromptType = .none,
organizationUseTotp: Bool = false,
revisionDate: Date = Date(year: 2023, month: 11, day: 5, hour: 9, minute: 41),
type: BitwardenSdk.CipherListViewType = .login(LoginListView(hasFido2: false, totp: nil, uris: [])),
viewPassword: Bool = true,
subtitle: String = "subtitle"
) -> CipherListView {
CipherListView(
id: id,
organizationId: organizationId,
folderId: folderId,
collectionIds: collectionIds,
key: key,
name: name,
subtitle: subtitle,
type: type,
favorite: favorite,
reprompt: reprompt,
organizationUseTotp: organizationUseTotp,
edit: edit,
viewPassword: viewPassword,
attachments: attachments,
creationDate: creationDate,
deletedDate: deletedDate,
revisionDate: revisionDate
)
}
}

extension Collection {
static func fixture(
id: String? = "",
Expand Down
Loading
Loading