Signal-iOS/SignalServiceKit/ZeroKnowledge/AuthCredentialStore.swift
2025-09-15 15:24:13 -05:00

203 lines
6.9 KiB
Swift

//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import LibSignalClient
class AuthCredentialStore {
private let dateProvider: DateProvider
private let callLinkAuthCredentialStore: KeyValueStore
private let groupAuthCredentialStore: KeyValueStore
private let backupMessagesAuthCredentialStore: KeyValueStore
private let backupMediaAuthCredentialStore: KeyValueStore
private let svr🐝AuthCredentialStore: KeyValueStore
init(dateProvider: @escaping DateProvider) {
self.dateProvider = dateProvider
self.callLinkAuthCredentialStore = KeyValueStore(collection: "CallLinkAuthCredential")
self.groupAuthCredentialStore = KeyValueStore(collection: "GroupsV2Impl.authCredentialStoreStore")
self.backupMessagesAuthCredentialStore = KeyValueStore(collection: "BackupAuthCredential")
self.backupMediaAuthCredentialStore = KeyValueStore(collection: "MediaAuthCredential")
self.svr🐝AuthCredentialStore = KeyValueStore(collection: "SVR🐝AuthCredential")
}
private static func callLinkAuthCredentialKey(for redemptionTime: UInt64) -> String {
return "\(redemptionTime)"
}
private static func groupAuthCredentialKey(for redemptionTime: UInt64) -> String {
return "ACWP_\(redemptionTime)"
}
private static func backupAuthCredentialKey(for redemptionTime: UInt64) -> String {
return "\(redemptionTime)"
}
// MARK: -
func callLinkAuthCredential(
for redemptionTime: UInt64,
tx: DBReadTransaction
) throws -> LibSignalClient.CallLinkAuthCredential? {
return try callLinkAuthCredentialStore.getData(
Self.callLinkAuthCredentialKey(for: redemptionTime),
transaction: tx
).map {
return try LibSignalClient.CallLinkAuthCredential(contents: $0)
}
}
func setCallLinkAuthCredential(
_ credential: LibSignalClient.CallLinkAuthCredential,
for redemptionTime: UInt64,
tx: DBWriteTransaction
) {
callLinkAuthCredentialStore.setData(
credential.serialize(),
key: Self.callLinkAuthCredentialKey(for: redemptionTime),
transaction: tx
)
}
func removeAllCallLinkAuthCredentials(tx: DBWriteTransaction) {
callLinkAuthCredentialStore.removeAll(transaction: tx)
}
// MARK: -
func groupAuthCredential(
for redemptionTime: UInt64,
tx: DBReadTransaction
) throws -> AuthCredentialWithPni? {
return try groupAuthCredentialStore.getData(
Self.groupAuthCredentialKey(for: redemptionTime),
transaction: tx
).map {
return try AuthCredentialWithPni.init(contents: $0)
}
}
func setGroupAuthCredential(
_ credential: AuthCredentialWithPni,
for redemptionTime: UInt64,
tx: DBWriteTransaction
) {
groupAuthCredentialStore.setData(
credential.serialize(),
key: Self.groupAuthCredentialKey(for: redemptionTime),
transaction: tx
)
}
func removeAllGroupAuthCredentials(tx: DBWriteTransaction) {
groupAuthCredentialStore.removeAll(transaction: tx)
}
// MARK: -
func backupAuthCredential(
for credentialType: BackupAuthCredentialType,
redemptionTime: UInt64,
tx: DBReadTransaction
) -> BackupAuthCredential? {
let store: KeyValueStore = switch credentialType {
case .media: backupMediaAuthCredentialStore
case .messages: backupMessagesAuthCredentialStore
}
do {
return try store.getData(
Self.backupAuthCredentialKey(for: redemptionTime),
transaction: tx
).map {
return try BackupAuthCredential.init(contents: $0)
}
} catch {
Logger.warn("Invalid backup credential format")
return nil
}
}
func setBackupAuthCredential(
_ credential: BackupAuthCredential,
for credentialType: BackupAuthCredentialType,
redemptionTime: UInt64,
tx: DBWriteTransaction
) {
let store: KeyValueStore = switch credentialType {
case .media: backupMediaAuthCredentialStore
case .messages: backupMessagesAuthCredentialStore
}
store.setData(
credential.serialize(),
key: Self.backupAuthCredentialKey(for: redemptionTime),
transaction: tx
)
}
static let svr🐝AuthCredentialExpirationTime: TimeInterval = .day - .hour
static let svr🐝AuthCredentialExpiryDateKey = "svr🐝AuthCredentialTimestampKey"
static let svr🐝AuthCredentialUsernameKey = "svr🐝AuthCredentialUsernameKey"
static let svr🐝AuthCredentialPasswordKey = "svr🐝AuthCredentialPasswordKey"
func svr🐝AuthCredential(tx: DBReadTransaction) -> LibSignalClient.Auth? {
guard
let username = svr🐝AuthCredentialStore.getString(Self.svr🐝AuthCredentialUsernameKey, transaction: tx),
let password = svr🐝AuthCredentialStore.getString(Self.svr🐝AuthCredentialPasswordKey, transaction: tx),
let expiryDate = svr🐝AuthCredentialStore.getDate(Self.svr🐝AuthCredentialExpiryDateKey, transaction: tx)
else {
return nil
}
guard expiryDate > dateProvider() else {
return nil
}
return Auth(
username: username,
password: password
)
}
func setSvr🐝AuthCredential(
_ credential: LibSignalClient.Auth?,
tx: DBWriteTransaction
) {
guard let credential else {
svr🐝AuthCredentialStore.removeAll(transaction: tx)
return
}
svr🐝AuthCredentialStore.setString(credential.username, key: Self.svr🐝AuthCredentialUsernameKey, transaction: tx)
svr🐝AuthCredentialStore.setString(credential.password, key: Self.svr🐝AuthCredentialPasswordKey, transaction: tx)
svr🐝AuthCredentialStore.setDate(
dateProvider().addingTimeInterval(Self.svr🐝AuthCredentialExpirationTime),
key: Self.svr🐝AuthCredentialExpiryDateKey,
transaction: tx
)
}
func removeAllBackupAuthCredentials(ofType credentialType: BackupAuthCredentialType, tx: DBWriteTransaction) {
let store: KeyValueStore = switch credentialType {
case .media: backupMediaAuthCredentialStore
case .messages: backupMessagesAuthCredentialStore
}
store.removeAll(transaction: tx)
switch credentialType {
case .media:
break
case .messages:
svr🐝AuthCredentialStore.removeAll(transaction: tx)
}
}
func removeAllBackupAuthCredentials(tx: DBWriteTransaction) {
for credentialType in BackupAuthCredentialType.allCases {
removeAllBackupAuthCredentials(ofType: credentialType, tx: tx)
}
}
}