Skip to content

Commit 7de1657

Browse files
authored
[PM-8388] Update pin verification to use the new SDK function. (#773)
1 parent fa6d33e commit 7de1657

File tree

5 files changed

+78
-101
lines changed

5 files changed

+78
-101
lines changed

BitwardenShared/Core/Auth/Repositories/AuthRepository.swift

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ protocol AuthRepository: AnyObject {
233233
/// Validates thes user's entered PIN.
234234
/// - Parameter pin: Pin to validate.
235235
/// - Returns: `true` if valid, `false` otherwise.
236-
func validatePin(pin: String) async -> Bool
236+
func validatePin(pin: String) async throws -> Bool
237237

238238
/// Verifies that the entered one-time password matches the one sent to the user.
239239
///
@@ -779,33 +779,12 @@ extension DefaultAuthRepository: AuthRepository {
779779
}
780780
}
781781

782-
func validatePin(pin: String) async -> Bool {
782+
func validatePin(pin: String) async throws -> Bool {
783783
guard let pinProtectedUserKey = try? await stateService.pinProtectedUserKey() else {
784784
return false
785785
}
786786

787-
// HACK: As the SDK doesn't provide a way to directly validate the pin yet, we have this method
788-
// which just tries to initialize the user crypto and if it succeeds then the PIN is correct, otherwise
789-
// the PIN is incorrect.
790-
791-
do {
792-
let account = try await stateService.getActiveAccount()
793-
let encryptionKeys = try await stateService.getAccountEncryptionKeys()
794-
795-
try await clientService.crypto().initializeUserCrypto(
796-
req: InitUserCryptoRequest(
797-
kdfParams: account.kdf.sdkKdf,
798-
email: account.profile.email,
799-
privateKey: encryptionKeys.encryptedPrivateKey,
800-
method: .pin(pin: pin, pinProtectedUserKey: pinProtectedUserKey)
801-
)
802-
)
803-
try await organizationService.initializeOrganizationCrypto()
804-
805-
return true
806-
} catch {
807-
return false
808-
}
787+
return try await clientService.auth().validatePin(pin: pin, pinProtectedUserKey: pinProtectedUserKey)
809788
}
810789

811790
func verifyOtp(_ otp: String) async throws {

BitwardenShared/Core/Auth/Repositories/AuthRepositoryTests.swift

Lines changed: 25 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,53 +1564,25 @@ class AuthRepositoryTests: BitwardenTestCase { // swiftlint:disable:this type_bo
15641564
XCTAssertFalse(isValid)
15651565
}
15661566

1567-
/// `validatePin(_:)` returns `true` if the pin is valid when initializing the user crypto.
1567+
/// `validatePin(_:)` returns `true` if the pin is valid.
15681568
func test_validatePin() async throws {
15691569
let account = Account.fixture()
15701570
stateService.activeAccount = account
1571-
1572-
stateService.accountEncryptionKeys = [
1573-
"1": AccountEncryptionKeys(encryptedPrivateKey: "PRIVATE_KEY", encryptedUserKey: "USER_KEY"),
1574-
]
1575-
1576-
stateService.encryptedPinByUserId[account.profile.userId] = "123"
15771571
stateService.pinProtectedUserKeyValue[account.profile.userId] = "123"
15781572

1579-
let isPinValid = await subject.validatePin(pin: "123")
1573+
clientService.mockAuth.validatePinResult = .success(true)
1574+
1575+
let isPinValid = try await subject.validatePin(pin: "123")
15801576

1581-
XCTAssertEqual(
1582-
clientService.mockCrypto.initializeUserCryptoRequest,
1583-
InitUserCryptoRequest(
1584-
kdfParams: .pbkdf2(iterations: UInt32(Constants.pbkdf2Iterations)),
1585-
1586-
privateKey: "PRIVATE_KEY",
1587-
method: .pin(pin: "123", pinProtectedUserKey: "123")
1588-
)
1589-
)
15901577
XCTAssertTrue(isPinValid)
15911578
}
15921579

15931580
/// `validatePin(_:)` returns `false` if the there is no active account.
15941581
func test_validatePin_noActiveAccount() async throws {
15951582
let account = Account.fixture()
15961583

1597-
stateService.accountEncryptionKeys = [
1598-
"1": AccountEncryptionKeys(encryptedPrivateKey: "PRIVATE_KEY", encryptedUserKey: "USER_KEY"),
1599-
]
1600-
1601-
stateService.encryptedPinByUserId[account.profile.userId] = "123"
1602-
1603-
let isPinValid = await subject.validatePin(pin: "123")
1584+
let isPinValid = try await subject.validatePin(pin: "123")
16041585

1605-
XCTAssertNotEqual(
1606-
clientService.mockCrypto.initializeUserCryptoRequest,
1607-
InitUserCryptoRequest(
1608-
kdfParams: .pbkdf2(iterations: UInt32(Constants.pbkdf2Iterations)),
1609-
1610-
privateKey: "PRIVATE_KEY",
1611-
method: .pin(pin: "123", pinProtectedUserKey: "123")
1612-
)
1613-
)
16141586
XCTAssertFalse(isPinValid)
16151587
}
16161588

@@ -1619,45 +1591,39 @@ class AuthRepositoryTests: BitwardenTestCase { // swiftlint:disable:this type_bo
16191591
let account = Account.fixture()
16201592
stateService.activeAccount = account
16211593

1622-
stateService.accountEncryptionKeys = [
1623-
"1": AccountEncryptionKeys(encryptedPrivateKey: "PRIVATE_KEY", encryptedUserKey: "USER_KEY"),
1624-
]
1625-
1626-
stateService.encryptedPinByUserId[account.profile.userId] = "123"
1627-
1628-
let isPinValid = await subject.validatePin(pin: "123")
1594+
let isPinValid = try await subject.validatePin(pin: "123")
16291595

1630-
XCTAssertNotEqual(
1631-
clientService.mockCrypto.initializeUserCryptoRequest,
1632-
InitUserCryptoRequest(
1633-
kdfParams: .pbkdf2(iterations: UInt32(Constants.pbkdf2Iterations)),
1634-
1635-
privateKey: "PRIVATE_KEY",
1636-
method: .pin(pin: "123", pinProtectedUserKey: "123")
1637-
)
1638-
)
16391596
XCTAssertFalse(isPinValid)
16401597
}
16411598

1642-
/// `validatePin(_:)` returns `false` if initializing user crypto throws.
1643-
func test_validatePin_initializeUserCryptoThrows() async throws {
1599+
/// `validatePin(_:)` returns `false` if the pin is not valid.
1600+
func test_validatePin_notValid() async throws {
16441601
let account = Account.fixture()
16451602
stateService.activeAccount = account
16461603

1647-
stateService.accountEncryptionKeys = [
1648-
"1": AccountEncryptionKeys(encryptedPrivateKey: "PRIVATE_KEY", encryptedUserKey: "USER_KEY"),
1649-
]
1650-
1651-
stateService.encryptedPinByUserId[account.profile.userId] = "123"
16521604
stateService.pinProtectedUserKeyValue[account.profile.userId] = "123"
16531605

1654-
clientService.mockCrypto.initializeUserCryptoResult = .failure(BitwardenTestError.example)
1606+
clientService.mockAuth.validatePinResult = .success(false)
16551607

1656-
let isPinValid = await subject.validatePin(pin: "123")
1608+
let isPinValid = try await subject.validatePin(pin: "123")
16571609

16581610
XCTAssertFalse(isPinValid)
16591611
}
16601612

1613+
/// `validatePin(_:)` throws when validating.
1614+
func test_validatePin_throws() async throws {
1615+
let account = Account.fixture()
1616+
stateService.activeAccount = account
1617+
1618+
stateService.pinProtectedUserKeyValue[account.profile.userId] = "123"
1619+
1620+
clientService.mockAuth.validatePinResult = .failure(BitwardenTestError.example)
1621+
1622+
await assertAsyncThrows(error: BitwardenTestError.example) {
1623+
_ = try await subject.validatePin(pin: "123")
1624+
}
1625+
}
1626+
16611627
/// `validatePin(_:)` returns `false` if initializing org crypto throws.
16621628
func test_validatePin_initializeOrgCryptoThrows() async throws {
16631629
let account = Account.fixture()
@@ -1672,7 +1638,7 @@ class AuthRepositoryTests: BitwardenTestCase { // swiftlint:disable:this type_bo
16721638

16731639
organizationService.initializeOrganizationCryptoError = BitwardenTestError.example
16741640

1675-
let isPinValid = await subject.validatePin(pin: "123")
1641+
let isPinValid = try await subject.validatePin(pin: "123")
16761642

16771643
XCTAssertFalse(isPinValid)
16781644
}

BitwardenShared/Core/Auth/Repositories/TestHelpers/MockAuthRepository.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class MockAuthRepository: AuthRepository { // swiftlint:disable:this type_body_l
7676
var validatePasswordPasswords = [String]()
7777
var validatePasswordResult: Result<Bool, Error> = .success(true)
7878

79-
var validatePinResult: Bool = true
79+
var validatePinResult: Result<Bool, Error> = .success(false)
8080

8181
var vaultTimeout = [String: SessionTimeoutValue]()
8282

@@ -305,8 +305,8 @@ class MockAuthRepository: AuthRepository { // swiftlint:disable:this type_body_l
305305
return try validatePasswordResult.get()
306306
}
307307

308-
func validatePin(pin: String) async -> Bool {
309-
validatePinResult
308+
func validatePin(pin: String) async throws -> Bool {
309+
try validatePinResult.get()
310310
}
311311

312312
func verifyOtp(_ otp: String) async throws {

BitwardenShared/UI/Auth/Utilities/UserVerificationHelper.swift

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,25 @@ extension DefaultUserVerificationHelper: UserVerificationHelper {
159159
continuation.resume(throwing: UserVerificationError.cancelled)
160160
},
161161
settingUp: false,
162-
completion: { pin in
163-
guard await self.authRepository.validatePin(pin: pin) else {
164-
self.userVerificationDelegate?.showAlert(
165-
.defaultAlert(title: Localizations.invalidPIN),
166-
onDismissed: {
167-
continuation.resume(returning: .notVerified)
168-
}
169-
)
170-
return
171-
}
162+
completion: { [weak self] pin in
163+
guard let self else { return }
164+
165+
do {
166+
guard try await authRepository.validatePin(pin: pin) else {
167+
userVerificationDelegate?.showAlert(
168+
.defaultAlert(title: Localizations.invalidPIN),
169+
onDismissed: {
170+
continuation.resume(returning: .notVerified)
171+
}
172+
)
173+
return
174+
}
172175

173-
continuation.resume(returning: .verified)
176+
continuation.resume(returning: .verified)
177+
} catch {
178+
errorReporter.log(error: error)
179+
continuation.resume(returning: .unableToPerform)
180+
}
174181
}
175182
)
176183

BitwardenShared/UI/Auth/Utilities/UserVerificationHelperTests.swift

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import XCTest
55

66
// MARK: - UserVerificationHelperTests
77

8-
class UserVerificationHelperTests: BitwardenTestCase {
8+
class UserVerificationHelperTests: BitwardenTestCase { // swiftlint:disable:this type_body_length
99
// MARK: Types
1010

1111
typealias VerifyFunction = () async throws -> UserVerificationResult
@@ -298,7 +298,7 @@ class UserVerificationHelperTests: BitwardenTestCase {
298298
/// `verifyPin()` with verified PIN.
299299
func test_verifyPin_verified() async throws {
300300
authRepository.isPinUnlockAvailableResult = .success(true)
301-
authRepository.validatePinResult = true
301+
authRepository.validatePinResult = .success(true)
302302

303303
let task = Task {
304304
try await self.subject.verifyPin()
@@ -318,7 +318,7 @@ class UserVerificationHelperTests: BitwardenTestCase {
318318
/// `verifyPin()` with not verified PIN.
319319
func test_verifyPin_notVerified() async throws {
320320
authRepository.isPinUnlockAvailableResult = .success(true)
321-
authRepository.validatePinResult = false
321+
authRepository.validatePinResult = .success(false)
322322

323323
let task = Task {
324324
try await self.subject.verifyPin()
@@ -348,6 +348,31 @@ class UserVerificationHelperTests: BitwardenTestCase {
348348
XCTAssertEqual(result, .notVerified)
349349
}
350350

351+
/// `verifyPin()` with throwing pin verification returns unable to perform.
352+
func test_verifyPin_throwsUnableToPerform() async throws {
353+
authRepository.isPinUnlockAvailableResult = .success(true)
354+
authRepository.validatePinResult = .failure(BitwardenTestError.example)
355+
356+
let task = Task {
357+
try await self.subject.verifyPin()
358+
}
359+
360+
try await waitForAsync {
361+
!self.userVerificationDelegate.alertShown.isEmpty
362+
}
363+
364+
try await enterPinInAlertAndSubmit()
365+
366+
try await waitForAsync {
367+
!self.errorReporter.errors.isEmpty
368+
}
369+
370+
let result = try await task.value
371+
372+
XCTAssertEqual(errorReporter.errors.last as? BitwardenTestError, .example)
373+
XCTAssertEqual(result, .unableToPerform)
374+
}
375+
351376
// MARK: Private
352377

353378
private func enterMasterPasswordInAlertAndSubmit() async throws {
@@ -387,4 +412,4 @@ class MockUserVerificationHelperDelegate: UserVerificationDelegate {
387412
showAlert(alert)
388413
alertOnDismissed = onDismissed
389414
}
390-
}
415+
} // swiftlint:disable:this file_length

0 commit comments

Comments
 (0)