Skip to content

Commit 3346c96

Browse files
Merge branch 'main' into brant/BITAU-152-handle-vault-lock-unlock
2 parents 5735a98 + d9d85ba commit 3346c96

File tree

85 files changed

+1699
-83
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1699
-83
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ jobs:
308308

309309
- name: Install Fastlane, Mint
310310
run: |
311+
brew update
311312
brew install fastlane mint
312313
313314
- name: Install Mint packages

AuthenticatorBridgeKit/AuthenticatorKeychainService.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,18 @@ public protocol AuthenticatorKeychainService: AnyObject {
2929
// MARK: - AuthenticatorKeychainServiceError
3030

3131
/// Enum with possible error cases that can be thrown from `AuthenticatorKeychainService`.
32-
public enum AuthenticatorKeychainServiceError: Error, Equatable {
32+
public enum AuthenticatorKeychainServiceError: Error, Equatable, CustomNSError {
3333
/// When a `KeychainService` is unable to locate an auth key for a given storage key.
3434
///
3535
/// - Parameter KeychainItem: The potential storage key for the auth key.
3636
///
3737
case keyNotFound(SharedKeychainItem)
38+
39+
/// The user-info dictionary.
40+
public var errorUserInfo: [String: Any] {
41+
switch self {
42+
case let .keyNotFound(keychainItem):
43+
return ["Keychain Item": keychainItem.unformattedKey]
44+
}
45+
}
3846
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
@testable import AuthenticatorBridgeKit
22

33
class MockErrorReporter: ErrorReporter {
4+
var currentUserId: String?
45
var errors = [Error]()
56
var isEnabled = false
7+
var region: (String, Bool)?
68

79
func log(error: Error) {
810
errors.append(error)
911
}
12+
13+
func setRegion(_ region: String, isPreAuth: Bool) {
14+
self.region = (region, isPreAuth)
15+
}
16+
17+
func setUserId(_ userId: String?) {
18+
currentUserId = userId
19+
}
1020
}

Bitwarden/Application/SceneDelegate.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
6060
await appProcessor.start(
6161
appContext: .mainApp,
6262
navigator: rootViewController,
63+
splashWindow: splashWindow,
6364
window: appWindow
6465
)
6566
hideSplash()

Bitwarden/Application/Services/ErrorReporter/CrashlyticsErrorReporter.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,18 @@ final class CrashlyticsErrorReporter: ErrorReporter {
3030

3131
Crashlytics.crashlytics().record(error: error)
3232
}
33+
34+
func setRegion(_ region: String, isPreAuth: Bool) {
35+
guard isEnabled else {
36+
return
37+
}
38+
Crashlytics.crashlytics().setCustomValue(region, forKey: isPreAuth ? "PreAuthRegion" : "Region")
39+
}
40+
41+
func setUserId(_ userId: String?) {
42+
guard isEnabled else {
43+
return
44+
}
45+
Crashlytics.crashlytics().setUserID(userId)
46+
}
3347
}

BitwardenShared/Core/Auth/Models/Enum/RegionType.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,13 @@ public enum RegionType: CaseIterable, Sendable {
4040
return nil
4141
}
4242
}
43+
44+
/// The name to be used by the error reporter.
45+
var errorReporterName: String {
46+
switch self {
47+
case .europe: return "EU"
48+
case .selfHosted: return "Self-Hosted"
49+
case .unitedStates: return "US"
50+
}
51+
}
4352
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import XCTest
2+
3+
@testable import BitwardenShared
4+
5+
class RegionTypeTests: BitwardenTestCase {
6+
// MARK: Tests
7+
8+
/// `getter:localizedName` returns the correct values.
9+
func test_localizedName() {
10+
XCTAssertEqual(RegionType.europe.localizedName, Localizations.eu)
11+
XCTAssertEqual(RegionType.selfHosted.localizedName, Localizations.selfHosted)
12+
XCTAssertEqual(RegionType.unitedStates.localizedName, Localizations.us)
13+
}
14+
15+
/// `getter:baseUrlDescription` returns the correct values.
16+
func test_baseUrlDescription() {
17+
XCTAssertEqual(RegionType.europe.baseUrlDescription, "bitwarden.eu")
18+
XCTAssertEqual(RegionType.selfHosted.baseUrlDescription, Localizations.selfHosted)
19+
XCTAssertEqual(RegionType.unitedStates.baseUrlDescription, "bitwarden.com")
20+
}
21+
22+
/// `getter:defaultURLs` returns the correct values.
23+
func test_defaultURLs() {
24+
XCTAssertEqual(RegionType.europe.defaultURLs?.api?.absoluteString, "https://api.bitwarden.eu")
25+
XCTAssertNil(RegionType.selfHosted.defaultURLs)
26+
XCTAssertEqual(RegionType.unitedStates.defaultURLs?.api?.absoluteString, "https://api.bitwarden.com")
27+
}
28+
29+
/// `getter:errorReporterName` returns the correct values.
30+
func test_errorReporterName() {
31+
XCTAssertEqual(RegionType.europe.errorReporterName, "EU")
32+
XCTAssertEqual(RegionType.selfHosted.errorReporterName, "Self-Hosted")
33+
XCTAssertEqual(RegionType.unitedStates.errorReporterName, "US")
34+
}
35+
}

BitwardenShared/Core/Auth/Services/KeychainService.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ protocol KeychainService: AnyObject {
3737

3838
// MARK: - KeychainServiceError
3939

40-
enum KeychainServiceError: Error, Equatable {
40+
enum KeychainServiceError: Error, Equatable, CustomNSError {
4141
/// When creating an accessControl fails.
4242
///
4343
/// - Parameter CFError: The potential system error.
@@ -55,6 +55,18 @@ enum KeychainServiceError: Error, Equatable {
5555
/// - Parameter OSStatus: The `OSStatus` returned from a keychain operation.
5656
///
5757
case osStatusError(OSStatus)
58+
59+
/// The user-info dictionary.
60+
public var errorUserInfo: [String: Any] {
61+
switch self {
62+
case .accessControlFailed:
63+
return [:]
64+
case let .keyNotFound(keychainItem):
65+
return ["Keychain Item": keychainItem.unformattedKey]
66+
case let .osStatusError(osStatus):
67+
return ["OS Status": osStatus]
68+
}
69+
}
5870
}
5971

6072
// MARK: - DefaultKeychainService
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// swiftlint:disable:this file_name
2+
3+
import XCTest
4+
5+
@testable import BitwardenShared
6+
7+
class KeychainServiceErrorTests: BitwardenTestCase {
8+
// MARK: Tests
9+
10+
/// `getter:errorUserInfo` gets the appropriate user info based on the error case.
11+
func test_errorUserInfo() {
12+
let errorAccessControlFailed = KeychainServiceError.accessControlFailed(nil)
13+
XCTAssertTrue(errorAccessControlFailed.errorUserInfo.isEmpty)
14+
15+
let errorKeyNotFound = KeychainServiceError.keyNotFound(KeychainItem.refreshToken(userId: "1"))
16+
XCTAssertEqual(errorKeyNotFound.errorUserInfo["Keychain Item"] as? String, "refreshToken_1")
17+
18+
let errorOSStatusError = KeychainServiceError.osStatusError(3)
19+
XCTAssertEqual(errorOSStatusError.errorUserInfo["OS Status"] as? Int32, 3)
20+
}
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// swiftlint:disable:this file_name
2+
3+
import BitwardenSdk
4+
import Foundation
5+
6+
extension BitwardenSdk.BitwardenError: CustomNSError {
7+
/// The user-info dictionary.
8+
public var errorUserInfo: [String: Any] {
9+
guard case let .E(message) = self else {
10+
return [:]
11+
}
12+
return ["Message": message]
13+
}
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// swiftlint:disable:this file_name
2+
3+
import BitwardenSdk
4+
import XCTest
5+
6+
@testable import BitwardenShared
7+
8+
class BitwardenErrorTests: BitwardenTestCase {
9+
// MARK: Tests
10+
11+
/// `getter:errorUserInfo` gets the appropriate user info based on the message of the error `E`
12+
func test_errorUserInfo() {
13+
let expectedMessage = "expectedMessage"
14+
let error = BitwardenSdk.BitwardenError.E(message: expectedMessage)
15+
let userInfo = error.errorUserInfo
16+
XCTAssertEqual(userInfo["Message"] as? String, expectedMessage)
17+
}
18+
}

BitwardenShared/Core/Platform/Services/API/Errors/ServerError.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import Foundation
2+
13
// MARK: - ServerError
24

35
/// An enumeration of server errors.
46
///
5-
enum ServerError: Error, Equatable {
7+
enum ServerError: Error, Equatable, CustomNSError {
68
/// A generic error.
79
///
810
/// - Parameter errorResponse: The error response returned from the API request.
@@ -24,4 +26,9 @@ enum ServerError: Error, Equatable {
2426
validationErrorResponse.errorModel.message
2527
}
2628
}
29+
30+
/// The user-info dictionary.
31+
public var errorUserInfo: [String: Any] {
32+
["Message": message]
33+
}
2734
}

BitwardenShared/Core/Platform/Services/EnvironmentService.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ protocol EnvironmentService {
5959
///
6060
class DefaultEnvironmentService: EnvironmentService {
6161
// MARK: Properties
62+
63+
/// The service used by the application to report non-fatal errors.
64+
let errorReporter: ErrorReporter
6265

6366
/// The service used by the application to manage account state.
6467
let stateService: StateService
@@ -77,10 +80,12 @@ class DefaultEnvironmentService: EnvironmentService {
7780
/// Initialize a `DefaultEnvironmentService`.
7881
///
7982
/// - Parameters:
83+
/// - errorReporter: The service used by the application to report non-fatal errors
8084
/// - stateService: The service used by the application to manage account state.
8185
/// - standardUserDefaults: The shared UserDefaults instance.
8286
///
83-
init(stateService: StateService, standardUserDefaults: UserDefaults = .standard) {
87+
init(errorReporter: ErrorReporter, stateService: StateService, standardUserDefaults: UserDefaults = .standard) {
88+
self.errorReporter = errorReporter
8489
self.stateService = stateService
8590
self.standardUserDefaults = standardUserDefaults
8691

@@ -105,6 +110,8 @@ class DefaultEnvironmentService: EnvironmentService {
105110
await setPreAuthURLs(urls: managedSettingsUrls ?? urls)
106111
environmentUrls = EnvironmentUrls(environmentUrlData: urls)
107112

113+
errorReporter.setRegion(region.errorReporterName, isPreAuth: false)
114+
108115
// swiftformat:disable:next redundantSelf
109116
Logger.application.info("Loaded environment URLs: \(String(describing: self.environmentUrls))")
110117
}
@@ -113,6 +120,8 @@ class DefaultEnvironmentService: EnvironmentService {
113120
await stateService.setPreAuthEnvironmentUrls(urls)
114121
environmentUrls = EnvironmentUrls(environmentUrlData: urls)
115122

123+
errorReporter.setRegion(region.errorReporterName, isPreAuth: true)
124+
116125
// swiftformat:disable:next redundantSelf
117126
Logger.application.info("Setting pre-auth URLs: \(String(describing: self.environmentUrls))")
118127
}

BitwardenShared/Core/Platform/Services/EnvironmentServiceTests.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import XCTest
55
class EnvironmentServiceTests: XCTestCase {
66
// MARK: Properties
77

8+
var errorReporter: MockErrorReporter!
89
var stateService: MockStateService!
910
var standardUserDefaults: UserDefaults!
1011
var subject: EnvironmentService!
@@ -14,11 +15,13 @@ class EnvironmentServiceTests: XCTestCase {
1415
override func setUp() {
1516
super.setUp()
1617

18+
errorReporter = MockErrorReporter()
1719
stateService = MockStateService()
1820
standardUserDefaults = UserDefaults(suiteName: "test")
1921
standardUserDefaults.removeObject(forKey: "com.apple.configuration.managed")
2022

2123
subject = DefaultEnvironmentService(
24+
errorReporter: errorReporter,
2225
stateService: stateService,
2326
standardUserDefaults: standardUserDefaults
2427
)
@@ -27,6 +30,7 @@ class EnvironmentServiceTests: XCTestCase {
2730
override func tearDown() {
2831
super.tearDown()
2932

33+
errorReporter = nil
3034
stateService = nil
3135
standardUserDefaults = nil
3236
subject = nil
@@ -66,6 +70,9 @@ class EnvironmentServiceTests: XCTestCase {
6670
XCTAssertEqual(subject.settingsURL, URL(string: "https://example.com/#/settings"))
6771
XCTAssertEqual(subject.webVaultURL, URL(string: "https://example.com"))
6872
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
73+
74+
XCTAssertEqual(errorReporter.region?.region, "Self-Hosted")
75+
XCTAssertEqual(errorReporter.region?.isPreAuth, false)
6976
}
7077

7178
/// `loadURLsForActiveAccount()` handles EU URLs
@@ -87,6 +94,9 @@ class EnvironmentServiceTests: XCTestCase {
8794
XCTAssertEqual(subject.settingsURL, URL(string: "https://vault.bitwarden.eu/#/settings"))
8895
XCTAssertEqual(subject.webVaultURL, URL(string: "https://vault.bitwarden.eu"))
8996
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
97+
98+
XCTAssertEqual(errorReporter.region?.region, "EU")
99+
XCTAssertEqual(errorReporter.region?.isPreAuth, false)
90100
}
91101

92102
/// `loadURLsForActiveAccount()` loads the managed config URLs.
@@ -153,6 +163,9 @@ class EnvironmentServiceTests: XCTestCase {
153163
XCTAssertEqual(subject.settingsURL, URL(string: "https://vault.bitwarden.com/#/settings"))
154164
XCTAssertEqual(subject.webVaultURL, URL(string: "https://vault.bitwarden.com"))
155165
XCTAssertEqual(stateService.preAuthEnvironmentUrls, .defaultUS)
166+
167+
XCTAssertEqual(errorReporter.region?.region, "US")
168+
XCTAssertEqual(errorReporter.region?.isPreAuth, false)
156169
}
157170

158171
/// `loadURLsForActiveAccount()` loads the preAuth URLs if there's no active account
@@ -173,6 +186,9 @@ class EnvironmentServiceTests: XCTestCase {
173186
XCTAssertEqual(subject.settingsURL, URL(string: "https://example.com/#/settings"))
174187
XCTAssertEqual(subject.webVaultURL, URL(string: "https://example.com"))
175188
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
189+
190+
XCTAssertEqual(errorReporter.region?.region, "Self-Hosted")
191+
XCTAssertEqual(errorReporter.region?.isPreAuth, false)
176192
}
177193

178194
/// `setPreAuthURLs(urls:)` sets the pre-auth URLs.
@@ -191,5 +207,7 @@ class EnvironmentServiceTests: XCTestCase {
191207
XCTAssertEqual(subject.settingsURL, URL(string: "https://example.com/#/settings"))
192208
XCTAssertEqual(subject.webVaultURL, URL(string: "https://example.com"))
193209
XCTAssertEqual(stateService.preAuthEnvironmentUrls, urls)
210+
XCTAssertEqual(errorReporter.region?.region, "Self-Hosted")
211+
XCTAssertEqual(errorReporter.region?.isPreAuth, true)
194212
}
195213
}

BitwardenShared/Core/Platform/Services/ErrorReporter/ErrorReporter.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,14 @@ public protocol ErrorReporter: AnyObject, AuthenticatorBridgeKit.ErrorReporter {
1515
/// - Parameter error: The error to log.
1616
///
1717
func log(error: Error)
18+
19+
/// Sets the current region the user is on.
20+
/// - Parameters:
21+
/// - region: Region the user is on (US, EU, SelfHosted).
22+
/// - isPreAuth: Whether this region is being used pre authentication or when already authenticated.
23+
func setRegion(_ region: String, isPreAuth: Bool)
24+
25+
/// Sets the current user iD to attach to errors.
26+
/// - Parameter userId: User ID to attach.
27+
func setUserId(_ userId: String?)
1828
}

BitwardenShared/Core/Platform/Services/ServiceContainer.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,11 @@ public class ServiceContainer: Services { // swiftlint:disable:this type_body_le
320320
let stateService = DefaultStateService(
321321
appSettingsStore: appSettingsStore,
322322
dataStore: dataStore,
323+
errorReporter: errorReporter,
323324
keychainRepository: keychainRepository
324325
)
325326

326-
let environmentService = DefaultEnvironmentService(stateService: stateService)
327+
let environmentService = DefaultEnvironmentService(errorReporter: errorReporter, stateService: stateService)
327328
let collectionService = DefaultCollectionService(collectionDataStore: dataStore, stateService: stateService)
328329
let settingsService = DefaultSettingsService(settingsDataStore: dataStore, stateService: stateService)
329330
let tokenService = DefaultTokenService(keychainRepository: keychainRepository, stateService: stateService)

0 commit comments

Comments
 (0)