Procházet zdrojové kódy

Merge pull request #2571 from nextcloud/e2ee_V20

E2ee v20 Step - ONE
Marino Faggiana před 1 rokem
rodič
revize
f7ea63be80
33 změnil soubory, kde provedl 1606 přidání a 690 odebrání
  1. 1 1
      Brand/Database.swift
  2. 37 0
      Nextcloud.xcodeproj/project.pbxproj
  3. 13 0
      iOSClient/Data/NCManageDatabase+Directory.swift
  4. 246 69
      iOSClient/Data/NCManageDatabase+E2EE.swift
  5. 9 4
      iOSClient/Data/NCManageDatabase+Metadata.swift
  6. 6 1
      iOSClient/Data/NCManageDatabase.swift
  7. 1 1
      iOSClient/Extensions/UIAlertController+Extension.swift
  8. 11 21
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  9. 2 4
      iOSClient/Menu/AppDelegate+Menu.swift
  10. 7 12
      iOSClient/Menu/NCCollectionViewCommon+Menu.swift
  11. 11 1
      iOSClient/Menu/NCShare+Menu.swift
  12. 23 18
      iOSClient/NCGlobal.swift
  13. 10 8
      iOSClient/Networking/E2EE/NCEndToEndEncryption.h
  14. 141 69
      iOSClient/Networking/E2EE/NCEndToEndEncryption.m
  15. 21 317
      iOSClient/Networking/E2EE/NCEndToEndMetadata.swift
  16. 469 0
      iOSClient/Networking/E2EE/NCEndToEndMetadataV1.swift
  17. 412 0
      iOSClient/Networking/E2EE/NCEndToEndMetadataV20.swift
  18. 36 11
      iOSClient/Networking/E2EE/NCNetworkingE2EE.swift
  19. 26 31
      iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift
  20. 8 21
      iOSClient/Networking/E2EE/NCNetworkingE2EEDelete.swift
  21. 10 17
      iOSClient/Networking/E2EE/NCNetworkingE2EERename.swift
  22. 33 42
      iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift
  23. 3 3
      iOSClient/Networking/NCNetworking.swift
  24. 10 2
      iOSClient/Settings/NCEndToEndInitialize.swift
  25. 1 1
      iOSClient/Settings/NCSettings.m
  26. 14 4
      iOSClient/Share/Advanced/NCShareAdvancePermission.swift
  27. 1 1
      iOSClient/Share/Advanced/NCShareCells.swift
  28. 1 1
      iOSClient/Share/NCShare+Helper.swift
  29. 5 5
      iOSClient/Share/NCShare.swift
  30. 1 1
      iOSClient/Share/NCSharePaging.swift
  31. 1 19
      iOSClient/Supporting Files/en.lproj/Localizable.strings
  32. 1 1
      iOSClient/Utility/CCUtility.m
  33. 35 4
      iOSClient/Utility/NCUtility.swift

+ 1 - 1
Brand/Database.swift

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

+ 37 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -203,6 +203,10 @@
 		F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
 		F72685E727C78E490019EF5E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F72685E927C78E490019EF5E /* InfoPlist.strings */; };
 		F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */; };
+		F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */; };
+		F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */; };
+		F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */; };
+		F72944F62A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */; };
 		F72A17D828B221E300F3F159 /* DashboardWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */; };
 		F72A47EC2487B06B005AD489 /* NCOperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */; };
 		F72AD70D28C24B93006CB92D /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72AD70C28C24B93006CB92D /* NextcloudKit */; };
@@ -651,6 +655,8 @@
 		F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */; };
 		F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F10F27ECDC4A008676F9 /* UIDevice+Extension.swift */; };
 		F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */; };
+		F7F623B52A5EF4D30022D3D4 /* Gzip in Frameworks */ = {isa = PBXBuildFile; productRef = F7F623B42A5EF4D30022D3D4 /* Gzip */; };
+		F7F623B72A5EFA0C0022D3D4 /* Gzip in Frameworks */ = {isa = PBXBuildFile; productRef = F7F623B62A5EFA0C0022D3D4 /* Gzip */; };
 		F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */; };
@@ -951,6 +957,8 @@
 		F7267A81225DFCE100D6DB7D /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = "<group>"; };
 		F72685E827C78E490019EF5E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCEndToEndInitialize.swift; sourceTree = "<group>"; };
+		F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV20.swift; sourceTree = "<group>"; };
+		F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV1.swift; sourceTree = "<group>"; };
 		F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardWidgetView.swift; sourceTree = "<group>"; };
 		F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCOperationQueue.swift; sourceTree = "<group>"; };
 		F72CD63925C19EBF00F46F9A /* NCAutoUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAutoUpload.swift; sourceTree = "<group>"; };
@@ -1424,6 +1432,7 @@
 				F73ADD2126554F8E0069EA0D /* SwiftEntryKit in Frameworks */,
 				F7EBCDCF277B81FF00A4EF67 /* UICKeyChainStore in Frameworks */,
 				F70821D829E59E6D001CA2D7 /* TagListView in Frameworks */,
+				F7F623B72A5EFA0C0022D3D4 /* Gzip in Frameworks */,
 				F72D7EB7263B1207000B3DFC /* MarkdownKit in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -1477,6 +1486,7 @@
 				F70B86752642CE3B00ED5349 /* FirebaseCrashlytics in Frameworks */,
 				F7A1050E29E587AF00FFD92B /* TagListView in Frameworks */,
 				F76DA969277B77EA0082465B /* DropDown in Frameworks */,
+				F7F623B52A5EF4D30022D3D4 /* Gzip in Frameworks */,
 				F75EAED826D2552E00F4320E /* MarqueeLabel in Frameworks */,
 				F710FC7A277B7D0000AA9FBF /* Realm in Frameworks */,
 				F72DA9B425F53E4E00B87DB1 /* SwiftRichString in Frameworks */,
@@ -2260,6 +2270,8 @@
 				F70CAE381F8CF31A008125FD /* NCEndToEndEncryption.h */,
 				F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */,
 				F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */,
+				F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */,
+				F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */,
 				F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */,
 				F7C30DF9291BCF790017149B /* NCNetworkingE2EECreateFolder.swift */,
 				F7C30DFC291BD0B80017149B /* NCNetworkingE2EEDelete.swift */,
@@ -2762,6 +2774,7 @@
 				F72CD01127A7E92400E59476 /* JGProgressHUD */,
 				F72AD70E28C24BA1006CB92D /* NextcloudKit */,
 				F70821D729E59E6D001CA2D7 /* TagListView */,
+				F7F623B62A5EFA0C0022D3D4 /* Gzip */,
 			);
 			productName = "Share Ext";
 			productReference = F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */;
@@ -2862,6 +2875,7 @@
 				F787AC08298BCB4A0001BB00 /* SVGKitSwift */,
 				F7A1050D29E587AF00FFD92B /* TagListView */,
 				F31F69632A2F929600162F76 /* PreviewSnapshots */,
+				F7F623B42A5EF4D30022D3D4 /* Gzip */,
 			);
 			productName = "Crypto Cloud";
 			productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */;
@@ -3036,6 +3050,7 @@
 				F31F694B2A2F6EFA00162F76 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
 				F31F69622A2F929600162F76 /* XCRemoteSwiftPackageReference "swiftui-preview-snapshots" */,
 				F31F69672A2F92F000162F76 /* XCRemoteSwiftPackageReference "SnapshotTestingHEIC" */,
+				F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */,
 			);
 			productRefGroup = F7F67B9F1A24D27800EE80DA;
 			projectDirPath = "";
@@ -3446,6 +3461,7 @@
 				F702F2D025EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F343A4BE2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
 				F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */,
+				F72944F62A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */,
 				F7EDE4D1262D7B8400414FE6 /* NCDataSource.swift in Sources */,
 				F71459D21D12E3B700CAFEEC /* CCUtility.m in Sources */,
 				F75A9EE723796C6F0044CFCE /* NCNetworking.swift in Sources */,
@@ -3470,6 +3486,7 @@
 				AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */,
 				F7148041262EBE4000693E51 /* NCShareExtension.swift in Sources */,
 				F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
+				F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
 				F7BAADCC1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -3632,6 +3649,7 @@
 				F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F758B460212C56A400515F55 /* NCScan.swift in Sources */,
 				F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */,
+				F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */,
 				F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */,
 				F765E9CD295C585800A09ED8 /* NCUploadScanDocument.swift in Sources */,
 				F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */,
@@ -3686,6 +3704,7 @@
 				F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */,
 				F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */,
 				F7501C332212E57500FB1415 /* NCMedia.swift in Sources */,
+				F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
 				F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */,
 				F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */,
@@ -5045,6 +5064,14 @@
 				minimumVersion = 10.1.1;
 			};
 		};
+		F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/1024jp/GzipSwift";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 6.0.0;
+			};
+		};
 /* End XCRemoteSwiftPackageReference section */
 
 /* Begin XCSwiftPackageProductDependency section */
@@ -5398,6 +5425,16 @@
 			package = F7ED547A25EEA65400956C55 /* XCRemoteSwiftPackageReference "QRCodeReader" */;
 			productName = QRCodeReader;
 		};
+		F7F623B42A5EF4D30022D3D4 /* Gzip */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */;
+			productName = Gzip;
+		};
+		F7F623B62A5EFA0C0022D3D4 /* Gzip */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */;
+			productName = Gzip;
+		};
 /* End XCSwiftPackageProductDependency section */
 	};
 	rootObject = F7F67BA01A24D27800EE80DA /* Project object */;

+ 13 - 0
iOSClient/Data/NCManageDatabase+Directory.swift

@@ -138,6 +138,19 @@ extension NCManageDatabase {
         return nil
     }
 
+    func getTableDirectory(account: String, serverUrl: String) -> tableDirectory? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
     func getTableDirectory(ocId: String) -> tableDirectory? {
 
         do {

+ 246 - 69
iOSClient/Data/NCManageDatabase+E2EE.swift

@@ -25,41 +25,45 @@ import Foundation
 import RealmSwift
 import NextcloudKit
 
-class tableE2eEncryption: Object {
+class tableE2eEncryptionLock: Object {
 
-    @objc dynamic var account = ""
-    @objc dynamic var authenticationTag: String = ""
-    @objc dynamic var blob = "files"
-    @objc dynamic var fileName = ""
-    @objc dynamic var fileNameIdentifier = ""
-    @objc dynamic var fileNamePath = ""
-    @objc dynamic var key = ""
-    @objc dynamic var initializationVector = ""
-    @objc dynamic var metadataKey = ""
-    @objc dynamic var metadataKeyFiledrop = ""
-    @objc dynamic var metadataKeyIndex: Int = 0
-    @objc dynamic var metadataVersion: Double = 0
-    @objc dynamic var mimeType = ""
-    @objc dynamic var serverUrl = ""
-
-    override static func primaryKey() -> String {
-        return "fileNamePath"
-    }
+    @Persisted(primaryKey: true) var fileId = ""
+    @Persisted var account = ""
+    @Persisted var date = Date()
+    @Persisted var serverUrl = ""
+    @Persisted var e2eToken = ""
 }
 
-class tableE2eEncryptionLock: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var date = NSDate()
-    @objc dynamic var fileId = ""
-    @objc dynamic var serverUrl = ""
-    @objc dynamic var e2eToken = ""
+class tableE2eEncryption: Object {
 
-    override static func primaryKey() -> String {
-        return "fileId"
-    }
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @Persisted var authenticationTag: String = ""
+    @Persisted var blob = "files"
+    @Persisted var fileName = ""
+    @Persisted var fileNameIdentifier = ""
+    @Persisted var key = ""
+    @Persisted var initializationVector = ""
+    @Persisted var metadataKey = ""
+    @Persisted var metadataKeyFiledrop = ""
+    @Persisted var metadataKeyIndex: Int = 0
+    @Persisted var metadataVersion: Double = 0
+    @Persisted var mimeType = ""
+    @Persisted var ocIdServerUrl: String = ""
+    @Persisted var serverUrl = ""
+
+    convenience init(account: String, ocIdServerUrl: String, fileNameIdentifier: String) {
+        self.init()
+        self.primaryKey = account + ocIdServerUrl + fileNameIdentifier
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.fileNameIdentifier = fileNameIdentifier
+     }
 }
 
+// MARK: -
+// MARK: Table V1, V1.2
+
 class tableE2eMetadata: Object {
 
     @Persisted(primaryKey: true) var serverUrl = ""
@@ -68,24 +72,71 @@ class tableE2eMetadata: Object {
     @Persisted var version: Double = 0
 }
 
+// MARK: -
+// MARK: Table V2
+
+class tableE2eMetadataV2: Object {
+
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @Persisted var counter: Int = 0
+    @Persisted var deleted: Bool = false
+    @Persisted var folders = Map<String, String>()
+    @Persisted var keyChecksums = List<String>()
+    @Persisted var ocIdServerUrl: String = ""
+    @Persisted var serverUrl: String = ""
+    @Persisted var version: String = NCGlobal.shared.e2eeVersionV20
+
+    convenience init(account: String, ocIdServerUrl: String) {
+        self.init()
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.primaryKey = account + ocIdServerUrl
+     }
+}
+
+class tableE2eUsersV2: Object {
+
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @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 ocIdServerUrl: String = ""
+    @Persisted var serverUrl: String = ""
+    @Persisted var userId = ""
+
+    convenience init(account: String, ocIdServerUrl: String, userId: String) {
+        self.init()
+        self.primaryKey = account + ocIdServerUrl + userId
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.userId = userId
+     }
+}
+
 extension NCManageDatabase {
 
     // MARK: -
-    // MARK: Table e2e Encryption
+    // MARK: tableE2eEncryption
 
-    @objc func addE2eEncryption(_ e2e: tableE2eEncryption) {
+    func addE2eEncryption(_ object: tableE2eEncryption) {
 
         do {
             let realm = try Realm()
             try realm.write {
-                realm.add(e2e, update: .all)
+                realm.add(object, update: .all)
             }
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
     }
 
-    @objc func deleteE2eEncryption(predicate: NSPredicate) {
+    func deleteE2eEncryption(predicate: NSPredicate) {
 
         do {
             let realm = try Realm()
@@ -98,7 +149,7 @@ extension NCManageDatabase {
         }
     }
 
-    @objc func getE2eEncryption(predicate: NSPredicate) -> tableE2eEncryption? {
+    func getE2eEncryption(predicate: NSPredicate) -> tableE2eEncryption? {
 
         do {
             let realm = try Realm()
@@ -112,40 +163,30 @@ extension NCManageDatabase {
         return nil
     }
 
-    @objc func getE2eEncryptions(predicate: NSPredicate) -> [tableE2eEncryption]? {
-
-        guard self.getActiveAccount() != nil else { return nil }
+    func getE2eEncryptions(predicate: NSPredicate) -> [tableE2eEncryption] {
 
         do {
             let realm = try Realm()
             realm.refresh()
             let results: Results<tableE2eEncryption>
             results = realm.objects(tableE2eEncryption.self).filter(predicate)
-            if results.isEmpty {
-                return nil
-            } else {
-                return Array(results.map { tableE2eEncryption.init(value: $0) })
-            }
+            return Array(results.map { tableE2eEncryption.init(value: $0) })
         } catch let error as NSError {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
 
-        return nil
+        return []
     }
 
-    @objc func renameFileE2eEncryption(serverUrl: String, fileNameIdentifier: String, newFileName: String, newFileNamePath: String) {
-
-        guard let activeAccount = self.getActiveAccount() else { return }
+    func renameFileE2eEncryption(account: String, serverUrl: String, fileNameIdentifier: String, newFileName: String, newFileNamePath: String) {
 
         do {
             let realm = try Realm()
+            realm.refresh()
             try realm.write {
-                guard let result = realm.objects(tableE2eEncryption.self).filter("account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", activeAccount.account, serverUrl, fileNameIdentifier).first else { return }
-                let object = tableE2eEncryption.init(value: result)
-                realm.delete(result)
-                object.fileName = newFileName
-                object.fileNamePath = newFileNamePath
-                realm.add(object)
+                guard let result = realm.objects(tableE2eEncryption.self).filter("account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", account, serverUrl, fileNameIdentifier).first else { return }
+                result.fileName = newFileName
+                realm.add(result, update: .all)
             }
         } catch let error as NSError {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
@@ -155,7 +196,7 @@ extension NCManageDatabase {
     // MARK: -
     // MARK: Table e2e Encryption Lock
 
-    @objc func getE2ETokenLock(account: String, serverUrl: String) -> tableE2eEncryptionLock? {
+    func getE2ETokenLock(account: String, serverUrl: String) -> tableE2eEncryptionLock? {
 
         do {
             let realm = try Realm()
@@ -169,7 +210,7 @@ extension NCManageDatabase {
         return nil
     }
 
-    @objc func getE2EAllTokenLock(account: String) -> [tableE2eEncryptionLock] {
+    func getE2EAllTokenLock(account: String) -> [tableE2eEncryptionLock] {
 
         do {
             let realm = try Realm()
@@ -187,24 +228,24 @@ extension NCManageDatabase {
         return []
     }
 
-    @objc func setE2ETokenLock(account: String, serverUrl: String, fileId: String, e2eToken: String) {
+    func setE2ETokenLock(account: String, serverUrl: String, fileId: String, e2eToken: String) {
 
         do {
             let realm = try Realm()
             try realm.write {
-                let addObject = tableE2eEncryptionLock()
-                addObject.account = account
-                addObject.fileId = fileId
-                addObject.serverUrl = serverUrl
-                addObject.e2eToken = e2eToken
-                realm.add(addObject, update: .all)
+                let object = tableE2eEncryptionLock()
+                object.account = account
+                object.fileId = fileId
+                object.serverUrl = serverUrl
+                object.e2eToken = e2eToken
+                realm.add(object, update: .all)
             }
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
     }
 
-    @objc func deleteE2ETokenLock(account: String, serverUrl: String) {
+    func deleteE2ETokenLock(account: String, serverUrl: String) {
 
         do {
             let realm = try Realm()
@@ -219,7 +260,7 @@ extension NCManageDatabase {
     }
 
     // MARK: -
-    // MARK: Table e2ee Metadata
+    // MARK: V1
 
     func getE2eMetadata(account: String, serverUrl: String) -> tableE2eMetadata? {
 
@@ -240,12 +281,148 @@ extension NCManageDatabase {
         do {
             let realm = try Realm()
             try realm.write {
-                let addObject = tableE2eMetadata()
-                addObject.account = account
-                addObject.metadataKey = metadataKey
-                addObject.serverUrl = serverUrl
-                addObject.version = version
-                realm.add(addObject, update: .all)
+                let object = tableE2eMetadata()
+                object.account = account
+                object.metadataKey = metadataKey
+                object.serverUrl = serverUrl
+                object.version = version
+                realm.add(object, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    // MARK: -
+    // MARK: V2
+
+    func addE2EUsersV2(account: String,
+                       serverUrl: String,
+                       ocIdServerUrl: 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 object = tableE2eUsersV2.init(account: account, ocIdServerUrl: ocIdServerUrl, userId: userId)
+                object.certificate = certificate
+                object.encryptedFiledropKey = encryptedFiledropKey
+                object.encryptedMetadataKey = encryptedMetadataKey
+                object.decryptedFiledropKey = decryptedFiledropKey
+                object.decryptedMetadataKey = decryptedMetadataKey
+                object.filedropKey = filedropKey
+                object.metadataKey = metadataKey
+                object.serverUrl = serverUrl
+                realm.add(object, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func deleteE2EUsersV2(account: String, ocIdServerUrl: String, userId: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                if let result = realm.objects(tableE2eUsersV2.self).filter("account == %@ AND ocIdServerUrl == %@ AND userId == %@", account, ocIdServerUrl, userId).first {
+                    realm.delete(result)
+                }
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getE2EUsersV2(account: String, ocIdServerUrl: String) -> Results<tableE2eUsersV2>? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableE2eUsersV2.self).filter("account == %@ AND ocIdServerUrl == %@", account, ocIdServerUrl)
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getE2EUsersV2(account: String, ocIdServerUrl: String, userId: String) -> tableE2eUsersV2? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableE2eUsersV2.self).filter("account == %@ && ocIdServerUrl == %@ AND userId == %@", account, ocIdServerUrl, userId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getE2eMetadataV2(account: String, ocIdServerUrl: String) -> tableE2eMetadataV2? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableE2eMetadataV2.self).filter("account == %@ && ocIdServerUrl == %@", account, ocIdServerUrl).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func incrementCounterE2eMetadataV2(account: String, serverUrl: String, ocIdServerUrl: String, version: String) -> tableE2eMetadataV2? {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                if let result = realm.objects(tableE2eMetadataV2.self).filter("account == %@ && ocIdServerUrl == %@", account, ocIdServerUrl).first {
+                    result.counter += 1
+                } else {
+                    let object = tableE2eMetadataV2.init(account: account, ocIdServerUrl: ocIdServerUrl)
+                    object.serverUrl = serverUrl
+                    object.counter = 1
+                    object.version = version
+                    realm.add(object, update: .all)
+                }
+            }
+            return realm.objects(tableE2eMetadataV2.self).filter("account == %@ && ocIdServerUrl == %@", account, ocIdServerUrl).first
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+
+        return nil
+    }
+
+    func addE2eMetadataV2(account: String, serverUrl: String, ocIdServerUrl: String, keyChecksums: [String]?, deleted: Bool, counter: Int, folders: [String: String]?, version: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let object = tableE2eMetadataV2.init(account: account, ocIdServerUrl: ocIdServerUrl)
+                if let keyChecksums {
+                    object.keyChecksums.append(objectsIn: keyChecksums)
+                }
+                object.deleted = deleted
+                object.counter = counter
+                let foldersDictionary = object.folders
+                if let folders {
+                    for folder in folders {
+                        foldersDictionary[folder.key] = folder.value
+                    }
+                }
+                object.serverUrl = serverUrl
+                object.version = version
+                realm.add(object, update: .all)
             }
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")

+ 9 - 4
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -232,7 +232,11 @@ extension tableMetadata {
     }
 
     @objc var isDirectoryE2EE: Bool {
-        NCUtility.shared.isDirectoryE2EE(serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId)
+        NCUtility.shared.isDirectoryE2EE(account: account, urlBase: urlBase, userId: userId, serverUrl: serverUrl)
+    }
+
+    var isDirectoryE2EETop: Bool {
+        NCUtility.shared.isDirectoryE2EETop(account: account, serverUrl: serverUrl)
     }
 
     /// Returns false if the user is lokced out of the file. I.e. The file is locked but by somone else
@@ -240,12 +244,13 @@ extension tableMetadata {
         return !lock || (lockOwner == user && lockOwnerType == 0)
     }
 
-    // Return if is sharable (temp)
-    // TODO: modifify for E2EE 2.0
+    // Return if is sharable
     func isSharable() -> Bool {
         guard NCGlobal.shared.capabilityFileSharingApiEnabled else { return false }
 
-        if !e2eEncrypted && !isDirectoryE2EE {
+        if NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20, isDirectoryE2EE {
+            return !isDirectoryE2EETop
+        } else if !e2eEncrypted && !isDirectoryE2EE {
             return true
         } else if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion26 && directory {
             // E2EE DIRECTORY SECURE FILE DROP (SHARE AVAILABLE)

+ 6 - 1
iOSClient/Data/NCManageDatabase.swift

@@ -98,9 +98,12 @@ class NCManageDatabase: NSObject {
                         migration.deleteData(forType: tableVideo.className())
                     }
 
-                    if oldSchemaVersion < 304 {
+                    if oldSchemaVersion < 306 {
                         migration.deleteData(forType: tableChunk.className())
                         migration.deleteData(forType: tableMetadata.className())
+                        migration.deleteData(forType: tableE2eEncryptionLock.className())
+                        migration.deleteData(forType: tableE2eEncryption.className())
+                        migration.deleteData(forType: tableE2eMetadata.className())
                     }
 
                 }, shouldCompactOnLaunch: { totalBytes, usedBytes in
@@ -202,6 +205,8 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableE2eEncryption.self, account: account)
         self.clearTable(tableE2eEncryptionLock.self, account: account)
         self.clearTable(tableE2eMetadata.self, account: account)
+        self.clearTable(tableE2eMetadataV2.self, account: account)
+        self.clearTable(tableE2eUsersV2.self, account: account)
         self.clearTable(tableExternalSites.self, account: account)
         self.clearTable(tableGPS.self, account: nil)
         self.clearTable(TableGroupfolders.self, account: account)

+ 1 - 1
iOSClient/Extensions/UIAlertController+Extension.swift

@@ -38,7 +38,7 @@ extension UIAlertController {
             guard let fileNameFolder = alertController.textFields?.first?.text else { return }
             if markE2ee {
                 Task {
-                    let error = await NCNetworkingE2EECreateFolder.shared.createFolderAndMarkE2EE(fileName: fileNameFolder, serverUrl: serverUrl, account: urlBase.account)
+                    let error = await NCNetworkingE2EECreateFolder.shared.createFolderAndMarkE2EE(fileName: fileNameFolder, serverUrl: serverUrl, account: urlBase.account, userId: urlBase.userId, createFolder: true)
                     if error != .success {
                         NCContentPresenter.shared.showError(error: error)
                     }

+ 11 - 21
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -38,7 +38,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     internal var emptyDataSet: NCEmptyDataSet?
     internal var backgroundImageView = UIImageView()
     internal var serverUrl: String = ""
-    internal var isDirectoryE2EE = false
     internal var isEditMode = false
     internal var selectOcId: [String] = []
     internal var selectIndexPath: [IndexPath] = []
@@ -53,7 +52,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
     private var autoUploadFileName = ""
     private var autoUploadDirectory = ""
-
     internal var groupByField = "name"
     internal var providers: [NKSearchProvider]?
     internal var searchResults: [NKSearchResult]?
@@ -953,8 +951,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     @objc func reloadDataSource(isForced: Bool = true) {
         guard !appDelegate.account.isEmpty else { return }
 
-        // E2EE
-        isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(serverUrl: serverUrl, userBase: appDelegate)
         // get auto upload folder
         autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName()
         autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account)
@@ -1073,16 +1069,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                     self.metadataFolder = metadataFolder
                     // E2EE
                     if let metadataFolder = metadataFolder, metadataFolder.e2eEncrypted, CCUtility.isEnd(toEndEnabled: self.appDelegate.account) {
-                        NextcloudKit.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: nil) { account, e2eMetadata, _, data, error in
+                        NextcloudKit.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: nil) { account, e2eMetadata, signature, data, error in
                             if error == .success, let e2eMetadata = e2eMetadata {
-                                let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: self.serverUrl, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, ownerId: metadataFolder.ownerId)
-                                if result.error == .success {
+                                let error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: signature, serverUrl: self.serverUrl, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, ownerId: metadataFolder.ownerId)
+                                if error == .success {
                                     self.reloadDataSource()
                                 } else {
-                                    NCContentPresenter.shared.showError(error: result.error)
+                                    NCContentPresenter.shared.showError(error: error)
                                 }
                             } else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
-                                NCContentPresenter.shared.showError(error: NKError(errorCode: NCGlobal.shared.errorDecodeMetadata, errorDescription: "_e2e_error_decode_metadata_"))
+                                NCContentPresenter.shared.showError(error: NKError(errorCode: NCGlobal.shared.errorE2EEKeyDecodeMetadata, errorDescription: "_e2e_error_"))
                             }
                             completion(tableDirectory, metadatas, metadatasUpdate, metadatasDelete, error)
                         }
@@ -1449,6 +1445,12 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
         guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return cell }
 
+        defer {
+            if appDelegate.disableSharesView || !metadata.isSharable() {
+                cell.hideButtonShare(true)
+            }
+        }
+
         var isShare = false
         var isMounted = false
         var a11yValues: [String] = []
@@ -1621,11 +1623,6 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             }
         }
 
-        // Disable Share Button
-        if appDelegate.disableSharesView {
-            cell.hideButtonShare(true)
-        }
-
         // Separator
         if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 || isSearchingMode {
             cell.cellSeparatorView?.isHidden = true
@@ -1667,13 +1664,6 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             cell.hideButtonMore(true)
         }
 
-        // ** IMPORT MUST BE AT THE END **
-        //
-
-        if !metadata.isSharable() {
-            cell.hideButtonShare(true)
-        }
-        
         return cell
     }
 

+ 2 - 4
iOSClient/Menu/AppDelegate+Menu.swift

@@ -37,8 +37,6 @@ extension AppDelegate {
         let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: appDelegate.account)
         let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(serverUrl: appDelegate.activeServerUrl, userBase: appDelegate)
         let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, appDelegate.activeServerUrl))
-        let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
-
 
         actions.append(
             NCMenuAction(
@@ -130,8 +128,8 @@ extension AppDelegate {
         )
 
         // Folder encrypted (ONLY ROOT)
-        if serverUrlHome == appDelegate.activeServerUrl && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
-        //if !isDirectoryE2EE && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
+        // if NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) == appDelegate.activeServerUrl && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
+        if !isDirectoryE2EE && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
             actions.append(
                 NCMenuAction(title: NSLocalizedString("_create_folder_e2ee_", comment: ""),
                              icon: UIImage(named: "folderEncrypted")!.image(color: NCBrandColor.shared.brandElement, size: 50),

+ 7 - 12
iOSClient/Menu/NCCollectionViewCommon+Menu.swift

@@ -145,24 +145,19 @@ extension NCCollectionViewCommon {
         }
 
         //
-        // SET FOLDER E2EE (ONLY ROOT)
+        // SET FOLDER E2EE -- IF > (ONLY ROOT) metadata.serverUrl == serverUrlHome,
         //
-        if metadata.serverUrl == serverUrlHome, metadata.isDirectoySettableE2EE {
+        if metadata.isDirectoySettableE2EE {
             actions.append(
                 NCMenuAction(
                     title: NSLocalizedString("_e2e_set_folder_encrypted_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "lock"),
                     order: 30,
                     action: { _ in
-                        NextcloudKit.shared.markE2EEFolder(fileId: metadata.fileId, delete: false) { account, error in
-                            if error == .success {
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl))
-                                NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: true, richWorkspace: nil, account: metadata.account)
-                                NCManageDatabase.shared.setMetadataEncrypted(ocId: metadata.ocId, encrypted: true)
-
-                                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl])
-                            } else {
-                                NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_mark_folder_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error)
+                        Task {
+                            let error = await NCNetworkingE2EECreateFolder.shared.createFolderAndMarkE2EE(fileName: metadata.fileName, serverUrl: metadata.serverUrl, account: metadata.account, userId: metadata.userId, createFolder: false)
+                            if error != .success {
+                                NCContentPresenter.shared.showError(error: error)
                             }
                         }
                     }
@@ -188,7 +183,7 @@ extension NCCollectionViewCommon {
 
                                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl])
                             } else {
-                                NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_delete_mark_folder_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error)
+                                NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error)
                             }
                         }
                     }

+ 11 - 1
iOSClient/Menu/NCShare+Menu.swift

@@ -62,7 +62,17 @@ extension NCShare {
                 title: NSLocalizedString("_share_unshare_", comment: ""),
                 icon: NCUtility.shared.loadImage(named: "trash"),
                 action: { _ in
-                    self.networking?.unShare(idShare: share.idShare)
+                    Task {
+                        if let metadata = self.metadata, metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
+                            let serverUrl = metadata.serverUrl + "/" + metadata.fileName
+                            let error = await NCNetworkingE2EE.shared.uploadMetadata(account: metadata.account, serverUrl: serverUrl, userId: metadata.userId, addUserId: nil, removeUserId: share.shareWith)
+                            if error != .success {
+                                NCContentPresenter.shared.showError(error: error)
+                                return
+                            }
+                        }
+                        self.networking?.unShare(idShare: share.idShare)
+                    }
                 }
             )
         )

+ 23 - 18
iOSClient/NCGlobal.swift

@@ -61,14 +61,6 @@ class NCGlobal: NSObject {
         return result.reduce(0, { $0 + $1 }) % maximum
     }
 
-    // Struct for Progress
-    //
-    struct progressType {
-        var progress: Float
-        var totalBytes: Int64
-        var totalBytesExpected: Int64
-    }
-
     // Directory on Group
     //
     @objc let directoryProviderStorage              = "File Provider Storage"
@@ -129,7 +121,10 @@ class NCGlobal: NSObject {
     // E2EE
     //
     let e2eePassphraseTest                          = "more over television factory tendency independence international intellectual impress interest sentence pony"
-    @objc let e2eeReadVersions                      = ["1.1", "1.2"]
+    @objc let e2eeVersions                          = ["1.1", "1.2", "2.0"]
+    let e2eeVersionV11                              = "1.1"
+    let e2eeVersionV12                              = "1.2"
+    let e2eeVersionV20                              = "2.0"
 
     // CHUNK
     let chunkSizeMBCellular                         = 10000000
@@ -222,15 +217,25 @@ class NCGlobal: NSObject {
     @objc let errorBadServerResponse: Int           = -1011
     @objc let errorInternalError: Int               = -99999
     @objc let errorFileNotSaved: Int                = -99998
-    @objc let errorDecodeMetadata: Int              = -99997
-    @objc let errorE2EENotEnabled: Int              = -99996
-    @objc let errorE2EE: Int                        = -99995
-    @objc let errorOffline: Int                     = -99994
-    @objc let errorCharactersForbidden: Int         = -99993
-    @objc let errorCreationFile: Int                = -99992
-    @objc let errorReadFile: Int                    = -99991
-    @objc let errorUnauthorizedFilesPasscode: Int   = -99990
-    @objc let errorDisableFilesApp: Int             = -99989
+    @objc let errorOffline: Int                     = -99997
+    @objc let errorCharactersForbidden: Int         = -99996
+    @objc let errorCreationFile: Int                = -99995
+    @objc let errorReadFile: Int                    = -99994
+    @objc let errorUnauthorizedFilesPasscode: Int   = -99993
+    @objc let errorDisableFilesApp: Int             = -99992
+    @objc let errorUnexpectedResponseFromDB: Int    = -99991
+    // E2EE
+    @objc let errorE2EENotEnabled: Int              = -98000
+    @objc let errorE2EEVersion: Int                 = -98001
+    @objc let errorE2EEKeyChecksums: Int            = -98002
+    @objc let errorE2EEKeyEncodeMetadata: Int       = -98003
+    @objc let errorE2EEKeyDecodeMetadata: Int       = -98004
+    @objc let errorE2EEKeyVerifySignature: Int      = -98005
+    @objc let errorE2EEKeyCiphertext: Int           = -98006
+    @objc let errorE2EEJSon: Int                    = -98007
+    @objc let errorE2EELock: Int                    = -98008
+    @objc let errorE2EEEncryptFile: Int             = -98009
+    @objc let errorE2EEEncryptPayloadFile: Int      = -98010
 
     // Constants to identify the different permissions of a file
     //

+ 10 - 8
iOSClient/Networking/E2EE/NCEndToEndEncryption.h

@@ -36,19 +36,20 @@
 // Certificate
 
 - (NSString *)createCSR:(NSString *)userId directory:(NSString *)directory;
-- (NSString *)encryptPrivateKey:(NSString *)userId directory: (NSString *)directory passphrase:(NSString *)passphrase privateKey:(NSString **)privateKey;
-- (NSData *)decryptPrivateKey:(NSString *)privateKey passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey;
+- (NSString *)encryptPrivateKey:(NSString *)userId directory: (NSString *)directory passphrase:(NSString *)passphrase privateKey:(NSString **)privateKey iterationCount:(unsigned int)iterationCount;
+- (NSData *)decryptPrivateKey:(NSString *)privateKey passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey iterationCount:(unsigned int)iterationCount;
 
 // Encrypt / Decrypt file material
 
-- (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key;
-- (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag;
+- (NSString *)encryptPayloadFile:(NSData *)encrypted key:(NSString *)key;
+- (NSString *)encryptPayloadFile:(NSData *)encrypted key:(NSString *)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag;
 - (NSData *)decryptPayloadFile:(NSString *)encrypted key:(NSString *)key;
 - (NSData *)decryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString *)initializationVector authenticationTag:(NSString *)authenticationTag;
 
 // Encrypt/Decrypt asymmetric
 
-- (NSData *)encryptAsymmetricString:(NSString *)plain publicKey:(NSString *)publicKey privateKey:(NSString *)privateKey;
+- (NSData *)encryptAsymmetricData:(NSData *)plainData certificate:(NSString *)certificate;
+- (NSData *)encryptAsymmetricData:(NSData *)plainData  privateKey:(NSString *)privateKey;
 - (NSData *)decryptAsymmetricData:(NSData *)cipherData privateKey:(NSString *)privateKey;
 
 // Encrypt / Decrypt file
@@ -58,15 +59,16 @@
 
 // Signature CMS
 
-- (NSData *)generateSignatureCMS:(NSData *)data certificate:(NSString *)certificate privateKey:(NSString *)privateKey publicKey:(NSString *)publicKey userId:(NSString *)userId;
-- (BOOL)verifySignatureCMS:(NSData *)cmsContent data:(NSData *)data publicKey:(NSString *)publicKey userId:(NSString *)userId;
+- (NSData *)generateSignatureCMS:(NSData *)data certificate:(NSString *)certificate privateKey:(NSString *)privateKey userId:(NSString *)userId;
+// - (BOOL)verifySignatureCMS:(NSData *)cmsContent data:(NSData *)data publicKey:(NSString *)publicKey userId:(NSString *)userId;
+- (BOOL)verifySignatureCMS:(NSData *)cmsContent data:(NSData *)data certificates:(NSArray*)certificates;
 
 // Utility
 
 - (void)Encodedkey:(NSString **)key initializationVector:(NSString **)initializationVector;
 - (NSData *)generateKey;
 - (NSString *)createSHA512:(NSString *)string;
-- (NSString *)createSHA256:(NSString *)string;
+- (NSString *)createSHA256:(NSData *)data;
 - (NSString *)extractPublicKeyFromCertificate:(NSString *)pemCertificate;
 
 @end

+ 141 - 69
iOSClient/Networking/E2EE/NCEndToEndEncryption.m

@@ -33,7 +33,6 @@
 
 #define IV_DELIMITER_ENCODED_OLD    @"fA=="
 #define IV_DELIMITER_ENCODED        @"|"
-#define PBKDF2_INTERACTION_COUNT    1024
 #define PBKDF2_KEY_LENGTH           256
 //#define PBKDF2_SALT                 @"$4$YmBjm3hk$Qb74D5IUYwghUmzsMqeNFx5z0/8$"
 
@@ -332,7 +331,7 @@
     return csr;
 }
 
-- (NSString *)encryptPrivateKey:(NSString *)userId directory:(NSString *)directory passphrase:(NSString *)passphrase privateKey:(NSString **)privateKey
+- (NSString *)encryptPrivateKey:(NSString *)userId directory:(NSString *)directory passphrase:(NSString *)passphrase privateKey:(NSString **)privateKey iterationCount:(unsigned int)iterationCount
 {
     NSMutableData *cipher = [NSMutableData new];
 
@@ -347,7 +346,7 @@
     // Remove all whitespaces from passphrase
     passphrase = [passphrase stringByReplacingOccurrencesOfString:@" " withString:@""];
     
-    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA1, PBKDF2_INTERACTION_COUNT, key.mutableBytes, key.length);
+    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA1, iterationCount, key.mutableBytes, key.length);
     
     NSData *initializationVector = [self generateIV:AES_IVEC_LENGTH];
     NSData *authenticationTag = [NSData new];
@@ -373,7 +372,7 @@
     }
 }
 
-- (NSData *)decryptPrivateKey:(NSString *)privateKey passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey
+- (NSData *)decryptPrivateKey:(NSString *)privateKey passphrase:(NSString *)passphrase publicKey:(NSString *)publicKey iterationCount:(unsigned int)iterationCount
 {
     NSMutableData *plain = [NSMutableData new];
 
@@ -401,7 +400,7 @@
     // Remove all whitespaces from passphrase
     passphrase = [passphrase stringByReplacingOccurrencesOfString:@" " withString:@""];
     
-    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA1, PBKDF2_INTERACTION_COUNT, key.mutableBytes, key.length);
+    CCKeyDerivationPBKDF(kCCPBKDF2, passphrase.UTF8String, passphrase.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA1, iterationCount, key.mutableBytes, key.length);
     
     BOOL result = [self decryptData:cipher plain:&plain key:key keyLen:AES_KEY_256_LENGTH initializationVector:initializationVector authenticationTag:authenticationTag];
     
@@ -416,49 +415,44 @@
 #pragma mark - Encrypt / Decrypt file material
 #
 
-- (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key
+- (NSString *)encryptPayloadFile:(NSData *)encrypted key:(NSString *)key
 {
     NSMutableData *cipher;
     NSData *authenticationTag = [NSData new];
 
-    NSData *encryptedData = [encrypted dataUsingEncoding:NSUTF8StringEncoding];
-    encryptedData = [[encryptedData base64EncodedStringWithOptions:0] dataUsingEncoding:NSUTF8StringEncoding];
-
     // Key
     NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
 
     // Initialization Vector
     NSData *initializationVector = [self generateIV:AES_IVEC_LENGTH];
-    
-    BOOL result = [self encryptData:encryptedData cipher:&cipher key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVector authenticationTag:&authenticationTag];
-    
+
+    BOOL result = [self encryptData:encrypted cipher:&cipher key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVector authenticationTag:&authenticationTag];
+
     if (cipher != nil && result) {
-        
+
         NSString *cipherString = [cipher base64EncodedStringWithOptions:0];
         NSString *initializationVectorString = [initializationVector base64EncodedStringWithOptions:0];
         NSString *payload = [NSString stringWithFormat:@"%@%@%@", cipherString, IV_DELIMITER_ENCODED, initializationVectorString];
-        
+
         return payload;
     }
-    
+
     return nil;
 }
 
-- (NSString *)encryptPayloadFile:(NSString *)encrypted key:(NSString *)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag
+
+- (NSString *)encryptPayloadFile:(NSData *)encrypted key:(NSString *)key initializationVector:(NSString **)initializationVector authenticationTag:(NSString **)authenticationTag
 {
     NSMutableData *cipher;
     NSData *authenticationTagData = [NSData new];
 
-    NSData *encryptedData = [encrypted dataUsingEncoding:NSUTF8StringEncoding];
-    encryptedData = [[encryptedData base64EncodedStringWithOptions:0] dataUsingEncoding:NSUTF8StringEncoding];
-
     // Key
     NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
 
     // Initialization Vector
     NSData *initializationVectorData = [self generateIV:AES_IVEC_LENGTH];
 
-    BOOL result = [self encryptData:encryptedData cipher:&cipher key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:&authenticationTagData];
+    BOOL result = [self encryptData:encrypted cipher:&cipher key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:&authenticationTagData];
 
     if (cipher != nil && result) {
 
@@ -515,6 +509,10 @@
 {
     NSMutableData *plain;
 
+    // Remove initializationVector Tag if exists [ANDROID]
+    NSString *android = [@"|" stringByAppendingString: initializationVector];
+    encrypted = [encrypted stringByReplacingOccurrencesOfString:android withString:@""];
+
     NSData *cipher = [[NSData alloc] initWithBase64EncodedString:encrypted options:0];
     NSData *keyData = [[NSData alloc] initWithBase64EncodedString:key options:0];
     NSData *initializationVectorData = [[NSData alloc] initWithBase64EncodedString:initializationVector options:0];
@@ -525,7 +523,7 @@
 
     BOOL result = [self decryptData:cipher plain:&plain key:keyData keyLen:AES_KEY_128_LENGTH initializationVector:initializationVectorData authenticationTag:authenticationTagData];
 
-    if (plain != nil && result) {
+    if (plain != nil && result && plain.length > 0) {
         return plain;
     }
 
@@ -581,78 +579,112 @@
 #pragma mark - Encrypt/Decrypt asymmetric
 #
 
-- (NSData *)encryptAsymmetricString:(NSString *)plain publicKey:(NSString *)publicKey privateKey:(NSString *)privateKey
+- (NSData *)encryptAsymmetricData:(NSData *)plainData certificate:(NSString *)certificate
 {
     EVP_PKEY *key = NULL;
     int status = 0;
-    
-    if (publicKey != nil) {
-        
-        unsigned char *pKey = (unsigned char *)[publicKey UTF8String];
+    unsigned char *pKey = (unsigned char *)[certificate UTF8String];
 
-        // Extract real publicKey
-        BIO *bio = BIO_new_mem_buf(pKey, -1);
-        if (!bio)
-            return nil;
-        
-        X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
-        if (!x509)
-            return nil;
-        
-        key = X509_get_pubkey(x509);
-        if (!key)
-            return nil;
-    }
-    
-    if (privateKey != nil) {
-        
-        unsigned char *pKey = (unsigned char *)[privateKey UTF8String];
+    // Extract real publicKey
+    BIO *bio = BIO_new_mem_buf(pKey, -1);
+    if (!bio)
+        return nil;
+
+    X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
+    if (!x509)
+        return nil;
+
+    key = X509_get_pubkey(x509);
+    if (!key)
+        return nil;
 
-        BIO *bio = BIO_new_mem_buf(pKey, -1);
-        if (!bio)
-            return nil;
-        
-        key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
-        if (!key)
-            return nil;
-    }
-    
     EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
     if (!ctx)
         return nil;
-    
+
     status = EVP_PKEY_encrypt_init(ctx);
     if (status <= 0)
         return nil;
-    
+
     status = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
     if (status <= 0)
         return nil;
-    
+
     status = EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256());
     if (status <= 0)
         return nil;
-    
+
     status = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256());
     if (status <= 0)
         return nil;
-    
+
     unsigned long outLen = 0;
-    NSData *plainData = [plain dataUsingEncoding:NSUTF8StringEncoding];
     status = EVP_PKEY_encrypt(ctx, NULL, &outLen, [plainData bytes], (int)[plainData length]);
     if (status <= 0 || outLen == 0)
         return nil;
-    
+
     unsigned char *out = (unsigned char *) malloc(outLen);
     status = EVP_PKEY_encrypt(ctx, out, &outLen, [plainData bytes], (int)[plainData length]);
     if (status <= 0)
         return nil;
-    
+
     NSData *outData = [[NSData alloc] initWithBytes:out length:outLen];
-    
+
     if (out)
         free(out);
-    
+
+    return outData;
+}
+
+- (NSData *)encryptAsymmetricData:(NSData *)plainData privateKey:(NSString *)privateKey
+{
+    EVP_PKEY *key = NULL;
+    int status = 0;
+    unsigned char *pKey = (unsigned char *)[privateKey UTF8String];
+
+    BIO *bio = BIO_new_mem_buf(pKey, -1);
+    if (!bio)
+        return nil;
+
+    key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+    if (!key)
+        return nil;
+
+    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
+    if (!ctx)
+        return nil;
+
+    status = EVP_PKEY_encrypt_init(ctx);
+    if (status <= 0)
+        return nil;
+
+    status = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
+    if (status <= 0)
+        return nil;
+
+    status = EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256());
+    if (status <= 0)
+        return nil;
+
+    status = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256());
+    if (status <= 0)
+        return nil;
+
+    unsigned long outLen = 0;
+    status = EVP_PKEY_encrypt(ctx, NULL, &outLen, [plainData bytes], (int)[plainData length]);
+    if (status <= 0 || outLen == 0)
+        return nil;
+
+    unsigned char *out = (unsigned char *) malloc(outLen);
+    status = EVP_PKEY_encrypt(ctx, out, &outLen, [plainData bytes], (int)[plainData length]);
+    if (status <= 0)
+        return nil;
+
+    NSData *outData = [[NSData alloc] initWithBytes:out length:outLen];
+
+    if (out)
+        free(out);
+
     return outData;
 }
 
@@ -1113,7 +1145,7 @@
 #pragma mark - CMS
 #
 
-- (NSData *)generateSignatureCMS:(NSData *)data certificate:(NSString *)certificate privateKey:(NSString *)privateKey publicKey:(NSString *)publicKey userId:(NSString *)userId
+- (NSData *)generateSignatureCMS:(NSData *)data certificate:(NSString *)certificate privateKey:(NSString *)privateKey userId:(NSString *)userId
 {
     unsigned char *pKey = (unsigned char *)[privateKey UTF8String];
     unsigned char *certKey = (unsigned char *)[certificate UTF8String];
@@ -1151,9 +1183,6 @@
 
     NSData *i2dCmsData = [NSData dataWithBytes:keyBytes length:len];
 
-    // TEST
-    [self verifySignatureCMS:i2dCmsData data:data publicKey:publicKey userId:userId];
-
     BIO_free(printBIO);
     BIO_free(certKeyBIO);
     BIO_free(pkeyBIO);
@@ -1220,6 +1249,50 @@
     return verifyResult;
 }
 
+- (BOOL)verifySignatureCMS:(NSData *)cmsContent data:(NSData *)data certificates:(NSArray*)certificates
+{
+    BIO *dataBIO = BIO_new_mem_buf((void*)data.bytes, (int)data.length);
+    BIO *printBIO = BIO_new_fp(stdout, BIO_NOCLOSE);
+    BIO *cmsBIO = BIO_new_mem_buf(cmsContent.bytes, (int)cmsContent.length);
+
+    CMS_ContentInfo *contentInfo = d2i_CMS_bio(cmsBIO, NULL);
+    CMS_ContentInfo_print_ctx(printBIO, contentInfo, 0, NULL);
+
+    BOOL verifyResult = CMS_verify(contentInfo, NULL, NULL, dataBIO, NULL, CMS_DETACHED | CMS_NO_SIGNER_CERT_VERIFY);
+
+    BIO_free(dataBIO);
+    BIO_free(printBIO);
+    BIO_free(cmsBIO);
+
+    if (verifyResult) {
+
+        struct stack_st_CMS_SignerInfo* signerInfos = CMS_get0_SignerInfos(contentInfo);
+        STACK_OF(X509) *signers = CMS_get0_signers(contentInfo);
+        int numSigners = sk_X509_num(signers);
+
+        for (NSString *certificate in certificates) {
+
+            const char *ptrCertificate = [certificate cStringUsingEncoding:NSUTF8StringEncoding];
+            BIO *certBio = BIO_new(BIO_s_mem());
+            BIO_write(certBio, ptrCertificate,(unsigned int)strlen(ptrCertificate));
+            X509 *certX509 = PEM_read_bio_X509(certBio, NULL, NULL, NULL);
+            if (!certX509) {
+                continue;
+            }
+
+            for (int i = 0; i < numSigners; ++i) {
+                struct CMS_SignerInfo_st *signerInfo = sk_CMS_SignerInfo_value(signerInfos, i);
+                if (CMS_SignerInfo_cert_cmp(signerInfo, certX509) == 0) {
+                    BIO_free(certBio);
+                    return true;
+                }
+            }
+        }
+    }
+
+    return verifyResult;
+}
+
 #
 #pragma mark - Utility
 #
@@ -1233,10 +1306,8 @@
     *initializationVector = [ivData base64EncodedStringWithOptions:0];
 }
 
-- (NSString *)createSHA256:(NSString *)string
+- (NSString *)createSHA256:(NSData *)data
 {
-    const char *cstr = [string cStringUsingEncoding:NSASCIIStringEncoding];
-    NSData *data = [NSData dataWithBytes:cstr length:string.length];
     uint8_t digest[CC_SHA256_DIGEST_LENGTH];
     CC_SHA256(data.bytes, (unsigned int)data.length, digest);
     NSMutableString* output = [NSMutableString  stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
@@ -1250,6 +1321,7 @@
 {
     const char *cstr = [string cStringUsingEncoding:NSUTF8StringEncoding];
     NSData *data = [NSData dataWithBytes:cstr length:string.length];
+
     uint8_t digest[CC_SHA512_DIGEST_LENGTH];
     CC_SHA512(data.bytes, (unsigned int)data.length, digest);
     NSMutableString* output = [NSMutableString  stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 21 - 317
iOSClient/Networking/E2EE/NCEndToEndMetadata.swift


+ 469 - 0
iOSClient/Networking/E2EE/NCEndToEndMetadataV1.swift

@@ -0,0 +1,469 @@
+//
+//  NCEndToEndMetadataV1.swift
+//  Created by Marino Faggiana on 09/08/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+import NextcloudKit
+
+extension NCEndToEndMetadata {
+
+    struct E2eeV1: Codable {
+
+        struct Metadata: Codable {
+            let metadataKeys: [String: String]
+            let version: Double
+        }
+
+        struct Encrypted: Codable {
+            let key: String
+            let filename: String
+            let mimetype: String
+        }
+
+        struct Files: Codable {
+            let initializationVector: String
+            let authenticationTag: String?
+            let metadataKey: Int
+            let encrypted: String
+        }
+
+        let metadata: Metadata
+        let files: [String: Files]?
+    }
+
+    struct E2eeV12: Codable {
+
+        struct Metadata: Codable {
+            let metadataKey: String
+            let version: Double
+            let checksum: String?
+        }
+
+        struct Encrypted: Codable {
+            let key: String
+            let filename: String
+            let mimetype: String
+        }
+
+        struct Files: Codable {
+            let initializationVector: String
+            let authenticationTag: String?
+            let encrypted: String
+        }
+
+        struct Filedrop: Codable {
+            let initializationVector: String
+            let authenticationTag: String?
+            let encrypted: String
+            let encryptedKey: String?
+            let encryptedTag: String?
+            let encryptedInitializationVector: String?
+        }
+
+        let metadata: Metadata
+        let files: [String: Files]?
+        let filedrop: [String: Filedrop]?
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // MARK: Ecode JSON Metadata V1.2
+    // --------------------------------------------------------------------------------------------
+
+    func encodeMetadataV12(account: String, serverUrl: String, ocIdServerUrl: String) -> (metadata: String?, signature: String?, error: NKError) {
+
+        let encoder = JSONEncoder()
+        var metadataKey: String = ""
+        let metadataVersion = 1.2
+        var files: [String: E2eeV12.Files] = [:]
+        var filesCodable: [String: E2eeV12.Files]?
+        var filedrop: [String: E2eeV12.Filedrop] = [:]
+        var filedropCodable: [String: E2eeV12.Filedrop]?
+        let privateKey = CCUtility.getEndToEndPrivateKey(account)
+        var fileNameIdentifiers: [String] = []
+
+        let e2eEncryptions = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
+
+        //
+        // metadata
+        //
+        if e2eEncryptions.isEmpty, let key = NCEndToEndEncryption.sharedManager()?.generateKey() as? NSData {
+
+            if let key = key.base64EncodedString().data(using: .utf8)?.base64EncodedString().data(using: .utf8),
+               let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricData(key, privateKey: privateKey) {
+                metadataKey = metadataKeyEncrypted.base64EncodedString()
+            }
+
+        } else if let metadatakey = (e2eEncryptions.first!.metadataKey.data(using: .utf8)?.base64EncodedString().data(using: .utf8)),
+                  let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricData(metadatakey, privateKey: privateKey) {
+
+            metadataKey = metadataKeyEncrypted.base64EncodedString()
+        }
+
+        for e2eEncryption in e2eEncryptions {
+
+            //
+            // files & folders
+            //
+            if e2eEncryption.blob == "files" || e2eEncryption.blob == "folders" {
+                let encrypted = E2eeV12.Encrypted(key: e2eEncryption.key, filename: e2eEncryption.fileName, mimetype: e2eEncryption.mimeType)
+                do {
+                    // Create "encrypted"
+                    var json = try encoder.encode(encrypted)
+                    json = json.base64EncodedString().data(using: .utf8)!
+                    if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(json, key: e2eEncryption.metadataKey) {
+                        let record = E2eeV12.Files(initializationVector: e2eEncryption.initializationVector, authenticationTag: e2eEncryption.authenticationTag, encrypted: encrypted)
+                        files.updateValue(record, forKey: e2eEncryption.fileNameIdentifier)
+                    }
+                    fileNameIdentifiers.append(e2eEncryption.fileNameIdentifier)
+                } catch let error {
+                    return (nil, nil, NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription))
+                }
+            }
+
+            //
+            // filedrop
+            //
+            if e2eEncryption.blob == "filedrop" {
+
+                var encryptedKey: String?
+                var encryptedInitializationVector: NSString?
+                var encryptedTag: NSString?
+
+                if let metadataKeyFiledrop = (e2eEncryption.metadataKeyFiledrop.data(using: .utf8)?.base64EncodedString().data(using: .utf8)),
+                   let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricData(metadataKeyFiledrop, privateKey: privateKey) {
+                    encryptedKey = metadataKeyEncrypted.base64EncodedString()
+                }
+                let encrypted = E2eeV12.Encrypted(key: e2eEncryption.key, filename: e2eEncryption.fileName, mimetype: e2eEncryption.mimeType)
+                do {
+                    // Create "encrypted"
+                    var json = try encoder.encode(encrypted)
+                    json = json.base64EncodedString().data(using: .utf8)!
+                    if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(json, key: e2eEncryption.metadataKeyFiledrop, initializationVector: &encryptedInitializationVector, authenticationTag: &encryptedTag) {
+                        let record = E2eeV12.Filedrop(initializationVector: e2eEncryption.initializationVector, authenticationTag: e2eEncryption.authenticationTag, encrypted: encrypted, encryptedKey: encryptedKey, encryptedTag: encryptedTag as? String, encryptedInitializationVector: encryptedInitializationVector as? String)
+                        filedrop.updateValue(record, forKey: e2eEncryption.fileNameIdentifier)
+                    }
+                } catch let error {
+                    return (nil, nil, NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription))
+                }
+            }
+        }
+
+        // Create checksum
+        let passphrase = CCUtility.getEndToEndPassphrase(account).replacingOccurrences(of: " ", with: "")
+        let dataChecksum = (passphrase + fileNameIdentifiers.sorted().joined() + metadataKey).data(using: .utf8)
+        let checksum = NCEndToEndEncryption.sharedManager().createSHA256(dataChecksum)
+
+        // Create Json
+        let metadata = E2eeV12.Metadata(metadataKey: metadataKey, version: metadataVersion, checksum: checksum)
+        if !files.isEmpty { filesCodable = files }
+        if !filedrop.isEmpty { filedropCodable = filedrop }
+        let e2ee = E2eeV12(metadata: metadata, files: filesCodable, filedrop: filedropCodable)
+        do {
+            let data = try encoder.encode(e2ee)
+            data.printJson()
+            let jsonString = String(data: data, encoding: .utf8)
+            // Updated metadata to 1.2
+            if NCManageDatabase.shared.getE2eMetadata(account: account, serverUrl: serverUrl) == nil {
+                NCManageDatabase.shared.setE2eMetadata(account: account, serverUrl: serverUrl, metadataKey: metadataKey, version: metadataVersion)
+            }
+            return (jsonString, nil, NKError())
+        } catch let error {
+            return (nil, nil, NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription))
+        }
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // MARK: Decode JSON Metadata V1.2
+    // --------------------------------------------------------------------------------------------
+
+    func decodeMetadataV12(_ json: String, serverUrl: String, account: String, ocIdServerUrl: String, urlBase: String, userId: String, ownerId: String?) -> NKError {
+
+        guard let data = json.data(using: .utf8) else {
+            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: "_e2e_error_")
+        }
+
+        let decoder = JSONDecoder()
+        let privateKey = CCUtility.getEndToEndPrivateKey(account)
+        var metadataVersion: Double = 0
+        var metadataKey = ""
+
+        do {
+            let json = try decoder.decode(E2eeV12.self, from: data)
+
+            let metadata = json.metadata
+            let files = json.files
+            let filedrop = json.filedrop
+            var fileNameIdentifiers: [String] = []
+
+            metadataVersion = metadata.version
+
+            //
+            // metadata
+            //
+            let data = Data(base64Encoded: metadata.metadataKey)
+
+            if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: privateKey),
+                let keyData = Data(base64Encoded: decrypted),
+                let key = String(data: keyData, encoding: .utf8) {
+                metadataKey = key
+            } else {
+                return NKError(errorCode: NCGlobal.shared.errorE2EEKeyDecodeMetadata, errorDescription: "_e2e_error_")
+            }
+
+            // DATA
+            NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
+
+            //
+            // files
+            //
+            if let files = files {
+                for file in files {
+                    let fileNameIdentifier = file.key
+                    let files = file.value as E2eeV12.Files
+                    let encrypted = files.encrypted
+                    let authenticationTag = files.authenticationTag
+                    let initializationVector = files.initializationVector
+
+                    fileNameIdentifiers.append(fileNameIdentifier)
+
+                    if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(encrypted, key: metadataKey),
+                       let decryptedData = Data(base64Encoded: decrypted) {
+                        do {
+                            decryptedData.printJson()
+                            let encrypted = try decoder.decode(E2eeV12.Encrypted.self, from: decryptedData)
+
+                            if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) {
+
+                                let object = tableE2eEncryption.init(account: account, ocIdServerUrl: ocIdServerUrl, fileNameIdentifier: fileNameIdentifier)
+
+                                object.authenticationTag = authenticationTag ?? ""
+                                object.blob = "files"
+                                object.fileName = encrypted.filename
+                                object.key = encrypted.key
+                                object.initializationVector = initializationVector
+                                object.metadataKey = metadataKey
+                                object.metadataVersion = metadataVersion
+                                object.mimeType = encrypted.mimetype
+                                object.serverUrl = serverUrl
+
+                                // Write file parameter for decrypted on DB
+                                NCManageDatabase.shared.addE2eEncryption(object)
+
+                                // Update metadata on tableMetadata
+                                metadata.fileNameView = encrypted.filename
+
+                                let results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: encrypted.filename, mimeType: metadata.contentType, directory: metadata.directory)
+
+                                metadata.contentType = results.mimeType
+                                metadata.iconName = results.iconName
+                                metadata.classFile = results.classFile
+
+                                NCManageDatabase.shared.addMetadata(metadata)
+                            }
+
+                        } catch let error {
+                            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription)
+                        }
+                    }
+                }
+            }
+
+            //
+            // filedrop
+            //
+            if let filedrop = filedrop {
+                for filedrop in filedrop {
+                    let fileNameIdentifier = filedrop.key
+                    let filedrop = filedrop.value as E2eeV12.Filedrop
+                    var metadataKeyFiledrop: String?
+
+                    if let encryptedKey = filedrop.encryptedKey,
+                       let data = Data(base64Encoded: encryptedKey),
+                       let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: privateKey) {
+                        let keyData = Data(base64Encoded: decrypted)
+                        metadataKeyFiledrop = String(data: keyData!, encoding: .utf8)
+                    }
+
+                    if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(filedrop.encrypted, key: metadataKeyFiledrop, initializationVector: filedrop.encryptedInitializationVector, authenticationTag: filedrop.encryptedTag),
+                       let decryptedData = Data(base64Encoded: decrypted) {
+                        do {
+                            decryptedData.printJson()
+                            let encrypted = try decoder.decode(E2eeV1.Encrypted.self, from: decryptedData)
+
+                            if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) {
+
+                                let object = tableE2eEncryption.init(account: account, ocIdServerUrl: ocIdServerUrl, fileNameIdentifier: fileNameIdentifier)
+
+                                object.authenticationTag = filedrop.authenticationTag ?? ""
+                                object.blob = "filedrop"
+                                object.fileName = encrypted.filename
+                                object.key = encrypted.key
+                                object.metadataKeyFiledrop = metadataKeyFiledrop ?? ""
+                                object.initializationVector = filedrop.initializationVector
+                                object.metadataKey = metadataKey
+                                object.metadataVersion = metadataVersion
+                                object.mimeType = encrypted.mimetype
+                                object.serverUrl = serverUrl
+
+                                // Write file parameter for decrypted on DB
+                                NCManageDatabase.shared.addE2eEncryption(object)
+
+                                // Update metadata on tableMetadata
+                                metadata.fileNameView = encrypted.filename
+
+                                let results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: encrypted.filename, mimeType: metadata.contentType, directory: metadata.directory)
+
+                                metadata.contentType = results.mimeType
+                                metadata.iconName = results.iconName
+                                metadata.classFile = results.classFile
+
+                                NCManageDatabase.shared.addMetadata(metadata)
+                            }
+
+                        } catch let error {
+                            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription)
+                        }
+                    }
+                }
+            }
+
+            // verify checksum
+            let passphrase = CCUtility.getEndToEndPassphrase(account).replacingOccurrences(of: " ", with: "")
+            let dataChecksum = (passphrase + fileNameIdentifiers.sorted().joined() + metadata.metadataKey).data(using: .utf8)
+            let checksum = NCEndToEndEncryption.sharedManager().createSHA256(dataChecksum)
+            if metadata.checksum != checksum {
+                return NKError(errorCode: NCGlobal.shared.errorE2EEKeyChecksums, errorDescription: "_e2e_error_")
+            }
+        } catch let error {
+            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription)
+        }
+
+        return NKError()
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // MARK: Decode JSON Metadata V1.1
+    // --------------------------------------------------------------------------------------------
+
+    func decodeMetadataV1(_ json: String, serverUrl: String, account: String, ocIdServerUrl: String, urlBase: String, userId: String) -> NKError {
+
+        guard let data = json.data(using: .utf8) else {
+            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: "_e2e_error_")
+        }
+
+        let decoder = JSONDecoder()
+        let privateKey = CCUtility.getEndToEndPrivateKey(account)
+        var metadataVersion: Double = 0
+
+        do {
+            let json = try decoder.decode(E2eeV1.self, from: data)
+
+            let metadata = json.metadata
+            let files = json.files
+            var metadataKeys: [String: String] = [:]
+
+            metadataVersion = metadata.version
+
+            // DATA
+            NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
+
+            //
+            // metadata
+            //
+            for metadataKey in metadata.metadataKeys {
+                let data = Data(base64Encoded: metadataKey.value)
+                if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: privateKey),
+                   let keyData = Data(base64Encoded: decrypted) {
+                    let key = String(data: keyData, encoding: .utf8)
+                    metadataKeys[metadataKey.key] = key
+                }
+            }
+
+            //
+            // verify version
+            //
+            if let tableE2eMetadata = NCManageDatabase.shared.getE2eMetadata(account: account, serverUrl: serverUrl) {
+                if tableE2eMetadata.version > metadataVersion {
+                    return NKError(errorCode: NCGlobal.shared.errorE2EEVersion, errorDescription: "Version \(tableE2eMetadata.version)")
+                }
+            }
+
+            //
+            // files
+            //
+            if let files = files {
+                for files in files {
+                    let fileNameIdentifier = files.key
+                    let files = files.value as E2eeV1.Files
+
+                    let encrypted = files.encrypted
+                    let authenticationTag = files.authenticationTag
+                    guard let metadataKey = metadataKeys["\(files.metadataKey)"] else { continue }
+                    let metadataKeyIndex = files.metadataKey
+                    let initializationVector = files.initializationVector
+
+                    if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(encrypted, key: metadataKey),
+                       let decryptedData = Data(base64Encoded: decrypted) {
+                        do {
+                            let encrypted = try decoder.decode(E2eeV1.Encrypted.self, from: decryptedData)
+
+                            if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) {
+
+                                let object = tableE2eEncryption.init(account: account, ocIdServerUrl: ocIdServerUrl, fileNameIdentifier: fileNameIdentifier)
+
+                                object.authenticationTag = authenticationTag ?? ""
+                                object.blob = "files"
+                                object.fileName = encrypted.filename
+                                object.key = encrypted.key
+                                object.initializationVector = initializationVector
+                                object.metadataKey = metadataKey
+                                object.metadataKeyIndex = metadataKeyIndex
+                                object.metadataVersion = metadataVersion
+                                object.mimeType = encrypted.mimetype
+                                object.serverUrl = serverUrl
+
+                                // Write file parameter for decrypted on DB
+                                NCManageDatabase.shared.addE2eEncryption(object)
+
+                                // Update metadata on tableMetadata
+                                metadata.fileNameView = encrypted.filename
+
+                                let results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: encrypted.filename, mimeType: metadata.contentType, directory: metadata.directory)
+
+                                metadata.contentType = results.mimeType
+                                metadata.iconName = results.iconName
+                                metadata.classFile = results.classFile
+
+                                NCManageDatabase.shared.addMetadata(metadata)
+                            }
+
+                        } catch let error {
+                            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription)
+                        }
+                    }
+                }
+            }
+        } catch let error {
+            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription)
+        }
+
+        return NKError()
+    }
+}

+ 412 - 0
iOSClient/Networking/E2EE/NCEndToEndMetadataV20.swift

@@ -0,0 +1,412 @@
+//
+//  NCEndToEndMetadataV20.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 09/08/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+import NextcloudKit
+import Gzip
+
+extension NCEndToEndMetadata {
+
+    struct E2eeV20: Codable {
+
+        struct Files: Codable {
+            let authenticationTag: String
+            let filename: String
+            let key: String
+            let mimetype: String
+            let nonce: String
+        }
+
+        struct ciphertext: Codable {
+            let counter: Int
+            let deleted: Bool?
+            let keyChecksums: [String]?
+            let files: [String: Files]?
+            let folders: [String: String]?
+        }
+
+        struct Metadata: Codable {
+            let ciphertext: String
+            let nonce: String
+            let authenticationTag: String
+        }
+
+        struct Users: Codable {
+            let userId: String
+            let certificate: String
+            let encryptedMetadataKey: String?
+            let encryptedFiledropKey: String?
+        }
+
+        struct Filedrop: Codable {
+            let ciphertext: String?
+            let nonce: String?
+            let authenticationTag: String?
+            let users: [String: UsersFiledrop]?
+
+            struct UsersFiledrop: Codable {
+                let userId: String?
+                let encryptedFiledropKey: String?
+            }
+        }
+
+        let metadata: Metadata
+        let users: [Users]?
+        let filedrop: [String: Filedrop]?
+        let version: String
+    }
+
+    struct E2eeV20Signature: Codable {
+
+        struct Metadata: Codable {
+            let ciphertext: String
+            let nonce: String
+            let authenticationTag: String
+        }
+
+        struct Users: Codable {
+            let userId: String
+            let certificate: String
+            let encryptedMetadataKey: String?
+        }
+
+        let metadata: Metadata
+        let users: [Users]?
+        let version: String
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // MARK: Ecode JSON Metadata V2.0
+    // --------------------------------------------------------------------------------------------
+
+    func encodeMetadataV20(account: String, serverUrl: String, ocIdServerUrl: String, userId: String, addUserId: String?, addCertificate: String?, removeUserId: String?) -> (metadata: String?, signature: String?, error: NKError) {
+
+        guard let keyGenerated = NCEndToEndEncryption.sharedManager()?.generateKey() as? Data,
+              let directoryTop = NCUtility.shared.getDirectoryE2EETop(serverUrl: serverUrl, account: account) else {
+            return (nil, nil, NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_e2e_error_"))
+        }
+
+        let isDirectoryTop = NCUtility.shared.isDirectoryE2EETop(account: account, serverUrl: serverUrl)
+        var metadataKey: String?
+        var keyChecksums: [String] = []
+        var usersCodable: [E2eeV20.Users] = []
+        var filedropCodable: [String: E2eeV20.Filedrop] = [:]
+        var folders: [String: String] = [:]
+
+        func addUser(userId: String?, certificate: String?) {
+
+            guard let userId, let certificate else { return }
+            let decryptedMetadataKey = keyGenerated
+            let metadataKey = keyGenerated.base64EncodedString()
+
+            if let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricData(keyGenerated, certificate: certificate) {
+
+                let encryptedMetadataKey = metadataKeyEncrypted.base64EncodedString()
+                NCManageDatabase.shared.addE2EUsersV2(account: account, serverUrl: serverUrl, ocIdServerUrl: ocIdServerUrl, userId: userId, certificate: certificate, encryptedFiledropKey: nil, encryptedMetadataKey: encryptedMetadataKey, decryptedFiledropKey: nil, decryptedMetadataKey: decryptedMetadataKey, filedropKey: nil, metadataKey: metadataKey)
+            }
+        }
+
+        if isDirectoryTop {
+
+            addUser(userId: userId, certificate: CCUtility.getEndToEndCertificate(account))
+            addUser(userId: addUserId, certificate: addCertificate)
+
+            if let removeUserId {
+                NCManageDatabase.shared.deleteE2EUsersV2(account: account, ocIdServerUrl: ocIdServerUrl, userId: removeUserId)
+            }
+
+            if let users = NCManageDatabase.shared.getE2EUsersV2(account: account, ocIdServerUrl: ocIdServerUrl) {
+                for user in users {
+                    addUser(userId: user.userId, certificate: user.certificate)
+                }
+            }
+        }
+
+        if let e2eUsers = NCManageDatabase.shared.getE2EUsersV2(account: account, ocIdServerUrl: directoryTop.ocId) {
+            for user in e2eUsers {
+                if isDirectoryTop {
+                    usersCodable.append(E2eeV20.Users(userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey, encryptedFiledropKey: user.encryptedFiledropKey))
+                }
+                if let hash = NCEndToEndEncryption.sharedManager().createSHA256(user.decryptedMetadataKey) {
+                    keyChecksums.append(hash)
+                }
+                if let addUserId, user.userId == addUserId {
+                    metadataKey = user.metadataKey
+                } else if user.userId == userId {
+                    metadataKey = user.metadataKey
+                }
+            }
+        }
+
+        guard let e2eMetadataV2 = NCManageDatabase.shared.incrementCounterE2eMetadataV2(account: account, serverUrl: serverUrl, ocIdServerUrl: ocIdServerUrl, version: NCGlobal.shared.e2eeVersionV20) else {
+            return (nil, nil, NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_e2e_error_"))
+        }
+
+        // Create ciphertext
+        let e2eEncryptions = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
+        var filesCodable: [String: E2eeV20.Files] = [:]
+
+        for e2eEncryption in e2eEncryptions {
+            if e2eEncryption.blob == "files" {
+                let file = E2eeV20.Files(authenticationTag: e2eEncryption.authenticationTag, filename: e2eEncryption.fileName, key: e2eEncryption.key, mimetype: e2eEncryption.mimeType, nonce: e2eEncryption.initializationVector)
+                filesCodable.updateValue(file, forKey: e2eEncryption.fileNameIdentifier)
+            } else if e2eEncryption.blob == "folders" {
+                folders[e2eEncryption.fileNameIdentifier] = e2eEncryption.fileName
+            }
+        }
+
+        let ciphertext = E2eeV20.ciphertext(counter: e2eMetadataV2.counter, deleted: false, keyChecksums: keyChecksums, files: filesCodable, folders: folders)
+        var authenticationTag: NSString?
+        var initializationVector: NSString?
+
+        do {
+            let json = try JSONEncoder().encode(ciphertext)
+            let jsonZip = try json.gzipped()
+            let ciphertext = NCEndToEndEncryption.sharedManager().encryptPayloadFile(jsonZip, key: metadataKey, initializationVector: &initializationVector, authenticationTag: &authenticationTag)
+
+            guard var ciphertext, let initializationVector = initializationVector as? String, let authenticationTag = authenticationTag as? String else {
+                return (nil, nil, NKError(errorCode: NCGlobal.shared.errorE2EEEncryptPayloadFile, errorDescription: "_e2e_error_"))
+            }
+
+            // Add initializationVector [ANDROID]
+            ciphertext = ciphertext + "|" + initializationVector
+
+            let metadataCodable = E2eeV20.Metadata(ciphertext: ciphertext, nonce: initializationVector, authenticationTag: authenticationTag)
+            let e2eeCodable = E2eeV20(metadata: metadataCodable, users: usersCodable, filedrop: filedropCodable, version: NCGlobal.shared.e2eeVersionV20)
+            let e2eeData = try JSONEncoder().encode(e2eeCodable)
+            e2eeData.printJson()
+
+            let e2eeJson = String(data: e2eeData, encoding: .utf8)
+            let signature = createSignature(account: account, userId: userId, metadata: metadataCodable, users: usersCodable, version: NCGlobal.shared.e2eeVersionV20, certificate: CCUtility.getEndToEndCertificate(account))
+            return (e2eeJson, signature, NKError())
+
+        } catch let error {
+            return (nil, nil, NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription))
+        }
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // MARK: Decode JSON Metadata V2.0
+    // --------------------------------------------------------------------------------------------
+
+    func decodeMetadataV20(_ json: String, signature: String?, serverUrl: String, account: String, ocIdServerUrl: String, urlBase: String, userId: String, ownerId: String?) -> NKError {
+
+        guard let data = json.data(using: .utf8),
+              let directoryTop = NCUtility.shared.getDirectoryE2EETop(serverUrl: serverUrl, account: account) else {
+            return NKError(errorCode: NCGlobal.shared.errorE2EEKeyDecodeMetadata, errorDescription: "_e2e_error_")
+        }
+
+        func addE2eEncryption(fileNameIdentifier: String, filename: String, authenticationTag: String, key: String, initializationVector: String, metadataKey: String, mimetype: String, blob: String) {
+
+            if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) {
+
+                let object = tableE2eEncryption.init(account: account, ocIdServerUrl: ocIdServerUrl, fileNameIdentifier: fileNameIdentifier)
+
+                object.authenticationTag = authenticationTag
+                object.blob = blob
+                object.fileName = filename
+                object.key = key
+                object.initializationVector = initializationVector
+                object.metadataKey = metadataKey
+                object.mimeType = mimetype
+                object.serverUrl = serverUrl
+
+                // Write file parameter for decrypted on DB
+                NCManageDatabase.shared.addE2eEncryption(object)
+
+                // Update metadata on tableMetadata
+                metadata.fileNameView = filename
+
+                let results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: filename, mimeType: metadata.contentType, directory: metadata.directory)
+
+                metadata.contentType = results.mimeType
+                metadata.iconName = results.iconName
+                metadata.classFile = results.classFile
+
+                NCManageDatabase.shared.addMetadata(metadata)
+            }
+        }
+
+        do {
+            let json = try JSONDecoder().decode(E2eeV20.self, from: data)
+
+            let metadata = json.metadata
+            let users = json.users
+            let filedrop = json.filedrop
+            let version = json.version as String? ?? NCGlobal.shared.e2eeVersionV20
+
+            if let users {
+                for user in users {
+
+                    var decryptedMetadataKey: Data?
+                    var decryptedFiledropKey: Data?
+                    var metadataKey: String?
+                    var filedropKey: String?
+
+                    if let encryptedMetadataKey = user.encryptedMetadataKey {
+                        let data = Data(base64Encoded: encryptedMetadataKey)
+                        if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: CCUtility.getEndToEndPrivateKey(account)) {
+                            decryptedMetadataKey = decrypted
+                            metadataKey = decrypted.base64EncodedString()
+                        }
+                    }
+
+                    if let encryptedFiledropKey = user.encryptedFiledropKey {
+                        let data = Data(base64Encoded: encryptedFiledropKey)
+                        if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: CCUtility.getEndToEndPrivateKey(account)) {
+                            decryptedFiledropKey = decrypted
+                            filedropKey = decrypted.base64EncodedString()
+                        }
+                    }
+
+                    NCManageDatabase.shared.addE2EUsersV2(account: account,
+                                                          serverUrl: serverUrl,
+                                                          ocIdServerUrl: ocIdServerUrl,
+                                                          userId: user.userId,
+                                                          certificate: user.certificate,
+                                                          encryptedFiledropKey: user.encryptedFiledropKey,
+                                                          encryptedMetadataKey: user.encryptedMetadataKey,
+                                                          decryptedFiledropKey: decryptedFiledropKey,
+                                                          decryptedMetadataKey: decryptedMetadataKey,
+                                                          filedropKey: filedropKey,
+                                                          metadataKey: metadataKey)
+                }
+            }
+
+            if let tableE2eUsersV2 = NCManageDatabase.shared.getE2EUsersV2(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId),
+               let metadataKey = tableE2eUsersV2.metadataKey,
+               let decryptedMetadataKey = tableE2eUsersV2.decryptedMetadataKey {
+
+                // SIGNATURE CHECK
+                if let signature,
+                    !verifySignature(account: account, signature: signature, userId: tableE2eUsersV2.userId, metadata: metadata, users: users, version: version, certificate: tableE2eUsersV2.certificate) {
+                    return NKError(errorCode: NCGlobal.shared.errorE2EEKeyVerifySignature, errorDescription: "_e2e_error_")
+                }
+
+                // CIPHERTEXT
+                if let decrypted = NCEndToEndEncryption.sharedManager().decryptPayloadFile(metadata.ciphertext, key: metadataKey, initializationVector: metadata.nonce, authenticationTag: metadata.authenticationTag) {
+                    if decrypted.isGzipped {
+                        do {
+                            let data = try decrypted.gunzipped()
+                            if let jsonText = String(data: data, encoding: .utf8) {
+                                print(jsonText)
+                            }
+
+                            let json = try JSONDecoder().decode(E2eeV20.ciphertext.self, from: data)
+
+                            // Checksums check
+                            if let keyChecksums = json.keyChecksums,
+                                let hash = NCEndToEndEncryption.sharedManager().createSHA256(decryptedMetadataKey),
+                                !keyChecksums.contains(hash) {
+                                return NKError(errorCode: NCGlobal.shared.errorE2EEKeyChecksums, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
+                            }
+
+                            NCManageDatabase.shared.addE2eMetadataV2(account: account, serverUrl: serverUrl, ocIdServerUrl: ocIdServerUrl, keyChecksums: json.keyChecksums, deleted: json.deleted ?? false, counter: json.counter, folders: json.folders, version: version)
+
+                            if let files = json.files {
+                                for file in files {
+                                    addE2eEncryption(fileNameIdentifier: file.key, filename: file.value.filename, authenticationTag: file.value.authenticationTag, key: file.value.key, initializationVector: file.value.nonce, metadataKey: metadataKey, mimetype: file.value.mimetype, blob: "files")
+                                }
+                            }
+
+                            if let folders = json.folders {
+                                for folder in folders {
+                                    addE2eEncryption(fileNameIdentifier: folder.key, filename: folder.value, authenticationTag: metadata.authenticationTag, key: metadataKey, initializationVector: metadata.nonce, metadataKey: metadataKey, mimetype: "httpd/unix-directory", blob: "folders")
+                                }
+                            }
+
+                        } catch let error {
+                            return NKError(error: error)
+                        }
+                    } else {
+                        return NKError(errorCode: NCGlobal.shared.errorE2EEKeyCiphertext, errorDescription: "_e2e_error_")
+                    }
+                } else {
+                    return NKError(errorCode: NCGlobal.shared.errorE2EEKeyCiphertext, errorDescription: "_e2e_error_")
+                }
+            }
+        } catch let error {
+            return NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription)
+        }
+
+        return NKError()
+    }
+
+    // MARK: -
+
+    func createSignature(account: String, userId: String, metadata: E2eeV20.Metadata, users: [E2eeV20.Users]?, version: String, certificate: String) -> String? {
+
+        guard let users else { return nil }
+
+        var usersSignatureCodable: [E2eeV20Signature.Users] = []
+        for user in users {
+            usersSignatureCodable.append(E2eeV20Signature.Users(userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey))
+        }
+        let signatureCodable = E2eeV20Signature(metadata: E2eeV20Signature.Metadata(ciphertext: metadata.ciphertext, nonce: metadata.nonce, authenticationTag: metadata.authenticationTag), users: usersSignatureCodable, version: version)
+
+        do {
+            let jsonEncoder = JSONEncoder()
+            let json = try jsonEncoder.encode(signatureCodable)
+            let dataSerialization = try JSONSerialization.jsonObject(with: json, options: [])
+            let decoded = try? JSONSerialization.data(withJSONObject: dataSerialization, options: [.sortedKeys, .withoutEscapingSlashes])
+            let base64 = decoded!.base64EncodedString()
+            if let base64Data = base64.data(using: .utf8),
+               let signatureData = NCEndToEndEncryption.sharedManager().generateSignatureCMS(base64Data, certificate: certificate, privateKey: CCUtility.getEndToEndPrivateKey(account), userId: userId) {
+                return signatureData.base64EncodedString()
+            }
+        } catch {
+            print("Error: \(error.localizedDescription)")
+        }
+
+        return nil
+    }
+
+    func verifySignature(account: String, signature: String, userId: String, metadata: E2eeV20.Metadata, users: [E2eeV20.Users]?, version: String, certificate: String) -> Bool {
+
+        guard let users else { return false }
+
+        var usersSignatureCodable: [E2eeV20Signature.Users] = []
+        for user in users {
+            usersSignatureCodable.append(E2eeV20Signature.Users(userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey))
+        }
+        let signatureCodable = E2eeV20Signature(metadata: E2eeV20Signature.Metadata(ciphertext: metadata.ciphertext, nonce: metadata.nonce, authenticationTag: metadata.authenticationTag), users: usersSignatureCodable, version: version)
+
+        do {
+            let jsonEncoder = JSONEncoder()
+            let json = try jsonEncoder.encode(signatureCodable)
+            let dataSerialization = try JSONSerialization.jsonObject(with: json, options: [])
+            let decoded = try? JSONSerialization.data(withJSONObject: dataSerialization, options: [.sortedKeys, .withoutEscapingSlashes])
+            let base64 = decoded!.base64EncodedString()
+            if let base64Data = base64.data(using: .utf8),
+               let signatureData = Data(base64Encoded: signature) {
+                let certificates = users.map { $0.certificate }
+                return NCEndToEndEncryption.sharedManager().verifySignatureCMS(signatureData, data: base64Data, certificates: certificates)
+            }
+
+        } catch {
+            print("Error: \(error.localizedDescription)")
+        }
+
+        return false
+    }
+}

+ 36 - 11
iOSClient/Networking/E2EE/NCNetworkingE2EE.swift

@@ -31,15 +31,6 @@ class NCNetworkingE2EE: NSObject {
         return instance
     }()
 
-    func isE2EEVersionWriteable(account: String) -> NKError? {
-
-        if NCGlobal.shared.e2eeReadVersions.last == NCGlobal.shared.capabilityE2EEApiVersion {
-            return nil
-        }
-        
-        return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_e2e_error_not_versionwriteable_")
-    }
-
     func generateRandomIdentifier() -> String {
 
         var UUID = NSUUID().uuidString
@@ -47,19 +38,53 @@ class NCNetworkingE2EE: NSObject {
         return UUID
     }
 
+    func uploadMetadata(account: String, serverUrl: String, userId: String, addUserId: String?, removeUserId: String?) async -> (NKError) {
+
+        var error = NKError()
+        var addCertificate: String?
+
+        if let addUserId {
+            let results = await NextcloudKit.shared.getE2EECertificate(user: addUserId)
+            if results.error == .success, let certificateUser = results.certificateUser {
+                addCertificate = certificateUser
+            } else {
+                return results.error
+            }
+        }
+
+        let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: account, serverUrl: serverUrl, userId: userId, addUserId: addUserId, addCertificate: addCertificate, removeUserId: removeUserId)
+        guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata, let signature = resultsEncode.signature else { return resultsEncode.error }
+
+        let results = await NCNetworkingE2EE.shared.lock(account: account, serverUrl: serverUrl)
+        error = results.error
+        if error == .success, let e2eToken = results.e2eToken, let fileId = results.fileId {
+            let results = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: signature, method: "PUT")
+            error = results.error
+        }
+
+        await NCNetworkingE2EE.shared.unlock(account: account, serverUrl: serverUrl)
+        return error
+    }
+
     func lock(account: String, serverUrl: String) async -> (fileId: String?, e2eToken: String?, error: NKError) {
 
         var e2eToken: String?
+        let e2EEApiVersion = NCGlobal.shared.capabilityE2EEApiVersion
+        var e2eCounter = "0"
 
         guard let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) else {
-            return (nil, nil, NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_e2e_error_lock_"))
+            return (nil, nil, NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_e2e_error_"))
         }
 
         if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) {
             e2eToken = tableLock.e2eToken
         }
 
-        let lockE2EEFolderResults = await NextcloudKit.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, e2eCounter: nil, method: "POST")
+        if e2EEApiVersion == NCGlobal.shared.e2eeVersionV20, let result = NCManageDatabase.shared.getE2eMetadataV2(account: account, ocIdServerUrl: directory.ocId) {
+            e2eCounter = "\(result.counter)"
+        }
+
+        let lockE2EEFolderResults = await NextcloudKit.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, e2eCounter: e2eCounter, method: "POST")
         if lockE2EEFolderResults.error == .success, let e2eToken = lockE2EEFolderResults.e2eToken {
             NCManageDatabase.shared.setE2ETokenLock(account: account, serverUrl: serverUrl, fileId: directory.fileId, e2eToken: e2eToken)
         }

+ 26 - 31
iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift

@@ -32,18 +32,16 @@ class NCNetworkingE2EECreateFolder: NSObject {
         return instance
     }()
 
-    func createFolderAndMarkE2EE(fileName: String, serverUrl: String, account: String) async -> NKError {
-
-        if let error = NCNetworkingE2EE.shared.isE2EEVersionWriteable(account: account) {
-            return error
-        }
+    func createFolderAndMarkE2EE(fileName: String, serverUrl: String, account: String, userId: String, createFolder: Bool) async -> NKError {
 
         let serverUrlFileName = serverUrl + "/" + fileName
         var error = NKError()
 
         // CREATE FOLDER
-        let createFolderResults = await NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlFileName)
-        if createFolderResults.error != .success { return createFolderResults.error }
+        if createFolder {
+            let createFolderResults = await NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlFileName)
+            if createFolderResults.error != .success { return createFolderResults.error }
+        }
 
         let readFileOrFolderResults = await NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0")
         error = readFileOrFolderResults.error
@@ -65,8 +63,10 @@ class NCNetworkingE2EECreateFolder: NSObject {
             let lockResults = await NCNetworkingE2EE.shared.lock(account: account, serverUrl: serverUrlFileName)
             if lockResults.error != .success { return lockResults.error }
 
-            let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata([], account: account, serverUrl: serverUrlFileName)
-            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: file.fileId, e2eToken: lockResults.e2eToken!, e2eMetadata: e2eMetadataNew, signature: nil, method: "POST")
+            let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: account, serverUrl: serverUrlFileName, userId: userId)
+            guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata else { return resultsEncode.error }
+
+            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: file.fileId, e2eToken: lockResults.e2eToken!, e2eMetadata: e2eMetadata, signature: resultsEncode.signature, method: "POST")
             error = putE2EEMetadataResults.error
 
             // UNLOCK
@@ -80,10 +80,6 @@ class NCNetworkingE2EECreateFolder: NSObject {
 
     func createFolder(fileName: String, serverUrl: String, account: String, urlBase: String, userId: String, withPush: Bool) async -> (NKError) {
 
-        if let error = NCNetworkingE2EE.shared.isE2EEVersionWriteable(account: account) {
-            return error
-        }
-        
         var fileNameFolder = CCUtility.removeForbiddenCharactersServer(fileName)!
         var serverUrlFileName = ""
         var fileNameIdentifier = ""
@@ -109,7 +105,7 @@ class NCNetworkingE2EECreateFolder: NSObject {
                 let markE2EEFolderResults = await NextcloudKit.shared.markE2EEFolder(fileId: fileId, delete: false)
                 error = markE2EEFolderResults.error
                 if error == .success {
-                    error = await createE2Ee(e2eToken: e2eToken, fileIdLock: fileIdLock, account: account, fileNameFolder: fileNameFolder, fileNameIdentifier: fileNameIdentifier, serverUrl: serverUrl, urlBase: urlBase, userId: userId)
+                    error = await createE2Ee(e2eToken: e2eToken, fileIdLock: fileIdLock, account: account, fileNameFolder: fileNameFolder, fileNameIdentifier: fileNameIdentifier, serverUrl: serverUrl, ocIdServerUrl: ocId!, urlBase: urlBase, userId: userId)
                 }
             }
         }
@@ -123,28 +119,27 @@ class NCNetworkingE2EECreateFolder: NSObject {
         return error
     }
 
-    private func createE2Ee(e2eToken: String, fileIdLock: String, account: String, fileNameFolder: String, fileNameIdentifier: String, serverUrl: String,  urlBase: String, userId: String) async -> (NKError) {
+    private func createE2Ee(e2eToken: String, fileIdLock: String, account: String, fileNameFolder: String, fileNameIdentifier: String, serverUrl: String, ocIdServerUrl: String, urlBase: String, userId: String) async -> (NKError) {
 
         var key: NSString?
         var initializationVector: NSString?
-        let object = tableE2eEncryption()
         var method = "POST"
 
         // Get last metadata
-        let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileIdLock, e2eToken: e2eToken)
-        if getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata {
-            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, ownerId: nil)
-            if result.error != .success { return result.error }
+        let results = await NextcloudKit.shared.getE2EEMetadata(fileId: fileIdLock, e2eToken: e2eToken)
+        if results.error == .success, let e2eMetadata = results.e2eMetadata {
+            let error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: results.signature, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, ownerId: nil)
+            if error != .success { return error }
             method = "PUT"
         }
 
         // Add new metadata
         NCEndToEndEncryption.sharedManager()?.encodedkey(&key, initializationVector: &initializationVector)
-        object.account = account
+
+        let object = tableE2eEncryption.init(account: account, ocIdServerUrl: ocIdServerUrl, fileNameIdentifier: fileNameIdentifier)
+        object.blob = "folders"
         object.authenticationTag = ""
         object.fileName = fileNameFolder
-        object.fileNameIdentifier = fileNameIdentifier
-        object.fileNamePath = ""
         object.key = key! as String
         object.initializationVector = initializationVector! as String
         if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) {
@@ -158,17 +153,15 @@ class NCNetworkingE2EECreateFolder: NSObject {
         object.serverUrl = serverUrl
         NCManageDatabase.shared.addE2eEncryption(object)
 
-        // Rebuild metadata for send it
-        guard let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)), let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: account, serverUrl: serverUrl) else {
-            return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
-        }
+        let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: account, serverUrl: serverUrl, userId: userId)
+        guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata else { return resultsEncode.error }
 
         // send metadata
-        let putE2EEMetadataResults =  await NextcloudKit.shared.putE2EEMetadata(fileId: fileIdLock, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, signature: nil, method: method)
+        let putE2EEMetadataResults =  await NextcloudKit.shared.putE2EEMetadata(fileId: fileIdLock, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: resultsEncode.signature, method: method)
         return putE2EEMetadataResults.error
     }
 
-    func markE2EEFolder(account: String, serverUrl: String, fileId: String, ocId: String) async -> (NKError) {
+    func markE2EEFolder(account: String, serverUrl: String, fileId: String, ocId: String, userId: String) async -> (NKError) {
 
         let markE2EEFolderResult = await NextcloudKit.shared.markE2EEFolder(fileId: fileId, delete: false)
         if markE2EEFolderResult.error != .success { return markE2EEFolderResult.error }
@@ -181,8 +174,10 @@ class NCNetworkingE2EECreateFolder: NSObject {
         let lockResults = await NCNetworkingE2EE.shared.lock(account: account, serverUrl: serverUrl)
         if lockResults.error != .success { return lockResults.error }
 
-        let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata([], account: account, serverUrl: serverUrl)
-        let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: lockResults.e2eToken!, e2eMetadata: e2eMetadataNew, signature: nil, method: "POST")
+        let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: account, serverUrl: serverUrl, userId: userId)
+        guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata else { return resultsEncode.error }
+        
+        let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: lockResults.e2eToken!, e2eMetadata: e2eMetadata, signature: resultsEncode.signature, method: "POST")
         let error = putE2EEMetadataResults.error
 
         // UNLOCK

+ 8 - 21
iOSClient/Networking/E2EE/NCNetworkingE2EEDelete.swift

@@ -34,39 +34,27 @@ class NCNetworkingE2EEDelete: NSObject {
 
     func delete(metadata: tableMetadata) async -> (NKError) {
 
-        if let error = NCNetworkingE2EE.shared.isE2EEVersionWriteable(account: metadata.account) {
-            return error
-        }
-
         var error = NKError()
 
         func sendE2EMetadata(e2eToken: String, fileId: String) async -> (NKError) {
 
-            var e2eMetadataNew: String?
-
             // Get last metadata
-            let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
-
-            guard getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata else {
-                return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
+            let results = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
+            guard results.error == .success, let e2eMetadata = results.e2eMetadata else {
+                return NKError(errorCode: NCGlobal.shared.errorE2EEKeyEncodeMetadata, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
             }
 
-            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
-            if result.error != .success { return result.error }
+            let error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: results.signature, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
+            if error != .success { return error }
 
             // delete
             NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", metadata.account, metadata.serverUrl, metadata.fileName))
 
-            // Rebuild metadata
-            if let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) {
-                e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: metadata.account, serverUrl: metadata.serverUrl)
-            } else {
-                e2eMetadataNew = NCEndToEndMetadata().encoderMetadata([], account: metadata.account, serverUrl: metadata.serverUrl)
-            }
+            let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: metadata.account, serverUrl: metadata.serverUrl, userId: metadata.userId)
+            guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata else { return resultsEncode.error }
 
             // Send metadata
-            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, signature: nil, method: "PUT")
-            
+            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: resultsEncode.signature, method: "PUT")
             return putE2EEMetadataResults.error
         }
 
@@ -86,7 +74,6 @@ class NCNetworkingE2EEDelete: NSObject {
 
         // ** Unlock **
         await NCNetworkingE2EE.shared.unlock(account: metadata.account, serverUrl: metadata.serverUrl)
-        
         return error
     }
 }

+ 10 - 17
iOSClient/Networking/E2EE/NCNetworkingE2EERename.swift

@@ -34,40 +34,33 @@ class NCNetworkingE2EERename: NSObject {
 
     func rename(metadata: tableMetadata, fileNameNew: String, indexPath: IndexPath) async -> (NKError) {
 
-        if let error = NCNetworkingE2EE.shared.isE2EEVersionWriteable(account: metadata.account) {
-            return error
-        }
-        
         var error = NKError()
 
         func sendE2EMetadata(e2eToken: String, fileId: String) async -> (NKError) {
 
             // Get last metadata
-            let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
-            guard getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata else {
-                return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
+            let results = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
+            guard results.error == .success, let e2eMetadata = results.e2eMetadata else {
+                return results.error
             }
 
-            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
-            if result.error != .success { return result.error }
+            error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: results.signature, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
+            if error != .success { return error }
 
             // rename
-            NCManageDatabase.shared.renameFileE2eEncryption(serverUrl: metadata.serverUrl, fileNameIdentifier: metadata.fileName, newFileName: fileNameNew, newFileNamePath: CCUtility.returnFileNamePath(fromFileName: fileNameNew, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId, account: metadata.account))
+            NCManageDatabase.shared.renameFileE2eEncryption(account: metadata.account, serverUrl: metadata.serverUrl, fileNameIdentifier: metadata.fileName, newFileName: fileNameNew, newFileNamePath: CCUtility.returnFileNamePath(fromFileName: fileNameNew, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId, account: metadata.account))
 
-            // Rebuild metadata
-            guard let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)), let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: metadata.account, serverUrl: metadata.serverUrl) else {
-                return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
-            }
+            let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: metadata.account, serverUrl: metadata.serverUrl, userId: metadata.userId)
+            guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata else { return resultsEncode.error }
 
             // send metadata
-            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, signature: nil, method: "PUT")
-            
+            let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: resultsEncode.signature, method: "PUT")
             return putE2EEMetadataResults.error
         }
 
         // verify if exists the new fileName
         if NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, fileNameNew)) != nil {
-            return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_file_already_exists_")
+            return NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_file_already_exists_")
         }
 
         // ** Lock **

+ 33 - 42
iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift

@@ -44,15 +44,8 @@ class NCNetworkingE2EEUpload: NSObject {
 
     func upload(metadata: tableMetadata, uploadE2EEDelegate: uploadE2EEDelegate? = nil) async -> (NKError) {
 
-        if let error = NCNetworkingE2EE.shared.isE2EEVersionWriteable(account: metadata.account) {
-            NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
-            NCContentPresenter.shared.showError(error: error)
-            return error
-        }
-
         var metadata = tableMetadata.init(value: metadata)
         let ocIdTemp = metadata.ocId
-        let errorCreateEncrypted = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_e2e_error_create_encrypted_")
 
         // Create metadata for upload
         if let result = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "serverUrl == %@ AND fileNameView == %@ AND ocId != %@", metadata.serverUrl, metadata.fileNameView, metadata.ocId)) {
@@ -62,7 +55,13 @@ class NCNetworkingE2EEUpload: NSObject {
         }
         metadata.session = NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload
         metadata.sessionError = ""
-        guard let result = NCManageDatabase.shared.addMetadata(metadata) else { return errorCreateEncrypted }
+        guard let result = NCManageDatabase.shared.addMetadata(metadata) else {
+            return NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
+            
+        }
+        guard let directory = NCManageDatabase.shared.getTableDirectory(predicate:  NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) else {
+            return NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
+        }
         metadata = result
 
         // ** Lock **
@@ -70,19 +69,18 @@ class NCNetworkingE2EEUpload: NSObject {
 
         guard let e2eToken = lockResults.e2eToken, let fileId = lockResults.fileId, lockResults.error == .success else {
             NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))
-            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_e2e_error_create_encrypted_")])
-            return errorCreateEncrypted
+            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": NKError(errorCode: NCGlobal.shared.errorE2EELock, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))])
+            return NKError(errorCode: NCGlobal.shared.errorE2EELock, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
         }
 
         // Send e2e metadata
-        let createE2EeError = await createE2Ee(metadata: metadata, e2eToken: e2eToken, fileId: fileId)
+        let createE2EeError = await createE2Ee(metadata: metadata, e2eToken: e2eToken, ocIdServerUrl: directory.ocId, fileId: fileId)
         guard createE2EeError == .success else {
             // ** Unlock **
             await NCNetworkingE2EE.shared.unlock(account: metadata.account, serverUrl: metadata.serverUrl)
-
             NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))
             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": createE2EeError])
-            return errorCreateEncrypted
+            return createE2EeError
         }
 
         // Send file
@@ -126,22 +124,20 @@ class NCNetworkingE2EEUpload: NSObject {
         return(sendFileResults.error)
     }
 
-    private func createE2Ee(metadata: tableMetadata, e2eToken: String, fileId: String) async -> (NKError) {
+    private func createE2Ee(metadata: tableMetadata, e2eToken: String, ocIdServerUrl: String, fileId: String) async -> (NKError) {
 
         var key: NSString?, initializationVector: NSString?, authenticationTag: NSString?
-        let objectE2eEncryption = tableE2eEncryption()
-        let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)!
         var method = "POST"
 
         if NCEndToEndEncryption.sharedManager()?.encryptFile(metadata.fileNameView, fileNameIdentifier: metadata.fileName, directory: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId), key: &key, initializationVector: &initializationVector, authenticationTag: &authenticationTag) == false {
-            return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_e2e_error_create_encrypted_")
+            return NKError(errorCode: NCGlobal.shared.errorE2EEEncryptFile, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
         }
 
         // Get last metadata
-        let getE2EEMetadataResults = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
-        if getE2EEMetadataResults.error == .success, let e2eMetadata = getE2EEMetadataResults.e2eMetadata {
-            let result = NCEndToEndMetadata().decoderMetadata(e2eMetadata, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
-            if result.error != .success { return result.error }
+        let results = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
+        if results.error == .success, let e2eMetadata = results.e2eMetadata {
+            let error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: results.signature, serverUrl: metadata.serverUrl, account: metadata.account, urlBase: metadata.urlBase, userId: metadata.userId, ownerId: metadata.ownerId)
+            if error != .success { return error }
             method = "PUT"
         }
 
@@ -149,33 +145,28 @@ class NCNetworkingE2EEUpload: NSObject {
         NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, metadata.fileNameView))
 
         // Add new metadata
+        let object = tableE2eEncryption.init(account: metadata.account, ocIdServerUrl: ocIdServerUrl, fileNameIdentifier: metadata.fileName)
         if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) {
-            objectE2eEncryption.metadataKey = result.metadataKey
-            objectE2eEncryption.metadataKeyIndex = result.metadataKeyIndex
+            object.metadataKey = result.metadataKey
+            object.metadataKeyIndex = result.metadataKeyIndex
         } else {
             let key = NCEndToEndEncryption.sharedManager()?.generateKey() as NSData?
-            objectE2eEncryption.metadataKey = key!.base64EncodedString()
-            objectE2eEncryption.metadataKeyIndex = 0
-        }
-        objectE2eEncryption.account = metadata.account
-        objectE2eEncryption.authenticationTag = authenticationTag! as String
-        objectE2eEncryption.fileName = metadata.fileNameView
-        objectE2eEncryption.fileNameIdentifier = metadata.fileName
-        objectE2eEncryption.fileNamePath = fileNameLocalPath
-        objectE2eEncryption.key = key! as String
-        objectE2eEncryption.initializationVector = initializationVector! as String
-        objectE2eEncryption.mimeType = metadata.contentType
-        objectE2eEncryption.serverUrl = metadata.serverUrl
-        NCManageDatabase.shared.addE2eEncryption(objectE2eEncryption)
-
-        // Rebuild metadata
-        guard let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)),
-              let e2eMetadataNew = NCEndToEndMetadata().encoderMetadata(tableE2eEncryption, account: metadata.account, serverUrl: metadata.serverUrl) else {
-            return NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_e2e_error_encode_metadata_", comment: ""))
+            object.metadataKey = key!.base64EncodedString()
+            object.metadataKeyIndex = 0
         }
+        object.authenticationTag = authenticationTag! as String
+        object.fileName = metadata.fileNameView
+        object.key = key! as String
+        object.initializationVector = initializationVector! as String
+        object.mimeType = metadata.contentType
+        object.serverUrl = metadata.serverUrl
+        NCManageDatabase.shared.addE2eEncryption(object)
+
+        let resultsEncode = NCEndToEndMetadata().encodeMetadata(account: metadata.account, serverUrl: metadata.serverUrl, userId: metadata.userId)
+        guard resultsEncode.error == .success, let e2eMetadata = resultsEncode.metadata else { return resultsEncode.error }
 
         // send metadata
-        let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadataNew, signature: nil, method: method)
+        let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: resultsEncode.signature, method: method)
         
         return putE2EEMetadataResults.error
     }

+ 3 - 3
iOSClient/Networking/NCNetworking.swift

@@ -125,10 +125,11 @@ class NCNetworking: NSObject, NKCommonDelegate {
 
     func networkReachabilityObserver(_ typeReachability: NKCommon.TypeReachability) {
 
-#if !EXTENSION
         if typeReachability == NKCommon.TypeReachability.reachableCellular || typeReachability == NKCommon.TypeReachability.reachableEthernetOrWiFi {
             if !lastReachability {
+#if !EXTENSION
                 NCService.shared.startRequestServicesServer()
+#endif
             }
             lastReachability = true
         } else {
@@ -139,7 +140,6 @@ class NCNetworking: NSObject, NKCommonDelegate {
             lastReachability = false
         }
         networkReachability = typeReachability
-#endif
     }
 
     func authenticationChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
@@ -1150,7 +1150,7 @@ class NCNetworking: NSObject, NKCommonDelegate {
 
     func createFolder(fileName: String, serverUrl: String, account: String, urlBase: String, userId: String, overwrite: Bool = false, withPush:Bool, completion: @escaping (_ error: NKError) -> Void) {
 
-        let isDirectoryEncrypted = NCUtility.shared.isDirectoryE2EE(serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId)
+        let isDirectoryEncrypted = NCUtility.shared.isDirectoryE2EE(account: account, urlBase: urlBase, userId: userId, serverUrl: serverUrl)
         let fileName = fileName.trimmingCharacters(in: .whitespacesAndNewlines)
         
         if isDirectoryEncrypted {

+ 10 - 2
iOSClient/Settings/NCEndToEndInitialize.swift

@@ -153,7 +153,7 @@ class NCEndToEndInitialize: NSObject {
 
                     let publicKey = CCUtility.getEndToEndCertificate(self.appDelegate.account)
 
-                    if let privateKeyData = (NCEndToEndEncryption.sharedManager().decryptPrivateKey(privateKeyChiper, passphrase: passphrase, publicKey: publicKey)),
+                    if let privateKeyData = (NCEndToEndEncryption.sharedManager().decryptPrivateKey(privateKeyChiper, passphrase: passphrase, publicKey: publicKey, iterationCount: 1024)),
                        let keyData = Data(base64Encoded: privateKeyData) {
                         let privateKey = String(data: keyData, encoding: .utf8)
                         CCUtility.setEndToEndPrivateKey(self.appDelegate.account, privateKey: privateKey)
@@ -178,6 +178,10 @@ class NCEndToEndInitialize: NSObject {
                             // Clear Table
                             NCManageDatabase.shared.clearTable(tableDirectory.self, account: account)
                             NCManageDatabase.shared.clearTable(tableE2eEncryption.self, account: account)
+                            NCManageDatabase.shared.clearTable(tableE2eEncryptionLock.self, account: account)
+                            NCManageDatabase.shared.clearTable(tableE2eMetadata.self, account: account)
+                            NCManageDatabase.shared.clearTable(tableE2eMetadataV2.self, account: account)
+                            NCManageDatabase.shared.clearTable(tableE2eUsersV2.self, account: account)
 
                             self.delegate?.endToEndInitializeSuccess()
 
@@ -259,7 +263,7 @@ class NCEndToEndInitialize: NSObject {
 
         var privateKeyString: NSString?
 
-        guard let privateKeyChiper = NCEndToEndEncryption.sharedManager().encryptPrivateKey(self.appDelegate.userId, directory: CCUtility.getDirectoryUserData(), passphrase: e2ePassphrase, privateKey: &privateKeyString) else {
+        guard let privateKeyChiper = NCEndToEndEncryption.sharedManager().encryptPrivateKey(self.appDelegate.userId, directory: CCUtility.getDirectoryUserData(), passphrase: e2ePassphrase, privateKey: &privateKeyString, iterationCount: 1024) else {
             let error = NKError(errorCode: error.errorCode, errorDescription: "Serious internal error to create PrivateKey chiper")
             NCContentPresenter.shared.messageNotification("E2E privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, priority: .max)
             return
@@ -285,6 +289,10 @@ class NCEndToEndInitialize: NSObject {
                         // Clear Table
                         NCManageDatabase.shared.clearTable(tableDirectory.self, account: account)
                         NCManageDatabase.shared.clearTable(tableE2eEncryption.self, account: account)
+                        NCManageDatabase.shared.clearTable(tableE2eEncryptionLock.self, account: account)
+                        NCManageDatabase.shared.clearTable(tableE2eMetadata.self, account: account)
+                        NCManageDatabase.shared.clearTable(tableE2eMetadataV2.self, account: account)
+                        NCManageDatabase.shared.clearTable(tableE2eUsersV2.self, account: account)
 
                         if copyPassphrase {
                             UIPasteboard.general.string = e2ePassphrase

+ 1 - 1
iOSClient/Settings/NCSettings.m

@@ -124,7 +124,7 @@
     BOOL isE2EEEnabled = [[NCGlobal shared] capabilityE2EEEnabled];
     NSString *versionE2EE = [[NCGlobal shared] capabilityE2EEApiVersion];
 
-    if (isE2EEEnabled == YES && [NCGlobal.shared.e2eeReadVersions containsObject:versionE2EE]) {
+    if (isE2EEEnabled == YES && [NCGlobal.shared.e2eeVersions containsObject:versionE2EE]) {
 
         section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_e2e_settings_title_", nil)];
         [form addFormSection:section];

+ 14 - 4
iOSClient/Share/Advanced/NCShareAdvancePermission.swift

@@ -45,10 +45,20 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
             self.present(alert, animated: true)
             return
         }
-        if isNewShare {
-            networking?.createShare(option: share)
-        } else {
-            networking?.updateShare(option: share)
+        Task {
+            if isNewShare {
+                if metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
+                    let serverUrl = metadata.serverUrl + "/" + metadata.fileName
+                    let error = await NCNetworkingE2EE.shared.uploadMetadata(account: metadata.account, serverUrl: serverUrl, userId: metadata.userId, addUserId: share.shareWith, removeUserId: nil)
+                    if error != .success {
+                        NCContentPresenter.shared.showError(error: error)
+                        return
+                    }
+                }
+                networking?.createShare(option: share)
+            } else {
+                networking?.updateShare(option: share)
+            }
         }
         navigationController?.popViewController(animated: true)
     }

+ 1 - 1
iOSClient/Share/Advanced/NCShareCells.swift

@@ -90,7 +90,7 @@ enum NCUserPermission: CaseIterable, NCPermission {
 
     case reshare, edit, create, delete, download
     static let forDirectory: [NCUserPermission] = NCUserPermission.allCases
-    static let forDirectoryE2EE: [NCUserPermission] = []
+    static let forDirectoryE2EE: [NCUserPermission] = NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 ? NCUserPermission.allCases : []
     static let forFile: [NCUserPermission] = [.reshare, .edit]
 
     var title: String {

+ 1 - 1
iOSClient/Share/NCShare+Helper.swift

@@ -81,7 +81,7 @@ class NCTableShareOptions: NCTableShareable {
     var attributes: String?
 
     private init(shareType: Int, metadata: tableMetadata, password: String?) {
-        if metadata.e2eEncrypted {
+        if metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
             self.permissions = NCGlobal.shared.permissionCreateShare
         } else {
             self.permissions = NCGlobal.shared.capabilityFileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices

+ 5 - 5
iOSClient/Share/NCShare.swift

@@ -84,12 +84,12 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
 
         guard let metadata = metadata else { return }
 
-        if metadata.e2eEncrypted {
+        if metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
             searchFieldTopConstraint.constant = -50
             searchField.isHidden = true
-        } else {
+         } else {
             checkSharedWithYou()
-        }
+         }
 
         reloadData()
 
@@ -301,7 +301,7 @@ extension NCShare: UITableViewDataSource {
         guard let metadata = self.metadata else { return 0}
         var numRows = shares.share?.count ?? 0
         if section == 0 {
-            if metadata.e2eEncrypted {
+            if metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
                 numRows = 1
             } else {
                 // don't allow link creation if reshare is disabled
@@ -317,7 +317,7 @@ extension NCShare: UITableViewDataSource {
             guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell, let metadata = self.metadata
             else { return UITableViewCell() }
             cell.delegate = self
-            if metadata.e2eEncrypted {
+            if metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
                 cell.tableShare = shares.firstShareLink
             } else {
                 if indexPath.row == 0 {

+ 1 - 1
iOSClient/Share/NCSharePaging.swift

@@ -95,7 +95,7 @@ class NCSharePaging: UIViewController {
         } else {
             pagingViewController.select(index: 0)
         }
-       
+
         (pagingViewController.view as? NCSharePagingView)?.setupConstraints()
         pagingViewController.reloadMenu()
     }

+ 1 - 19
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -47,7 +47,6 @@
 "_save_"                    = "Save";
 "_warning_"                 = "Warning";
 "_error_"                   = "Error";
-"_error_e2ee_"              = "Error E2EE";
 "_no_"                      = "No";
 "_yes_"                     = "Yes";
 "_select_"                  = "Select";
@@ -707,24 +706,7 @@
 "_e2e_set_folder_encrypted_"        = "Encrypt";
 "_e2e_remove_folder_encrypted_"     = "Decrypt";
 "_e2e_goto_settings_for_enable_"    = "This is an encrypted directory, go to \"Settings\" and enable end-to-end encryption";
-"_e2e_delete_folder_not_permitted_" = "Deletion of the directory marked as \"encrypted\" is not allowed";
-"_e2e_error_encode_metadata_"       = "Serious internal error in encoding metadata";
-"_e2e_error_decode_metadata_"       = "Serious internal error in decoding metadata";
-"_e2e_error_create_encrypted_"      = "Could not create encrypted file";
-"_e2e_error_update_metadata_"       = "Update metadata error";
-"_e2e_error_store_metadata_"        = "Could not save metadata";
-"_e2e_error_send_metadata_"         = "Could not send metadata";
-"_e2e_error_delete_metadata_"       = "Could not delete metadata";
-"_e2e_error_get_metadata_"          = "Could not fetch metadata";
-"_e2e_error_not_enabled_"           = "Serious internal error. End-to-end encryption not enabled";
-"_e2e_error_record_not_found_"      = "Serious internal error. Records not found";
-"_e2e_error_unlock_"                = "Could not unlock folder";
-"_e2e_error_lock_"                  = "Could not lock folder";
-"_e2e_error_delete_mark_folder_"    = "Decrypt marked folder";
-"_e2e_error_mark_folder_"           = "Encrypt folder";
-"_e2e_error_directory_not_empty_"   = "The directory is not empty";
-"_e2e_error_not_move_"              = "It is not possible move files to encrypted directory";
-"_e2e_error_not_versionwriteable_"  = "The E2EE version of the server is not compatible with this client";
+"_e2e_error_"                       = "Serious internal error end-to-end encryption";
 "_scans_document_"                  = "Scan document";
 "_scanned_images_"                  = "Scanned images";
 "_scan_document_pdf_page_"          = "Page";

+ 1 - 1
iOSClient/Utility/CCUtility.m

@@ -372,7 +372,7 @@
     NSString *privateKey = [self getEndToEndPrivateKey:account];
     NSString *passphrase = [self getEndToEndPassphrase:account];
             
-    if (passphrase.length > 0 && privateKey.length > 0 && certificate.length > 0 && publicKey.length > 0 && isE2EEEnabled && [NCGlobal.shared.e2eeReadVersions containsObject:versionE2EE]) {
+    if (passphrase.length > 0 && privateKey.length > 0 && certificate.length > 0 && publicKey.length > 0 && isE2EEEnabled && [NCGlobal.shared.e2eeVersions containsObject:versionE2EE]) {
         return YES;
     } else {
         return NO;

+ 35 - 4
iOSClient/Utility/NCUtility.swift

@@ -748,19 +748,50 @@ class NCUtility: NSObject {
     }
 
     func isDirectoryE2EE(serverUrl: String, userBase: NCUserBaseUrl) -> Bool {
-        return isDirectoryE2EE(serverUrl: serverUrl, account: userBase.account, urlBase: userBase.urlBase, userId: userBase.userId)
+        return isDirectoryE2EE(account: userBase.account, urlBase: userBase.urlBase, userId: userBase.userId, serverUrl: serverUrl)
     }
+
     func isDirectoryE2EE(file: NKFile) -> Bool {
-        return isDirectoryE2EE(serverUrl: file.serverUrl, account: file.account, urlBase: file.urlBase, userId: file.userId)
+        return isDirectoryE2EE(account: file.account, urlBase: file.urlBase, userId: file.userId, serverUrl: file.serverUrl)
     }
-    @objc func isDirectoryE2EE(serverUrl: String, account: String, urlBase: String, userId: String) -> Bool {
+
+    func isDirectoryE2EE(account: String, urlBase: String, userId: String, serverUrl: String) -> Bool {
         if serverUrl == NCUtilityFileSystem.shared.getHomeServer(urlBase: urlBase, userId: userId) || serverUrl == ".." { return false }
-        if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) {
+        if let directory = NCManageDatabase.shared.getTableDirectory(account: account, serverUrl: serverUrl) {
             return directory.e2eEncrypted
         }
         return false
     }
 
+    func isDirectoryE2EETop(account: String, serverUrl: String) -> Bool {
+        if let url = URL(string: serverUrl)?.deletingLastPathComponent() {
+            if let directory = NCManageDatabase.shared.getTableDirectory(account: account, serverUrl: String(url.absoluteString.dropLast())) {
+                return !directory.e2eEncrypted
+            }
+        }
+        return true
+    }
+
+    func getDirectoryE2EETop(serverUrl: String, account: String) -> tableDirectory? {
+
+        var serverUrl = serverUrl
+        var top: tableDirectory?
+
+        while let url = URL(string: serverUrl)?.deletingLastPathComponent(),
+              let directory = NCManageDatabase.shared.getTableDirectory(account: account, serverUrl: serverUrl) {
+
+            if directory.e2eEncrypted {
+                top = directory
+            } else {
+                return top
+            }
+
+            serverUrl = String(url.absoluteString.dropLast())
+        }
+
+        return top
+    }
+
     func createViewImageAndText(image: UIImage, title: String? = nil) -> UIView {
 
         let imageView = UIImageView()

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů