Add BackupCDNCache for read credentials, metadata

This commit is contained in:
Sasha Weiss 2025-07-11 16:38:50 -07:00 committed by GitHub
parent 87b79704a7
commit be9340bdb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 283 additions and 172 deletions

View File

@ -2763,6 +2763,9 @@
D9C964092BE44D700058F143 /* XCTest+Thenable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C964072BE44D510058F143 /* XCTest+Thenable.swift */; };
D9C964102BE451CE0058F143 /* TSMessageStorageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C9640F2BE451CE0058F143 /* TSMessageStorageTest.swift */; };
D9C964142BE45A030058F143 /* SignedPreKeyDeletionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C964132BE45A030058F143 /* SignedPreKeyDeletionTests.swift */; };
D9C96F712E21A6BE00CA885A /* BackupCDNReadCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C96F702E21A6B900CA885A /* BackupCDNReadCredential.swift */; };
D9C96F752E21AA5800CA885A /* BackupCDNCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C96F742E21AA4900CA885A /* BackupCDNCache.swift */; };
D9C96F772E21ADF000CA885A /* BackupCDNMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C96F762E21ADBE00CA885A /* BackupCDNMetadata.swift */; };
D9CA61482C2E2D0000F99EA3 /* BackupArchiveAdHocCallArchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9CA61472C2E2D0000F99EA3 /* BackupArchiveAdHocCallArchiver.swift */; };
D9CA614B2C2F675E00F99EA3 /* PrivateStoryThreadDeletionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9CA614A2C2F675E00F99EA3 /* PrivateStoryThreadDeletionManager.swift */; };
D9CA8AB02B698DFF00787167 /* DeletedCallRecordCleanupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9CA8AAF2B698DFF00787167 /* DeletedCallRecordCleanupManager.swift */; };
@ -6720,6 +6723,9 @@
D9C964072BE44D510058F143 /* XCTest+Thenable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTest+Thenable.swift"; sourceTree = "<group>"; };
D9C9640F2BE451CE0058F143 /* TSMessageStorageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSMessageStorageTest.swift; sourceTree = "<group>"; };
D9C964132BE45A030058F143 /* SignedPreKeyDeletionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignedPreKeyDeletionTests.swift; sourceTree = "<group>"; };
D9C96F702E21A6B900CA885A /* BackupCDNReadCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupCDNReadCredential.swift; sourceTree = "<group>"; };
D9C96F742E21AA4900CA885A /* BackupCDNCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupCDNCache.swift; sourceTree = "<group>"; };
D9C96F762E21ADBE00CA885A /* BackupCDNMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupCDNMetadata.swift; sourceTree = "<group>"; };
D9CA61472C2E2D0000F99EA3 /* BackupArchiveAdHocCallArchiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupArchiveAdHocCallArchiver.swift; sourceTree = "<group>"; };
D9CA614A2C2F675E00F99EA3 /* PrivateStoryThreadDeletionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateStoryThreadDeletionManager.swift; sourceTree = "<group>"; };
D9CA8AAF2B698DFF00787167 /* DeletedCallRecordCleanupManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedCallRecordCleanupManager.swift; sourceTree = "<group>"; };
@ -9626,6 +9632,9 @@
667BB2042C58073600E79B57 /* Attachments */,
66A1F4E02E035BE40095DE4B /* BackupExportJob */,
D9388C8F2DA4751A0048D4F9 /* Settings */,
D9C96F742E21AA4900CA885A /* BackupCDNCache.swift */,
D9C96F762E21ADBE00CA885A /* BackupCDNMetadata.swift */,
D9C96F702E21A6B900CA885A /* BackupCDNReadCredential.swift */,
C1A0F79C2B9F57340009DC0D /* BackupKeyMaterial.swift */,
C1A0F79E2B9F59920009DC0D /* BackupKeyMaterialImpl.swift */,
C14391122BD1C0DF00ED6FCB /* BackupRequestManager.swift */,
@ -17748,6 +17757,9 @@
66734F012CA1ED3F00558494 /* BackupAttachmentUploadScheduler.swift in Sources */,
66C7952D2C9B78E900C13937 /* BackupAttachmentUploadStore.swift in Sources */,
C18806342BD8080B0024044A /* BackupAuthCredentialManager.swift in Sources */,
D9C96F752E21AA5800CA885A /* BackupCDNCache.swift in Sources */,
D9C96F772E21ADF000CA885A /* BackupCDNMetadata.swift in Sources */,
D9C96F712E21A6BE00CA885A /* BackupCDNReadCredential.swift in Sources */,
66A1F4E22E035C020095DE4B /* BackupExportJob.swift in Sources */,
D923DF9C2DC135D200CDAFC3 /* BackupIdManager.swift in Sources */,
C1A0F79D2B9F57340009DC0D /* BackupKeyMaterial.swift in Sources */,

View File

@ -0,0 +1,138 @@
//
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
struct BackupCDNCache {
private enum Constants {
static let cdnMetadataLifetime: TimeInterval = BackupCDNReadCredential.lifetime
}
private let kvStore: KeyValueStore
init() {
self.kvStore = KeyValueStore(collection: "BackupCDNCache")
}
// MARK: -
func wipe(tx: DBWriteTransaction) {
kvStore.removeAll(transaction: tx)
}
// MARK: -
private static func backupCDNAuthCredentialKey(
cdnNumber: Int32,
authType: BackupAuthCredentialType,
) -> String {
let cdn2 = "BackupCDN2:\(authType.rawValue)"
let cdn3 = "BackupCDN3:\(authType.rawValue)"
switch cdnNumber {
case 2:
return cdn2
case 3:
return cdn3
default:
owsFailDebug("Unexpected CDN number \(cdnNumber): assuming CDN3!")
return cdn3
}
}
func backupCDNReadCredential(
cdnNumber: Int32,
authType: BackupAuthCredentialType,
now: Date,
tx: DBReadTransaction,
) -> BackupCDNReadCredential? {
do {
let cachedCredential: BackupCDNReadCredential? = try kvStore.getCodableValue(
forKey: Self.backupCDNAuthCredentialKey(cdnNumber: cdnNumber, authType: authType),
transaction: tx
)
if
let cachedCredential,
!cachedCredential.isExpired(now: now)
{
return cachedCredential
}
} catch {
Logger.warn("Failed to deserialize BackupCDNReadCredential!")
}
return nil
}
func setBackupCDNReadCredential(
_ backupCDNReadCredential: BackupCDNReadCredential,
cdnNumber: Int32,
authType: BackupAuthCredentialType,
tx: DBWriteTransaction,
) {
do {
try kvStore.setCodable(
backupCDNReadCredential,
key: Self.backupCDNAuthCredentialKey(cdnNumber: cdnNumber, authType: authType),
transaction: tx
)
} catch {
Logger.warn("Failed to serialize BackupCDNReadCredential! \(error)")
}
}
// MARK: -
private static func backupCDNMetadataKeys(authType: BackupAuthCredentialType) -> (
metadata: String,
metadataSavedDate: String
) {
return (
"BackupCDNMetadata:\(authType.rawValue)",
"BackupCDNMetadataSavedDate:\(authType.rawValue)",
)
}
func backupCDNMetadata(
authType: BackupAuthCredentialType,
now: Date,
tx: DBReadTransaction,
) -> BackupCDNMetadata? {
let (metadataKey, metadataSavedDateKey) = Self.backupCDNMetadataKeys(authType: authType)
if
let metadataSavedDate = kvStore.getDate(metadataSavedDateKey, transaction: tx),
now > metadataSavedDate.addingTimeInterval(Constants.cdnMetadataLifetime)
{
// It's been long enough that we should skip the cached value.
return nil
}
do {
if let metadata: BackupCDNMetadata = try kvStore.getCodableValue(forKey: metadataKey, transaction: tx) {
return metadata
}
} catch {
Logger.warn("Failed to deserialize BackupCDNMetadata! \(error)")
}
return nil
}
func setBackupCDNMetadata(
_ backupCDNMetadata: BackupCDNMetadata,
authType: BackupAuthCredentialType,
dateProvider: DateProvider,
tx: DBWriteTransaction,
) {
let (metadataKey, metadataSavedDateKey) = Self.backupCDNMetadataKeys(authType: authType)
do {
try kvStore.setCodable(backupCDNMetadata, key: metadataKey, transaction: tx)
kvStore.setDate(dateProvider(), key: metadataSavedDateKey, transaction: tx)
} catch {
Logger.warn("Failed to serialize BackupCDNMetadata! \(error)")
}
}
}

View File

@ -0,0 +1,28 @@
//
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
/// Backup info provided by the server that is cached locally, so this can be discarded and
/// refreshed at any time.
///
/// `cdn`, `backupDir`, and `mediaDir` should be static as long as backup state doesn't
/// significantly change (e.g. - changing subscription level, re-enabling backups after the grace period)
struct BackupCDNMetadata: Codable, Equatable {
/// The CDN type where the message backup is stored. Media may be stored elsewhere.
let cdn: Int32
/// The base directory of your backup data on the cdn. The message backup can befound in the
/// returned cdn at /backupDir/backupName and stored media can be found at /backupDir/mediaDir/mediaId
let backupDir: String
/// The prefix path component for media objects on a cdn. Stored media for mediaId
/// can be found at /backupDir/mediaDir/mediaId.
let mediaDir: String
/// The name of the most recent message backup on the cdn. The backup is at /backupDir/backupName
let backupName: String
/// The amount of space used to store media
let usedSpace: Int64
}

View File

@ -0,0 +1,23 @@
//
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
struct BackupCDNReadCredential: Codable {
static let lifetime: TimeInterval = .day
let createDate: Date
let headers: HttpHeaders
func isExpired(now: Date) -> Bool {
return now > createDate.addingTimeInterval(Self.lifetime)
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.headers = try container.decode(HttpHeaders.self, forKey: .headers)
// createDate will default to current date, but can be overwritten during decodable initialization
self.createDate = try container.decodeIfPresent(Date.self, forKey: .createDate) ?? Date()
}
}

View File

@ -142,38 +142,8 @@ extension BackupRequestManager {
public struct BackupRequestManagerImpl: BackupRequestManager {
private enum Constants {
static let keyValueStoreCollectionName = "BackupRequestManager"
static let cdnNumberOfDaysFetchIntervalInSeconds: TimeInterval = .day
private static let keyValueStoreCdn2CredentialKey = "Cdn2Credential:"
private static let keyValueStoreCdn3CredentialKey = "Cdn3Credential:"
static func cdnCredentialCacheKey(for cdn: Int32, auth: BackupServiceAuth) -> String {
switch cdn {
case 2:
return Constants.keyValueStoreCdn2CredentialKey + auth.type.rawValue
case 3:
return Constants.keyValueStoreCdn3CredentialKey + auth.type.rawValue
default:
owsFailDebug("Invalid CDN version requested")
return Constants.keyValueStoreCdn3CredentialKey + auth.type.rawValue
}
}
static let backupInfoNumberOfDaysFetchIntervalInSeconds: TimeInterval = .day
private static let keyValueStoreBackupInfoKeyPrefix = "BackupInfo:"
private static let keyValueStoreLastBackupInfoFetchTimeKeyPrefix = "LastBackupInfoFetchTime:"
static func backupInfoCacheInfo(for auth: BackupServiceAuth) -> (infoKey: String, lastfetchTimeKey: String) {
(
keyValueStoreBackupInfoKeyPrefix + auth.type.rawValue,
keyValueStoreLastBackupInfoFetchTimeKeyPrefix + auth.type.rawValue
)
}
}
private let backupAuthCredentialManager: BackupAuthCredentialManager
private let backupCDNCache: BackupCDNCache
private let backupKeyMaterial: BackupKeyMaterial
private let dateProvider: DateProvider
private let db: any DB
@ -182,16 +152,18 @@ public struct BackupRequestManagerImpl: BackupRequestManager {
init(
backupAuthCredentialManager: BackupAuthCredentialManager,
backupCDNCache: BackupCDNCache,
backupKeyMaterial: BackupKeyMaterial,
dateProvider: @escaping DateProvider,
db: any DB,
networkManager: NetworkManager
) {
self.backupAuthCredentialManager = backupAuthCredentialManager
self.backupCDNCache = backupCDNCache
self.backupKeyMaterial = backupKeyMaterial
self.dateProvider = dateProvider
self.db = db
self.kvStore = KeyValueStore(collection: Constants.keyValueStoreCollectionName)
self.kvStore = KeyValueStore(collection: "BackupRequestManager")
self.networkManager = networkManager
}
@ -247,82 +219,32 @@ public struct BackupRequestManagerImpl: BackupRequestManager {
// MARK: - Backup Info
/// Backup info provided by the server that is cached locally, so this can be discarded and
/// refreshed at any time.
///
/// `cdn`, `backupDir`, and `mediaDir` should be static as long as backup state doesn't
/// significantly change (e.g. - changing subscription level, re-enabling backups after the grace period)
fileprivate struct BackupRemoteInfo: Codable, Equatable {
/// The CDN type where the message backup is stored. Media may be stored elsewhere.
public let cdn: Int32
/// The base directory of your backup data on the cdn. The message backup can befound in the
/// returned cdn at /backupDir/backupName and stored media can be found at /backupDir/mediaDir/mediaId
public let backupDir: String
/// The prefix path component for media objects on a cdn. Stored media for mediaId
/// can be found at /backupDir/mediaDir/mediaId.
public let mediaDir: String
/// The name of the most recent message backup on the cdn. The backup is at /backupDir/backupName
public let backupName: String
/// The amount of space used to store media
let usedSpace: Int64
}
/// Fetch details about the current backup
private func fetchBackupInfo(auth: BackupServiceAuth) async throws -> BackupRemoteInfo {
let cacheInfo = Constants.backupInfoCacheInfo(for: auth)
let cachedBackupInfo = db.read { tx -> BackupRemoteInfo? in
let lastInfoFetchTime = kvStore.getDate(
cacheInfo.lastfetchTimeKey,
transaction: tx
) ?? .distantPast
// Refresh backup info after 24 hours
if abs(lastInfoFetchTime.timeIntervalSinceNow) < Constants.backupInfoNumberOfDaysFetchIntervalInSeconds {
do {
if let backupInfo: BackupRemoteInfo = try kvStore.getCodableValue(
forKey: cacheInfo.infoKey,
transaction: tx
) {
return backupInfo
}
} catch {
// Failure to deserialize this object should be ok since it's simply
// a cache of the remote info and can be refetched. But still worth
// a log entry in case something results in repeated errors.
Logger.debug("Couldn't decode backup info, fetch remotely")
}
}
return nil
private func fetchBackupCDNMetadata(auth: BackupServiceAuth) async throws -> BackupCDNMetadata {
if let cachedCDNMetadata = db.read(block: { tx in
backupCDNCache.backupCDNMetadata(
authType: auth.type,
now: dateProvider(),
tx: tx
)
}) {
return cachedCDNMetadata
}
if let cachedBackupInfo {
return cachedBackupInfo
}
let backupInfo: BackupRemoteInfo = try await executeBackupService(
let cdnMetadata: BackupCDNMetadata = try await executeBackupService(
auth: auth,
requestFactory: OWSRequestFactory.backupInfoRequest(auth:)
)
try await db.awaitableWrite { tx in
try kvStore.setCodable(
backupInfo,
key: cacheInfo.infoKey,
transaction: tx
)
kvStore.setDate(
dateProvider(),
key: cacheInfo.lastfetchTimeKey,
transaction: tx
await db.awaitableWrite { tx in
backupCDNCache.setBackupCDNMetadata(
cdnMetadata,
authType: auth.type,
dateProvider: dateProvider,
tx: tx
)
}
return backupInfo
return cdnMetadata
}
// TODO: [Backups] Call this regularly, or move it somewhere it is called regularly
@ -340,45 +262,39 @@ public struct BackupRequestManagerImpl: BackupRequestManager {
private func fetchCDNReadCredentials(
cdn: Int32,
auth: BackupServiceAuth
) async throws -> CDNReadCredential {
let cacheKey = Constants.cdnCredentialCacheKey(for: cdn, auth: auth)
let result = db.read { tx -> CDNReadCredential? in
do {
if
let backupAuthCredential: CDNReadCredential = try kvStore.getCodableValue(forKey: cacheKey, transaction: tx),
backupAuthCredential.isExpired.negated
{
return backupAuthCredential
}
} catch {
// Failure to deserialize this object should be ok since the credential
// can be refetched. But still worth a log entry in case something
// results in repeated errors.
Logger.info("Couldn't decode backup info, fetch remotely")
}
return nil
) async throws -> BackupCDNReadCredential {
if let cachedCDNReadCredential = db.read(block: { tx in
backupCDNCache.backupCDNReadCredential(
cdnNumber: cdn,
authType: auth.type,
now: dateProvider(),
tx: tx
)
}) {
return cachedCDNReadCredential
}
if let result {
return result
}
let authCredential: CDNReadCredential = try await executeBackupService(
let cdnReadCredential: BackupCDNReadCredential = try await executeBackupService(
auth: auth,
requestFactory: { OWSRequestFactory.fetchCDNCredentials(auth: $0, cdn: cdn) }
requestFactory: { OWSRequestFactory.fetchBackupCDNCredentials(auth: $0, cdn: cdn) }
)
try await db.awaitableWrite { tx in
try kvStore.setCodable(authCredential, key: cacheKey, transaction: tx)
await db.awaitableWrite { tx in
backupCDNCache.setBackupCDNReadCredential(
cdnReadCredential,
cdnNumber: cdn,
authType: auth.type,
tx: tx
)
}
return authCredential
return cdnReadCredential
}
public func fetchBackupRequestMetadata(auth: BackupServiceAuth) async throws -> BackupReadCredential {
let info = try await fetchBackupInfo(auth: auth)
let authCredential = try await fetchCDNReadCredentials(cdn: info.cdn, auth: auth)
return BackupReadCredential(credential: authCredential, info: info)
let metadata = try await fetchBackupCDNMetadata(auth: auth)
let authCredential = try await fetchCDNReadCredentials(cdn: metadata.cdn, auth: auth)
return BackupReadCredential(credential: authCredential, metadata: metadata)
}
public func fetchMediaTierCdnRequestMetadata(
@ -386,9 +302,9 @@ public struct BackupRequestManagerImpl: BackupRequestManager {
auth: BackupServiceAuth
) async throws -> MediaTierReadCredential {
owsAssertDebug(auth.type == .media)
let info = try await fetchBackupInfo(auth: auth)
let metadata = try await fetchBackupCDNMetadata(auth: auth)
let authCredential = try await fetchCDNReadCredentials(cdn: cdn, auth: auth)
return MediaTierReadCredential(cdn: cdn, credential: authCredential, info: info)
return MediaTierReadCredential(cdn: cdn, credential: authCredential, metadata: metadata)
}
public func copyToMediaTier(
@ -501,43 +417,24 @@ public struct BackupRequestManagerImpl: BackupRequestManager {
}
}
private struct CDNReadCredential: Codable {
private static let cdnCredentialLifetimeInSeconds: TimeInterval = .day
let createDate: Date
let headers: HttpHeaders
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.headers = try container.decode(HttpHeaders.self, forKey: .headers)
// createDate will default to current date, but can be overwritten during decodable initialization
self.createDate = try container.decodeIfPresent(Date.self, forKey: .createDate) ?? Date()
}
var isExpired: Bool {
return abs(createDate.timeIntervalSinceNow) >= CDNReadCredential.cdnCredentialLifetimeInSeconds
}
}
public struct MediaTierReadCredential {
public let cdn: Int32
private let credential: CDNReadCredential
private let info: BackupRequestManagerImpl.BackupRemoteInfo
private let credential: BackupCDNReadCredential
private let metadata: BackupCDNMetadata
fileprivate init(
cdn: Int32,
credential: CDNReadCredential,
info: BackupRequestManagerImpl.BackupRemoteInfo
credential: BackupCDNReadCredential,
metadata: BackupCDNMetadata,
) {
self.cdn = cdn
self.credential = credential
self.info = info
self.metadata = metadata
}
var isExpired: Bool {
return credential.isExpired
return credential.isExpired(now: Date())
}
var cdnAuthHeaders: HttpHeaders {
@ -545,29 +442,29 @@ public struct MediaTierReadCredential {
}
func mediaTierUrlPrefix() -> String {
return "backups/\(info.backupDir)/\(info.mediaDir)"
return "backups/\(metadata.backupDir)/\(metadata.mediaDir)"
}
}
public struct BackupReadCredential {
private let credential: CDNReadCredential
private let info: BackupRequestManagerImpl.BackupRemoteInfo
private let credential: BackupCDNReadCredential
private let metadata: BackupCDNMetadata
fileprivate init(
credential: CDNReadCredential,
info: BackupRequestManagerImpl.BackupRemoteInfo
credential: BackupCDNReadCredential,
metadata: BackupCDNMetadata
) {
self.credential = credential
self.info = info
self.metadata = metadata
}
var isExpired: Bool {
return credential.isExpired
return credential.isExpired(now: Date())
}
var cdn: Int32 {
return info.cdn
return metadata.cdn
}
var cdnAuthHeaders: HttpHeaders {
@ -575,6 +472,6 @@ public struct BackupReadCredential {
}
func backupLocationUrl() -> String {
return "backups/\(info.backupDir)/\(info.backupName)"
return "backups/\(metadata.backupDir)/\(metadata.backupName)"
}
}

View File

@ -369,6 +369,7 @@ public class AppSetup {
db: db,
networkManager: networkManager
),
backupCDNCache: BackupCDNCache(),
backupKeyMaterial: backupKeyMaterial,
dateProvider: dateProvider,
db: db,

View File

@ -60,7 +60,7 @@ extension OWSRequestFactory {
return request
}
public static func fetchCDNCredentials(auth: BackupServiceAuth, cdn: Int32) -> TSRequest {
public static func fetchBackupCDNCredentials(auth: BackupServiceAuth, cdn: Int32) -> TSRequest {
var request = TSRequest(
url: URL(string: "v1/archives/auth/read?cdn=\(cdn)")!,
method: "GET",

View File

@ -9,14 +9,14 @@ import LibSignalClient
class AuthCredentialStore {
private let callLinkAuthCredentialStore: KeyValueStore
private let groupAuthCredentialStore: KeyValueStore
private let backupAuthCredentialStore: KeyValueStore
private let mediaAuthCredentialStore: KeyValueStore
private let backupMessagesAuthCredentialStore: KeyValueStore
private let backupMediaAuthCredentialStore: KeyValueStore
init() {
self.callLinkAuthCredentialStore = KeyValueStore(collection: "CallLinkAuthCredential")
self.groupAuthCredentialStore = KeyValueStore(collection: "GroupsV2Impl.authCredentialStoreStore")
self.backupAuthCredentialStore = KeyValueStore(collection: "BackupAuthCredential")
self.mediaAuthCredentialStore = KeyValueStore(collection: "MediaAuthCredential")
self.backupMessagesAuthCredentialStore = KeyValueStore(collection: "BackupAuthCredential")
self.backupMediaAuthCredentialStore = KeyValueStore(collection: "MediaAuthCredential")
}
private static func callLinkAuthCredentialKey(for redemptionTime: UInt64) -> String {
@ -98,7 +98,11 @@ class AuthCredentialStore {
redemptionTime: UInt64,
tx: DBReadTransaction
) -> BackupAuthCredential? {
let store = credentialType == .messages ? backupAuthCredentialStore : mediaAuthCredentialStore
let store: KeyValueStore = switch credentialType {
case .media: backupMediaAuthCredentialStore
case .messages: backupMessagesAuthCredentialStore
}
do {
return try store.getData(
Self.backupAuthCredentialKey(for: redemptionTime),
@ -118,7 +122,11 @@ class AuthCredentialStore {
redemptionTime: UInt64,
tx: DBWriteTransaction
) {
let store = credentialType == .messages ? backupAuthCredentialStore : mediaAuthCredentialStore
let store: KeyValueStore = switch credentialType {
case .media: backupMediaAuthCredentialStore
case .messages: backupMessagesAuthCredentialStore
}
store.setData(
credential.serialize(),
key: Self.backupAuthCredentialKey(for: redemptionTime),
@ -127,7 +135,11 @@ class AuthCredentialStore {
}
func removeAllBackupAuthCredentials(ofType credentialType: BackupAuthCredentialType, tx: DBWriteTransaction) {
let store = credentialType == .messages ? backupAuthCredentialStore : mediaAuthCredentialStore
let store: KeyValueStore = switch credentialType {
case .media: backupMediaAuthCredentialStore
case .messages: backupMessagesAuthCredentialStore
}
store.removeAll(transaction: tx)
}