Container_EscrowRecords.swift   [plain text]


import CoreData
import Foundation

extension Container {

    func onqueueCachedRecordsContainEgoPeerBottle(cachedRecords: [OTEscrowRecord]) -> Bool {
        guard let egoPeerID = self.containerMO.egoPeerID else {
            os_log("onqueueCachedRecordsContainEgoPeerBottle: No identity.", log: tplogDebug, type: .default)
            return false
        }
        guard let bottles: Set<BottleMO> = self.containerMO.bottles as? Set<BottleMO>  else {
            os_log("onqueueCachedRecordsContainEgoPeerBottle: No Bottles.", log: tplogDebug, type: .default)
            return false
        }
        var matchesCached: Bool = false
        for bottle in bottles {
            guard let bottleID: String = bottle.bottleID else {
                continue
            }
            if bottle.peerID == egoPeerID && (cachedRecords.compactMap { $0.escrowInformationMetadata.bottleId }).contains(bottleID) {
                matchesCached = true
                break
            }
        }
        return matchesCached
    }

    func escrowRecordMOToEscrowRecords(record: EscrowRecordMO, viability: Viability) -> OTEscrowRecord? {
        let escrowRecord = OTEscrowRecord()
        let escrowRecordMetadata = OTEscrowRecordMetadata()
        let clientMetadata = OTEscrowRecordMetadataClientMetadata()

        if let e = escrowRecord {
            if let creationDate = record.creationDate {
                e.creationDate = UInt64(creationDate.timeIntervalSince1970)
            }
            e.label = record.label ?? ""
            e.remainingAttempts = UInt64(record.remainingAttempts)
            e.silentAttemptAllowed = UInt64(record.silentAttemptAllowed)
            e.recordStatus = record.recordStatus == 0 ? .RECORD_STATUS_VALID : .RECORD_STATUS_INVALID

            switch viability {
            case .full:
                e.recordViability = .RECORD_VIABILITY_FULLY_VIABLE
            case .partial:
                e.recordViability = .RECORD_VIABILITY_PARTIALLY_VIABLE
            case .none:
                e.recordViability = .RECORD_VIABILITY_LEGACY
            }

            switch record.sosViability {
            case 0:
                e.viabilityStatus = .SOS_VIABLE_UNKNOWN
            case 1:
                e.viabilityStatus = .SOS_VIABLE
            case 2:
                e.viabilityStatus = .SOS_NOT_VIABLE
            default:
                e.viabilityStatus = .SOS_VIABLE_UNKNOWN
            }

            if let metadata = escrowRecordMetadata {
                if let m = record.escrowMetadata {
                    metadata.backupKeybagDigest = m.backupKeybagDigest ?? Data()
                    if let timestamp = m.secureBackupTimestamp {
                        metadata.secureBackupTimestamp = UInt64(timestamp.timeIntervalSince1970)
                    }
                    metadata.secureBackupUsesMultipleIcscs = UInt64(m.secureBackupUsesMultipleiCSCS)
                    metadata.bottleId = m.bottleID ?? ""
                    metadata.escrowedSpki = m.escrowedSPKI ?? Data()
                    metadata.peerInfo = m.peerInfo ?? Data()
                    metadata.serial = m.serial ?? ""
                    if let cmToFill = clientMetadata {
                        if let cm = m.clientMetadata {
                            cmToFill.deviceMid = cm.deviceMid ?? ""
                            cmToFill.deviceColor = cm.deviceColor ?? ""
                            cmToFill.deviceModel = cm.deviceModel ?? ""
                            cmToFill.deviceName = cm.deviceName ?? ""
                            cmToFill.devicePlatform = UInt64(cm.devicePlatform)
                            cmToFill.deviceModelClass = cm.deviceModelClass ?? ""
                            cmToFill.deviceModelVersion = cm.deviceModelVersion ?? ""
                            cmToFill.deviceEnclosureColor = cm.deviceEnclosureColor ?? ""
                            if let timestamp = cm.secureBackupMetadataTimestamp {
                                cmToFill.secureBackupMetadataTimestamp = UInt64(timestamp.timeIntervalSince1970)
                            }
                            cmToFill.secureBackupUsesComplexPassphrase = UInt64(cm.secureBackupUsesComplexPassphrase)
                            cmToFill.secureBackupUsesNumericPassphrase = UInt64(cm.secureBackupUsesNumericPassphrase)
                            cmToFill.secureBackupNumericPassphraseLength = UInt64(cm.secureBackupNumericPassphraseLength)
                        }
                    }
                    metadata.clientMetadata = clientMetadata
                }
                e.escrowInformationMetadata = metadata
            }
        }

        return escrowRecord
    }

    func setEscrowRecord(record: EscrowInformation, viability: Viability) {
        let escrowRecordMO = EscrowRecordMO(context: self.moc)
        escrowRecordMO.label = record.label
        escrowRecordMO.creationDate = record.creationDate.date
        escrowRecordMO.remainingAttempts = Int64(record.remainingAttempts)
        escrowRecordMO.silentAttemptAllowed = Int64(record.silentAttemptAllowed)
        escrowRecordMO.recordStatus = Int64(record.recordStatus.rawValue)
        escrowRecordMO.sosViability = Int64(record.viabilityStatus.rawValue)
        
        let escrowRecordMetadataMO = EscrowMetadataMO(context: self.moc)
        escrowRecordMetadataMO.backupKeybagDigest = record.escrowInformationMetadata.backupKeybagDigest
        escrowRecordMetadataMO.secureBackupUsesMultipleiCSCS = Int64(record.escrowInformationMetadata.secureBackupUsesMultipleIcscs)
        escrowRecordMetadataMO.bottleID = record.escrowInformationMetadata.bottleID
        escrowRecordMetadataMO.secureBackupTimestamp = record.escrowInformationMetadata.secureBackupTimestamp.date
        escrowRecordMetadataMO.escrowedSPKI = record.escrowInformationMetadata.escrowedSpki
        escrowRecordMetadataMO.peerInfo = record.escrowInformationMetadata.peerInfo
        escrowRecordMetadataMO.serial = record.escrowInformationMetadata.serial
        escrowRecordMO.escrowMetadata = escrowRecordMetadataMO

        let escrowRecordClientMetadataMO = EscrowClientMetadataMO(context: self.moc)
        escrowRecordClientMetadataMO.secureBackupMetadataTimestamp = record.escrowInformationMetadata.clientMetadata.secureBackupMetadataTimestamp.date
        escrowRecordClientMetadataMO.secureBackupNumericPassphraseLength = Int64(record.escrowInformationMetadata.clientMetadata.secureBackupNumericPassphraseLength)
        escrowRecordClientMetadataMO.secureBackupUsesComplexPassphrase = Int64(record.escrowInformationMetadata.clientMetadata.secureBackupUsesComplexPassphrase)
        escrowRecordClientMetadataMO.secureBackupUsesNumericPassphrase = Int64(record.escrowInformationMetadata.clientMetadata.secureBackupUsesNumericPassphrase)
        escrowRecordClientMetadataMO.deviceColor = record.escrowInformationMetadata.clientMetadata.deviceColor
        escrowRecordClientMetadataMO.deviceEnclosureColor = record.escrowInformationMetadata.clientMetadata.deviceEnclosureColor
        escrowRecordClientMetadataMO.deviceMid = record.escrowInformationMetadata.clientMetadata.deviceMid
        escrowRecordClientMetadataMO.deviceModel = record.escrowInformationMetadata.clientMetadata.deviceModel
        escrowRecordClientMetadataMO.deviceModelClass = record.escrowInformationMetadata.clientMetadata.deviceModelClass
        escrowRecordClientMetadataMO.deviceModelVersion = record.escrowInformationMetadata.clientMetadata.deviceModelVersion
        escrowRecordClientMetadataMO.deviceName = record.escrowInformationMetadata.clientMetadata.deviceName
        escrowRecordClientMetadataMO.devicePlatform = Int64(record.escrowInformationMetadata.clientMetadata.devicePlatform)

        escrowRecordMetadataMO.clientMetadata = escrowRecordClientMetadataMO

        os_log("setEscrowRecord saving new escrow record: %@", log: tplogDebug, type: .default, escrowRecordMO)
        switch viability {
        case .full:
            self.containerMO.addToFullyViableEscrowRecords(escrowRecordMO)
            break
        case .partial:
            self.containerMO.addToPartiallyViableEscrowRecords(escrowRecordMO)
            break
        case .none:
            self.containerMO.addToLegacyEscrowRecords(escrowRecordMO)
            break
        }
    }

    func onqueueCachedBottlesFromEscrowRecords() -> (TPCachedViableBottles) {
        var viableRecords: [String] = []
        var partiallyViableRecords: [String] = []

        if let fullyViableEscrowRecords = self.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO> {
            viableRecords = fullyViableEscrowRecords.compactMap { $0.escrowMetadata?.bottleID }
        }
        if let partiallyViableEscrowRecords = self.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO> {
            partiallyViableRecords = partiallyViableEscrowRecords.compactMap { $0.escrowMetadata?.bottleID }
        }
        return TPCachedViableBottles(viableBottles: viableRecords, partialBottles: partiallyViableRecords)
    }

    func onqueueCachedEscrowRecords() -> ([OTEscrowRecord]) {
        var escrowRecords: [OTEscrowRecord] = []

        if let fullyViableEscrowRecords = self.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO> {
            for record in fullyViableEscrowRecords {
                let convertedRecord = escrowRecordMOToEscrowRecords(record: record, viability: .full)
                if let r = convertedRecord {
                    escrowRecords.append(r)
                }
            }
        }
        if let partiallyViableEscrowRecords = self.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO> {
            for record in partiallyViableEscrowRecords {
                let convertedRecord = escrowRecordMOToEscrowRecords(record: record, viability: .partial)
                if let r = convertedRecord {
                    escrowRecords.append(r)
                }
            }
        }
        if let legacyEscrowRecords = self.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO> {
            for record in legacyEscrowRecords {
                let convertedRecord = escrowRecordMOToEscrowRecords(record: record, viability: .none)
                if let r = convertedRecord {
                    escrowRecords.append(r)
                }
            }
        }
        return escrowRecords
    }

    func fetchEscrowRecords(forceFetch: Bool, reply: @escaping ([Data]?, Error?) -> Void) {
        self.semaphore.wait()
        let reply: ([Data]?, Error?) -> Void = {
            os_log("fetchEscrowRecords complete: %@", log: tplogTrace, type: .info, traceError($1))
            self.semaphore.signal()
            reply($0, $1)
        }

        self.fetchEscrowRecordsWithSemaphore(forceFetch: forceFetch, reply: reply)
    }
}