diff --git a/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift b/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift index 1b0a0e5..edbb471 100644 --- a/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift +++ b/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift @@ -11,6 +11,12 @@ final class ClientMartinOMEMO { init(_ credentials: Credentials) { self.credentials = credentials + _ = regenerateKeys(wipe: false) + print("ClientMartinOMEMO init") + } + + deinit { + print("ClientMartinOMEMO deinit") } var signal: (SignalStorage, SignalContext) { @@ -20,25 +26,25 @@ final class ClientMartinOMEMO { signalStorage.setup(withContext: signalContext) return (signalStorage, signalContext) } - // func regenerateKeys(wipe: Bool = false) -> Bool { - // if wipe { - // wipeSignedPreKeys() - // } - // } - // if wipe { - // DBOMEMOStore.instance.wipe(forAccount: context!.sessionObject.userBareJid!) - // } - // - // let hasKeyPair = identityKeyStore.keyPair() != nil - // if wipe || identityKeyStore.localRegistrationId() == 0 || !hasKeyPair { - // let regId: UInt32 = signalContext.generateRegistrationId() - // AccountSettings.omemoRegistrationId(for: context!.sessionObject.userBareJid!, value: regId) - // - // let keyPair = SignalIdentityKeyPair.generateKeyPair(context: signalContext) - // if !identityKeyStore.save(identity: SignalAddress(name: context!.sessionObject.userBareJid!.stringValue, deviceId: Int32(identityKeyStore.localRegistrationId())), key: keyPair) {} - // } - // return true - // } + + private func regenerateKeys(wipe: Bool = false) -> Bool { + if wipe { + OMEMOSession.wipe(account: credentials.bareJid) + OMEMOPreKey.wipe(account: credentials.bareJid) + OMEMOSignedPreKey.wipe(account: credentials.bareJid) + OMEMOIdentity.wipe(account: credentials.bareJid) + } + + let hasKeyPair = keyPair() != nil + if wipe || localRegistrationId() == 0 || !hasKeyPair { + // let regId: UInt32 = signalContext.generateRegistrationId() + // AccountSettings.omemoRegistrationId(for: context!.sessionObject.userBareJid!, value: regId) + // + // let keyPair = SignalIdentityKeyPair.generateKeyPair(context: signalContext) + // if !identityKeyStore.save(identity: SignalAddress(name: context!.sessionObject.userBareJid!.stringValue, deviceId: Int32(identityKeyStore.localRegistrationId())), key: keyPair) {} + } + return true + } } // MARK: - Session @@ -123,6 +129,107 @@ extension ClientMartinOMEMO: SignalSessionStoreProtocol { } } +// MARK: - Identity +extension ClientMartinOMEMO: SignalIdentityKeyStoreProtocol { + func keyPair() -> (any MartinOMEMO.SignalIdentityKeyPairProtocol)? { + // guard let deviceId = localRegistrationId(forAccount: account) else { + // return nil + // } + // + // guard + // let data = try! Database.main.reader({ database in + // try database.select(query: .omemoKeyPairForAccount, params: ["account": account, "name": account.stringValue, "deviceId": deviceId]).mapFirst { $0.data(for: "key") } + // }) + // else { + // return nil + // } + // + // return SignalIdentityKeyPair(fromKeyPairData: data) + nil + } + + func localRegistrationId() -> UInt32 { + // + // + // + // + // + // + 0 + } + + func save(identity: MartinOMEMO.SignalAddress, key: (any MartinOMEMO.SignalIdentityKeyProtocol)?) -> Bool { + print(identity, key) + return false + } + + func save(identity: MartinOMEMO.SignalAddress, publicKeyData: Data?) -> Bool { + print(identity, publicKeyData) + return false + } + + func isTrusted(identity _: MartinOMEMO.SignalAddress, key _: (any MartinOMEMO.SignalIdentityKeyProtocol)?) -> Bool { + true + } + + func isTrusted(identity _: MartinOMEMO.SignalAddress, publicKeyData _: Data?) -> Bool { + true + } + + func setStatus(_ status: MartinOMEMO.IdentityStatus, forIdentity: MartinOMEMO.SignalAddress) -> Bool { + print(status, forIdentity) + return false + } + + func setStatus(active: Bool, forIdentity: MartinOMEMO.SignalAddress) -> Bool { + print(active, forIdentity) + return false + } + + func identities(forName name: String) -> [MartinOMEMO.Identity] { + do { + return try Database.shared.dbQueue.read { db in + try Row.fetchAll( + db, + sql: "SELECT * FROM omemo_identities WHERE account = :account AND name = :name", + arguments: ["account": credentials.bareJid, "name": name] + ) + }.compactMap { row in + guard + let fingerprint = row["fingerprint"] as? String, + let statusInt = row["status"] as? Int, + let status = MartinOMEMO.IdentityStatus(rawValue: statusInt), + let deviceId = row["device_id"] as? Int32, + let own = row["own"] as? Int, + let key = row["key"] as? Data + else { + return nil + } + return MartinOMEMO.Identity(address: MartinOMEMO.SignalAddress(name: name, deviceId: deviceId), status: status, fingerprint: fingerprint, key: key, own: own > 0) + } + } catch { + logIt(.error, "Error fetching chats: \(error.localizedDescription)") + return [] + } + } + + func identityFingerprint(forAddress address: MartinOMEMO.SignalAddress) -> String? { + do { + let data = try Database.shared.dbQueue.read { db in + try Row.fetchOne( + db, + sql: "SELECT fingerprint FROM omemo_identities WHERE account = :account AND name = :name AND device_id = :deviceId", + arguments: ["account": credentials.bareJid, "name": address.name, "deviceId": address.deviceId] + ) + } + return data?["fingerprint"] + } catch { + logIt(.error, "Error fetching chats: \(error.localizedDescription)") + return nil + } + } +} + // MARK: - PreKey extension ClientMartinOMEMO: SignalPreKeyStoreProtocol { func currentPreKeyId() -> UInt32 { @@ -357,107 +464,6 @@ extension ClientMartinOMEMO: SignalSignedPreKeyStoreProtocol { } } -// MARK: - Identity -extension ClientMartinOMEMO: SignalIdentityKeyStoreProtocol { - func keyPair() -> (any MartinOMEMO.SignalIdentityKeyPairProtocol)? { - // guard let deviceId = localRegistrationId(forAccount: account) else { - // return nil - // } - // - // guard - // let data = try! Database.main.reader({ database in - // try database.select(query: .omemoKeyPairForAccount, params: ["account": account, "name": account.stringValue, "deviceId": deviceId]).mapFirst { $0.data(for: "key") } - // }) - // else { - // return nil - // } - // - // return SignalIdentityKeyPair(fromKeyPairData: data) - nil - } - - func localRegistrationId() -> UInt32 { - // - // - // - // - // - // - 0 - } - - func save(identity: MartinOMEMO.SignalAddress, key: (any MartinOMEMO.SignalIdentityKeyProtocol)?) -> Bool { - print(identity, key) - return false - } - - func save(identity: MartinOMEMO.SignalAddress, publicKeyData: Data?) -> Bool { - print(identity, publicKeyData) - return false - } - - func isTrusted(identity _: MartinOMEMO.SignalAddress, key _: (any MartinOMEMO.SignalIdentityKeyProtocol)?) -> Bool { - true - } - - func isTrusted(identity _: MartinOMEMO.SignalAddress, publicKeyData _: Data?) -> Bool { - true - } - - func setStatus(_ status: MartinOMEMO.IdentityStatus, forIdentity: MartinOMEMO.SignalAddress) -> Bool { - print(status, forIdentity) - return false - } - - func setStatus(active: Bool, forIdentity: MartinOMEMO.SignalAddress) -> Bool { - print(active, forIdentity) - return false - } - - func identities(forName name: String) -> [MartinOMEMO.Identity] { - do { - return try Database.shared.dbQueue.read { db in - try Row.fetchAll( - db, - sql: "SELECT * FROM omemo_identities WHERE account = :account AND name = :name", - arguments: ["account": credentials.bareJid, "name": name] - ) - }.compactMap { row in - guard - let fingerprint = row["fingerprint"] as? String, - let statusInt = row["status"] as? Int, - let status = MartinOMEMO.IdentityStatus(rawValue: statusInt), - let deviceId = row["device_id"] as? Int32, - let own = row["own"] as? Int, - let key = row["key"] as? Data - else { - return nil - } - return MartinOMEMO.Identity(address: MartinOMEMO.SignalAddress(name: name, deviceId: deviceId), status: status, fingerprint: fingerprint, key: key, own: own > 0) - } - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - return [] - } - } - - func identityFingerprint(forAddress address: MartinOMEMO.SignalAddress) -> String? { - do { - let data = try Database.shared.dbQueue.read { db in - try Row.fetchOne( - db, - sql: "SELECT fingerprint FROM omemo_identities WHERE account = :account AND name = :name AND device_id = :deviceId", - arguments: ["account": credentials.bareJid, "name": address.name, "deviceId": address.deviceId] - ) - } - return data?["fingerprint"] - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - return nil - } - } -} - // MARK: - SenderKey extension ClientMartinOMEMO: SignalSenderKeyStoreProtocol { func storeSenderKey(_: Data, address _: MartinOMEMO.SignalAddress?, groupId _: String?) -> Bool { diff --git a/ConversationsClassic/AppData/Model/OMEMO.swift b/ConversationsClassic/AppData/Model/OMEMO.swift index 8276f66..65ff9ef 100644 --- a/ConversationsClassic/AppData/Model/OMEMO.swift +++ b/ConversationsClassic/AppData/Model/OMEMO.swift @@ -69,10 +69,22 @@ extension OMEMOSession { return [] } } + + static func wipe(account: String) { + do { + _ = try Database.shared.dbQueue.write { db in + try OMEMOSession + .filter(Column("account") == account) + .deleteAll(db) + } + } catch { + logIt(.error, "Failed to wipe OMEMO session: \(error)") + } + } } // MARK: - Identity -struct OMEMOIdentity: Codable & Equatable, DatabaseValueConvertible { +struct OMEMOIdentity: DBStorable { static let databaseTableName = "omemo_identities" let account: String @@ -82,10 +94,28 @@ struct OMEMOIdentity: Codable & Equatable, DatabaseValueConvertible { let key: Data let own: Bool let status: Int + + var id: String { + "\(account)_\(name)_\(deviceId)" + } +} + +extension OMEMOIdentity { + static func wipe(account: String) { + do { + _ = try Database.shared.dbQueue.write { db in + try OMEMOIdentity + .filter(Column("account") == account) + .deleteAll(db) + } + } catch { + logIt(.error, "Failed to wipe OMEMO identity: \(error)") + } + } } // MARK: - PreKey -struct OMEMOPreKey: Codable & Equatable, DatabaseValueConvertible { +struct OMEMOPreKey: DBStorable { static let databaseTableName = "omemo_pre_keys" let account: String @@ -93,11 +123,39 @@ struct OMEMOPreKey: Codable & Equatable, DatabaseValueConvertible { let key: Data } +extension OMEMOPreKey { + static func wipe(account: String) { + do { + _ = try Database.shared.dbQueue.write { db in + try OMEMOPreKey + .filter(Column("account") == account) + .deleteAll(db) + } + } catch { + logIt(.error, "Failed to wipe OMEMO pre key: \(error)") + } + } +} + // MARK: - SignedPreKey -struct OMEMOSignedPreKey: Codable & Equatable, DatabaseValueConvertible { +struct OMEMOSignedPreKey: DBStorable { static let databaseTableName = "omemo_signed_pre_keys" let account: String let id: Int let key: Data } + +extension OMEMOSignedPreKey { + static func wipe(account: String) { + do { + _ = try Database.shared.dbQueue.write { db in + try OMEMOSignedPreKey + .filter(Column("account") == account) + .deleteAll(db) + } + } catch { + logIt(.error, "Failed to wipe OMEMO signed pre key: \(error)") + } + } +}