From 09de4e4968b01aeee8df26b5daf2b5e8d7cb7026 Mon Sep 17 00:00:00 2001 From: Philipp Schmid <25935690+phil1995@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:52:58 +0200 Subject: [PATCH 01/13] Fix background URLSession identifier collisions --- Cryptomator/AppDelegate.swift | 1 - .../Manager/CloudProviderDBManager.swift | 153 +++++++++++++----- .../Manager/VaultDBManager.swift | 3 +- .../RootViewController.swift | 1 - 4 files changed, 114 insertions(+), 44 deletions(-) diff --git a/Cryptomator/AppDelegate.swift b/Cryptomator/AppDelegate.swift index 729e12a5c..f8fdf6e23 100644 --- a/Cryptomator/AppDelegate.swift +++ b/Cryptomator/AppDelegate.swift @@ -38,7 +38,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { cleanup() // Set up cloud storage services - CloudProviderDBManager.shared.useBackgroundSession = false DropboxSetup.constants = DropboxSetup(appKey: CloudAccessSecrets.dropboxAppKey, sharedContainerIdentifier: nil, keychainService: CryptomatorConstants.mainAppBundleId, forceForegroundSession: true) GoogleDriveSetup.constants = GoogleDriveSetup(clientId: CloudAccessSecrets.googleDriveClientId, redirectURL: CloudAccessSecrets.googleDriveRedirectURL!, sharedContainerIdentifier: nil) let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) diff --git a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift index 4a52aee6e..7b5b725ad 100644 --- a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift +++ b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift @@ -12,16 +12,23 @@ import PCloudSDKSwift public protocol CloudProviderManager { func getProvider(with accountUID: String) throws -> CloudProvider + func getBackgroundSessionProvider(with accountUID: String, sessionIdentifier: String) throws -> CloudProvider } public protocol CloudProviderUpdating { func providerShouldUpdate(with accountUID: String) } +struct CachedProvider { + let accountUID: String + let provider: CloudProvider + let backgroundSessionIdentifier: String? + var isBackgroundSession: Bool { backgroundSessionIdentifier != nil } +} + public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating { - static var cachedProvider = [String: CloudProvider]() + static var cachedProvider = [CachedProvider]() public static let shared = CloudProviderDBManager(accountManager: CloudProviderAccountDBManager.shared) - public var useBackgroundSession = true let accountManager: CloudProviderAccountDBManager private let maxPageSizeForFileProvider = 500 @@ -31,17 +38,25 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating } public func getProvider(with accountUID: String) throws -> CloudProvider { - if let provider = CloudProviderDBManager.cachedProvider[accountUID] { - return provider + if let entry = CloudProviderDBManager.cachedProvider.first(where: { + $0.accountUID == accountUID && !$0.isBackgroundSession + }) { + return entry.provider + } + return try createProvider(for: accountUID) + } + + public func getBackgroundSessionProvider(with accountUID: String, sessionIdentifier: String) throws -> any CloudProvider { + if let entry = CloudProviderDBManager.cachedProvider.first(where: { + $0.accountUID == accountUID && $0.backgroundSessionIdentifier == sessionIdentifier + }) { + return entry.provider } return try createProvider(for: accountUID) } /** Creates and returns a cloud provider for the given `accountUID`. - - If `useBackgroundURLSession` is set to `true`, the number of returned items from a `fetchItemList(forFolderAt:pageToken:)` call is limited to 500. - This is necessary because otherwise memory limit problems can occur with folders with many items in the `FileProviderExtension` where a background `URLSession` is used. */ func createProvider(for accountUID: String) throws -> CloudProvider { let cloudProviderType = try accountManager.getCloudProviderType(for: accountUID) @@ -49,66 +64,122 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating switch cloudProviderType { case .dropbox: let credential = DropboxCredential(tokenUID: accountUID) - provider = DropboxCloudProvider(credential: credential, maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : .max) + provider = DropboxCloudProvider(credential: credential, maxPageSize: .max) case .googleDrive: let credential = GoogleDriveCredential(userID: accountUID) - provider = try GoogleDriveCloudProvider(credential: credential, - useBackgroundSession: useBackgroundSession, - maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : .max) + provider = try GoogleDriveCloudProvider(credential: credential, maxPageSize: .max) case .oneDrive: let credential = try OneDriveCredential(with: accountUID) - provider = try OneDriveCloudProvider(credential: credential, - useBackgroundSession: useBackgroundSession, - maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : .max) + provider = try OneDriveCloudProvider(credential: credential, maxPageSize: .max) case .pCloud: - provider = try createPCloudProvider(for: accountUID) + let credential = try PCloudCredential(userID: accountUID) + let client = PCloud.createClient(with: credential.user) + provider = try PCloudCloudProvider(client: client) case .webDAV: - guard let credential = WebDAVCredentialManager.shared.getCredentialFromKeychain(with: accountUID) else { + let credential = try getWebDAVCredential(for: accountUID) + let client = WebDAVClient(credential: credential) + provider = try WebDAVProvider(with: client, maxPageSize: .max) + case .localFileSystem: + guard let rootURL = try LocalFileSystemBookmarkManager.getBookmarkedRootURL(for: accountUID) else { throw CloudProviderAccountError.accountNotFoundError } - let client: WebDAVClient - if useBackgroundSession { - client = WebDAVClient.withBackgroundSession(credential: credential, sharedContainerIdentifier: CryptomatorConstants.appGroupName) - } else { - client = WebDAVClient(credential: credential) - } - provider = try WebDAVProvider(with: client, maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : .max) + provider = try LocalFileSystemProvider(rootURL: rootURL, maxPageSize: .max) + case .s3: + let credential = try getS3Credential(for: accountUID) + provider = try S3CloudProvider(credential: credential) + } + CloudProviderDBManager.cachedProvider.append( + .init( + accountUID: accountUID, + provider: provider, + backgroundSessionIdentifier: nil + ) + ) + return provider + } + + // swiftlint:disable:next orphaned_doc_comment + /** + Creates and returns a cloud provider for the given `accountUID` using a background URLSession with the given `sessionIdentifier`. + + The number of returned items from a `fetchItemList(forFolderAt:pageToken:)` call is limited to 500. + This is necessary because otherwise memory limit problems can occur with folders with many items in the `FileProviderExtension` where a background `URLSession` is used. + */ + // swiftlint:disable:next function_body_length + func createBackgroundSessionProvider(for accountUID: String, sessionIdentifier: String) throws -> CloudProvider { + let cloudProviderType = try accountManager.getCloudProviderType(for: accountUID) + let provider: CloudProvider + + switch cloudProviderType { + case .dropbox: + let credential = DropboxCredential(tokenUID: accountUID) + provider = DropboxCloudProvider(credential: credential, maxPageSize: maxPageSizeForFileProvider) + case .googleDrive: + let credential = GoogleDriveCredential(userID: accountUID) + provider = try GoogleDriveCloudProvider.withBackgroundSession( + credential: credential, + maxPageSize: maxPageSizeForFileProvider, + sessionIdentifier: sessionIdentifier, + sharedContainerIdentifier: CryptomatorConstants.appGroupName + ) + case .oneDrive: + let credential = try OneDriveCredential(with: accountUID) + provider = try OneDriveCloudProvider.withBackgroundSession( + credential: credential, + maxPageSize: maxPageSizeForFileProvider, + identifier: sessionIdentifier + ) + case .pCloud: + let credential = try PCloudCredential(userID: accountUID) + let client = PCloud.createBackgroundClient( + with: credential.user, + sessionIdentifier: sessionIdentifier, + sharedContainerIdentifier: CryptomatorConstants.appGroupName + ) + provider = try PCloudCloudProvider(client: client) + case .webDAV: + let credential = try getWebDAVCredential(for: accountUID) + let client = WebDAVClient.withBackgroundSession( + credential: credential, + sessionIdentifier: sessionIdentifier, + sharedContainerIdentifier: CryptomatorConstants.appGroupName + ) + provider = try WebDAVProvider(with: client, maxPageSize: maxPageSizeForFileProvider) case .localFileSystem: guard let rootURL = try LocalFileSystemBookmarkManager.getBookmarkedRootURL(for: accountUID) else { throw CloudProviderAccountError.accountNotFoundError } - provider = try LocalFileSystemProvider(rootURL: rootURL, maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : .max) + provider = try LocalFileSystemProvider(rootURL: rootURL, maxPageSize: maxPageSizeForFileProvider) case .s3: - provider = try createS3Provider(for: accountUID) + let credential = try getS3Credential(for: accountUID) + provider = try S3CloudProvider.withBackgroundSession(credential: credential, sharedContainerIdentifier: CryptomatorConstants.appGroupName) } - CloudProviderDBManager.cachedProvider[accountUID] = provider + CloudProviderDBManager.cachedProvider.append( + .init( + accountUID: accountUID, + provider: provider, + backgroundSessionIdentifier: sessionIdentifier + ) + ) return provider } - private func createS3Provider(for accountUID: String) throws -> CloudProvider { + private func getS3Credential(for accountUID: String) throws -> S3Credential { guard let credential = S3CredentialManager.shared.getCredential(with: accountUID) else { throw CloudProviderAccountError.accountNotFoundError } - if useBackgroundSession { - return try S3CloudProvider.withBackgroundSession(credential: credential, sharedContainerIdentifier: CryptomatorConstants.appGroupName) - } else { - return try S3CloudProvider(credential: credential) - } + return credential } - private func createPCloudProvider(for accountUID: String) throws -> CloudProvider { - let credential = try PCloudCredential(userID: accountUID) - let client: PCloudClient - if useBackgroundSession { - client = PCloud.createBackgroundClient(with: credential.user, sharedContainerIdentifier: CryptomatorConstants.appGroupName) - } else { - client = PCloud.createClient(with: credential.user) + private func getWebDAVCredential(for accountUID: String) throws -> WebDAVCredential { + guard let credential = WebDAVCredentialManager.shared.getCredentialFromKeychain(with: accountUID) else { + throw CloudProviderAccountError.accountNotFoundError } - return try PCloudCloudProvider(client: client) + return credential } public func providerShouldUpdate(with accountUID: String) { - CloudProviderDBManager.cachedProvider[accountUID] = nil + CloudProviderDBManager.cachedProvider.removeAll(where: { $0.accountUID == accountUID }) // call XPCService for FileProvider } } diff --git a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/VaultDBManager.swift b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/VaultDBManager.swift index 1c24c9aba..435baeb73 100644 --- a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/VaultDBManager.swift +++ b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/VaultDBManager.swift @@ -483,7 +483,8 @@ public class VaultDBManager: VaultManager { private func createVaultProvider(cachedVault: CachedVault, masterkey: Masterkey, masterkeyFile: MasterkeyFile) throws -> CloudProvider { let vaultUID = cachedVault.vaultUID let vaultAccount = try vaultAccountManager.getAccount(with: vaultUID) - let provider = try providerManager.getProvider(with: vaultAccount.delegateAccountUID) + // it's important to use the vaultUID as background URLSession identifier to avoid identifier collisions + let provider = try providerManager.getBackgroundSessionProvider(with: vaultAccount.delegateAccountUID, sessionIdentifier: vaultUID) let decorator: CloudProvider if let vaultConfigToken = cachedVault.vaultConfigToken { let unverifiedVaultConfig = try UnverifiedVaultConfig(token: vaultConfigToken) diff --git a/FileProviderExtensionUI/RootViewController.swift b/FileProviderExtensionUI/RootViewController.swift index 99f427bbf..35feadd20 100644 --- a/FileProviderExtensionUI/RootViewController.swift +++ b/FileProviderExtensionUI/RootViewController.swift @@ -61,7 +61,6 @@ class RootViewController: FPUIActionExtensionViewController { LoggerSetup.oneTimeSetup() // Set up cloud storage services - CloudProviderDBManager.shared.useBackgroundSession = false DropboxSetup.constants = DropboxSetup(appKey: CloudAccessSecrets.dropboxAppKey, sharedContainerIdentifier: nil, keychainService: CryptomatorConstants.mainAppBundleId, forceForegroundSession: true) GoogleDriveSetup.constants = GoogleDriveSetup(clientId: CloudAccessSecrets.googleDriveClientId, redirectURL: CloudAccessSecrets.googleDriveRedirectURL!, sharedContainerIdentifier: nil) let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) From bf9ae79122a9edde64dea442fc6ddc9edf63dcfe Mon Sep 17 00:00:00 2001 From: Philipp Schmid <25935690+phil1995@users.noreply.github.com> Date: Sat, 6 Apr 2024 17:07:35 +0200 Subject: [PATCH 02/13] Temporarily use a specific branch for cloud-access-swift --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- CryptomatorCommon/Package.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 967f9b0ad..7775a02bc 100644 --- a/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/cryptomator/cloud-access-swift.git", "state" : { - "revision" : "bb9cc1c300be890f3a47efa0ac0808ee7c42146d", - "version" : "1.9.2" + "branch" : "feature/unique-identifier-bg-session", + "revision" : "c00d647ea80801eee8e9cc7e7c4222e4dec17151" } }, { diff --git a/CryptomatorCommon/Package.swift b/CryptomatorCommon/Package.swift index ecb713a4b..b46fed2fc 100644 --- a/CryptomatorCommon/Package.swift +++ b/CryptomatorCommon/Package.swift @@ -26,7 +26,7 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/cryptomator/cloud-access-swift.git", .upToNextMinor(from: "1.9.0")), + .package(url: "https://github.com/cryptomator/cloud-access-swift.git", branch: "feature/unique-identifier-bg-session"), .package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", .upToNextMinor(from: "3.8.0")), .package(url: "https://github.com/PhilLibs/simple-swift-dependencies", .upToNextMajor(from: "0.1.0")), .package(url: "https://github.com/siteline/SwiftUI-Introspect.git", .upToNextMajor(from: "0.3.0")), From d38bd50b60367dba870dae46459f1e4ef460cf4a Mon Sep 17 00:00:00 2001 From: Philipp Schmid <25935690+phil1995@users.noreply.github.com> Date: Sat, 6 Apr 2024 17:14:56 +0200 Subject: [PATCH 03/13] Update tests --- .../Manager/CloudProviderManagerTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CryptomatorCommon/Tests/CryptomatorCommonCoreTests/Manager/CloudProviderManagerTests.swift b/CryptomatorCommon/Tests/CryptomatorCommonCoreTests/Manager/CloudProviderManagerTests.swift index be08fd73c..7a0add33b 100644 --- a/CryptomatorCommon/Tests/CryptomatorCommonCoreTests/Manager/CloudProviderManagerTests.swift +++ b/CryptomatorCommon/Tests/CryptomatorCommonCoreTests/Manager/CloudProviderManagerTests.swift @@ -25,12 +25,12 @@ class CloudProviderManagerTests: XCTestCase { DropboxSetup.constants = DropboxSetup(appKey: "", sharedContainerIdentifier: nil, keychainService: nil, forceForegroundSession: false) let account = CloudProviderAccount(accountUID: UUID().uuidString, cloudProviderType: .dropbox) try accountManager.saveNewAccount(account) - XCTAssertNil(CloudProviderDBManager.cachedProvider[account.accountUID]) + XCTAssert(CloudProviderDBManager.cachedProvider.isEmpty) let provider = try manager.getProvider(with: account.accountUID) guard provider is DropboxCloudProvider else { XCTFail("Provider has wrong type") return } - XCTAssertNotNil(CloudProviderDBManager.cachedProvider[account.accountUID]) + XCTAssertEqual(CloudProviderDBManager.cachedProvider.filter { $0.accountUID == account.accountUID }.count, 1) } } From 035ffe2f8e6855d5cf5fa29e743315a5e369d6bc Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 17:28:42 +0200 Subject: [PATCH 04/13] Updated cloud-access-swift --- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- Cryptomator/AppDelegate.swift | 8 +++++--- Cryptomator/Common/CloudAuthenticator.swift | 3 +-- CryptomatorCommon/Package.swift | 2 +- .../Manager/CloudProviderDBManager.swift | 8 +++----- FileProviderExtension/FileProviderExtension.swift | 5 +++-- FileProviderExtensionUI/RootViewController.swift | 8 +++++--- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7775a02bc..0defb2bc4 100644 --- a/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Cryptomator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/cryptomator/cloud-access-swift.git", "state" : { - "branch" : "feature/unique-identifier-bg-session", - "revision" : "c00d647ea80801eee8e9cc7e7c4222e4dec17151" + "revision" : "cd7a18abcaf09349f066363c7524b738f4f4ad79", + "version" : "1.10.1" } }, { diff --git a/Cryptomator/AppDelegate.swift b/Cryptomator/AppDelegate.swift index f8fdf6e23..c91d18079 100644 --- a/Cryptomator/AppDelegate.swift +++ b/Cryptomator/AppDelegate.swift @@ -40,13 +40,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Set up cloud storage services DropboxSetup.constants = DropboxSetup(appKey: CloudAccessSecrets.dropboxAppKey, sharedContainerIdentifier: nil, keychainService: CryptomatorConstants.mainAppBundleId, forceForegroundSession: true) GoogleDriveSetup.constants = GoogleDriveSetup(clientId: CloudAccessSecrets.googleDriveClientId, redirectURL: CloudAccessSecrets.googleDriveRedirectURL!, sharedContainerIdentifier: nil) - let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) - oneDriveConfiguration.cacheConfig.keychainSharingGroup = CryptomatorConstants.mainAppBundleId do { - OneDriveSetup.clientApplication = try MSALPublicClientApplication(configuration: oneDriveConfiguration) + let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) + oneDriveConfiguration.cacheConfig.keychainSharingGroup = CryptomatorConstants.mainAppBundleId + let oneDriveClientApplication = try MSALPublicClientApplication(configuration: oneDriveConfiguration) + OneDriveSetup.constants = OneDriveSetup(clientApplication: oneDriveClientApplication, sharedContainerIdentifier: nil) } catch { DDLogError("Setting up OneDrive failed with error: \(error)") } + PCloudSetup.constants = PCloudSetup(appKey: CloudAccessSecrets.pCloudAppKey, sharedContainerIdentifier: nil) // Set up payment queue SKPaymentQueue.default().add(StoreObserver.shared) diff --git a/Cryptomator/Common/CloudAuthenticator.swift b/Cryptomator/Common/CloudAuthenticator.swift index be92c3a1e..fb7306d26 100644 --- a/Cryptomator/Common/CloudAuthenticator.swift +++ b/Cryptomator/Common/CloudAuthenticator.swift @@ -52,8 +52,7 @@ class CloudAuthenticator { } func authenticatePCloud(from viewController: UIViewController) -> Promise { - let authenticator = PCloudAuthenticator(appKey: CloudAccessSecrets.pCloudAppKey) - return authenticator.authenticate(from: viewController).then { credential -> CloudProviderAccount in + return PCloudAuthenticator.authenticate(from: viewController).then { credential -> CloudProviderAccount in try credential.saveToKeychain() let account = CloudProviderAccount(accountUID: credential.userID, cloudProviderType: .pCloud) try self.accountManager.saveNewAccount(account) diff --git a/CryptomatorCommon/Package.swift b/CryptomatorCommon/Package.swift index b46fed2fc..7a467a8a8 100644 --- a/CryptomatorCommon/Package.swift +++ b/CryptomatorCommon/Package.swift @@ -26,7 +26,7 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/cryptomator/cloud-access-swift.git", branch: "feature/unique-identifier-bg-session"), + .package(url: "https://github.com/cryptomator/cloud-access-swift.git", .upToNextMinor(from: "1.10.0")), .package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", .upToNextMinor(from: "3.8.0")), .package(url: "https://github.com/PhilLibs/simple-swift-dependencies", .upToNextMajor(from: "0.1.0")), .package(url: "https://github.com/siteline/SwiftUI-Introspect.git", .upToNextMajor(from: "0.3.0")), diff --git a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift index 7b5b725ad..62ed5e3d6 100644 --- a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift +++ b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift @@ -119,22 +119,20 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating provider = try GoogleDriveCloudProvider.withBackgroundSession( credential: credential, maxPageSize: maxPageSizeForFileProvider, - sessionIdentifier: sessionIdentifier, - sharedContainerIdentifier: CryptomatorConstants.appGroupName + sessionIdentifier: sessionIdentifier ) case .oneDrive: let credential = try OneDriveCredential(with: accountUID) provider = try OneDriveCloudProvider.withBackgroundSession( credential: credential, maxPageSize: maxPageSizeForFileProvider, - identifier: sessionIdentifier + sessionIdentifier: sessionIdentifier ) case .pCloud: let credential = try PCloudCredential(userID: accountUID) let client = PCloud.createBackgroundClient( with: credential.user, - sessionIdentifier: sessionIdentifier, - sharedContainerIdentifier: CryptomatorConstants.appGroupName + sessionIdentifier: sessionIdentifier ) provider = try PCloudCloudProvider(client: client) case .webDAV: diff --git a/FileProviderExtension/FileProviderExtension.swift b/FileProviderExtension/FileProviderExtension.swift index 2458a4f48..3aa574061 100644 --- a/FileProviderExtension/FileProviderExtension.swift +++ b/FileProviderExtension/FileProviderExtension.swift @@ -30,10 +30,11 @@ class FileProviderExtension: NSFileProviderExtension { FileProviderExtension.sharedDatabaseInitialized = true DropboxSetup.constants = DropboxSetup(appKey: CloudAccessSecrets.dropboxAppKey, sharedContainerIdentifier: CryptomatorConstants.appGroupName, keychainService: CryptomatorConstants.mainAppBundleId, forceForegroundSession: false) GoogleDriveSetup.constants = GoogleDriveSetup(clientId: CloudAccessSecrets.googleDriveClientId, redirectURL: CloudAccessSecrets.googleDriveRedirectURL!, sharedContainerIdentifier: CryptomatorConstants.appGroupName) - OneDriveSetup.sharedContainerIdentifier = CryptomatorConstants.appGroupName let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) oneDriveConfiguration.cacheConfig.keychainSharingGroup = CryptomatorConstants.mainAppBundleId - OneDriveSetup.clientApplication = try MSALPublicClientApplication(configuration: oneDriveConfiguration) + let oneDriveClientApplication = try MSALPublicClientApplication(configuration: oneDriveConfiguration) + OneDriveSetup.constants = OneDriveSetup(clientApplication: oneDriveClientApplication, sharedContainerIdentifier: CryptomatorConstants.appGroupName) + PCloudSetup.constants = PCloudSetup(appKey: CloudAccessSecrets.pCloudAppKey, sharedContainerIdentifier: CryptomatorConstants.appGroupName) } catch { // MARK: Handle error diff --git a/FileProviderExtensionUI/RootViewController.swift b/FileProviderExtensionUI/RootViewController.swift index 35feadd20..8e885d318 100644 --- a/FileProviderExtensionUI/RootViewController.swift +++ b/FileProviderExtensionUI/RootViewController.swift @@ -63,13 +63,15 @@ class RootViewController: FPUIActionExtensionViewController { // Set up cloud storage services DropboxSetup.constants = DropboxSetup(appKey: CloudAccessSecrets.dropboxAppKey, sharedContainerIdentifier: nil, keychainService: CryptomatorConstants.mainAppBundleId, forceForegroundSession: true) GoogleDriveSetup.constants = GoogleDriveSetup(clientId: CloudAccessSecrets.googleDriveClientId, redirectURL: CloudAccessSecrets.googleDriveRedirectURL!, sharedContainerIdentifier: nil) - let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) - oneDriveConfiguration.cacheConfig.keychainSharingGroup = CryptomatorConstants.mainAppBundleId do { - OneDriveSetup.clientApplication = try MSALPublicClientApplication(configuration: oneDriveConfiguration) + let oneDriveConfiguration = MSALPublicClientApplicationConfig(clientId: CloudAccessSecrets.oneDriveClientId, redirectUri: CloudAccessSecrets.oneDriveRedirectURI, authority: nil) + oneDriveConfiguration.cacheConfig.keychainSharingGroup = CryptomatorConstants.mainAppBundleId + let oneDriveClientApplication = try MSALPublicClientApplication(configuration: oneDriveConfiguration) + OneDriveSetup.constants = OneDriveSetup(clientApplication: oneDriveClientApplication, sharedContainerIdentifier: nil) } catch { DDLogError("Setting up OneDrive failed with error: \(error)") } + PCloudSetup.constants = PCloudSetup(appKey: CloudAccessSecrets.pCloudAppKey, sharedContainerIdentifier: nil) return {} }() From cff54c17e480dd73f1adc8e40862de2fc69906fb Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 17:31:44 +0200 Subject: [PATCH 05/13] Fixed unused background session creation --- .../CryptomatorCommonCore/Manager/CloudProviderDBManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift index 62ed5e3d6..ef424aa09 100644 --- a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift +++ b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift @@ -52,7 +52,7 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating }) { return entry.provider } - return try createProvider(for: accountUID) + return try createBackgroundSessionProvider(for: accountUID, sessionIdentifier: sessionIdentifier) } /** From 2d277499fcb1b542abc8e88ce542415758856246 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 17:33:40 +0200 Subject: [PATCH 06/13] Applied SwiftFormat --- CryptomatorFileProvider/FileProviderAdapter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CryptomatorFileProvider/FileProviderAdapter.swift b/CryptomatorFileProvider/FileProviderAdapter.swift index 2ff7e112c..1440df15c 100644 --- a/CryptomatorFileProvider/FileProviderAdapter.swift +++ b/CryptomatorFileProvider/FileProviderAdapter.swift @@ -210,7 +210,7 @@ public class FileProviderAdapter: FileProviderAdapterType { } return completionHandler(nil, NSFileProviderError(.noSuchItem)) } - let localImportHandler: (Error?) -> Void = { error in + let localImportHandler: Error? -> Void = { error in if let error = error { completionHandler(nil, error) } else { From 5559242fa086f8a19517b10cc7d54a490d1e6713 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 17:37:37 +0200 Subject: [PATCH 07/13] Use self-hosted runner --- .github/workflows/build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50343ef4a..c294b677a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,11 +6,10 @@ on: jobs: build: name: Build and test - runs-on: macos-14 + runs-on: [self-hosted, macOS, ARM64] env: DERIVED_DATA_PATH: 'DerivedData' DEVICE: 'iPhone 15 Pro' - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" strategy: matrix: config: ['freemium', 'premium'] From ca61b4ff11ba034f8e5af8ac6077e0b14a2fb8dd Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 17:39:34 +0200 Subject: [PATCH 08/13] Use Xcode 15.3 in CI build --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c294b677a..3fc514cef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,8 +31,8 @@ jobs: run: | cd fastlane ./scripts/create-cloud-access-secrets.sh - - name: Select Xcode 15.2 - run: sudo xcode-select -s /Applications/Xcode_15.2.app + - name: Select Xcode 15.3 + run: sudo xcode-select -s /Applications/Xcode_15.3.app - name: Configuration for freemium if: ${{ matrix.config == 'freemium' }} run: | From 4a8240a0be99272d3b81b601f625438e5cede461 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 17:49:28 +0200 Subject: [PATCH 09/13] Revert "Applied SwiftFormat" This reverts commit 2d277499fcb1b542abc8e88ce542415758856246. --- CryptomatorFileProvider/FileProviderAdapter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CryptomatorFileProvider/FileProviderAdapter.swift b/CryptomatorFileProvider/FileProviderAdapter.swift index 1440df15c..2ff7e112c 100644 --- a/CryptomatorFileProvider/FileProviderAdapter.swift +++ b/CryptomatorFileProvider/FileProviderAdapter.swift @@ -210,7 +210,7 @@ public class FileProviderAdapter: FileProviderAdapterType { } return completionHandler(nil, NSFileProviderError(.noSuchItem)) } - let localImportHandler: Error? -> Void = { error in + let localImportHandler: (Error?) -> Void = { error in if let error = error { completionHandler(nil, error) } else { From 3910d16994a44a48ff4e654e6a6246b85cc9c74b Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 18:20:45 +0200 Subject: [PATCH 10/13] Shortened createBackgroundSessionProvider function so that disabling SwiftLint is not necessary --- .../Manager/CloudProviderDBManager.swift | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift index ef424aa09..030468582 100644 --- a/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift +++ b/CryptomatorCommon/Sources/CryptomatorCommonCore/Manager/CloudProviderDBManager.swift @@ -98,14 +98,12 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating return provider } - // swiftlint:disable:next orphaned_doc_comment /** Creates and returns a cloud provider for the given `accountUID` using a background URLSession with the given `sessionIdentifier`. The number of returned items from a `fetchItemList(forFolderAt:pageToken:)` call is limited to 500. This is necessary because otherwise memory limit problems can occur with folders with many items in the `FileProviderExtension` where a background `URLSession` is used. */ - // swiftlint:disable:next function_body_length func createBackgroundSessionProvider(for accountUID: String, sessionIdentifier: String) throws -> CloudProvider { let cloudProviderType = try accountManager.getCloudProviderType(for: accountUID) let provider: CloudProvider @@ -116,32 +114,17 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating provider = DropboxCloudProvider(credential: credential, maxPageSize: maxPageSizeForFileProvider) case .googleDrive: let credential = GoogleDriveCredential(userID: accountUID) - provider = try GoogleDriveCloudProvider.withBackgroundSession( - credential: credential, - maxPageSize: maxPageSizeForFileProvider, - sessionIdentifier: sessionIdentifier - ) + provider = try GoogleDriveCloudProvider.withBackgroundSession(credential: credential, maxPageSize: maxPageSizeForFileProvider, sessionIdentifier: sessionIdentifier) case .oneDrive: let credential = try OneDriveCredential(with: accountUID) - provider = try OneDriveCloudProvider.withBackgroundSession( - credential: credential, - maxPageSize: maxPageSizeForFileProvider, - sessionIdentifier: sessionIdentifier - ) + provider = try OneDriveCloudProvider.withBackgroundSession(credential: credential, maxPageSize: maxPageSizeForFileProvider, sessionIdentifier: sessionIdentifier) case .pCloud: let credential = try PCloudCredential(userID: accountUID) - let client = PCloud.createBackgroundClient( - with: credential.user, - sessionIdentifier: sessionIdentifier - ) + let client = PCloud.createBackgroundClient(with: credential.user, sessionIdentifier: sessionIdentifier) provider = try PCloudCloudProvider(client: client) case .webDAV: let credential = try getWebDAVCredential(for: accountUID) - let client = WebDAVClient.withBackgroundSession( - credential: credential, - sessionIdentifier: sessionIdentifier, - sharedContainerIdentifier: CryptomatorConstants.appGroupName - ) + let client = WebDAVClient.withBackgroundSession(credential: credential, sessionIdentifier: sessionIdentifier, sharedContainerIdentifier: CryptomatorConstants.appGroupName) provider = try WebDAVProvider(with: client, maxPageSize: maxPageSizeForFileProvider) case .localFileSystem: guard let rootURL = try LocalFileSystemBookmarkManager.getBookmarkedRootURL(for: accountUID) else { From e75f6e2512bb6e808f590b2fdbf24b255d32557a Mon Sep 17 00:00:00 2001 From: Cryptobot Date: Thu, 18 Apr 2024 18:38:18 +0200 Subject: [PATCH 11/13] New Crowdin updates (#348) [ci skip] --- SharedResources/ca.lproj/Localizable.strings | 10 ++++++++++ SharedResources/cs.lproj/Localizable.strings | 1 + SharedResources/da.lproj/Localizable.strings | 12 +++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/SharedResources/ca.lproj/Localizable.strings b/SharedResources/ca.lproj/Localizable.strings index e1653121c..dfa810429 100644 --- a/SharedResources/ca.lproj/Localizable.strings +++ b/SharedResources/ca.lproj/Localizable.strings @@ -22,6 +22,7 @@ "common.button.next" = "Següent"; "common.button.ok" = "D'acord"; "common.button.refresh" = "Refresca"; +"common.button.register" = "Registre"; "common.button.remove" = "Elimina"; "common.button.retry" = "Reintenta"; "common.button.signOut" = "Tanca la sessió"; @@ -59,6 +60,7 @@ "addVault.openExistingVault.chooseCloud.header" = "On es troba la caixa forta?"; "addVault.openExistingVault.detectedMasterkey.text" = "Cryptomator ha detectat la caixa forta \"%@\".\nVoleu afegir aquesta caixa forta?"; "addVault.openExistingVault.detectedMasterkey.add" = "Afegeix aquesta caixa forta"; +"addVault.openExistingVault.downloadVault.progress" = "Descàrrega de la caixa forta…"; "addVault.openExistingVault.password.footer" = "Introduïu la contrasenya per a \"%@\"."; "addVault.openExistingVault.progress" = "Ara s'afegeix la caixa forta…"; "addVault.success.info" = "S'ha afegit la caixa forta \"%@\".\nAccediu a la caixa forta via l'app de fitxers."; @@ -111,10 +113,18 @@ "getFolderIntent.error.missingPath" = "No s'ha proporcionat cap ruta. Proporcioneu una ruta vàlida que retorni una carpeta."; "getFolderIntent.error.noVaultSelected" = "No s'ha seleccionat cap caixa forta."; + +"hubAuthentication.title" = "Caixa forta de Hub"; "hubAuthentication.accessNotGranted" = "El vostre dispositiu no ha estat encara autoritzat a accedir a aquesta caixa forta. Demaneu autorització al propietari."; "hubAuthentication.licenseExceeded" = "Aquest Cryptomator Hub no té una llicència vàlida. Informa si us plau a l'administrador perquè actualitzi o renovi la llicència."; "hubAuthentication.deviceRegistration.deviceName.cells.name" = "Nom del dispositiu"; +"hubAuthentication.deviceRegistration.deviceName.footer.title" = "Sembla que és el primer accés al Hub des d'aquest dispositiu. Per identificar-lo i poder autoritzar l'accés heu de posar nom a aquest dispositiu."; +"hubAuthentication.deviceRegistration.accountKey.footer.title" = "Cal la vostra Account Key per a iniciar sessió des d'una aplicació o navegador nous. La trobareu al vostre perfil."; +"hubAuthentication.deviceRegistration.needsAuthorization.alert.title" = "Registre de dispositiu correcte"; "hubAuthentication.deviceRegistration.needsAuthorization.alert.message" = "Per a accedir a la caixa forta, el vostre dispositiu ha de ser autoritzat pel propietari de la caixa."; +"hubAuthentication.requireAccountInit.alert.title" = "Acció necessària"; +"hubAuthentication.requireAccountInit.alert.message" = "Per a continuar, si us plau, seguiu els passos necessaris en el vostre perfil d'usuari de Hub."; +"hubAuthentication.requireAccountInit.alert.actionButton" = "Vés al perfil"; "intents.saveFile.missingFile" = "El fitxer proporcionat no és vàlid."; "intents.saveFile.invalidFolder" = "La carpeta proporcionada no és vàlida."; diff --git a/SharedResources/cs.lproj/Localizable.strings b/SharedResources/cs.lproj/Localizable.strings index de842ad8d..d5f7408c1 100644 --- a/SharedResources/cs.lproj/Localizable.strings +++ b/SharedResources/cs.lproj/Localizable.strings @@ -60,6 +60,7 @@ "addVault.openExistingVault.chooseCloud.header" = "Kde je trezor umístěn?"; "addVault.openExistingVault.detectedMasterkey.text" = "Cryptomator detekoval trezor \"%@\".\nChcete přidat tento trezor?"; "addVault.openExistingVault.detectedMasterkey.add" = "Přidat tento trezor"; +"addVault.openExistingVault.downloadVault.progress" = "Stahování trezoru…"; "addVault.openExistingVault.password.footer" = "Zadejte heslo pro \"%@\"."; "addVault.openExistingVault.progress" = "Přidávání trezoru…"; "addVault.success.info" = "Úspěšně přidán trezor \"%@\".\nPřistupujte k tomuto trezoru prostřednictvím aplikace Soubory."; diff --git a/SharedResources/da.lproj/Localizable.strings b/SharedResources/da.lproj/Localizable.strings index 8d789792e..ebf214eb0 100644 --- a/SharedResources/da.lproj/Localizable.strings +++ b/SharedResources/da.lproj/Localizable.strings @@ -21,7 +21,8 @@ "common.button.enable" = "Aktivér"; "common.button.next" = "Næste"; "common.button.ok" = "OK"; -"common.button.refresh" = "Opdatér"; +"common.button.refresh" = "Genopfrisk"; +"common.button.register" = "Registrer"; "common.button.remove" = "Fjern"; "common.button.retry" = "Forsøg igen"; "common.button.signOut" = "Log ud"; @@ -59,6 +60,7 @@ "addVault.openExistingVault.chooseCloud.header" = "Hvor er boksen placeret?"; "addVault.openExistingVault.detectedMasterkey.text" = "Kryptomator fandt boksen \"%@\".\nVil du tilføje denne boks?"; "addVault.openExistingVault.detectedMasterkey.add" = "Tilføj denne boks"; +"addVault.openExistingVault.downloadVault.progress" = "Downloader Boks…"; "addVault.openExistingVault.password.footer" = "Indtast adgangskode for \"%@\"."; "addVault.openExistingVault.progress" = "Tilføjer boks…"; "addVault.success.info" = "Tilføjede boksen \"%@\".\nFå adgang til denne boks via Filer appen."; @@ -111,10 +113,18 @@ "getFolderIntent.error.missingPath" = "Ingen sti blev angivet. Angiv venligst en gyldig sti til en mappe."; "getFolderIntent.error.noVaultSelected" = "Ingen boks er valgt."; + +"hubAuthentication.title" = "Hub Boks"; "hubAuthentication.accessNotGranted" = "Din enhed er endnu ikke blevet godkendt til at få adgang til denne boks. Spørg boks-ejeren om godkendelse."; "hubAuthentication.licenseExceeded" = "Din Cryptomator Hub har en ugyldig licens. Få venligst en Hub administrator til at opgradere eller forny licensen."; "hubAuthentication.deviceRegistration.deviceName.cells.name" = "Enheds-navn"; +"hubAuthentication.deviceRegistration.deviceName.footer.title" = "Det ser ud til at dette er første gang denne enhed tilgår Hub. For at kunne identificere den for adgangstilladelse, skal du navngive denne enhed."; +"hubAuthentication.deviceRegistration.accountKey.footer.title" = "Din kontonøgle er påkrævet til at logge ind fra nye apps eller browsere. Den kan findes i din profil."; +"hubAuthentication.deviceRegistration.needsAuthorization.alert.title" = "Registrering af Enhed Lykkedes"; "hubAuthentication.deviceRegistration.needsAuthorization.alert.message" = "For at tilgå boksen, skal din enhed godkendes af boks-ejeren."; +"hubAuthentication.requireAccountInit.alert.title" = "Handling Påkrævet"; +"hubAuthentication.requireAccountInit.alert.message" = "For at fortsætte, skal du fuldføre de nødvendige trin i din Hub brugerprofil."; +"hubAuthentication.requireAccountInit.alert.actionButton" = "Gå til Profil"; "intents.saveFile.missingFile" = "Den angivne fil er ikke gyldig."; "intents.saveFile.invalidFolder" = "Den angivne mappe er ikke gyldig."; From 3f4f3d19e52aef82850af5dd92f9c96466d009d5 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 18 Apr 2024 19:06:25 +0200 Subject: [PATCH 12/13] Preparing 2.5.2 --- Cryptomator.xcodeproj/project.pbxproj | 4 ++-- fastlane/changelog.txt | 2 +- fastlane/config/freemium/metadata/de-DE/release_notes.txt | 2 +- fastlane/config/freemium/metadata/en-US/release_notes.txt | 2 +- fastlane/config/premium/metadata/de-DE/release_notes.txt | 2 +- fastlane/config/premium/metadata/en-US/release_notes.txt | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cryptomator.xcodeproj/project.pbxproj b/Cryptomator.xcodeproj/project.pbxproj index f577662f6..0ba9b83b7 100644 --- a/Cryptomator.xcodeproj/project.pbxproj +++ b/Cryptomator.xcodeproj/project.pbxproj @@ -3300,7 +3300,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 2.5.1; + MARKETING_VERSION = 2.5.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -3362,7 +3362,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 2.5.1; + MARKETING_VERSION = 2.5.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200"; diff --git a/fastlane/changelog.txt b/fastlane/changelog.txt index 6afe6a9f2..8d4343f6c 100644 --- a/fastlane/changelog.txt +++ b/fastlane/changelog.txt @@ -1 +1 @@ -- Fixed "Content Unavailable" error when unlocking vault that was created on macOS in iCloud Drive (#316) \ No newline at end of file +- Fixed "Content Unavailable" error when unlocking multiple vaults in Google Drive, OneDrive, pCloud, and WebDAV (#342, #345, #351) \ No newline at end of file diff --git a/fastlane/config/freemium/metadata/de-DE/release_notes.txt b/fastlane/config/freemium/metadata/de-DE/release_notes.txt index e3ee06575..c5bae17dd 100644 --- a/fastlane/config/freemium/metadata/de-DE/release_notes.txt +++ b/fastlane/config/freemium/metadata/de-DE/release_notes.txt @@ -1 +1 @@ -- Fehler "Inhalt nicht verfügbar" beim Entsperren eines Tresors, der auf macOS in iCloud Drive erstellt wurde, behoben (#316) \ No newline at end of file +- Fehler "Inhalt nicht verfügbar" beim Entsperren mehrerer Tresore in Google Drive, OneDrive, pCloud und WebDAV behoben (#342, #345, #351) \ No newline at end of file diff --git a/fastlane/config/freemium/metadata/en-US/release_notes.txt b/fastlane/config/freemium/metadata/en-US/release_notes.txt index 6afe6a9f2..8d4343f6c 100644 --- a/fastlane/config/freemium/metadata/en-US/release_notes.txt +++ b/fastlane/config/freemium/metadata/en-US/release_notes.txt @@ -1 +1 @@ -- Fixed "Content Unavailable" error when unlocking vault that was created on macOS in iCloud Drive (#316) \ No newline at end of file +- Fixed "Content Unavailable" error when unlocking multiple vaults in Google Drive, OneDrive, pCloud, and WebDAV (#342, #345, #351) \ No newline at end of file diff --git a/fastlane/config/premium/metadata/de-DE/release_notes.txt b/fastlane/config/premium/metadata/de-DE/release_notes.txt index e3ee06575..c5bae17dd 100644 --- a/fastlane/config/premium/metadata/de-DE/release_notes.txt +++ b/fastlane/config/premium/metadata/de-DE/release_notes.txt @@ -1 +1 @@ -- Fehler "Inhalt nicht verfügbar" beim Entsperren eines Tresors, der auf macOS in iCloud Drive erstellt wurde, behoben (#316) \ No newline at end of file +- Fehler "Inhalt nicht verfügbar" beim Entsperren mehrerer Tresore in Google Drive, OneDrive, pCloud und WebDAV behoben (#342, #345, #351) \ No newline at end of file diff --git a/fastlane/config/premium/metadata/en-US/release_notes.txt b/fastlane/config/premium/metadata/en-US/release_notes.txt index 6afe6a9f2..8d4343f6c 100644 --- a/fastlane/config/premium/metadata/en-US/release_notes.txt +++ b/fastlane/config/premium/metadata/en-US/release_notes.txt @@ -1 +1 @@ -- Fixed "Content Unavailable" error when unlocking vault that was created on macOS in iCloud Drive (#316) \ No newline at end of file +- Fixed "Content Unavailable" error when unlocking multiple vaults in Google Drive, OneDrive, pCloud, and WebDAV (#342, #345, #351) \ No newline at end of file From 1289ab02d38b392cde1d772615048b005395b37e Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Fri, 19 Apr 2024 08:27:01 +0200 Subject: [PATCH 13/13] Added privacy manifest --- Cryptomator.xcodeproj/project.pbxproj | 10 ++++++++++ SharedResources/PrivacyInfo.xcprivacy | 28 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 SharedResources/PrivacyInfo.xcprivacy diff --git a/Cryptomator.xcodeproj/project.pbxproj b/Cryptomator.xcodeproj/project.pbxproj index 0ba9b83b7..91b4f6ac5 100644 --- a/Cryptomator.xcodeproj/project.pbxproj +++ b/Cryptomator.xcodeproj/project.pbxproj @@ -391,6 +391,10 @@ 740D3684266A1B180058744D /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740D3683266A1B180058744D /* SettingsCoordinator.swift */; }; 742679FC26A56CF9004C61BC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 742679F926A56B33004C61BC /* Localizable.strings */; }; 742679FD26A56CFA004C61BC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 742679F926A56B33004C61BC /* Localizable.strings */; }; + 74420BC32BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 74420BC22BD2449900E77F92 /* PrivacyInfo.xcprivacy */; }; + 74420BC42BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 74420BC22BD2449900E77F92 /* PrivacyInfo.xcprivacy */; }; + 74420BC52BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 74420BC22BD2449900E77F92 /* PrivacyInfo.xcprivacy */; }; + 74420BC62BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 74420BC22BD2449900E77F92 /* PrivacyInfo.xcprivacy */; }; 7460FFEF26FCC6FC0018BCC4 /* OnboardingNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7460FFEE26FCC6FC0018BCC4 /* OnboardingNavigationController.swift */; }; 746815462475605E00038679 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4AE97DB324572E4A00452814 /* Assets.xcassets */; }; 746815472475605E00038679 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AE97DB524572E4A00452814 /* LaunchScreen.storyboard */; }; @@ -996,6 +1000,7 @@ 74275AE728478E160058AD25 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Intents.strings; sourceTree = ""; }; 74397A842832A05E00CB9410 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; 74397A852832A09B00CB9410 /* sw-TZ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sw-TZ"; path = "sw-TZ.lproj/Localizable.strings"; sourceTree = ""; }; + 74420BC22BD2449900E77F92 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 7460FFED26FB6C100018BCC4 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; }; 7460FFEE26FCC6FC0018BCC4 /* OnboardingNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingNavigationController.swift; sourceTree = ""; }; 74626665283BD2D20070924B /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/Localizable.strings"; sourceTree = ""; }; @@ -2024,6 +2029,7 @@ children = ( 4AE97DB324572E4A00452814 /* Assets.xcassets */, 4AF91CC625A6437000ACF01E /* Colors.xcassets */, + 74420BC22BD2449900E77F92 /* PrivacyInfo.xcprivacy */, 742679F926A56B33004C61BC /* Localizable.strings */, ); path = SharedResources; @@ -2380,6 +2386,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 74420BC42BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */, 4A80407B2769201400D7D999 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2390,6 +2397,7 @@ files = ( 4A6A5213268B66AC006F7368 /* Colors.xcassets in Resources */, 742679FD26A56CFA004C61BC /* Localizable.strings in Resources */, + 74420BC52BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */, 4A6A5212268B6697006F7368 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2398,6 +2406,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 74420BC62BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */, 4A1A7AC628327419008EEC84 /* Assets.xcassets in Resources */, 4A1A7AC528326554008EEC84 /* Localizable.strings in Resources */, ); @@ -2413,6 +2422,7 @@ 742679FC26A56CF9004C61BC /* Localizable.strings in Resources */, 7408E6C52677954000D7FAEA /* about.html in Resources */, 7408E6CA2677985800D7FAEA /* jquery-3.6.0.slim.min.js in Resources */, + 74420BC32BD2449900E77F92 /* PrivacyInfo.xcprivacy in Resources */, 746815462475605E00038679 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SharedResources/PrivacyInfo.xcprivacy b/SharedResources/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..bfb731504 --- /dev/null +++ b/SharedResources/PrivacyInfo.xcprivacy @@ -0,0 +1,28 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + DDA9.1 + C617.1 + 3B52.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + 1C8F.1 + + + + +