Signal-iOS/SignalServiceKit/SecureValueRecovery/LocalStorage/SVRLocalStorage.swift
2025-04-14 09:46:48 -07:00

151 lines
5.1 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public protocol SVRLocalStorage {
func getIsMasterKeyBackedUp(_ transaction: DBReadTransaction) -> Bool
func clearStorageServiceKeys(_ transaction: DBWriteTransaction)
}
public protocol SVRLocalStorageInternal: SVRLocalStorage {
func getPinType(_ transaction: DBReadTransaction) -> SVR.PinType?
func getEncodedPINVerificationString(_ transaction: DBReadTransaction) -> String?
func getSVR2MrEnclaveStringValue(_ transaction: DBReadTransaction) -> String?
// MARK: - Setters
func setIsMasterKeyBackedUp(_ value: Bool, _ transaction: DBWriteTransaction)
func setPinType(_ value: SVR.PinType, _ transaction: DBWriteTransaction)
func setEncodedPINVerificationString(_ value: String?, _ transaction: DBWriteTransaction)
func setSVR2MrEnclaveStringValue(_ value: String?, _ transaction: DBWriteTransaction)
// MARK: - Clearing Keys
func clearSVRKeys(_ transaction: DBWriteTransaction)
// MARK: - Cleanup
func cleanupDeadKeys(_ transaction: DBWriteTransaction)
}
/// Stores state related to SVR independent of enclave; e.g. do we have backups at all,
/// what type is our pin, etc.
internal class SVRLocalStorageImpl: SVRLocalStorageInternal {
private let svrKvStore: KeyValueStore
public init() {
// Collection name must not be changed; matches that historically kept in KeyBackupServiceImpl.
self.svrKvStore = KeyValueStore(collection: "kOWSKeyBackupService_Keys")
}
// MARK: - Getters
public func getIsMasterKeyBackedUp(_ transaction: DBReadTransaction) -> Bool {
return svrKvStore.getBool(Keys.isMasterKeyBackedUp, defaultValue: false, transaction: transaction)
}
public func getPinType(_ transaction: DBReadTransaction) -> SVR.PinType? {
guard let raw = svrKvStore.getInt(Keys.pinType, transaction: transaction) else {
return nil
}
return SVR.PinType(rawValue: raw)
}
public func getEncodedPINVerificationString(_ transaction: DBReadTransaction) -> String? {
return svrKvStore.getString(Keys.encodedPINVerificationString, transaction: transaction)
}
public func getSVR2MrEnclaveStringValue(_ transaction: DBReadTransaction) -> String? {
return svrKvStore.getString(Keys.svr2MrEnclaveStringValue, transaction: transaction)
}
// MARK: - Setters
public func setIsMasterKeyBackedUp(_ value: Bool, _ transaction: DBWriteTransaction) {
svrKvStore.setBool(value, key: Keys.isMasterKeyBackedUp, transaction: transaction)
}
public func setPinType(_ value: SVR.PinType, _ transaction: DBWriteTransaction) {
svrKvStore.setInt(value.rawValue, key: Keys.pinType, transaction: transaction)
}
public func setEncodedPINVerificationString(_ value: String?, _ transaction: DBWriteTransaction) {
svrKvStore.setString(value, key: Keys.encodedPINVerificationString, transaction: transaction)
}
public func setSVR2MrEnclaveStringValue(_ value: String?, _ transaction: DBWriteTransaction) {
svrKvStore.setString(value, key: Keys.svr2MrEnclaveStringValue, transaction: transaction)
}
// MARK: - Clearing Keys
public func clearSVRKeys(_ transaction: DBWriteTransaction) {
svrKvStore.removeValues(
forKeys: [
Keys.pinType,
Keys.encodedPINVerificationString,
Keys.isMasterKeyBackedUp,
Keys.syncedStorageServiceKey,
Keys.legacy_svr1EnclaveName,
Keys.svr2MrEnclaveStringValue
],
transaction: transaction
)
}
public func clearStorageServiceKeys(_ transaction: DBWriteTransaction) {
svrKvStore.removeValue(forKey: Keys.syncedStorageServiceKey, transaction: transaction)
}
// MARK: - Cleanup
func cleanupDeadKeys(_ transaction: DBWriteTransaction) {
svrKvStore.removeValues(
forKeys: [
Keys.legacy_svr1EnclaveName,
],
transaction: transaction
)
}
// MARK: - Identifiers
private enum Keys {
// These must not change, they match what was historically in KeyBackupServiceImpl.
static let pinType = "pinType"
static let encodedPINVerificationString = "encodedVerificationString"
static let isMasterKeyBackedUp = "isMasterKeyBackedUp"
static let syncedStorageServiceKey = "Storage Service Encryption"
static let syncedBackupKey = "Backup Key"
// Kept around because its existence indicates we had an svr1 backup.
// TODO: Remove after Nov 1, 2024
static let legacy_svr1EnclaveName = "enclaveName"
static let svr2MrEnclaveStringValue = "svr2_mrenclaveStringValue"
}
}
#if TESTABLE_BUILD
public class SVRLocalStorageMock: SVRLocalStorage {
var isMasterKeyBackedUp: Bool = false
public func clearStorageServiceKeys(_ transaction: DBWriteTransaction) {
fatalError("not implemented")
}
public func getIsMasterKeyBackedUp(_ transaction: DBReadTransaction) -> Bool {
return isMasterKeyBackedUp
}
}
#endif