Skip to content

Commit

Permalink
Bugfix: Missing lock icons in vaults list (#386)
Browse files Browse the repository at this point in the history
Co-authored-by: Tobias Hagemann <[email protected]>
  • Loading branch information
iammajid and tobihagemann authored Oct 16, 2024
1 parent 483223f commit 840ff2b
Show file tree
Hide file tree
Showing 14 changed files with 31 additions and 113 deletions.
8 changes: 0 additions & 8 deletions Cryptomator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,6 @@
4ABCF3522726D24800A7FBB7 /* MoveVaultViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABCF3512726D24800A7FBB7 /* MoveVaultViewModelTests.swift */; };
4AC005F127C3D80B006FFE87 /* PremiumManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC005F027C3D80B006FFE87 /* PremiumManager.swift */; };
4AC005F327C3D932006FFE87 /* PremiumManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC005F227C3D932006FFE87 /* PremiumManagerMock.swift */; };
4AC1157627F5BD890023F51B /* Promise+AllIgnoringResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC1157527F5BD890023F51B /* Promise+AllIgnoringResult.swift */; };
4AC1157827F5BEFD0023F51B /* Promise+AllIgnoringResultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC1157727F5BEFD0023F51B /* Promise+AllIgnoringResultsTests.swift */; };
4AC86270273598CC00E15BA5 /* UIViewController+ProgressHUDError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC8626F273598CC00E15BA5 /* UIViewController+ProgressHUDError.swift */; };
4AD0F61C24AF203F0026B765 /* FileProvider+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AD0F61B24AF203F0026B765 /* FileProvider+Actions.swift */; };
4AD3D7D6282EBDE7008188CD /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AD3D7D5282EBDE7008188CD /* Intents.framework */; };
Expand Down Expand Up @@ -830,8 +828,6 @@
4ABCF3512726D24800A7FBB7 /* MoveVaultViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveVaultViewModelTests.swift; sourceTree = "<group>"; };
4AC005F027C3D80B006FFE87 /* PremiumManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumManager.swift; sourceTree = "<group>"; };
4AC005F227C3D932006FFE87 /* PremiumManagerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumManagerMock.swift; sourceTree = "<group>"; };
4AC1157527F5BD890023F51B /* Promise+AllIgnoringResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+AllIgnoringResult.swift"; sourceTree = "<group>"; };
4AC1157727F5BEFD0023F51B /* Promise+AllIgnoringResultsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+AllIgnoringResultsTests.swift"; sourceTree = "<group>"; };
4AC8626F273598CC00E15BA5 /* UIViewController+ProgressHUDError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+ProgressHUDError.swift"; sourceTree = "<group>"; };
4AD0F61B24AF203F0026B765 /* FileProvider+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProvider+Actions.swift"; sourceTree = "<group>"; };
4AD3D7D4282EBDE7008188CD /* CryptomatorIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = CryptomatorIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1218,7 +1214,6 @@
4AFBFA19282946BF00E30818 /* InMemoryProgressManagerTests.swift */,
4AB1D4EF27D20420009060AB /* LocalURLProviderTests.swift */,
4A0AA12C2ABA277800CF24FD /* PermissionProviderImplTests.swift */,
4AC1157727F5BEFD0023F51B /* Promise+AllIgnoringResultsTests.swift */,
4ADC66C427A7F6D6002E6CC7 /* UnlockMonitorTests.swift */,
4A4F47F224B875070033328B /* URL+NameCollisionExtensionTests.swift */,
4AE5196427F48D6600BA6E4A /* WorkflowDependencyFactoryTests.swift */,
Expand Down Expand Up @@ -1932,7 +1927,6 @@
4AEE6EE02822A33400E1B35E /* NSFileProviderItemIdentifier+Database.swift */,
4A0AA12A2AB8DB1800CF24FD /* PermissionProvider.swift */,
4AEE6EE92825716400E1B35E /* ProgressManager.swift */,
4AC1157527F5BD890023F51B /* Promise+AllIgnoringResult.swift */,
4ADD233F26737CD400374E4E /* RootFileProviderItem.swift */,
4A7514A02937F777002E802E /* SessionTaskRegistrator.swift */,
4ADC66C027A7F426002E6CC7 /* UnlockMonitor.swift */,
Expand Down Expand Up @@ -2578,7 +2572,6 @@
4AB1C33C265E9DBC00DC7A49 /* CloudTaskExecutorTestCase.swift in Sources */,
4AE5196727F495BF00BA6E4A /* WorkflowDependencyTasksCollectionMock.swift in Sources */,
4A0AA12F2ABA2A1600CF24FD /* PermissionProviderMock.swift in Sources */,
4AC1157827F5BEFD0023F51B /* Promise+AllIgnoringResultsTests.swift in Sources */,
4AE5196527F48D6600BA6E4A /* WorkflowDependencyFactoryTests.swift in Sources */,
4A49FABE271ECDE80069A0CC /* ItemEnumerationTaskManagerTests.swift in Sources */,
4A248229266E2DD6002D9F59 /* FileProviderAdapterCreateDirectoryTests.swift in Sources */,
Expand Down Expand Up @@ -2963,7 +2956,6 @@
4ADD234026737CD400374E4E /* RootFileProviderItem.swift in Sources */,
747F2F232587BC250072FB30 /* ItemMetadataDBManager.swift in Sources */,
4A511D47265FEFBE000A0E01 /* DownloadTask.swift in Sources */,
4AC1157627F5BD890023F51B /* Promise+AllIgnoringResult.swift in Sources */,
4A09E54E27071F4F0056D32A /* ErrorMapper.swift in Sources */,
4AEECD35279EB0FD00C6E2B5 /* FileProviderEnumerator.swift in Sources */,
4AE0D8DC2653DF1300DF5D22 /* DownloadTaskExecutor.swift in Sources */,
Expand Down
4 changes: 0 additions & 4 deletions Cryptomator/Snapshots/SnapshotCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ private class SnapshotVaultLockingMock: VaultLocking {
reply(true)
}

func getUnlockedVaultDomainIdentifiers(reply: @escaping ([NSFileProviderDomainIdentifier]) -> Void) {
fatalError()
}

var serviceName: NSFileProviderServiceName = .init("org.cryptomator.ios.vault-locking")

func makeListenerEndpoint() throws -> NSXPCListenerEndpoint {
Expand Down
7 changes: 1 addition & 6 deletions Cryptomator/VaultList/VaultCellViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ protocol VaultCellViewModelProtocol: TableViewCellViewModel, ViewModel {
var vault: VaultInfo { get }
var lockButtonIsHidden: AnyPublisher<Bool, Never> { get }
func lockVault() -> Promise<Void>
func setVaultUnlockStatus(unlocked: Bool)
}

class VaultCellViewModel: TableViewCellViewModel, VaultCellViewModelProtocol {
Expand Down Expand Up @@ -46,18 +45,14 @@ class VaultCellViewModel: TableViewCellViewModel, VaultCellViewModelProtocol {
return getXPCPromise.then { xpc in
xpc.proxy.lockVault(domainIdentifier: domainIdentifier)
}.then {
self.setVaultUnlockStatus(unlocked: false)
self.vault.vaultIsUnlocked.value = false
}.catch { error in
self.errorPublisher.send(error)
}.always {
self.fileProviderConnector.invalidateXPC(getXPCPromise)
}
}

func setVaultUnlockStatus(unlocked: Bool) {
vault.vaultIsUnlocked.value = unlocked
}

override func hash(into hasher: inout Hasher) {
hasher.combine(vault.vaultUID)
}
Expand Down
31 changes: 15 additions & 16 deletions Cryptomator/VaultList/VaultListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,24 +104,23 @@ class VaultListViewModel: ViewModel, VaultListViewModelProtocol {
}

func refreshVaultLockStates() -> Promise<Void> {
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: .vaultLocking, domain: nil)
let promises = vaultCellViewModels.map { vaultCellViewModel in
return checkVaultUnlockStatus(for: vaultCellViewModel.vault)
}
return all(ignoringResult: promises)
}

private func checkVaultUnlockStatus(for vault: VaultInfo) -> Promise<Void> {
let domainIdentifier = NSFileProviderDomainIdentifier(vault.vaultUID)
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: .vaultLocking, domainIdentifier: domainIdentifier)

return getXPCPromise.then { xpc in
return wrap { handler in
xpc.proxy.getUnlockedVaultDomainIdentifiers(reply: handler)
}
}.then { unlockedVaultDomainIdentifiers -> Void in
for domainIdentifier in unlockedVaultDomainIdentifiers {
let vaultInfo = self.vaultCellViewModels.first { $0.vault.vaultUID == domainIdentifier.rawValue }
vaultInfo?.setVaultUnlockStatus(unlocked: true)
}
self.vaultCellViewModels.filter { vaultCellViewModel in
unlockedVaultDomainIdentifiers.allSatisfy { domainIdentifier in
vaultCellViewModel.vault.vaultUID != domainIdentifier.rawValue
}
}.forEach { vaultCellViewModel in
vaultCellViewModel.setVaultUnlockStatus(unlocked: false)
}
return xpc.proxy.getIsUnlockedVault(domainIdentifier: domainIdentifier)
}.then { isUnlocked -> Void in
DDLogDebug("Vault \(vault.vaultUID) unlock status: \(isUnlocked ? "Unlocked" : "Locked")")
vault.vaultIsUnlocked.value = isUnlocked
}.catch { error in
DDLogError("Failed to check unlock status for vault \(vault.vaultUID): \(error)")
}.always {
self.fileProviderConnector.invalidateXPC(getXPCPromise)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import Promises
func lockVault(domainIdentifier: NSFileProviderDomainIdentifier)
func gracefulLockVault(domainIdentifier: NSFileProviderDomainIdentifier, reply: @escaping (Error?) -> Void)
func getIsUnlockedVault(domainIdentifier: NSFileProviderDomainIdentifier, reply: @escaping (Bool) -> Void)
func getUnlockedVaultDomainIdentifiers(reply: @escaping ([NSFileProviderDomainIdentifier]) -> Void)
}

public extension NSFileProviderServiceName {
Expand All @@ -41,10 +40,4 @@ public extension VaultLocking {
self.getIsUnlockedVault(domainIdentifier: domainIdentifier, reply: replyHandler)
}
}

func getUnlockedVaultDomainIdentifiers() -> Promise<[NSFileProviderDomainIdentifier]> {
return wrap { replyHandler in
self.getUnlockedVaultDomainIdentifiers(reply: replyHandler)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation
import Promises

func all<Value, Container: Sequence>(ignoringResult promises: Container) -> Promise<Void> where Container.Element == Promise<Value> {
public func all<Value, Container: Sequence>(ignoringResult promises: Container) -> Promise<Void> where Container.Element == Promise<Value> {
return any(promises).then { _ -> Void in
// discard result
}.recover { _ -> Void in
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//
// Promise+AllIgnoringResultsTests.swift
// CryptomatorFileProviderTests
// CryptomatorCommonCoreTests
//
// Created by Philipp Schmid on 31.03.22.
// Copyright © 2022 Skymatic GmbH. All rights reserved.
//

import CryptomatorCommonCore
import Promises
import XCTest
@testable import CryptomatorFileProvider

class Promise_AllIgnoringResultsTests: XCTestCase {
func testWaitForAll() throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,13 @@ extension XCTestCase {
}
wait(for: [expectation], timeout: 1.0)
}

func XCTAssertGetsNotExecuted<T>(_ promise: Promise<T>, timeout seconds: TimeInterval = 1.0, file: StaticString = #filePath, line: UInt = #line) {
let expectation = XCTestExpectation()
expectation.isInverted = true
promise.always {
expectation.fulfill()
}
wait(for: [expectation], timeout: seconds)
}
}
13 changes: 0 additions & 13 deletions CryptomatorFileProvider/FileProviderAdapterManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,6 @@ public class FileProviderAdapterManager: FileProviderAdapterProviding {
return adapterCache.getItem(identifier: domainIdentifier) != nil
}

public func getDomainIdentifiersOfUnlockedVaults() -> [NSFileProviderDomainIdentifier] {
let cachedIdentifiers = adapterCache.getAllCachedIdentifiers()
cachedIdentifiers.forEach { updateLockStatus(domainIdentifier: $0) }
return adapterCache.getAllCachedIdentifiers()
}

/**
Locks a vault gracefully.
Expand Down Expand Up @@ -250,7 +244,6 @@ protocol FileProviderAdapterCacheType {
func cacheItem(_ item: AdapterCacheItem, identifier: NSFileProviderDomainIdentifier)
func removeItem(identifier: NSFileProviderDomainIdentifier)
func getItem(identifier: NSFileProviderDomainIdentifier) -> AdapterCacheItem?
func getAllCachedIdentifiers() -> [NSFileProviderDomainIdentifier]
}

class FileProviderAdapterCache: FileProviderAdapterCacheType {
Expand All @@ -274,10 +267,4 @@ class FileProviderAdapterCache: FileProviderAdapterCacheType {
return cachedAdapters[identifier]
}
}

func getAllCachedIdentifiers() -> [NSFileProviderDomainIdentifier] {
queue.sync {
return cachedAdapters.map { $0.key }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,4 @@ public class VaultLockingServiceSource: ServiceSource, VaultLocking {
public func getIsUnlockedVault(domainIdentifier: NSFileProviderDomainIdentifier, reply: @escaping (Bool) -> Void) {
reply(FileProviderAdapterManager.shared.vaultIsUnlocked(domainIdentifier: domainIdentifier))
}

public func getUnlockedVaultDomainIdentifiers(reply: @escaping ([NSFileProviderDomainIdentifier]) -> Void) {
reply(FileProviderAdapterManager.shared.getDomainIdentifiersOfUnlockedVaults())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import CocoaLumberjackSwift
import CryptomatorCloudAccessCore
import CryptomatorCommonCore
import Foundation
import Promises

Expand Down
30 changes: 0 additions & 30 deletions CryptomatorFileProviderTests/FileProviderAdapterManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,34 +226,4 @@ class FileProviderAdapterManagerTests: XCTestCase {
XCTAssertEqual(1, maintenanceManagerMock.disableMaintenanceModeCallsCount)
XCTAssert(cache.isEmpty)
}

func testGetDomainIdentifiersOfUnlockedVaults() throws {
let unlockedDomainIdentifier = NSFileProviderDomainIdentifier(rawValue: "1")
let lockedDomainIdentifier = NSFileProviderDomainIdentifier(rawValue: "2")
notificatorManagerMock.getFileProviderNotificatorForReturnValue = fileProviderNotificatorMock
let unlockedVaultMaintenanceManagerMock = MaintenanceManagerMock()
let lockedVaultMaintenanceManagerMock = MaintenanceManagerMock()
let unlockedVaultAdapterCacheItem = AdapterCacheItem(adapter: FileProviderAdapterTypeMock(), maintenanceManager: unlockedVaultMaintenanceManagerMock, workingSetObserver: workingSetObservationMock)
let lockedVaultAdapterCacheItem = AdapterCacheItem(adapter: FileProviderAdapterTypeMock(), maintenanceManager: lockedVaultMaintenanceManagerMock, workingSetObserver: workingSetObservationMock)

var cache = [NSFileProviderDomainIdentifier: AdapterCacheItem]()
cache[unlockedDomainIdentifier] = unlockedVaultAdapterCacheItem
cache[lockedDomainIdentifier] = lockedVaultAdapterCacheItem
adapterCacheMock.getItemIdentifierClosure = { return cache[$0] }
adapterCacheMock.getAllCachedIdentifiersClosure = { cache.map { $0.key }}
adapterCacheMock.removeItemIdentifierClosure = {
cache[$0] = nil
}
vaultKeepUnlockedHelperMock.shouldAutoLockVaultWithVaultUIDClosure = { $0 != unlockedDomainIdentifier.rawValue }

XCTAssertEqual([unlockedDomainIdentifier], fileProviderAdapterManager.getDomainIdentifiersOfUnlockedVaults())

XCTAssertFalse(unlockedVaultMaintenanceManagerMock.enableMaintenanceModeCalled)
XCTAssertFalse(unlockedVaultMaintenanceManagerMock.disableMaintenanceModeCalled)
XCTAssertEqual(1, lockedVaultMaintenanceManagerMock.enableMaintenanceModeCallsCount)
XCTAssertEqual(1, lockedVaultMaintenanceManagerMock.disableMaintenanceModeCallsCount)

XCTAssertEqual(1, cache.count)
XCTAssertNotNil(cache[unlockedDomainIdentifier])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,4 @@ final class FileProviderAdapterCacheTypeMock: FileProviderAdapterCacheType {
getItemIdentifierReceivedInvocations.append(identifier)
return getItemIdentifierClosure.map({ $0(identifier) }) ?? getItemIdentifierReturnValue
}

// MARK: - getAllCachedIdentifiers

var getAllCachedIdentifiersCallsCount = 0
var getAllCachedIdentifiersCalled: Bool {
getAllCachedIdentifiersCallsCount > 0
}

var getAllCachedIdentifiersReturnValue: [NSFileProviderDomainIdentifier]!
var getAllCachedIdentifiersClosure: (() -> [NSFileProviderDomainIdentifier])?

func getAllCachedIdentifiers() -> [NSFileProviderDomainIdentifier] {
getAllCachedIdentifiersCallsCount += 1
return getAllCachedIdentifiersClosure.map({ $0() }) ?? getAllCachedIdentifiersReturnValue
}
}
9 changes: 2 additions & 7 deletions CryptomatorTests/VaultListViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,9 @@ class VaultListViewModelTests: XCTestCase {
vaultLockingMock.unlockedVaults.append(NSFileProviderDomainIdentifier("vault1"))

vaultListViewModel.refreshVaultLockStates().then {
XCTAssertNil(self.fileProviderConnectorMock.passedDomain)
XCTAssertEqual(self.fileProviderConnectorMock.passedDomainIdentifier?.rawValue, "vault1")
XCTAssertEqual(NSFileProviderServiceName("org.cryptomator.ios.vault-locking"), self.fileProviderConnectorMock.passedServiceName)

XCTAssertEqual(1, vaultLockingMock.unlockedVaults.count)
let unlockedVaults = vaultListViewModel.getVaults().filter({ $0.vaultIsUnlocked.value })
XCTAssertEqual(1, unlockedVaults.count)
XCTAssertTrue(unlockedVaults.contains(where: { $0.vaultUID == "vault1" }))
Expand All @@ -144,7 +143,7 @@ class VaultListViewModelTests: XCTestCase {
expectation.fulfill()
}
wait(for: [expectation], timeout: 1.0)
XCTAssertEqual(1, fileProviderConnectorMock.xpcInvalidationCallCount)
XCTAssertEqual(2, fileProviderConnectorMock.xpcInvalidationCallCount)
}
}

Expand Down Expand Up @@ -245,10 +244,6 @@ class VaultLockingMock: VaultLocking {
reply(unlockedVaults.contains(domainIdentifier))
}

func getUnlockedVaultDomainIdentifiers(reply: @escaping ([NSFileProviderDomainIdentifier]) -> Void) {
reply(unlockedVaults)
}

let serviceName = NSFileProviderServiceName("org.cryptomator.ios.vault-locking")

func makeListenerEndpoint() throws -> NSXPCListenerEndpoint {
Expand Down

0 comments on commit 840ff2b

Please sign in to comment.