From e4e83cbb9e1a421630edd0d0c0a7b1b067e1a183 Mon Sep 17 00:00:00 2001 From: fmodf Date: Tue, 27 Aug 2024 15:00:39 +0200 Subject: [PATCH] wip --- .swiftlint.yml | 9 +- .../AppData/Client/Client+MartinOMEMO.swift | 174 ++++++++++++++++++ .../AppData/Client/Client.swift | 7 +- .../AppData/Services/AESGSMEngine.swift | 18 ++ .../Services/Database+Migrations.swift | 44 +++++ project.yml | 1 + 6 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift create mode 100644 ConversationsClassic/AppData/Services/AESGSMEngine.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 5eafdf8..a59820e 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -54,8 +54,12 @@ trailing_semicolon: severity: error type_name: - min_length: 3 - severity: warning + min_length: + warninig: 3 + error: 0 + max_length: + warninig: 40 + error: 80 identifier_name: min_length: 3 @@ -73,6 +77,7 @@ identifier_name: - tz - to - db + - _db # Disable rules from the default enabled set. disabled_rules: diff --git a/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift b/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift new file mode 100644 index 0000000..5341c9e --- /dev/null +++ b/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift @@ -0,0 +1,174 @@ +import Foundation +import GRDB +import Martin +import MartinOMEMO + +final class ClientMartinOMEMO { + let credentials: Credentials + + init(_ credentials: Credentials) { + self.credentials = credentials + } + + var signal: (SignalStorage, SignalContext) { + let signalStorage = SignalStorage(sessionStore: self, preKeyStore: self, signedPreKeyStore: self, identityKeyStore: self, senderKeyStore: self) + // swiftlint:disable:next force_unwrapping + let signalContext = SignalContext(withStorage: signalStorage)! + signalStorage.setup(withContext: signalContext) + return (signalStorage, signalContext) + } +} + +extension ClientMartinOMEMO: SignalSessionStoreProtocol, SignalPreKeyStoreProtocol, SignalSignedPreKeyStoreProtocol, SignalIdentityKeyStoreProtocol, SignalSenderKeyStoreProtocol { + func sessionRecord(forAddress address: MartinOMEMO.SignalAddress) -> Data? { + // static let omemoSessionRecordLoad = Query("SELECT key FROM omemo_sessions WHERE account = :account AND name = :name AND device_id = :deviceId") + + // do { + // let data = try Database.shared.dbQueue.read { db in + // + // try Row.fetchOne(db, sql: "SELECT key FROM omemo_sessions WHERE account = :account AND name = :name AND device_id = :deviceId", arguments: ["account": address.account, "name": address.name, "deviceId": address.deviceId]) + // } + // return data?["key"] + // } catch { + // logIt(.error, "Error fetching chats: \(error.localizedDescription)") + // return nil + // } + print(address) + return nil + } + + func allDevices(for _: String, activeAndTrusted: Bool) -> [Int32] { + print(activeAndTrusted, "allDevices") + return [] + } + + func storeSessionRecord(_ data: Data, forAddress: MartinOMEMO.SignalAddress) -> Bool { + print(data, forAddress) + return false + } + + func containsSessionRecord(forAddress: MartinOMEMO.SignalAddress) -> Bool { + print(forAddress) + return false + } + + func deleteSessionRecord(forAddress: MartinOMEMO.SignalAddress) -> Bool { + print(forAddress) + return false + } + + func deleteAllSessions(for _: String) -> Bool { + print("deleteAllSessions") + return false + } + + func currentPreKeyId() -> UInt32 { + 0 + } + + func loadPreKey(withId: UInt32) -> Data? { + print(withId) + return nil + } + + func storePreKey(_ data: Data, withId: UInt32) -> Bool { + print(data, withId) + return false + } + + func containsPreKey(withId: UInt32) -> Bool { + print(withId) + return false + } + + func deletePreKey(withId: UInt32) -> Bool { + print(withId) + return false + } + + func flushDeletedPreKeys() -> Bool { + false + } + + func countSignedPreKeys() -> Int { + 0 + } + + func loadSignedPreKey(withId: UInt32) -> Data? { + print(withId) + return nil + } + + func storeSignedPreKey(_ data: Data, withId: UInt32) -> Bool { + print(data, withId) + return false + } + + func containsSignedPreKey(withId: UInt32) -> Bool { + print(withId) + return false + } + + func deleteSignedPreKey(withId: UInt32) -> Bool { + print(withId) + return false + } + + func keyPair() -> (any MartinOMEMO.SignalIdentityKeyPairProtocol)? { + nil + } + + func localRegistrationId() -> UInt32 { + 0 + } + + func save(identity: MartinOMEMO.SignalAddress, key: (any MartinOMEMO.SignalIdentityKeyProtocol)?) -> Bool { + print(identity, key) + return false + } + + func isTrusted(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, publicKeyData: Data?) -> Bool { + print(identity, publicKeyData) + return false + } + + 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: String) -> [MartinOMEMO.Identity] { + print(forName) + return [] + } + + func identityFingerprint(forAddress address: MartinOMEMO.SignalAddress) -> String? { + print(address) + return nil + } + + func storeSenderKey(_ key: Data, address: MartinOMEMO.SignalAddress?, groupId: String?) -> Bool { + print(key, address, groupId) + return false + } + + func loadSenderKey(forAddress: MartinOMEMO.SignalAddress?, groupId: String?) -> Data? { + print(forAddress, groupId) + return nil + } +} diff --git a/ConversationsClassic/AppData/Client/Client.swift b/ConversationsClassic/AppData/Client/Client.swift index f8453c2..35f885e 100644 --- a/ConversationsClassic/AppData/Client/Client.swift +++ b/ConversationsClassic/AppData/Client/Client.swift @@ -2,6 +2,7 @@ import Combine import Foundation import GRDB import Martin +import MartinOMEMO enum ClientState: Equatable { enum ClientConnectionState { @@ -190,13 +191,17 @@ private extension Client { client.connectionConfiguration.userJid = .init(credentials.bareJid) client.connectionConfiguration.credentials = .password(password: credentials.pass) + // OMEMO + let omemoManager = ClientMartinOMEMO(credentials) + let (signalStorage, signalContext) = omemoManager.signal + client.modulesManager.register(OMEMOModule(aesGCMEngine: AESGSMEngine.shared, signalContext: signalContext, signalStorage: signalStorage)) + // group chats // client.modulesManager.register(MucModule(roomManager: manager)) // channels // client.modulesManager.register(MixModule(channelManager: manager)) - // add client to clients return client } } diff --git a/ConversationsClassic/AppData/Services/AESGSMEngine.swift b/ConversationsClassic/AppData/Services/AESGSMEngine.swift new file mode 100644 index 0000000..0c9b26a --- /dev/null +++ b/ConversationsClassic/AppData/Services/AESGSMEngine.swift @@ -0,0 +1,18 @@ +import CryptoKit +import Foundation +import MartinOMEMO + +final class AESGSMEngine: AES_GCM_Engine { + static let shared = AESGSMEngine() + + private init() {} + func encrypt(iv: Data, key: Data, message: Data, output: UnsafeMutablePointer?, tag: UnsafeMutablePointer?) -> Bool { + print(iv, key, message, output, tag) + return false + } + + func decrypt(iv: Data, key: Data, encoded: Data, auth tag: Data?, output: UnsafeMutablePointer?) -> Bool { + print(iv, key, encoded, tag, output) + return false + } +} diff --git a/ConversationsClassic/AppData/Services/Database+Migrations.swift b/ConversationsClassic/AppData/Services/Database+Migrations.swift index f1c3cf6..7f08b48 100644 --- a/ConversationsClassic/AppData/Services/Database+Migrations.swift +++ b/ConversationsClassic/AppData/Services/Database+Migrations.swift @@ -59,6 +59,50 @@ extension Database { } } + migrator.registerMigration("Add OMEMO tables") { db in + try db.create(table: "omemo_sessions", options: [.ifNotExists]) { table in + table.column("account", .text).notNull() + table.column("name", .text).notNull() + table.column("device_id", .integer).notNull() + table.column("key", .text).notNull() + table.primaryKey(["account", "name", "device_id"], onConflict: .replace) + } + + try db.create(table: "omemo_identities", options: [.ifNotExists]) { table in + table.column("account", .text).notNull() + table.column("name", .text).notNull() + table.column("device_id", .integer).notNull() + table.column("fingerprint", .text).notNull() + table.column("key", .blob).notNull() + table.column("own", .integer).notNull() + table.column("status", .integer).notNull() + table.primaryKey(["account", "name", "fingerprint"], onConflict: .ignore) + } + + try db.create(table: "omemo_pre_keys", options: [.ifNotExists]) { table in + table.column("account", .text).notNull() + table.column("id", .integer).notNull() + table.column("key", .blob).notNull() + table.primaryKey(["account", "id"], onConflict: .replace) + } + + try db.create(table: "omemo_signed_pre_keys", options: [.ifNotExists]) { table in + table.column("account", .text).notNull() + table.column("id", .integer).notNull() + table.column("key", .blob).notNull() + table.primaryKey(["account", "id"], onConflict: .replace) + } + + try db.alter(table: "chats") { table in + table.add(column: "encryption", .text) + } + + try db.alter(table: "chat_history") { table in + table.add(column: "encryption", .integer) + table.add(column: "fingerprint", .text) + } + } + // return migrator return migrator }() diff --git a/project.yml b/project.yml index 358e184..a920fc2 100644 --- a/project.yml +++ b/project.yml @@ -75,6 +75,7 @@ targets: # keychain-access-groups: imt.narayana.ConversationsClassic.ios dependencies: - sdk: Security.framework + - sdk: CryptoKit.framework # - framework: Lib/WebRTC.xcframework # - target: Engine - package: SwiftfulRouting