diff --git a/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift b/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift index 5e4dc22..40a4a97 100644 --- a/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift +++ b/ConversationsClassic/AppData/Client/Client+MartinOMEMO.swift @@ -134,7 +134,7 @@ extension ClientMartinOMEMO: SignalSessionStoreProtocol { } return true } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") + logIt(.error, "Error deleting session: \(error.localizedDescription)") return false } } @@ -149,7 +149,7 @@ extension ClientMartinOMEMO: SignalSessionStoreProtocol { } return true } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") + logIt(.error, "Error deleting all sessions: \(error.localizedDescription)") return false } } @@ -162,7 +162,7 @@ extension ClientMartinOMEMO: SignalSessionStoreProtocol { .deleteAll(db) } } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") + logIt(.error, "Error wiping sessions: \(error.localizedDescription)") } } } @@ -275,140 +275,46 @@ extension ClientMartinOMEMO: SignalIdentityKeyStoreProtocol { // MARK: - PreKey extension ClientMartinOMEMO: SignalPreKeyStoreProtocol { func currentPreKeyId() -> UInt32 { - do { - let data = try Database.shared.dbQueue.read { db in - try Row.fetchOne( - db, - sql: "SELECT max(id) FROM omemo_pre_keys WHERE account = :account", - arguments: ["account": credentials.bareJid] - ) - } - return data?["id"] ?? 0 - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - return 0 - } + let id = OMEMOPreKey.currentIdFor(account: credentials.bareJid) + return UInt32(id) } func loadPreKey(withId: UInt32) -> Data? { - do { - let data = try Database.shared.dbQueue.read { db in - try Row.fetchOne( - db, - sql: "SELECT key FROM omemo_pre_keys WHERE account = :account AND id = :id", - arguments: ["account": credentials.bareJid, "id": withId] - ) - } - return data?["key"] - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - return nil - } + OMEMOPreKey.keyFor(account: credentials.bareJid, id: withId) } func storePreKey(_ data: Data, withId: UInt32) -> Bool { do { - try Database.shared.dbQueue.write { db in - try db.execute( - sql: "INSERT INTO omemo_pre_keys (account, id, key) VALUES (:account, :id, :key)", - arguments: ["account": credentials.bareJid, "id": withId, "key": data] + _ = try Database.shared.dbQueue.write { db in + try OMEMOPreKey( + account: credentials.bareJid, + id: Int(withId), + key: data, + markForDeletion: false ) + .insert(db) } return true } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") + logIt(.error, "Error pre key store: \(error.localizedDescription)") return false } } func containsPreKey(withId: UInt32) -> Bool { - do { - let rec = try Database.shared.dbQueue.read { db in - try Row.fetchOne( - db, - sql: "SELECT key FROM omemo_pre_keys WHERE account = :account AND id = :id", - arguments: ["account": credentials.bareJid, "id": withId] - ) - } - return rec != nil - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - return false - } + OMEMOPreKey.contains(account: credentials.bareJid, id: withId) } func deletePreKey(withId: UInt32) -> Bool { - queue.async { - print("queueing prekey with id \(withId) for removal..") - self.preKeysMarkedForRemoval.append(withId) - } - return true + OMEMOPreKey.markForDeletion(account: credentials.bareJid, id: withId) } - // TODO: Check logic of this function carefully!!! func flushDeletedPreKeys() -> Bool { - false - // !queue.sync { () -> [UInt32] in - // defer { - // preKeysMarkedForRemoval.removeAll() - // } - // print("removing queued prekeys: \(preKeysMarkedForRemoval)") - // do { - // Database.shared.dbQueue.write { db in - // try db.execute( - // sql: "DETLETE FROM omemo_pre_keys WHERE account = :account AND id IN (:ids)", - // arguments: ["account": credentials.bareJid, "ids": preKeysMarkedForRemoval] - // ) - // } - // } catch { - // logIt(.error, "Error fetching chats: \(error.localizedDescription)") - // return [0] - // } - // - // // return preKeysMarkedForRemoval.filter { id in DBOMEMOStore.instance.deletePreKey(forAccount: context!.sessionObject.userBareJid!, withId: id) } - // }.isEmpty - // - // - // - // do { - // try Database.shared.dbQueue.write { db in - // try db.execute( - // sql: """ - // DELETE FROM omemo_pre_keys - // WHERE account = :account - // AND id IN ( - // SELECT id - // FROM omemo_pre_keys - // WHERE account = :account - // AND id NOT IN ( - // SELECT id - // FROM omemo_pre_keys - // WHERE account = :account - // ORDER BY id DESC - // LIMIT 100) - // ) - // """, - // arguments: ["account": credentials.bareJid] - // ) - // } - // return true - // } catch { - // logIt(.error, "Error fetching chats: \(error.localizedDescription)") - // return false - // } + OMEMOPreKey.deleteMarked(account: credentials.bareJid) } func preKeysWipe() { - do { - try Database.shared.dbQueue.write { db in - try db.execute( - sql: "DELETE FROM omemo_pre_keys WHERE account = :account", - arguments: ["account": credentials.bareJid] - ) - } - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - } + OMEMOPreKey.wipe(account: credentials.bareJid) } } @@ -425,7 +331,7 @@ extension ClientMartinOMEMO: SignalSignedPreKeyStoreProtocol { } return data?["count(1)"] ?? 0 } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") + logIt(.error, "Error signed pre keys counting: \(error.localizedDescription)") return 0 } } diff --git a/ConversationsClassic/AppData/Model/OMEMO.swift b/ConversationsClassic/AppData/Model/OMEMO.swift index 8a2e3c1..40ead87 100644 --- a/ConversationsClassic/AppData/Model/OMEMO.swift +++ b/ConversationsClassic/AppData/Model/OMEMO.swift @@ -178,6 +178,7 @@ struct OMEMOPreKey: DBStorable { let account: String let id: Int let key: Data + let markForDeletion: Bool } extension OMEMOPreKey { @@ -192,6 +193,76 @@ extension OMEMOPreKey { logIt(.error, "Failed to wipe OMEMO pre key: \(error)") } } + + static func currentIdFor(account: String) -> Int { + do { + return try Database.shared.dbQueue.read { db in + try OMEMOPreKey + .filter(Column("account") == account) + .order(Column("id").desc) + .fetchOne(db) + .map(\.id) + } ?? 0 + } catch { + return 0 + } + } + + static func keyFor(account: String, id: UInt32) -> Data? { + do { + return try Database.shared.dbQueue.read { db in + try OMEMOPreKey + .filter(Column("account") == account) + .filter(Column("id") == id) + .fetchOne(db) + }?.key + } catch { + return nil + } + } + + static func contains(account: String, id: UInt32) -> Bool { + do { + return try Database.shared.dbQueue.read { db in + try OMEMOPreKey + .filter(Column("account") == account) + .filter(Column("id") == id) + .fetchOne(db) != nil + } + } catch { + return false + } + } + + static func markForDeletion(account: String, id: UInt32) -> Bool { + do { + _ = try Database.shared.dbQueue.write { db in + try OMEMOPreKey + .filter(Column("account") == account) + .filter(Column("id") == id) + .updateAll(db, Column("markForDeletion").set(to: true)) + } + return true + } catch { + logIt(.error, "Failed to mark OMEMO pre key for deletion: \(error)") + return false + } + } + + static func deleteMarked(account: String) -> Bool { + do { + _ = try Database.shared.dbQueue.write { db in + try OMEMOPreKey + .filter(Column("account") == account) + .filter(Column("markForDeletion") == true) + .deleteAll(db) + } + return true + } catch { + logIt(.error, "Failed to delete marked OMEMO pre keys: \(error)") + return false + } + } } // MARK: - SignedPreKey diff --git a/ConversationsClassic/AppData/Services/Database+Migrations.swift b/ConversationsClassic/AppData/Services/Database+Migrations.swift index 88b84c5..455e9b1 100644 --- a/ConversationsClassic/AppData/Services/Database+Migrations.swift +++ b/ConversationsClassic/AppData/Services/Database+Migrations.swift @@ -83,6 +83,7 @@ extension Database { table.column("account", .text).notNull() table.column("id", .integer).notNull() table.column("key", .blob).notNull() + table.column("markForDeletion", .boolean).notNull().defaults(to: false) table.primaryKey(["account", "id"], onConflict: .replace) }