Marino Faggiana 1 year ago
parent
commit
657ba0d9f9

+ 1 - 1
Brand/Database.swift

@@ -26,4 +26,4 @@ import Foundation
 // Database Realm
 //
 let databaseName                    = "nextcloud.realm"
-let databaseSchemaVersion: UInt64   = 304
+let databaseSchemaVersion: UInt64   = 308

+ 160 - 14
iOSClient/Data/NCManageDatabase+E2EE.swift

@@ -25,6 +25,19 @@ import Foundation
 import RealmSwift
 import NextcloudKit
 
+class tableE2eEncryptionLock: Object {
+
+    @objc dynamic var account = ""
+    @objc dynamic var date = NSDate()
+    @objc dynamic var fileId = ""
+    @objc dynamic var serverUrl = ""
+    @objc dynamic var e2eToken = ""
+
+    override static func primaryKey() -> String {
+        return "fileId"
+    }
+}
+
 class tableE2eEncryption: Object {
 
     @objc dynamic var account = ""
@@ -47,18 +60,8 @@ class tableE2eEncryption: Object {
     }
 }
 
-class tableE2eEncryptionLock: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var date = NSDate()
-    @objc dynamic var fileId = ""
-    @objc dynamic var serverUrl = ""
-    @objc dynamic var e2eToken = ""
-
-    override static func primaryKey() -> String {
-        return "fileId"
-    }
-}
+// MARK: -
+// MARK: Table V1, V1.2
 
 class tableE2eMetadata: Object {
 
@@ -68,10 +71,38 @@ class tableE2eMetadata: Object {
     @Persisted var version: Double = 0
 }
 
+
+// MARK: -
+// MARK: Table V2
+
+class tableE2eMetadataV2: Object {
+
+    @Persisted(primaryKey: true) var accountServerUrl = ""
+    @Persisted var keyChecksums: String = ""
+    @Persisted var deleted: Bool = false
+    @Persisted var counter: Int = 0
+    @Persisted var folders: String = ""
+    @Persisted var version: String = "2.0"
+}
+
+class tableE2eUsersV2: Object {
+
+    @Persisted(primaryKey: true) var accountServerUrlUserId = ""
+    @Persisted var certificate = ""
+    @Persisted var encryptedFiledropKey: String?
+    @Persisted var encryptedMetadataKey: String?
+    @Persisted var decryptedFiledropKey: Data?
+    @Persisted var decryptedMetadataKey: Data?
+    @Persisted var filedropKey: String?
+    @Persisted var metadataKey: String?
+    @Persisted var serverUrl = ""
+    @Persisted var userId = ""
+}
+
 extension NCManageDatabase {
 
     // MARK: -
-    // MARK: Table e2e Encryption
+    // MARK: tableE2eEncryption
 
     @objc func addE2eEncryption(_ e2e: tableE2eEncryption) {
 
@@ -219,7 +250,7 @@ extension NCManageDatabase {
     }
 
     // MARK: -
-    // MARK: Table e2ee Metadata
+    // MARK: V1
 
     func getE2eMetadata(account: String, serverUrl: String) -> tableE2eMetadata? {
 
@@ -251,4 +282,119 @@ extension NCManageDatabase {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
     }
+
+    // MARK: -
+    // MARK: V2
+
+    func setE2EUsersV2(account: String,
+                       serverUrl: String,
+                       userId: String,
+                       certificate: String,
+                       encryptedFiledropKey: String?,
+                       encryptedMetadataKey: String?,
+                       decryptedFiledropKey: Data?,
+                       decryptedMetadataKey: Data?,
+                       filedropKey: String?,
+                       metadataKey: String?) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let addObject = tableE2eUsersV2()
+                addObject.accountServerUrlUserId = account + serverUrl + userId
+                addObject.certificate = certificate
+                addObject.encryptedFiledropKey = encryptedFiledropKey
+                addObject.encryptedMetadataKey = encryptedMetadataKey
+                addObject.decryptedFiledropKey = decryptedFiledropKey
+                addObject.decryptedMetadataKey = decryptedMetadataKey
+                addObject.filedropKey = filedropKey
+                addObject.metadataKey = metadataKey
+                addObject.serverUrl = serverUrl
+                addObject.userId = userId
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getE2EUsersV2(account: String, serverUrl: String, userId: String) -> tableE2eUsersV2? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableE2eUsersV2.self).filter("accountServerUrlUserId == %@", account + serverUrl + userId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func deleteE2EUsersV2(account: String, serverUrl: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let results = realm.objects(tableE2eEncryption.self).filter("account == %@ AND serverUrl == %@", account, serverUrl)
+                realm.delete(results)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getE2eMetadataV2(account: String, serverUrl: String) -> tableE2eMetadataV2? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableE2eMetadataV2.self).filter("accountServerUrl == %@", account + serverUrl).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func setE2eMetadataV2(account: String, serverUrl: String, keyChecksums: [String]?, deleted: Bool, counter: Int, folders: [String: String]?, version: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let addObject = tableE2eMetadataV2()
+                addObject.accountServerUrl = account + serverUrl
+                if let keyChecksums {
+                    addObject.keyChecksums = keyChecksums.joined(separator: ",")
+                }
+                addObject.deleted = deleted
+                addObject.counter = counter
+                if let folders {
+                    var arrayFolders: [String] = []
+                    for folder in folders {
+                        let item = folder.key + ":" + folder.value
+                        arrayFolders.append(item)
+                    }
+                    addObject.folders = arrayFolders.joined(separator: ",")
+                }
+                addObject.version = version
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func deleteE2eMetadataV2(account: String, serverUrl: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let results = realm.objects(tableE2eMetadataV2.self).filter("accountServerUrl == %@", account + serverUrl)
+                realm.delete(results)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
 }

+ 18 - 22
iOSClient/Networking/E2EE/NCEndToEndMetadata.swift

@@ -119,14 +119,6 @@ class NCEndToEndMetadata: NSObject {
         let version: String
     }
 
-    struct PlainUsers {
-        let userId: String
-        let certificate: String
-        let metadataKey: String
-        let decryptedMetadataKey: Data
-        let filedropKey: String
-    }
-
     // --------------------------------------------------------------------------------------------
     // MARK: Encode JSON Metadata Bridge
     // --------------------------------------------------------------------------------------------
@@ -298,7 +290,6 @@ class NCEndToEndMetadata: NSObject {
                 object.key = key
                 object.initializationVector = initializationVector
                 object.metadataKey = metadataKey
-                object.metadataVersion = metadataVersion
                 object.mimeType = mimetype
                 object.serverUrl = serverUrl
 
@@ -320,8 +311,6 @@ class NCEndToEndMetadata: NSObject {
 
         let decoder = JSONDecoder()
         let privateKey = CCUtility.getEndToEndPrivateKey(account)
-        var metadataVersion: Double = 0
-        var plainUsers: [PlainUsers] = []
 
         do {
             let json = try decoder.decode(E2eeV20.self, from: data)
@@ -329,9 +318,11 @@ class NCEndToEndMetadata: NSObject {
             let metadata = json.metadata
             let users = json.users
             let filedrop = json.filedrop
-            metadataVersion = Double(json.version) ?? 0
+            let version = json.version as String? ?? "2.0"
 
             // DATA
+            NCManageDatabase.shared.deleteE2eMetadataV2(account: account, serverUrl: serverUrl)
+            NCManageDatabase.shared.deleteE2EUsersV2(account: account, serverUrl: serverUrl)
             NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
 
             //
@@ -340,9 +331,10 @@ class NCEndToEndMetadata: NSObject {
 
             for user in users {
 
-                var metadataKey = ""
-                var filedropKey = ""
-                var decryptedMetadataKey = Data()
+                var decryptedMetadataKey: Data?
+                var decryptedFiledropKey: Data?
+                var metadataKey: String?
+                var filedropKey: String?
 
                 if let encryptedMetadataKey = user.encryptedMetadataKey {
                     let data = Data(base64Encoded: encryptedMetadataKey)
@@ -355,19 +347,20 @@ class NCEndToEndMetadata: NSObject {
                 if let encryptedFiledropKey = user.encryptedFiledropKey {
                     let data = Data(base64Encoded: encryptedFiledropKey)
                     if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: privateKey) {
+                        decryptedFiledropKey = decrypted
                         filedropKey = decrypted.base64EncodedString()
                     }
                 }
 
-                plainUsers.append(PlainUsers(userId: user.userId, certificate: user.certificate, metadataKey: metadataKey, decryptedMetadataKey: decryptedMetadataKey, filedropKey: filedropKey))
+                NCManageDatabase.shared.setE2EUsersV2(account: account, serverUrl: serverUrl, userId: user.userId, certificate: user.certificate, encryptedFiledropKey: user.encryptedFiledropKey, encryptedMetadataKey: user.encryptedMetadataKey, decryptedFiledropKey: decryptedFiledropKey, decryptedMetadataKey: decryptedMetadataKey, filedropKey: filedropKey, metadataKey: metadataKey)
             }
 
             //
             // metadata
             //
 
-            if let plainUser = plainUsers.first(where: { $0.userId == userId }) {
-                if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(metadata.ciphertext, key: plainUser.metadataKey, initializationVector: metadata.nonce, authenticationTag: metadata.authenticationTag) {
+            if let tableE2eUsersV2 = NCManageDatabase.shared.getE2EUsersV2(account: account, serverUrl: serverUrl, userId: userId), let metadataKey = tableE2eUsersV2.metadataKey {
+                if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(metadata.ciphertext, key: tableE2eUsersV2.metadataKey, initializationVector: metadata.nonce, authenticationTag: metadata.authenticationTag) {
                     if decrypted.isGzipped {
                         do {
                             let data = try decrypted.gunzipped()
@@ -377,15 +370,18 @@ class NCEndToEndMetadata: NSObject {
                             if let json = try JSONSerialization.jsonObject(with: data) as? [String: AnyObject] {
 
                                 let keyChecksums = json["keyChecksums"] as? [String]
-                                let deleted = json["deleted"]
+                                let deleted = json["deleted"] as? Bool ?? false
+                                let counter = json["counter"] as? Int ?? 0
 
                                 // TEST hash
                                 if let keyChecksums,
-                                   let hash = NCEndToEndEncryption.sharedManager().createSHA256(from: plainUser.decryptedMetadataKey),
+                                   let hash = NCEndToEndEncryption.sharedManager().createSHA256(from: tableE2eUsersV2.decryptedMetadataKey),
                                    !keyChecksums.contains(hash) {
                                     return NKError(errorCode: NCGlobal.shared.errorE2EEKeyChecksums, errorDescription: NSLocalizedString("_e3ee_keyChecksum_", comment: ""))
                                 }
 
+                                NCManageDatabase.shared.setE2eMetadataV2(account: account, serverUrl: serverUrl, keyChecksums: keyChecksums, deleted: deleted, counter: counter, folders: json["folders"] as? [String: String], version: version)
+
                                 if let files = json["files"] as? [String: Any] {
                                     for file in files {
                                         let uid = file.key
@@ -395,7 +391,7 @@ class NCEndToEndMetadata: NSObject {
                                                let mimetype = dic["mimetype"],
                                                let key = dic["key"],
                                                let filename = dic["filename"] {
-                                                addE2eEncryption(fileNameIdentifier: uid, filename: filename, authenticationTag: authenticationTag, key: key, initializationVector: nonce, metadataKey: plainUser.metadataKey, mimetype: mimetype)
+                                                addE2eEncryption(fileNameIdentifier: uid, filename: filename, authenticationTag: authenticationTag, key: key, initializationVector: nonce, metadataKey: metadataKey, mimetype: mimetype)
                                             }
                                         }
                                     }
@@ -403,7 +399,7 @@ class NCEndToEndMetadata: NSObject {
 
                                 if let folders = json["folders"] as? [String: String] {
                                     for folder in folders {
-                                        addE2eEncryption(fileNameIdentifier: folder.key, filename: folder.value, authenticationTag: metadata.authenticationTag, key: plainUser.metadataKey, initializationVector: metadata.nonce, metadataKey: plainUser.metadataKey, mimetype: "httpd/unix-directory")
+                                        addE2eEncryption(fileNameIdentifier: folder.key, filename: folder.value, authenticationTag: metadata.authenticationTag, key: metadataKey, initializationVector: metadata.nonce, metadataKey: metadataKey, mimetype: "httpd/unix-directory")
                                     }
                                 }
                             }