Skip to content

Commit

Permalink
BIT-2043: Display passkeys in vault (#535)
Browse files Browse the repository at this point in the history
  • Loading branch information
matt-livefront authored Mar 19, 2024
1 parent aeac35b commit 0dbf027
Show file tree
Hide file tree
Showing 38 changed files with 262 additions and 7 deletions.
45 changes: 44 additions & 1 deletion BitwardenShared/Core/Vault/Extensions/BitwardenSdk+Vault.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,31 @@ extension CipherIdentityModel {
}
}

extension CipherLoginFido2Credential {
init(fido2Credential credential: Fido2Credential) {
self.init(
counter: credential.counter,
creationDate: credential.creationDate,
credentialId: credential.credentialId,
discoverable: credential.discoverable,
keyAlgorithm: credential.keyAlgorithm,
keyCurve: credential.keyCurve,
keyType: credential.keyType,
keyValue: credential.keyValue,
rpId: credential.rpId,
rpName: credential.rpName,
userDisplayName: credential.userDisplayName,
userHandle: credential.userHandle,
userName: credential.userName
)
}
}

extension CipherLoginModel {
init(login: BitwardenSdk.Login) {
self.init(
autofillOnPageLoad: login.autofillOnPageLoad,
fido2Credentials: login.fido2Credentials?.map(CipherLoginFido2Credential.init),
password: login.password,
passwordRevisionDate: login.passwordRevisionDate,
totp: login.totp,
Expand Down Expand Up @@ -330,6 +351,28 @@ extension BitwardenSdk.CipherRepromptType {
}
}

extension BitwardenSdk.Fido2Credential: Identifiable, @unchecked Sendable {
public var id: String { credentialId }

init(cipherLoginFido2Credential model: CipherLoginFido2Credential) {
self.init(
credentialId: model.credentialId,
keyType: model.keyType,
keyAlgorithm: model.keyAlgorithm,
keyCurve: model.keyCurve,
keyValue: model.keyValue,
rpId: model.rpId,
userHandle: model.userHandle,
userName: model.userName,
counter: model.counter,
rpName: model.rpName,
userDisplayName: model.userDisplayName,
discoverable: model.discoverable,
creationDate: model.creationDate
)
}
}

extension BitwardenSdk.Field {
init(cipherFieldModel model: CipherFieldModel) {
self.init(
Expand Down Expand Up @@ -390,7 +433,7 @@ extension BitwardenSdk.Login {
uris: model.uris?.map(LoginUri.init),
totp: model.totp,
autofillOnPageLoad: model.autofillOnPageLoad,
fido2Credentials: nil
fido2Credentials: model.fido2Credentials?.map(Fido2Credential.init)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,44 @@ extension CollectionView {
}
}

extension Fido2Credential {
static func fixture(
counter: String = "",
creationDate: Date = Date(year: 2024, month: 3, day: 15, hour: 9, minute: 15),
credentialId: String = "",
discoverable: String = "",
keyAlgorithm: String = "",
keyCurve: String = "",
keyType: String = "",
keyValue: String = "",
rpId: String = "",
rpName: String? = nil,
userDisplayName: String? = nil,
userHandle: String? = nil,
userName: String? = nil
) -> Fido2Credential {
Fido2Credential(
credentialId: credentialId,
keyType: keyType,
keyAlgorithm: keyAlgorithm,
keyCurve: keyCurve,
keyValue: keyValue,
rpId: rpId,
userHandle: userHandle,
userName: userName,
counter: counter,
rpName: rpName,
userDisplayName: userDisplayName,
discoverable: discoverable,
creationDate: creationDate
)
}
}

extension BitwardenSdk.Login {
static func fixture(
autofillOnPageLoad: Bool? = nil,
fido2Credentials: [Fido2Credential]? = nil,
password: String? = nil,
passwordRevisionDate: Date? = nil,
uris: [LoginUri]? = nil,
Expand All @@ -313,13 +348,14 @@ extension BitwardenSdk.Login {
uris: uris,
totp: totp,
autofillOnPageLoad: autofillOnPageLoad,
fido2Credentials: nil
fido2Credentials: fido2Credentials
)
}
}

extension BitwardenSdk.LoginView {
static func fixture(
fido2Credentials: [Fido2Credential]? = nil,
password: String? = nil,
passwordRevisionDate: DateTime? = nil,
uris: [LoginUriView]? = nil,
Expand All @@ -334,7 +370,7 @@ extension BitwardenSdk.LoginView {
uris: uris,
totp: totp,
autofillOnPageLoad: autofillOnPageLoad,
fido2Credentials: nil
fido2Credentials: fido2Credentials
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Foundation

/// API model for a login cipher's FIDO2 credential.
///
struct CipherLoginFido2Credential: Codable, Equatable {
// MARK: Properties

/// The signature counter for the credential.
let counter: String

/// The creation date and time of the credential.
let creationDate: Date

/// The unique identifier of the credential.
let credentialId: String

/// Whether the FIDO2 credential is discoverable.
let discoverable: String

/// The public key algorithm of the credential.
let keyAlgorithm: String

/// The key curve of the credential.
let keyCurve: String

/// The type of public key of the credential.
let keyType: String

/// The public key of the credential.
let keyValue: String

/// The relying party (RP) identity.
let rpId: String

/// An optional name of the relying party (RP).
let rpName: String?

/// An optional display name of the user associated to the credential.
let userDisplayName: String?

/// An optional unique identifier used to identify an account.
let userHandle: String?

/// An optional formal name of the user associated to the credential.
let userName: String?
}
3 changes: 3 additions & 0 deletions BitwardenShared/Core/Vault/Models/API/CipherLoginModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ struct CipherLoginModel: Codable, Equatable {
/// Whether the login should be autofilled when the page loads.
let autofillOnPageLoad: Bool?

/// A list of FIDO2 credentials for the login.
let fido2Credentials: [CipherLoginFido2Credential]?

/// The login's password.
let password: String?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Foundation
extension CipherLoginModel {
static func fixture(
autofillOnPageLoad: Bool? = nil,
fido2Credentials: [CipherLoginFido2Credential]? = nil,
password: String? = nil,
passwordRevisionDate: Date? = nil,
totp: String? = nil,
Expand All @@ -13,6 +14,7 @@ extension CipherLoginModel {
) -> CipherLoginModel {
self.init(
autofillOnPageLoad: autofillOnPageLoad,
fido2Credentials: fido2Credentials,
password: password,
passwordRevisionDate: passwordRevisionDate,
totp: totp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class CipherAPIServiceTests: XCTestCase { // swiftlint:disable:this type_body_le
key: nil,
login: CipherLoginModel(
autofillOnPageLoad: nil,
fido2Credentials: nil,
password: "encrypted password",
passwordRevisionDate: nil,
totp: "totp",
Expand Down Expand Up @@ -105,6 +106,7 @@ class CipherAPIServiceTests: XCTestCase { // swiftlint:disable:this type_body_le
key: nil,
login: CipherLoginModel(
autofillOnPageLoad: nil,
fido2Credentials: nil,
password: "encrypted password",
passwordRevisionDate: nil,
totp: "totp",
Expand Down Expand Up @@ -231,6 +233,7 @@ class CipherAPIServiceTests: XCTestCase { // swiftlint:disable:this type_body_le
key: nil,
login: CipherLoginModel(
autofillOnPageLoad: nil,
fido2Credentials: nil,
password: "encrypted password",
passwordRevisionDate: nil,
totp: "totp",
Expand Down Expand Up @@ -282,6 +285,7 @@ class CipherAPIServiceTests: XCTestCase { // swiftlint:disable:this type_body_le
key: nil,
login: CipherLoginModel(
autofillOnPageLoad: nil,
fido2Credentials: nil,
password: "encrypted password",
passwordRevisionDate: nil,
totp: "totp",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,24 @@
"password": "encrypted password",
"passwordRevisionDate": null,
"totp": "totp",
"autofillOnPageLoad": null
"autofillOnPageLoad": null,
"fido2Credentials": [
{
"credentialId": "encrypted credentialId",
"keyType": "encrypted keyType",
"keyAlgorithm": "encrypted keyAlgorithm",
"keyCurve": "encrypted keyCurve",
"keyValue": "encrypted keyValue",
"rpId": "encrypted rpId",
"rpName": "encrypted rpName",
"userHandle": "encrypted userHandle",
"userName": "encrypted userName",
"userDisplayName": "encrypted userDisplayName",
"counter": "encrypted counter",
"discoverable": "encrypted discoverable",
"creationDate": "2024-03-15T17:31:02.244Z"
}
]
},
"card": null,
"identity": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ class SyncAPIServiceTests: BitwardenTestCase {
edit: true,
id: "3792af7a-4441-11ee-be56-0242ac120002",
login: .fixture(
fido2Credentials: [
CipherLoginFido2Credential(
counter: "encrypted counter",
creationDate: Date(timeIntervalSince1970: 1_710_523_862.244),
credentialId: "encrypted credentialId",
discoverable: "encrypted discoverable",
keyAlgorithm: "encrypted keyAlgorithm",
keyCurve: "encrypted keyCurve",
keyType: "encrypted keyType",
keyValue: "encrypted keyValue",
rpId: "encrypted rpId",
rpName: "encrypted rpName",
userDisplayName: "encrypted userDisplayName",
userHandle: "encrypted userHandle",
userName: "encrypted userName"
),
],
password: "encrypted password",
totp: "totp",
uris: [
Expand Down
17 changes: 17 additions & 0 deletions BitwardenShared/Core/Vault/Services/SyncServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,23 @@ class SyncServiceTests: BitwardenTestCase {
edit: true,
id: "3792af7a-4441-11ee-be56-0242ac120002",
login: .fixture(
fido2Credentials: [
CipherLoginFido2Credential(
counter: "encrypted counter",
creationDate: Date(timeIntervalSince1970: 1_710_523_862.244),
credentialId: "encrypted credentialId",
discoverable: "encrypted discoverable",
keyAlgorithm: "encrypted keyAlgorithm",
keyCurve: "encrypted keyCurve",
keyType: "encrypted keyType",
keyValue: "encrypted keyValue",
rpId: "encrypted rpId",
rpName: "encrypted rpName",
userDisplayName: "encrypted userDisplayName",
userHandle: "encrypted userHandle",
userName: "encrypted userName"
),
],
password: "encrypted password",
totp: "totp",
uris: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,23 @@ struct AddEditItemView_Previews: PreviewProvider {
],
totp: nil,
autofillOnPageLoad: nil,
fido2Credentials: nil
fido2Credentials: [
Fido2Credential(
credentialId: "1",
keyType: "",
keyAlgorithm: "",
keyCurve: "",
keyValue: "",
rpId: "",
userHandle: nil,
userName: nil,
counter: "",
rpName: nil,
userDisplayName: nil,
discoverable: "",
creationDate: Date(timeIntervalSince1970: 1_710_494_110)
),
]
),
identity: nil,
card: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ class AddEditItemViewTests: BitwardenTestCase { // swiftlint:disable:this type_b
hasPremium: true
)!
processor.state.loginState = .fixture(
fido2Credentials: [.fixture()],
isPasswordVisible: false,
password: "password1!",
uris: [
Expand Down Expand Up @@ -610,6 +611,7 @@ class AddEditItemViewTests: BitwardenTestCase { // swiftlint:disable:this type_b
)!
processor.state.loginState = .fixture(
canViewPassword: false,
fido2Credentials: [.fixture()],
isPasswordVisible: false,
password: "password1!",
uris: [
Expand All @@ -635,6 +637,7 @@ class AddEditItemViewTests: BitwardenTestCase { // swiftlint:disable:this type_b
hasPremium: true
)!
processor.state.loginState = .fixture(
fido2Credentials: [.fixture()],
isPasswordVisible: false,
password: "password1!",
uris: [
Expand Down Expand Up @@ -662,6 +665,7 @@ class AddEditItemViewTests: BitwardenTestCase { // swiftlint:disable:this type_b
processor.state.type = .login
processor.state.name = "Name"
processor.state.loginState = .fixture(
fido2Credentials: [.fixture()],
isPasswordVisible: true,
password: "password1!",
uris: [
Expand All @@ -685,6 +689,7 @@ class AddEditItemViewTests: BitwardenTestCase { // swiftlint:disable:this type_b
hasPremium: true
)!
processor.state.loginState = .fixture(
fido2Credentials: [.fixture()],
isPasswordVisible: true,
password: "password1!",
uris: [
Expand Down
Loading

0 comments on commit 0dbf027

Please sign in to comment.