Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UnauthorizedError screen for invalid cloud access in Files app #384

Merged
merged 5 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cryptomator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@
74F5DC1C26DCD2FB00AFE989 /* StoreObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F5DC1B26DCD2FB00AFE989 /* StoreObserver.swift */; };
74F5DC1F26DD036D00AFE989 /* StoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F5DC1E26DD036D00AFE989 /* StoreManager.swift */; };
74FC576125ADED030003ED27 /* VaultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FC576025ADED030003ED27 /* VaultCell.swift */; };
B330CB452CB5735300C21E03 /* UnauthorizedErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B330CB442CB5735000C21E03 /* UnauthorizedErrorViewController.swift */; };
B3D19A442CB937C700CD18A5 /* FileProviderCoordinatorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D19A432CB937BF00CD18A5 /* FileProviderCoordinatorError.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -1041,6 +1043,8 @@
74F5DC1B26DCD2FB00AFE989 /* StoreObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreObserver.swift; sourceTree = "<group>"; };
74F5DC1E26DD036D00AFE989 /* StoreManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreManager.swift; sourceTree = "<group>"; };
74FC576025ADED030003ED27 /* VaultCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultCell.swift; sourceTree = "<group>"; };
B330CB442CB5735000C21E03 /* UnauthorizedErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnauthorizedErrorViewController.swift; sourceTree = "<group>"; };
B3D19A432CB937BF00CD18A5 /* FileProviderCoordinatorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderCoordinatorError.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -1663,7 +1667,9 @@
4A9FCB0B251A02A3002A8B41 /* FileProviderExtensionUI.entitlements */,
4AA621EB249A6A8400A0BCBD /* Info.plist */,
4A6A521A268B7147006F7368 /* FileProviderCoordinator.swift */,
B3D19A432CB937BF00CD18A5 /* FileProviderCoordinatorError.swift */,
4A6A5218268B6D31006F7368 /* OnboardingViewController.swift */,
B330CB442CB5735000C21E03 /* UnauthorizedErrorViewController.swift */,
4A6A520C268B5EF7006F7368 /* RootViewController.swift */,
4A9BED65268F2D9C00721BAA /* UnlockVaultViewController.swift */,
4AFD8C0E269304A700F77BA6 /* UnlockVaultViewModel.swift */,
Expand Down Expand Up @@ -2670,6 +2676,8 @@
4A804082276952C300D7D999 /* FileProviderCoordinatorSnapshotMock.swift in Sources */,
4A9BED66268F2D9D00721BAA /* UnlockVaultViewController.swift in Sources */,
4A6A521B268B7147006F7368 /* FileProviderCoordinator.swift in Sources */,
B330CB452CB5735300C21E03 /* UnauthorizedErrorViewController.swift in Sources */,
B3D19A442CB937C700CD18A5 /* FileProviderCoordinatorError.swift in Sources */,
4A6A5219268B6D32006F7368 /* OnboardingViewController.swift in Sources */,
4AFD8C0F269304A700F77BA6 /* UnlockVaultViewModel.swift in Sources */,
);
Expand Down
17 changes: 17 additions & 0 deletions FileProviderExtensionUI/FileProviderCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ class FileProviderCoordinator: Coordinator {
navigationController.pushViewController(onboardingVC, animated: false)
}

func showUnauthorizedError(vaultName: String) {
let unauthorizedErrorVC = UnauthorizedErrorViewController(vaultName: vaultName)
unauthorizedErrorVC.coordinator = self
navigationController.pushViewController(unauthorizedErrorVC, animated: true)
}

func openCryptomatorApp() {
let url = URL(string: "cryptomator:")!
extensionContext.open(url) { success in
Expand Down Expand Up @@ -134,6 +140,8 @@ class FileProviderCoordinator: Coordinator {
switch error {
case CloudProviderError.noInternetConnection, LocalizedCloudProviderError.itemNotFound:
break
case LocalizedCloudProviderError.unauthorized:
throw FileProviderCoordinatorError.unauthorized(vaultName: domain.displayName)
default:
throw error
}
Expand Down Expand Up @@ -190,6 +198,15 @@ class FileProviderCoordinator: Coordinator {
guard let hostViewController = hostViewController else {
return
}

if let fileProviderError = error as? FileProviderCoordinatorError {
switch fileProviderError {
case let .unauthorized(vaultName):
showUnauthorizedError(vaultName: vaultName)
return
}
}

tobihagemann marked this conversation as resolved.
Show resolved Hide resolved
handleError(error, for: hostViewController)
}
}
13 changes: 13 additions & 0 deletions FileProviderExtensionUI/FileProviderCoordinatorError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// FileProviderCoordinatorError.swift
// Cryptomator
//
// Created by Majid Achhoud on 11.10.24.
// Copyright © 2024 Skymatic GmbH. All rights reserved.
//

import Foundation

public enum FileProviderCoordinatorError: Error {
case unauthorized(vaultName: String)
}
81 changes: 81 additions & 0 deletions FileProviderExtensionUI/UnauthorizedErrorViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// UnauthorizedErrorViewController.swift
// Cryptomator
//
// Created by Majid Achhoud on 08.10.24.
// Copyright © 2024 Skymatic GmbH. All rights reserved.
//

import CryptomatorCommonCore
import UIKit

class UnauthorizedErrorViewController: UITableViewController {
weak var coordinator: FileProviderCoordinator?
private var vaultName: String

private lazy var openCryptomatorCell: UITableViewCell = {
let cell = UITableViewCell()
cell.textLabel?.text = LocalizedString.getValue("fileProvider.onboarding.button.openCryptomator")
cell.textLabel?.textColor = .cryptomatorPrimary
return cell
}()
tobihagemann marked this conversation as resolved.
Show resolved Hide resolved

init(vaultName: String) {
self.vaultName = vaultName
super.init(style: .insetGrouped)
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
title = vaultName
let doneButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(done))
navigationItem.rightBarButtonItem = doneButton
tableView.backgroundColor = .cryptomatorBackground
tableView.cellLayoutMarginsFollowReadableWidth = true
}
tobihagemann marked this conversation as resolved.
Show resolved Hide resolved

@objc func done() {
coordinator?.userCancelled()
}

override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

// MARK: - UITableViewDataSource

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return openCryptomatorCell
}

// MARK: - UITableViewDelegate

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return UnauthorizedErrorHeaderView(vaultName: vaultName)
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
coordinator?.openCryptomatorApp()
}
}

private class UnauthorizedErrorHeaderView: LargeHeaderFooterView {
init(vaultName: String) {
let config = UIImage.SymbolConfiguration(pointSize: 100)
tobihagemann marked this conversation as resolved.
Show resolved Hide resolved
let symbolImage = UIImage(systemName: "exclamationmark.triangle.fill", withConfiguration: config)?.withTintColor(.systemYellow, renderingMode: .alwaysOriginal)

tobihagemann marked this conversation as resolved.
Show resolved Hide resolved
let infoText = String(format: LocalizedString.getValue("fileprovider.error.reauthentication"), vaultName)

super.init(image: symbolImage, infoText: infoText)
}
}
1 change: 1 addition & 0 deletions SharedResources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"fileProvider.error.biometricalAuthWrongPassword.message" = "The password that has been saved for %@ is wrong. Please try again and enter your password to re-enable %@.";
"fileProvider.error.defaultLock.title" = "Unlock Required";
"fileProvider.error.defaultLock.message" = "To access and show the contents of your vault, it has to be unlocked.";
"fileprovider.error.reauthentication" = "Access to your vault \"%@\" was denied. Open the main app to check your connection and re-authenticate if needed.";
tobihagemann marked this conversation as resolved.
Show resolved Hide resolved
"fileProvider.error.unlockButton" = "Unlock";
"fileProvider.clearFileFromCache.title" = "Clear File from Cache";
"fileProvider.clearFileFromCache.message" = "This only removes the local file from your device and does not delete the file in the cloud.";
Expand Down
Loading