From 65f577efed4f916a1073892547ea8663796c4abc Mon Sep 17 00:00:00 2001 From: Sasha Weiss Date: Fri, 29 May 2026 11:18:26 -0700 Subject: [PATCH] Stop caching SVRB auth credentials --- .../Backups/Archiving/BackupPurpose.swift | 119 +++++------------- .../Backups/BackupRequestManager.swift | 4 - .../Storage/Database/GRDBSchemaMigrator.swift | 9 ++ .../ZeroKnowledge/AuthCredentialStore.swift | 52 -------- .../BackupAuthCredentialManager.swift | 19 --- .../AttachmentUploadManagerTestMocks.swift | 1 - 6 files changed, 39 insertions(+), 165 deletions(-) diff --git a/SignalServiceKit/Backups/Archiving/BackupPurpose.swift b/SignalServiceKit/Backups/Archiving/BackupPurpose.swift index ca593fa894..e4b85b6a36 100644 --- a/SignalServiceKit/Backups/Archiving/BackupPurpose.swift +++ b/SignalServiceKit/Backups/Archiving/BackupPurpose.swift @@ -107,39 +107,22 @@ extension BackupImportSource { logger: PrefixedLogger, ) async throws -> MessageBackupKey { switch self { - case let .remote(key, noneSource): + case let .remote(key, nonceSource): let forwardSecrecyToken: BackupForwardSecrecyToken? - switch noneSource { + switch nonceSource { case let .provisioningMessage(token): forwardSecrecyToken = token case let .svrB(metadataHeader, chatAuth): - do { - forwardSecrecyToken = try await self.fetchForwardSecrecyTokenFromSvr( - key: key, - metadataHeader: metadataHeader, - chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: false, - backupRequestManager: backupRequestManager, - db: db, - libsignalNet: libsignalNet, - nonceStore: nonceStore, - logger: logger, - ) - } catch SignalError.webSocketError { - // This may represent an "expired auth" error from the SVRB - // servers. Try again, force-refreshing credentials. - forwardSecrecyToken = try await self.fetchForwardSecrecyTokenFromSvr( - key: key, - metadataHeader: metadataHeader, - chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: true, - backupRequestManager: backupRequestManager, - db: db, - libsignalNet: libsignalNet, - nonceStore: nonceStore, - logger: logger, - ) - } + forwardSecrecyToken = try await self.fetchForwardSecrecyTokenFromSvr( + key: key, + metadataHeader: metadataHeader, + chatAuth: chatAuth, + backupRequestManager: backupRequestManager, + db: db, + libsignalNet: libsignalNet, + nonceStore: nonceStore, + logger: logger, + ) } return try MessageBackupKey( @@ -161,29 +144,17 @@ extension BackupImportSource { key: MessageRootBackupKey, metadataHeader: BackupNonce.MetadataHeader, chatAuth: ChatServiceAuth, - forceRefreshSVRBAuthCredential: Bool, backupRequestManager: BackupRequestManager, db: any DB, libsignalNet: LibSignalClient.Net, nonceStore: BackupNonceMetadataStore, logger: PrefixedLogger, ) async throws -> BackupForwardSecrecyToken { - let svrBAuth: LibSignalClient.Auth - do { - svrBAuth = try await backupRequestManager.fetchSVRBAuthCredential( - key: key, - chatServiceAuth: chatAuth, - forceRefresh: forceRefreshSVRBAuthCredential, - logger: logger, - ) - } catch let error as CancellationError { - throw error - } catch let error where error.isNetworkFailureOrTimeout { - throw error - } catch let error { - owsFailDebug("Permanently failed to fetch svrB auth! \(error)") - throw SVRBError.unrecoverable - } + let svrBAuth = try await backupRequestManager.fetchSVRBAuthCredential( + key: key, + chatServiceAuth: chatAuth, + logger: logger, + ) let svrB = libsignalNet.svrB(auth: svrBAuth) @@ -212,7 +183,6 @@ extension BackupImportSource { key: key, metadataHeader: metadataHeader, chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: false, backupRequestManager: backupRequestManager, db: db, libsignalNet: libsignalNet, @@ -273,29 +243,14 @@ extension BackupExportPurpose { ) async throws -> EncryptionMetadata { switch self { case let .remoteExport(key, chatAuth): - do { - return try await storeEncryptionMetadataToSVRB( - key: key, - chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: false, - backupRequestManager: backupRequestManager, - db: db, - libsignalNet: libsignalNet, - nonceStore: nonceStore, - ) - } catch SignalError.webSocketError { - // This may represent an "expired auth" error from the SVRB - // servers. Try again, force-refreshing credentials. - return try await storeEncryptionMetadataToSVRB( - key: key, - chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: true, - backupRequestManager: backupRequestManager, - db: db, - libsignalNet: libsignalNet, - nonceStore: nonceStore, - ) - } + return try await storeEncryptionMetadataToSVRB( + key: key, + chatAuth: chatAuth, + backupRequestManager: backupRequestManager, + db: db, + libsignalNet: libsignalNet, + nonceStore: nonceStore, + ) case let .linkNsync(ephemeralKey, aci): let backupId = ephemeralKey.deriveBackupId(aci: aci) let encryptionKey = try MessageBackupKey( @@ -315,28 +270,16 @@ extension BackupExportPurpose { private func storeEncryptionMetadataToSVRB( key: MessageRootBackupKey, chatAuth: ChatServiceAuth, - forceRefreshSVRBAuthCredential: Bool, backupRequestManager: BackupRequestManager, db: any DB, libsignalNet: LibSignalClient.Net, nonceStore: BackupNonceMetadataStore, ) async throws -> EncryptionMetadata { - let svrBAuth: LibSignalClient.Auth - do { - svrBAuth = try await backupRequestManager.fetchSVRBAuthCredential( - key: key, - chatServiceAuth: chatAuth, - forceRefresh: forceRefreshSVRBAuthCredential, - logger: logger, - ) - } catch let error as CancellationError { - throw error - } catch let error where error.isNetworkFailureOrTimeout { - throw error - } catch let error { - owsFailDebug("Permanently failed to fetch svrB auth. \(error)") - throw SVRBError.unrecoverable - } + let svrBAuth = try await backupRequestManager.fetchSVRBAuthCredential( + key: key, + chatServiceAuth: chatAuth, + logger: logger, + ) let svrB = libsignalNet.svrB(auth: svrBAuth) @@ -374,7 +317,6 @@ extension BackupExportPurpose { return try await storeEncryptionMetadataToSVRB( key: key, chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: false, backupRequestManager: backupRequestManager, db: db, libsignalNet: libsignalNet, @@ -387,7 +329,6 @@ extension BackupExportPurpose { return try await storeEncryptionMetadataToSVRB( key: key, chatAuth: chatAuth, - forceRefreshSVRBAuthCredential: false, backupRequestManager: backupRequestManager, db: db, libsignalNet: libsignalNet, diff --git a/SignalServiceKit/Backups/BackupRequestManager.swift b/SignalServiceKit/Backups/BackupRequestManager.swift index 7d2028b67b..ef88c80f65 100644 --- a/SignalServiceKit/Backups/BackupRequestManager.swift +++ b/SignalServiceKit/Backups/BackupRequestManager.swift @@ -154,7 +154,6 @@ public protocol BackupRequestManager { func fetchSVRBAuthCredential( key: MessageRootBackupKey, chatServiceAuth auth: ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth } @@ -485,13 +484,11 @@ public struct BackupRequestManagerImpl: BackupRequestManager { public func fetchSVRBAuthCredential( key: MessageRootBackupKey, chatServiceAuth auth: ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth { return try await backupAuthCredentialManager.fetchSVRBAuthCredential( key: key, chatServiceAuth: auth, - forceRefresh: forceRefresh, logger: logger, ) } @@ -679,7 +676,6 @@ public class BackupRequestManagerMock: BackupRequestManager { public func fetchSVRBAuthCredential( key: SignalServiceKit.MessageRootBackupKey, chatServiceAuth auth: SignalServiceKit.ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth { return LibSignalClient.Auth(username: "", password: "") diff --git a/SignalServiceKit/Storage/Database/GRDBSchemaMigrator.swift b/SignalServiceKit/Storage/Database/GRDBSchemaMigrator.swift index eabfe8cfd5..e1144f8f52 100644 --- a/SignalServiceKit/Storage/Database/GRDBSchemaMigrator.swift +++ b/SignalServiceKit/Storage/Database/GRDBSchemaMigrator.swift @@ -329,6 +329,7 @@ public class GRDBSchemaMigrator { case dropAttachmentContentTypeAUTrigger case addOrphanedAttachmentTimestamp case migrateSecureValueRecovery + case wipeCachedSVRBAuthCredentials // NOTE: Every time we add a migration id, consider // incrementing grdbSchemaVersionLatest. @@ -5169,6 +5170,14 @@ public class GRDBSchemaMigrator { return .success(()) } + migrator.registerMigration(.wipeCachedSVRBAuthCredentials) { tx in + try tx.database.execute(sql: """ + DELETE FROM keyvalue + WHERE collection = 'SVR🐝AuthCredential' + """) + return .success(()) + } + // MARK: - Schema Migration Insertion Point } diff --git a/SignalServiceKit/ZeroKnowledge/AuthCredentialStore.swift b/SignalServiceKit/ZeroKnowledge/AuthCredentialStore.swift index a65bd1dade..c7019cc3b1 100644 --- a/SignalServiceKit/ZeroKnowledge/AuthCredentialStore.swift +++ b/SignalServiceKit/ZeroKnowledge/AuthCredentialStore.swift @@ -11,14 +11,12 @@ public class AuthCredentialStore { private let groupAuthCredentialStore: KeyValueStore private let backupMessagesAuthCredentialStore: KeyValueStore private let backupMediaAuthCredentialStore: KeyValueStore - private let svrBAuthCredentialStore: KeyValueStore public init() { self.callLinkAuthCredentialStore = KeyValueStore(collection: "CallLinkAuthCredential") self.groupAuthCredentialStore = KeyValueStore(collection: "GroupsV2Impl.authCredentialStoreStore") self.backupMessagesAuthCredentialStore = KeyValueStore(collection: "BackupAuthCredential") self.backupMediaAuthCredentialStore = KeyValueStore(collection: "MediaAuthCredential") - self.svrBAuthCredentialStore = KeyValueStore(collection: "SVR🐝AuthCredential") } private static func callLinkAuthCredentialKey(for redemptionTime: UInt64) -> String { @@ -136,49 +134,6 @@ public class AuthCredentialStore { ) } - static let svrBAuthCredentialExpirationTime: TimeInterval = .day - .hour - static let svrBAuthCredentialExpiryDateKey = "svr🐝AuthCredentialTimestampKey" - static let svrBAuthCredentialUsernameKey = "svr🐝AuthCredentialUsernameKey" - static let svrBAuthCredentialPasswordKey = "svr🐝AuthCredentialPasswordKey" - - func svrBAuthCredential( - now: Date, - tx: DBReadTransaction, - ) -> LibSignalClient.Auth? { - guard - let username = svrBAuthCredentialStore.getString(Self.svrBAuthCredentialUsernameKey, transaction: tx), - let password = svrBAuthCredentialStore.getString(Self.svrBAuthCredentialPasswordKey, transaction: tx), - let expiryDate = svrBAuthCredentialStore.getDate(Self.svrBAuthCredentialExpiryDateKey, transaction: tx) - else { - return nil - } - guard expiryDate > now else { - return nil - } - return Auth( - username: username, - password: password, - ) - } - - func setSVRBAuthCredential( - _ credential: LibSignalClient.Auth?, - now: Date, - tx: DBWriteTransaction, - ) { - guard let credential else { - svrBAuthCredentialStore.removeAll(transaction: tx) - return - } - svrBAuthCredentialStore.setString(credential.username, key: Self.svrBAuthCredentialUsernameKey, transaction: tx) - svrBAuthCredentialStore.setString(credential.password, key: Self.svrBAuthCredentialPasswordKey, transaction: tx) - svrBAuthCredentialStore.setDate( - now.addingTimeInterval(Self.svrBAuthCredentialExpirationTime), - key: Self.svrBAuthCredentialExpiryDateKey, - transaction: tx, - ) - } - func removeAllBackupAuthCredentials(ofType credentialType: BackupAuthCredentialType, tx: DBWriteTransaction) { let store: KeyValueStore = switch credentialType { case .media: backupMediaAuthCredentialStore @@ -186,13 +141,6 @@ public class AuthCredentialStore { } store.removeAll(transaction: tx) - - switch credentialType { - case .media: - break - case .messages: - svrBAuthCredentialStore.removeAll(transaction: tx) - } } public func removeAllBackupAuthCredentials(tx: DBWriteTransaction) { diff --git a/SignalServiceKit/ZeroKnowledge/BackupAuthCredentialManager.swift b/SignalServiceKit/ZeroKnowledge/BackupAuthCredentialManager.swift index 5b873645a8..13ae32bb1b 100644 --- a/SignalServiceKit/ZeroKnowledge/BackupAuthCredentialManager.swift +++ b/SignalServiceKit/ZeroKnowledge/BackupAuthCredentialManager.swift @@ -52,7 +52,6 @@ public protocol BackupAuthCredentialManager { func fetchSVRBAuthCredential( key: MessageRootBackupKey, chatServiceAuth: ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth } @@ -189,14 +188,12 @@ class BackupAuthCredentialManagerImpl: BackupAuthCredentialManager { func fetchSVRBAuthCredential( key: MessageRootBackupKey, chatServiceAuth auth: ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth { try await serialTaskQueue.run { try await _fetchSVRBAuthCredential( key: key, chatServiceAuth: auth, - forceRefresh: forceRefresh, logger: logger, ) } @@ -205,20 +202,8 @@ class BackupAuthCredentialManagerImpl: BackupAuthCredentialManager { private func _fetchSVRBAuthCredential( key: MessageRootBackupKey, chatServiceAuth auth: ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth { - let now = dateProvider() - - if - !forceRefresh, - let cachedCredential = db.read(block: { tx in - authCredentialStore.svrBAuthCredential(now: now, tx: tx) - }) - { - return cachedCredential - } - let backupServiceAuth = try await _fetchBackupServiceAuth( key: key, localAci: key.aci, @@ -238,10 +223,6 @@ class BackupAuthCredentialManagerImpl: BackupAuthCredentialManager { password: receivedSVRBAuthCredential.password, ) - await db.awaitableWrite { tx in - authCredentialStore.setSVRBAuthCredential(svrBAuth, now: now, tx: tx) - } - return svrBAuth } diff --git a/SignalServiceKit/tests/Network/Upload/AttachmentUploadManagerTestMocks.swift b/SignalServiceKit/tests/Network/Upload/AttachmentUploadManagerTestMocks.swift index aae60097be..ffc387ea72 100644 --- a/SignalServiceKit/tests/Network/Upload/AttachmentUploadManagerTestMocks.swift +++ b/SignalServiceKit/tests/Network/Upload/AttachmentUploadManagerTestMocks.swift @@ -198,7 +198,6 @@ class _AttachmentUploadManager_BackupRequestManagerMock: BackupRequestManager { func fetchSVRBAuthCredential( key: SignalServiceKit.MessageRootBackupKey, chatServiceAuth auth: SignalServiceKit.ChatServiceAuth, - forceRefresh: Bool, logger: PrefixedLogger, ) async throws -> LibSignalClient.Auth { return LibSignalClient.Auth(username: "", password: "")