Skip to content

Commit 11f7358

Browse files
[PM-25990] Add flight recorder logs for vault unlock method and PIN migration (#1994)
Co-authored-by: Katherine Bertelsen <kbertelsen@bitwarden.com>
1 parent 31ac0c4 commit 11f7358

File tree

6 files changed

+46
-3
lines changed

6 files changed

+46
-3
lines changed

BitwardenKit/Core/Platform/Extensions/Logger+Bitwarden.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ public extension Logger {
99
/// Logger instance for general application-level logs.
1010
static let application = Logger(subsystem: subsystem, category: "Application")
1111

12+
/// Logger instance for flight recorder logs.
13+
static let flightRecorder = Logger(subsystem: subsystem, category: "FlightRecorder")
14+
1215
/// Logger instance for use by processors in the application.
1316
static let processor = Logger(subsystem: subsystem, category: "Processor")
1417

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// swiftlint:disable:this file_name
2+
3+
import BitwardenSdk
4+
5+
extension BitwardenSdk.InitUserCryptoMethod {
6+
/// A safe string representation of the crypto method that excludes sensitive associated values.
7+
var methodType: String {
8+
switch self {
9+
case .authRequest:
10+
return "Auth Request"
11+
case .password:
12+
return "Password"
13+
case .decryptedKey:
14+
return "Decrypted Key (Never Lock/Biometrics)"
15+
case .deviceKey:
16+
return "Device Key"
17+
case .keyConnector:
18+
return "Key Connector"
19+
case .pin:
20+
return "PIN"
21+
case .pinEnvelope:
22+
return "PIN Envelope"
23+
}
24+
}
25+
}

BitwardenShared/Core/Auth/Repositories/AuthRepository.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,9 @@ class DefaultAuthRepository {
435435
/// The service used by the application to report non-fatal errors.
436436
private let errorReporter: ErrorReporter
437437

438+
/// The service used by the application for recording temporary debug logs.
439+
private let flightRecorder: FlightRecorder
440+
438441
/// The keychain service used by this repository.
439442
private let keychainService: KeychainRepository
440443

@@ -476,6 +479,7 @@ class DefaultAuthRepository {
476479
/// - configService: The service to get server-specified configuration.
477480
/// - environmentService: The service used by the application to manage the environment settings.
478481
/// - errorReporter: The service used by the application to report non-fatal errors.
482+
/// - flightRecorder: The service used by the application for recording temporary debug logs.
479483
/// - keychainService: The keychain service used by the application.
480484
/// - keyConnectorService: The service used by the application to manage Key Connector.
481485
/// - organizationAPIService: The service used by the application to make organization-related API requests.
@@ -497,6 +501,7 @@ class DefaultAuthRepository {
497501
configService: ConfigService,
498502
environmentService: EnvironmentService,
499503
errorReporter: ErrorReporter,
504+
flightRecorder: FlightRecorder,
500505
keychainService: KeychainRepository,
501506
keyConnectorService: KeyConnectorService,
502507
organizationAPIService: OrganizationAPIService,
@@ -516,6 +521,7 @@ class DefaultAuthRepository {
516521
self.configService = configService
517522
self.environmentService = environmentService
518523
self.errorReporter = errorReporter
524+
self.flightRecorder = flightRecorder
519525
self.keychainService = keychainService
520526
self.keyConnectorService = keyConnectorService
521527
self.organizationAPIService = organizationAPIService
@@ -1109,6 +1115,8 @@ extension DefaultAuthRepository: AuthRepository {
11091115
method: method
11101116
)
11111117

1118+
await flightRecorder.log("[Auth] Vault unlocked, method: \(method.methodType)")
1119+
11121120
switch method {
11131121
case .authRequest:
11141122
// Remove admin pending login request if exists
@@ -1236,6 +1244,7 @@ extension DefaultAuthRepository: AuthRepository {
12361244
enrollPinResponse: enrollPinResponse,
12371245
requirePasswordAfterRestart: stateService.pinUnlockRequiresPasswordAfterRestart()
12381246
)
1247+
await flightRecorder.log("[Auth] Migrated from legacy PIN to PIN-protected user key envelope")
12391248
case .decryptedKey,
12401249
.password:
12411250
// If the user has a pin, but requires master password after restart, set the pin
@@ -1245,6 +1254,7 @@ extension DefaultAuthRepository: AuthRepository {
12451254
encryptedPin: encryptedPin
12461255
)
12471256
try await stateService.setPinProtectedUserKeyToMemory(enrollPinResponse.pinProtectedUserKeyEnvelope)
1257+
await flightRecorder.log("[Auth] Set PIN-protected user key in memory")
12481258
case .pinEnvelope:
12491259
break
12501260
}

BitwardenShared/Core/Auth/Repositories/AuthRepositoryTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class AuthRepositoryTests: BitwardenTestCase { // swiftlint:disable:this type_bo
2121
var configService: MockConfigService!
2222
var environmentService: MockEnvironmentService!
2323
var errorReporter: MockErrorReporter!
24+
var flightRecorder: MockFlightRecorder!
2425
var keyConnectorService: MockKeyConnectorService!
2526
var keychainService: MockKeychainRepository!
2627
var organizationService: MockOrganizationService!
@@ -101,6 +102,7 @@ class AuthRepositoryTests: BitwardenTestCase { // swiftlint:disable:this type_bo
101102
configService = MockConfigService()
102103
environmentService = MockEnvironmentService()
103104
errorReporter = MockErrorReporter()
105+
flightRecorder = MockFlightRecorder()
104106
keyConnectorService = MockKeyConnectorService()
105107
keychainService = MockKeychainRepository()
106108
organizationService = MockOrganizationService()
@@ -119,6 +121,7 @@ class AuthRepositoryTests: BitwardenTestCase { // swiftlint:disable:this type_bo
119121
configService: configService,
120122
environmentService: environmentService,
121123
errorReporter: errorReporter,
124+
flightRecorder: flightRecorder,
122125
keychainService: keychainService,
123126
keyConnectorService: keyConnectorService,
124127
organizationAPIService: APIService(client: client),

BitwardenShared/Core/Platform/Services/FlightRecorder.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ actor DefaultFlightRecorder {
202202
// timer's sleep time is slightly off from the true expiration.
203203
let sleepSeconds = max(Double(seconds), UI.duration(1))
204204

205-
Logger.application.debug(
205+
Logger.flightRecorder.debug(
206206
"""
207207
FlightRecorder: next log lifecycle: \(nextLogLifecycleDate), \
208208
sleeping for \(sleepSeconds) seconds
@@ -252,14 +252,14 @@ actor DefaultFlightRecorder {
252252

253253
// Check if the active log should be disabled after its duration has elapsed.
254254
if let activeLog = data.activeLog, activeLog.endDate <= timeProvider.presentTime {
255-
Logger.application.debug("FlightRecorder: active log reached end date, deactivating")
255+
Logger.flightRecorder.debug("FlightRecorder: active log reached end date, deactivating")
256256
data.activeLog = nil
257257
}
258258

259259
for (index, log) in data.inactiveLogs.enumerated() {
260260
guard log.expirationDate <= timeProvider.presentTime else { continue }
261261

262-
Logger.application.debug(
262+
Logger.flightRecorder.debug(
263263
"FlightRecorder: removing expired log \(log.startDate) \(log.duration.shortDescription)"
264264
)
265265

@@ -433,6 +433,7 @@ extension DefaultFlightRecorder: FlightRecorder {
433433

434434
func log(_ message: String, file: String, line: UInt) async {
435435
guard var data = await getFlightRecorderData(), let log = data.activeLog else { return }
436+
Logger.flightRecorder.debug("\(message)")
436437
do {
437438
let timestampedMessage = "\(dateFormatter.string(from: timeProvider.presentTime)): \(message)\n"
438439
try await append(message: timestampedMessage, to: log)

BitwardenShared/Core/Platform/Services/ServiceContainer.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ public class ServiceContainer: Services { // swiftlint:disable:this type_body_le
654654
configService: configService,
655655
environmentService: environmentService,
656656
errorReporter: errorReporter,
657+
flightRecorder: flightRecorder,
657658
keychainService: keychainRepository,
658659
keyConnectorService: keyConnectorService,
659660
organizationAPIService: apiService,

0 commit comments

Comments
 (0)