[BITAU-121] Add accountDomain and accountEmail to AuthenticatorBridge items (#1017)

This commit is contained in:
Brant DeBow 2024-10-10 16:58:49 -04:00 committed by GitHub
parent 621d9019be
commit 0e113bf7cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 95 additions and 47 deletions

View File

@ -6,6 +6,12 @@ import Foundation
public struct AuthenticatorBridgeItemDataModel: Codable, Equatable {
// MARK: Properties
/// The domain of the Bitwarden account that owns this item. (e.g. https://vault.bitwarden.com)
public let accountDomain: String?
/// The email of the Bitwarden account that owns this item.
public let accountEmail: String?
/// Bool indicating if this item is a favorite.
public let favorite: Bool
@ -18,6 +24,6 @@ public struct AuthenticatorBridgeItemDataModel: Codable, Equatable {
/// The TOTP key used to generate codes.
public let totpKey: String?
/// The username of the Bitwarden account that owns this iteam.
/// The username of the item.
public let username: String?
}

View File

@ -6,6 +6,12 @@ import Foundation
public struct AuthenticatorBridgeItemDataView: Codable, Equatable {
// MARK: Properties
/// The domain of the Bitwarden account that owns this item. (e.g. https://vault.bitwarden.com)
public let accountDomain: String?
/// The email of the Bitwarden account that owns this item.
public let accountEmail: String?
/// Bool indicating if this item is a favorite.
public let favorite: Bool
@ -18,19 +24,29 @@ public struct AuthenticatorBridgeItemDataView: Codable, Equatable {
/// The TOTP key used to generate codes.
public let totpKey: String?
/// The username of the Bitwarden account that owns this iteam.
/// The username of the item.
public let username: String?
/// Initialize an `AuthenticatorBridgeItemDataView` with the values provided.
///
/// - Parameters:
/// - accountDomain: The domain of the Bitwarden account that owns this item.
/// - accountEmail: The email of the Bitwarden account that owns this item
/// - favorite: Bool indicating if this item is a favorite.
/// - id: The unique id of the item.
/// - name: The name of the item.
/// - totpKey: The TOTP key used to generate codes.
/// - username: The username of the Bitwarden account that owns this item.
/// - username: The username of the item.
///
public init(favorite: Bool, id: String, name: String, totpKey: String?, username: String?) {
public init(accountDomain: String?,
accountEmail: String?,
favorite: Bool,
id: String,
name: String,
totpKey: String?,
username: String?) {
self.accountDomain = accountDomain
self.accountEmail = accountEmail
self.favorite = favorite
self.id = id
self.name = name

View File

@ -62,6 +62,8 @@ public class DefaultAuthenticatorCryptographyService: SharedCryptographyService
return items.map { item in
AuthenticatorBridgeItemDataView(
accountDomain: (try? decrypt(item.accountDomain, withKey: symmetricKey)) ?? "",
accountEmail: (try? decrypt(item.accountEmail, withKey: symmetricKey)) ?? "",
favorite: item.favorite,
id: item.id,
name: (try? decrypt(item.name, withKey: symmetricKey)) ?? "",
@ -79,6 +81,8 @@ public class DefaultAuthenticatorCryptographyService: SharedCryptographyService
return items.map { item in
AuthenticatorBridgeItemDataModel(
accountDomain: encrypt(item.accountDomain, withKey: symmetricKey) ?? "",
accountEmail: encrypt(item.accountEmail, withKey: symmetricKey) ?? "",
favorite: item.favorite,
id: item.id,
name: encrypt(item.name, withKey: symmetricKey) ?? "",

View File

@ -49,7 +49,13 @@ final class AuthenticatorBridgeItemDataTests: AuthenticatorBridgeKitTestCase {
context: dataStore.persistentContainer.viewContext,
userId: "userId",
authenticatorItem: AuthenticatorBridgeItemDataModel(
favorite: true, id: "is", name: "name", totpKey: "TOTP Key", username: "username"
accountDomain: "https://vault.example.com",
accountEmail: "test@example.com",
favorite: true,
id: "is",
name: "name",
totpKey: "TOTP Key",
username: "username"
)
)

View File

@ -71,6 +71,16 @@ final class SharedCryptographyServiceTests: AuthenticatorBridgeKitTestCase {
// Encrypted values should not remain equal, unless they were `nil`
XCTAssertNotEqual(item.name, encryptedItem.name)
if item.accountDomain != nil {
XCTAssertNotEqual(item.accountDomain, encryptedItem.accountDomain)
} else {
XCTAssertNil(encryptedItem.accountDomain)
}
if item.accountEmail != nil {
XCTAssertNotEqual(item.accountEmail, encryptedItem.accountEmail)
} else {
XCTAssertNil(encryptedItem.accountEmail)
}
if item.totpKey != nil {
XCTAssertNotEqual(item.totpKey, encryptedItem.totpKey)
} else {

View File

@ -4,6 +4,8 @@ import Foundation
extension AuthenticatorBridgeItemDataView {
static func fixture(
accountDomain: String? = "",
accountEmail: String? = "",
favorite: Bool = false,
id: String = UUID().uuidString,
name: String = "Name",
@ -11,6 +13,8 @@ extension AuthenticatorBridgeItemDataView {
username: String? = nil
) -> AuthenticatorBridgeItemDataView {
AuthenticatorBridgeItemDataView(
accountDomain: accountDomain,
accountEmail: accountEmail,
favorite: favorite,
id: id,
name: name,
@ -23,9 +27,12 @@ extension AuthenticatorBridgeItemDataView {
[
AuthenticatorBridgeItemDataView.fixture(),
AuthenticatorBridgeItemDataView.fixture(favorite: true),
AuthenticatorBridgeItemDataView.fixture(accountDomain: "https://vault.example.com"),
AuthenticatorBridgeItemDataView.fixture(accountEmail: "bw@example.com"),
AuthenticatorBridgeItemDataView.fixture(totpKey: "TOTP Key"),
AuthenticatorBridgeItemDataView.fixture(username: "Username"),
AuthenticatorBridgeItemDataView.fixture(totpKey: "TOTP Key", username: "Username"),
AuthenticatorBridgeItemDataView.fixture(accountEmail: ""),
AuthenticatorBridgeItemDataView.fixture(totpKey: ""),
AuthenticatorBridgeItemDataView.fixture(username: ""),
AuthenticatorBridgeItemDataView.fixture(totpKey: "", username: ""),

View File

@ -7,30 +7,14 @@ class MockSharedCryptographyService: SharedCryptographyService {
var decryptCalled = false
var encryptCalled = false
func decryptAuthenticatorItemDatas(
_ items: [AuthenticatorBridgeKit.AuthenticatorBridgeItemData]
) async throws -> [AuthenticatorBridgeKit.AuthenticatorBridgeItemDataView] {
decryptCalled = true
return items.compactMap { item in
guard let model = item.model else { return nil }
return AuthenticatorBridgeItemDataView(
favorite: model.favorite,
id: model.id,
name: model.name,
totpKey: model.totpKey,
username: model.username
)
}
}
func decryptAuthenticatorItems(
_ items: [AuthenticatorBridgeItemDataModel]
) async throws -> [AuthenticatorBridgeItemDataView] {
decryptCalled = true
return items.map { model in
AuthenticatorBridgeItemDataView(
accountDomain: model.accountDomain,
accountEmail: model.accountEmail,
favorite: model.favorite,
id: model.id,
name: model.name,
@ -46,6 +30,8 @@ class MockSharedCryptographyService: SharedCryptographyService {
encryptCalled = true
return items.map { view in
AuthenticatorBridgeItemDataModel(
accountDomain: view.accountDomain,
accountEmail: view.accountEmail,
favorite: view.favorite,
id: view.id,
name: view.name,

View File

@ -160,16 +160,17 @@ actor DefaultAuthenticatorSyncService: NSObject, AuthenticatorSyncService {
let decryptedCiphers = try await totpCiphers.asyncMap { cipher in
try await self.clientService.vault(for: userId).ciphers().decrypt(cipher: cipher)
}
let account = try await stateService.getActiveAccount()
let username = account.profile.email
let account = try? await stateService.getAccount(userId: userId)
return decryptedCiphers.map { cipher in
AuthenticatorBridgeItemDataView(
accountDomain: account?.settings.environmentUrls?.webVaultHost,
accountEmail: account?.profile.email,
favorite: false,
id: cipher.id ?? UUID().uuidString,
name: cipher.name,
totpKey: cipher.login?.totp,
username: username
username: cipher.login?.username
)
}
}

View File

@ -103,7 +103,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -111,7 +111,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
deletedDate: Date(timeIntervalSinceNow: -10000),
id: "Deleted",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -134,7 +134,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -163,7 +163,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
cipherDataStore.cipherSubjectByUserId["1"]?.send([
.fixture(
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -172,11 +172,13 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
waitFor(authBridgeItemService.storedItems["1"]?.first != nil)
let item = try XCTUnwrap(authBridgeItemService.storedItems["1"]?.first)
XCTAssertEqual(item.accountDomain, "vault.bitwarden.com")
XCTAssertEqual(item.accountEmail, "user@bitwarden.com")
XCTAssertEqual(item.favorite, false)
XCTAssertNotNil(item.id)
XCTAssertEqual(item.name, "Bitwarden")
XCTAssertEqual(item.totpKey, "totp")
XCTAssertEqual(item.username, "user@bitwarden.com")
XCTAssertEqual(item.username, "masked@example.com")
}
/// Verifies that the AuthSyncService responds to new Ciphers published by converting them into ItemViews and
@ -190,7 +192,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -199,11 +201,13 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
waitFor(authBridgeItemService.storedItems["1"]?.first != nil)
let item = try XCTUnwrap(authBridgeItemService.storedItems["1"]?.first)
XCTAssertEqual(item.accountDomain, "vault.bitwarden.com")
XCTAssertEqual(item.accountEmail, "user@bitwarden.com")
XCTAssertEqual(item.favorite, false)
XCTAssertEqual(item.id, "1234")
XCTAssertEqual(item.name, "Bitwarden")
XCTAssertEqual(item.totpKey, "totp")
XCTAssertEqual(item.username, "user@bitwarden.com")
XCTAssertEqual(item.username, "masked@example.com")
}
/// Verifies that the AuthSyncService handles an error when attempting to fetch the accounts to check
@ -343,7 +347,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -360,7 +364,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -392,7 +396,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -416,7 +420,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -424,14 +428,18 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
waitFor(authBridgeItemService.storedItems["1"]?.first != nil)
let item = try XCTUnwrap(authBridgeItemService.storedItems["1"]?.first)
XCTAssertEqual(item.accountDomain, "vault.bitwarden.com")
XCTAssertEqual(item.accountEmail, "user@bitwarden.com")
XCTAssertEqual(item.favorite, false)
XCTAssertEqual(item.id, "1234")
XCTAssertEqual(item.name, "Bitwarden")
XCTAssertEqual(item.totpKey, "totp")
XCTAssertEqual(item.username, "user@bitwarden.com")
XCTAssertEqual(item.username, "masked@example.com")
await stateService.addAccount(.fixture(profile: .fixture(email: "different@bitwarden.com",
userId: "2")))
await stateService.addAccount(.fixture(
profile: .fixture(email: "different@bitwarden.com", userId: "2"),
settings: .fixture(environmentUrls: .fixture(webVault: URL(string: "https://vault.example.com")))
))
stateService.syncToAuthenticatorByUserId["2"] = true
vaultTimeoutService.isClientLocked["2"] = false
stateService.syncToAuthenticatorSubject.send(("2", true))
@ -440,7 +448,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "4321",
login: .fixture(
username: "different@bitwarden.com",
username: "masked2@example.com",
totp: "totp2"
)
),
@ -448,11 +456,13 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
waitFor(authBridgeItemService.storedItems["2"]?.first != nil)
let otherItem = try XCTUnwrap(authBridgeItemService.storedItems["2"]?.first)
XCTAssertEqual(otherItem.accountDomain, "vault.example.com")
XCTAssertEqual(otherItem.accountEmail, "different@bitwarden.com")
XCTAssertEqual(otherItem.favorite, false)
XCTAssertEqual(otherItem.id, "4321")
XCTAssertEqual(otherItem.name, "Bitwarden")
XCTAssertEqual(otherItem.totpKey, "totp2")
XCTAssertEqual(otherItem.username, "different@bitwarden.com")
XCTAssertEqual(otherItem.username, "masked2@example.com")
}
/// When the sync is turned on, but the vault is locked, the service should subscribe and wait
@ -473,7 +483,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -482,11 +492,13 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
waitFor(authBridgeItemService.storedItems["1"]?.first != nil)
let item = try XCTUnwrap(authBridgeItemService.storedItems["1"]?.first)
XCTAssertEqual(item.accountDomain, "vault.bitwarden.com")
XCTAssertEqual(item.accountEmail, "user@bitwarden.com")
XCTAssertEqual(item.favorite, false)
XCTAssertEqual(item.id, "1234")
XCTAssertEqual(item.name, "Bitwarden")
XCTAssertEqual(item.totpKey, "totp")
XCTAssertEqual(item.username, "user@bitwarden.com")
XCTAssertEqual(item.username, "masked@example.com")
}
/// Verifies that the AuthSyncService stops listening for Cipher updates when the user's vault is locked.
@ -508,7 +520,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -545,7 +557,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),
@ -585,7 +597,7 @@ final class AuthenticatorSyncServiceTests: BitwardenTestCase { // swiftlint:disa
.fixture(
id: "1234",
login: .fixture(
username: "user@bitwarden.com",
username: "masked@example.com",
totp: "totp"
)
),