Skip to content

Commit

Permalink
Added Box support (#352)
Browse files Browse the repository at this point in the history
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
  • Loading branch information
iammajid and tobihagemann authored Sep 11, 2024
1 parent a855f11 commit 80a1670
Show file tree
Hide file tree
Showing 34 changed files with 364 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,26 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/leif-ibsen/ASN1",
"state" : {
"revision" : "8a5cb6ce9b4a009a5b8d82465caf1aafb720096e",
"version" : "2.5.0"
"revision" : "4b4e82513e3b4d51a7573972fd7123222dd3a3bd",
"version" : "2.6.0"
}
},
{
"identity" : "asn1swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tikhop/ASN1Swift",
"state" : {
"revision" : "177417b6bf89431a0750ee640012b6aed8961c6a",
"version" : "1.2.5"
"revision" : "403cd95194e6a962e16db7c0d373d89fce83e0f7",
"version" : "1.2.7"
}
},
{
"identity" : "aws-sdk-ios-spm",
"kind" : "remoteSourceControl",
"location" : "https://github.com/aws-amplify/aws-sdk-ios-spm.git",
"state" : {
"revision" : "cfcf97f6994b6ffd9a3244dc638458f5822aba56",
"version" : "2.34.0"
"revision" : "8ff8bebfe24271f7b16c5abaeb78daf82bee3a80",
"version" : "2.34.2"
}
},
{
Expand All @@ -50,17 +50,26 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/leif-ibsen/BigInt",
"state" : {
"revision" : "ba54c8b51392627d4cc9b05a672cce558be56e04",
"version" : "1.17.0"
"revision" : "bf55e4ce076a5e2dde0db13d9b03d820cfad420d",
"version" : "1.19.0"
}
},
{
"identity" : "box-swift-sdk-gen",
"kind" : "remoteSourceControl",
"location" : "https://github.com/box/box-swift-sdk-gen.git",
"state" : {
"revision" : "7b2e3963a4f9d7c608ba9176fa3c32d260599906",
"version" : "0.3.1"
}
},
{
"identity" : "cloud-access-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/cryptomator/cloud-access-swift.git",
"state" : {
"revision" : "cd7a18abcaf09349f066363c7524b738f4f4ad79",
"version" : "1.10.1"
"revision" : "6ee5a3374c1530c0808b7855e567cac2b7618952",
"version" : "1.11.0"
}
},
{
Expand All @@ -86,8 +95,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/leif-ibsen/Digest",
"state" : {
"revision" : "1202dcb976e481e7c228492c5a8d5159cfa4ea97",
"version" : "1.4.0"
"revision" : "05f079878ec5fb05c7d9c94f35dbc4f5ec054d54",
"version" : "1.6.0"
}
},
{
Expand Down Expand Up @@ -149,8 +158,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/AzureAD/microsoft-authentication-library-for-objc.git",
"state" : {
"revision" : "9d15d7980a52945dd17ea529bcf4c92f2c0d9a12",
"version" : "1.3.1"
"revision" : "d2f81ded070ac6452b2a6acb5bc45eb566427fe7",
"version" : "1.3.3"
}
},
{
Expand Down Expand Up @@ -203,8 +212,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log",
"state" : {
"revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5",
"version" : "1.5.4"
"revision" : "9cb486020ebf03bfa5b5df985387a14a98744537",
"version" : "1.6.1"
}
},
{
Expand Down Expand Up @@ -239,8 +248,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state" : {
"revision" : "b13b1d1a8e787a5ffc71ac19dcaf52183ab27ba2",
"version" : "1.1.1"
"revision" : "96beb108a57f24c8476ae1f309239270772b2940",
"version" : "1.2.5"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class CreateNewVaultCoordinator: AccountListing, CloudChoosing, DefaultShowEditA
}

func start() {
let viewModel = ChooseCloudViewModel(clouds: [.localFileSystem(type: .iCloudDrive), .dropbox, .googleDrive, .oneDrive, .pCloud, .webDAV(type: .custom), .s3(type: .custom), .localFileSystem(type: .custom)], headerTitle: LocalizedString.getValue("addVault.createNewVault.chooseCloud.header"))
let viewModel = ChooseCloudViewModel(clouds: [.localFileSystem(type: .iCloudDrive), .dropbox, .googleDrive, .oneDrive, .pCloud, .box, .webDAV(type: .custom), .s3(type: .custom), .localFileSystem(type: .custom)], headerTitle: LocalizedString.getValue("addVault.createNewVault.chooseCloud.header"))
let chooseCloudVC = ChooseCloudViewController(viewModel: viewModel)
chooseCloudVC.title = LocalizedString.getValue("addVault.createNewVault.title")
chooseCloudVC.coordinator = self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class OpenExistingVaultCoordinator: AccountListing, CloudChoosing, DefaultShowEd
}

func start() {
let viewModel = ChooseCloudViewModel(clouds: [.localFileSystem(type: .iCloudDrive), .dropbox, .googleDrive, .oneDrive, .pCloud, .webDAV(type: .custom), .s3(type: .custom), .localFileSystem(type: .custom)], headerTitle: LocalizedString.getValue("addVault.openExistingVault.chooseCloud.header"))
let viewModel = ChooseCloudViewModel(clouds: [.localFileSystem(type: .iCloudDrive), .dropbox, .googleDrive, .oneDrive, .pCloud, .box, .webDAV(type: .custom), .s3(type: .custom), .localFileSystem(type: .custom)], headerTitle: LocalizedString.getValue("addVault.openExistingVault.chooseCloud.header"))
let chooseCloudVC = ChooseCloudViewController(viewModel: viewModel)
chooseCloudVC.title = LocalizedString.getValue("addVault.openExistingVault.title")
chooseCloudVC.coordinator = self
Expand Down
1 change: 1 addition & 0 deletions Cryptomator/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
DDLogError("Setting up OneDrive failed with error: \(error)")
}
PCloudSetup.constants = PCloudSetup(appKey: CloudAccessSecrets.pCloudAppKey, sharedContainerIdentifier: nil)
BoxSetup.constants = BoxSetup(clientId: CloudAccessSecrets.boxClientId, clientSecret: CloudAccessSecrets.boxClientSecret, sharedContainerIdentifier: nil)

// Set up payment queue
SKPaymentQueue.default().add(StoreObserver.shared)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
// Copyright © 2021 Skymatic GmbH. All rights reserved.
//

import AuthenticationServices
import CocoaLumberjackSwift
import CryptomatorCommon
import CryptomatorCommonCore
import Foundation
import Promises
import UIKit

class AccountListViewController: ListViewController<AccountCellContent> {
class AccountListViewController: ListViewController<AccountCellContent>, ASWebAuthenticationPresentationContextProviding {
weak var coordinator: (Coordinator & AccountListing)?
private let viewModel: AccountListViewModelProtocol

Expand Down Expand Up @@ -103,6 +105,16 @@ class AccountListViewController: ListViewController<AccountCellContent> {
}
}

// MARK: - ASWebAuthenticationPresentationContextProviding

func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
guard let window = UIApplication.shared.windows.first else {
DDLogInfo("No window could be found as presentation anchor.")
return ASPresentationAnchor()
}
return window
}

// MARK: - Internal

private func handleLogout(_ sender: AccountCellButton) {
Expand Down Expand Up @@ -130,7 +142,7 @@ class AccountListViewController: ListViewController<AccountCellContent> {

private func supportsEditing(_ cloudProviderType: CloudProviderType) -> Bool {
switch cloudProviderType {
case .dropbox, .googleDrive, .localFileSystem, .oneDrive, .pCloud:
case .box, .dropbox, .googleDrive, .localFileSystem, .oneDrive, .pCloud:
return false
case .s3, .webDAV:
return true
Expand Down
51 changes: 34 additions & 17 deletions Cryptomator/Common/CloudAccountList/AccountListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,46 +66,55 @@ class AccountListViewModel: AccountListViewModelProtocol {
}
}

func refreshBoxItems() -> Promise<Void> {
return all(accountInfos
.map { BoxCredential(tokenStorage: BoxTokenStorage(userID: $0.accountUID)) }
.map { self.createAccountCellContent(for: $0) }
).then { accounts in
self.accounts = accounts
}
}

func createAccountCellContent(from accountInfo: AccountInfo) throws -> AccountCellContent {
switch cloudProviderType {
case .box:
return createAccountCellContentPlaceholder()
case .dropbox:
let credential = DropboxCredential(tokenUID: accountInfo.accountUID)
return createAccountCellContentPlaceholder(for: credential)
return createAccountCellContentPlaceholder()
case .googleDrive:
let credential = GoogleDriveCredential(userID: accountInfo.accountUID)
return try createAccountCellContent(for: credential)
case .localFileSystem:
throw AccountListError.unsupportedCloudProviderType
case .oneDrive:
let credential = try OneDriveCredential(with: accountInfo.accountUID)
return try createAccountCellContent(for: credential)
case .pCloud:
let credential = try PCloudCredential(userID: accountInfo.accountUID)
return createAccountCellContentPlaceholder(for: credential)
case .webDAV:
guard let credential = WebDAVCredentialManager.shared.getCredentialFromKeychain(with: accountInfo.accountUID) else {
throw CloudProviderAccountError.accountNotFoundError
}
return createAccountCellContent(for: credential)
case .localFileSystem:
throw AccountListError.unsupportedCloudProviderType
return createAccountCellContentPlaceholder()
case .s3:
guard let credential = S3CredentialManager.shared.getCredential(with: accountInfo.accountUID) else {
throw CloudProviderAccountError.accountNotFoundError
}
let displayName = try S3CredentialManager.shared.getDisplayName(for: credential)
return createAccountCellContent(for: credential, displayName: displayName)
case .webDAV:
guard let credential = WebDAVCredentialManager.shared.getCredentialFromKeychain(with: accountInfo.accountUID) else {
throw CloudProviderAccountError.accountNotFoundError
}
return createAccountCellContent(for: credential)
}
}

private func createAccountCellContentPlaceholder() -> AccountCellContent {
return AccountCellContent(mainLabelText: "(…)", detailLabelText: nil)
}

private func createAccountCellContent(for credential: DropboxCredential) -> Promise<AccountCellContent> {
return credential.getUsername().then { username in
AccountCellContent(mainLabelText: username, detailLabelText: nil)
}
}

private func createAccountCellContentPlaceholder(for credential: DropboxCredential) -> AccountCellContent {
return AccountCellContent(mainLabelText: "(…)", detailLabelText: nil)
}

private func createAccountCellContent(for credential: GoogleDriveCredential) throws -> AccountCellContent {
let username = try credential.getUsername()
return AccountCellContent(mainLabelText: username, detailLabelText: nil)
Expand All @@ -122,8 +131,10 @@ class AccountListViewModel: AccountListViewModelProtocol {
}
}

private func createAccountCellContentPlaceholder(for credential: PCloudCredential) -> AccountCellContent {
return AccountCellContent(mainLabelText: "(…)", detailLabelText: nil)
func createAccountCellContent(for credential: BoxCredential) -> Promise<AccountCellContent> {
return credential.getUsername().then { username in
AccountCellContent(mainLabelText: username, detailLabelText: nil)
}
}

func createAccountCellContent(for credential: WebDAVCredential) -> AccountCellContent {
Expand Down Expand Up @@ -203,6 +214,12 @@ class AccountListViewModel: AccountListViewModelProtocol {
}.catch { error in
self.databaseChangedPublisher.send(.failure(error))
}
} else if self.cloudProviderType == .box {
self.refreshBoxItems().then {
self.databaseChangedPublisher.send(.success(self.accounts))
}.catch { error in
self.databaseChangedPublisher.send(.failure(error))
}
}
})
return databaseChangedPublisher.eraseToAnyPublisher()
Expand Down
35 changes: 27 additions & 8 deletions Cryptomator/Common/CloudAuthenticator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ class CloudAuthenticator {
}
}

func authenticateBox(from viewController: UIViewController) -> Promise<CloudProviderAccount> {
let tokenStorage = BoxTokenStorage()
let credential = BoxCredential(tokenStorage: tokenStorage)
return BoxAuthenticator.authenticate(from: viewController, tokenStorage: tokenStorage).then { _ -> Promise<CloudProviderAccount> in
return credential.getUserID().then { userID in
tokenStorage.userID = userID // this will actually save the access token to the keychain
let account = CloudProviderAccount(accountUID: userID, cloudProviderType: .box)
try self.accountManager.saveNewAccount(account)
return account
}
}
}

func authenticateWebDAV(from viewController: UIViewController) -> Promise<CloudProviderAccount> {
return WebDAVAuthenticator.authenticate(from: viewController).then { credential -> CloudProviderAccount in
let account = CloudProviderAccount(accountUID: credential.identifier, cloudProviderType: .webDAV(type: .custom))
Expand All @@ -78,43 +91,49 @@ class CloudAuthenticator {

func authenticate(_ cloudProviderType: CloudProviderType, from viewController: UIViewController) -> Promise<CloudProviderAccount> {
switch cloudProviderType {
case .box:
return authenticateBox(from: viewController)
case .dropbox:
return authenticateDropbox(from: viewController)
case .googleDrive:
return authenticateGoogleDrive(from: viewController)
case .localFileSystem:
return Promise(CloudAuthenticatorError.functionNotYetSupported)
case .oneDrive:
return authenticateOneDrive(from: viewController)
case .pCloud:
return authenticatePCloud(from: viewController)
case .webDAV:
return authenticateWebDAV(from: viewController)
case .localFileSystem:
return Promise(CloudAuthenticatorError.functionNotYetSupported)
case .s3:
return authenticateS3(from: viewController)
case .webDAV:
return authenticateWebDAV(from: viewController)
}
}

func deauthenticate(account: CloudProviderAccount) throws {
switch account.cloudProviderType {
case .box:
let tokenStorage = BoxTokenStorage(userID: account.accountUID)
let credential = BoxCredential(tokenStorage: tokenStorage)
_ = credential.deauthenticate()
case .dropbox:
let credential = DropboxCredential(tokenUID: account.accountUID)
credential.deauthenticate()
case .googleDrive:
let credential = GoogleDriveCredential(userID: account.accountUID)
credential.deauthenticate()
case .localFileSystem:
break
case .oneDrive:
let credential = try OneDriveCredential(with: account.accountUID)
try credential.deauthenticate()
case .pCloud:
let credential = try PCloudCredential(userID: account.accountUID)
try credential.deauthenticate()
case .webDAV:
try WebDAVCredentialManager.shared.removeCredentialFromKeychain(with: account.accountUID)
case .localFileSystem:
break
case .s3:
try S3CredentialManager.shared.removeCredential(with: account.accountUID)
case .webDAV:
try WebDAVCredentialManager.shared.removeCredentialFromKeychain(with: account.accountUID)
}
let correspondingVaults = try vaultAccountManager.getAllAccounts().filter { $0.delegateAccountUID == account.accountUID }
_ = Promise<Void>(on: .global()) { fulfill, _ in
Expand Down
10 changes: 6 additions & 4 deletions Cryptomator/Common/CloudProviderType+Localization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@ import Foundation
extension CloudProviderType {
func localizedString() -> String {
switch self {
case .box:
return "Box"
case .dropbox:
return "Dropbox"
case .googleDrive:
return "Google Drive"
case let .localFileSystem(localFileSystemType):
return localFileSystemType.localizedString()
case .oneDrive:
return "OneDrive"
case .pCloud:
return "pCloud"
case .webDAV:
return "WebDAV"
case let .localFileSystem(localFileSystemType):
return localFileSystemType.localizedString()
case .s3:
return "S3"
case .webDAV:
return "WebDAV"
}
}
}
Expand Down
Loading

0 comments on commit 80a1670

Please sign in to comment.