diff --git a/Sources/Packages/Sources/SecretKit/Erasers/AnySecretStore.swift b/Sources/Packages/Sources/SecretKit/Erasers/AnySecretStore.swift index 3e831b0..93d2460 100644 --- a/Sources/Packages/Sources/SecretKit/Erasers/AnySecretStore.swift +++ b/Sources/Packages/Sources/SecretKit/Erasers/AnySecretStore.swift @@ -2,21 +2,19 @@ import Foundation import Combine /// Type eraser for SecretStore. -public class AnySecretStore: SecretStore { +public class AnySecretStore: SecretStore, @unchecked Sendable { - let base: Any - private let _isAvailable: () -> Bool - private let _id: () -> UUID - private let _name: () -> String - private let _secrets: () -> [AnySecret] - private let _sign: (Data, AnySecret, SigningRequestProvenance) async throws -> Data - private let _verify: (Data, Data, AnySecret) async throws -> Bool - private let _existingPersistedAuthenticationContext: (AnySecret) async -> PersistedAuthenticationContext? - private let _persistAuthentication: (AnySecret, TimeInterval) async throws -> Void - private let _reloadSecrets: () async -> Void + private let _isAvailable: @Sendable () -> Bool + private let _id: @Sendable () -> UUID + private let _name: @Sendable () -> String + private let _secrets: @Sendable () -> [AnySecret] + private let _sign: @Sendable (Data, AnySecret, SigningRequestProvenance) async throws -> Data + private let _verify: @Sendable (Data, Data, AnySecret) async throws -> Bool + private let _existingPersistedAuthenticationContext: @Sendable (AnySecret) async -> PersistedAuthenticationContext? + private let _persistAuthentication: @Sendable (AnySecret, TimeInterval) async throws -> Void + private let _reloadSecrets: @Sendable () async -> Void public init(_ secretStore: SecretStoreType) where SecretStoreType: SecretStore { - base = secretStore _isAvailable = { secretStore.isAvailable } _name = { secretStore.name } _id = { secretStore.id } @@ -66,11 +64,11 @@ public class AnySecretStore: SecretStore { } -public final class AnySecretStoreModifiable: AnySecretStore, SecretStoreModifiable { +public final class AnySecretStoreModifiable: AnySecretStore, SecretStoreModifiable, @unchecked Sendable { - private let _create: (String, Bool) async throws -> Void - private let _delete: (AnySecret) async throws -> Void - private let _update: (AnySecret, String) async throws -> Void + private let _create: @Sendable (String, Bool) async throws -> Void + private let _delete: @Sendable (AnySecret) async throws -> Void + private let _update: @Sendable (AnySecret, String) async throws -> Void public init(modifiable secretStore: SecretStoreType) where SecretStoreType: SecretStoreModifiable { _create = { try await secretStore.create(name: $0, requiresAuthentication: $1) } diff --git a/Sources/Packages/Sources/SecretKit/SecretStoreList.swift b/Sources/Packages/Sources/SecretKit/SecretStoreList.swift index 0f1da09..af0dc9e 100644 --- a/Sources/Packages/Sources/SecretKit/SecretStoreList.swift +++ b/Sources/Packages/Sources/SecretKit/SecretStoreList.swift @@ -15,14 +15,14 @@ import Observation /// Adds a non-type-erased SecretStore to the list. public func add(store: SecretStoreType) { - addInternal(store: AnySecretStore(store)) + stores.append(AnySecretStore(store)) } /// Adds a non-type-erased modifiable SecretStore. public func add(store: SecretStoreType) { let modifiable = AnySecretStoreModifiable(modifiable: store) modifiableStore = modifiable - addInternal(store: modifiable) + stores.append(modifiable) } /// A boolean describing whether there are any Stores available. @@ -35,14 +35,3 @@ import Observation } } - -extension SecretStoreList { - - private func addInternal(store: AnySecretStore) { - stores.append(store) -// store.objectWillChange.sink { -// self.objectWillChange.send() -// }.store(in: &cancellables) - } - -} diff --git a/Sources/Packages/Sources/SecretKit/Types/PersistedAuthenticationContext.swift b/Sources/Packages/Sources/SecretKit/Types/PersistedAuthenticationContext.swift index 65ceaf8..edd6dea 100644 --- a/Sources/Packages/Sources/SecretKit/Types/PersistedAuthenticationContext.swift +++ b/Sources/Packages/Sources/SecretKit/Types/PersistedAuthenticationContext.swift @@ -1,7 +1,7 @@ import Foundation /// Protocol describing a persisted authentication context. This is an authorization that can be reused for multiple access to a secret that requires authentication for a specific period of time. -public protocol PersistedAuthenticationContext { +public protocol PersistedAuthenticationContext: Sendable { /// Whether the context remains valid. var valid: Bool { get } /// The date at which the authorization expires and the context becomes invalid. diff --git a/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift b/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift index f0a465b..0114af7 100644 --- a/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift +++ b/Sources/Packages/Sources/SecretKit/Types/SecretStore.swift @@ -2,7 +2,7 @@ import Foundation import Combine /// Manages access to Secrets, and performs signature operations on data using those Secrets. -public protocol SecretStore: Identifiable { +public protocol SecretStore: Identifiable, Sendable { associatedtype SecretType: Secret diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index 216033b..371cdd5 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -21,16 +21,15 @@ extension SecureEnclave { } private let _secrets: Mutex<[Secret]> = .init([]) - private var persistedAuthenticationContexts: [Secret: PersistentAuthenticationContext] = [:] + private let persistedAuthenticationContexts: Mutex<[Secret: PersistentAuthenticationContext]> = .init([:]) /// Initializes a Store. public init() { - // FIXME: THIS -// Task { -// for await _ in DistributedNotificationCenter.default().notifications(named: .secretStoreUpdated) { -// await reloadSecretsInternal(notifyAgent: false) -// } -// } + Task { + for await _ in DistributedNotificationCenter.default().notifications(named: .secretStoreUpdated) { + await reloadSecretsInternal(notifyAgent: false) + } + } loadSecrets() } @@ -106,40 +105,42 @@ extension SecureEnclave { } public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data { - let context: LAContext - if let existing = persistedAuthenticationContexts[secret], existing.valid { - context = existing.context - } else { + let context: Mutex +// if let existing = persistedAuthenticationContexts.withLock({ $0 })[secret], existing.valid { +// context = existing.context +// } else { let newContext = LAContext() newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button") - context = newContext - } - context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)") - let attributes = KeychainDictionary([ - kSecClass: kSecClassKey, - kSecAttrKeyClass: kSecAttrKeyClassPrivate, - kSecAttrApplicationLabel: secret.id as CFData, - kSecAttrKeyType: Constants.keyType, - kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, - kSecAttrApplicationTag: Constants.keyTag, - kSecUseAuthenticationContext: context, - kSecReturnRef: true + context = .init(newContext) +// } + return try context.withLock { context in + context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)") + let attributes = KeychainDictionary([ + kSecClass: kSecClassKey, + kSecAttrKeyClass: kSecAttrKeyClassPrivate, + kSecAttrApplicationLabel: secret.id as CFData, + kSecAttrKeyType: Constants.keyType, + kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, + kSecAttrApplicationTag: Constants.keyTag, + kSecUseAuthenticationContext: context, + kSecReturnRef: true ]) - var untyped: CFTypeRef? - let status = SecItemCopyMatching(attributes, &untyped) - if status != errSecSuccess { - throw KeychainError(statusCode: status) + var untyped: CFTypeRef? + let status = SecItemCopyMatching(attributes, &untyped) + if status != errSecSuccess { + throw KeychainError(statusCode: status) + } + guard let untypedSafe = untyped else { + throw KeychainError(statusCode: errSecSuccess) + } + let key = untypedSafe as! SecKey + var signError: SecurityError? + + guard let signature = SecKeyCreateSignature(key, .ecdsaSignatureMessageX962SHA256, data as CFData, &signError) else { + throw SigningError(error: signError) + } + return signature as Data } - guard let untypedSafe = untyped else { - throw KeychainError(statusCode: errSecSuccess) - } - let key = untypedSafe as! SecKey - var signError: SecurityError? - - guard let signature = SecKeyCreateSignature(key, .ecdsaSignatureMessageX962SHA256, data as CFData, &signError) else { - throw SigningError(error: signError) - } - return signature as Data } public func verify(signature: Data, for data: Data, with secret: Secret) throws -> Bool { @@ -178,7 +179,7 @@ extension SecureEnclave { } public func existingPersistedAuthenticationContext(secret: Secret) -> PersistedAuthenticationContext? { - guard let persisted = persistedAuthenticationContexts[secret], persisted.valid else { return nil } + guard let persisted = persistedAuthenticationContexts.withLock({ $0 })[secret], persisted.valid else { return nil } return persisted } @@ -197,9 +198,11 @@ extension SecureEnclave { newContext.localizedReason = String(localized: "auth_context_persist_for_duration_unknown_\(secret.name)") } newContext.evaluatePolicy(LAPolicy.deviceOwnerAuthentication, localizedReason: newContext.localizedReason) { [weak self] success, _ in - guard success else { return } + guard success, let self else { return } let context = PersistentAuthenticationContext(secret: secret, context: newContext, duration: duration) - self?.persistedAuthenticationContexts[secret] = context + self.persistedAuthenticationContexts.withLock { + $0[secret] = context + } } } @@ -322,12 +325,12 @@ extension SecureEnclave { extension SecureEnclave { /// A context describing a persisted authentication. - private struct PersistentAuthenticationContext: PersistedAuthenticationContext { + private final class PersistentAuthenticationContext: PersistedAuthenticationContext { /// The Secret to persist authentication for. let secret: Secret /// The LAContext used to authorize the persistent context. - let context: LAContext + nonisolated(unsafe) let context: LAContext /// An expiration date for the context. /// - Note - Monotonic time instead of Date() to prevent people setting the clock back. let monotonicExpiration: UInt64 diff --git a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift index 1280508..1aead35 100644 --- a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift +++ b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift @@ -1,5 +1,6 @@ import Foundation -import Combine +import Synchronization +import Observation import Security import CryptoTokenKit import LocalAuthentication @@ -8,32 +9,54 @@ import SecretKit extension SmartCard { /// An implementation of Store backed by a Smart Card. - public final class Store: SecretStore { + @Observable public final class Store: SecretStore { + + public var isAvailable: Bool { + _isAvailable.withLock { $0 } + } + private let _isAvailable: Mutex = .init(false) - @Published public var isAvailable: Bool = false public let id = UUID() - public private(set) var name = String(localized: "smart_card") - @Published public private(set) var secrets: [Secret] = [] - private let watcher = TKTokenWatcher() - private var tokenID: String? + public var name: String { + _name.withLock { $0 } + } + private let _name: Mutex = .init(String(localized: "smart_card")) + public var secrets: [Secret] { + _secrets.withLock { $0 } + } + private let _secrets: Mutex<[Secret]> = .init([]) + private let watcher: Mutex = .init(TKTokenWatcher()) + private let tokenID: Mutex = .init(nil) /// Initializes a Store. public init() { - tokenID = watcher.nonSecureEnclaveTokens.first - // FIXME: THIS - watcher.setInsertionHandler { string in - guard self.tokenID == nil else { return } - guard !string.contains("setoken") else { return } - - self.tokenID = string -// DispatchQueue.main.async { -// reload() -// } - self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string) + tokenID.withLock { tokenID in + watcher.withLock { watcher in + let id = watcher.nonSecureEnclaveTokens.first + watcher.setInsertionHandler { string in +// guard self.tokenID == nil else { return } +// guard !string.contains("setoken") else { return } +// +//// self.tokenID.withLock { +//// $0 = string +//// } +// // DispatchQueue.main.async { +// // reload() +// // } +// watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: string) + } + tokenID = id + } } - if let tokenID = tokenID { - self.isAvailable = true - self.watcher.addRemovalHandler(self.smartcardRemoved, forTokenID: tokenID) + // FIXME: THIS + if let tokenID = tokenID.withLock({ $0 }) { + _isAvailable.withLock { + $0 = true + } + watcher.withLock { + $0.addRemovalHandler(self.smartcardRemoved, forTokenID: tokenID) + + } } loadSecrets() } @@ -49,7 +72,7 @@ extension SmartCard { } public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data { - guard let tokenID = tokenID else { fatalError() } + guard let tokenID = tokenID.withLock({ $0 }) else { fatalError() } let context = LAContext() context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)") context.localizedCancelTitle = String(localized: "auth_context_request_deny_button") @@ -119,9 +142,13 @@ extension SmartCard { extension SmartCard.Store { private func reloadSecretsInternal() { - self.isAvailable = self.tokenID != nil + _isAvailable.withLock { + $0 = tokenID.withLock({ $0 }) != nil + } let before = self.secrets - self.secrets.removeAll() + self._secrets.withLock { + $0.removeAll() + } self.loadSecrets() if self.secrets != before { NotificationCenter.default.post(name: .secretStoreReloaded, object: self) @@ -131,19 +158,23 @@ extension SmartCard.Store { /// Resets the token ID and reloads secrets. /// - Parameter tokenID: The ID of the token that was removed. private func smartcardRemoved(for tokenID: String? = nil) { - self.tokenID = nil + self.tokenID.withLock { + $0 = nil + } reloadSecrets() } /// Loads all secrets from the store. private func loadSecrets() { - guard let tokenID = tokenID else { return } + guard let tokenID = tokenID.withLock({ $0 }) else { return } let fallbackName = String(localized: "smart_card") - if let driverName = watcher.tokenInfo(forTokenID: tokenID)?.driverName { - name = driverName - } else { - name = fallbackName + _name.withLock { + if let driverName = watcher.withLock({ $0.tokenInfo(forTokenID: tokenID)?.driverName }) { + $0 = driverName + } else { + $0 = fallbackName + } } let attributes = KeychainDictionary([ @@ -167,7 +198,9 @@ extension SmartCard.Store { let publicKey = publicKeyAttributes[kSecValueData] as! Data return SmartCard.Secret(id: tokenID, name: name, algorithm: algorithm, keySize: keySize, publicKey: publicKey) } - secrets.append(contentsOf: wrapped) + _secrets.withLock { + $0.append(contentsOf: wrapped) + } } } @@ -211,7 +244,7 @@ extension SmartCard.Store { /// - Returns: The decrypted data. /// - Warning: Encryption functions are deliberately only exposed on a library level, and are not exposed in Secretive itself to prevent users from data loss. Any pull requests which expose this functionality in the app will not be merged. public func decrypt(data: Data, with secret: SecretType) throws -> Data { - guard let tokenID = tokenID else { fatalError() } + guard let tokenID = tokenID.withLock({ $0 }) else { fatalError() } let context = LAContext() context.localizedReason = String(localized: "auth_context_request_decrypt_description_\(secret.name)") context.localizedCancelTitle = String(localized: "auth_context_request_deny_button") diff --git a/Sources/Secretive/App.swift b/Sources/Secretive/App.swift index fbd7e5e..8d6ed8b 100644 --- a/Sources/Secretive/App.swift +++ b/Sources/Secretive/App.swift @@ -69,26 +69,24 @@ struct Secretive: App { extension Secretive { private func reinstallAgent() { -// justUpdatedChecker.check() - // FIXME: THIS -// LaunchAgentController().install { -// // Wait a second for launchd to kick in (next runloop isn't enough). -// DispatchQueue.main.asyncAfter(deadline: .now() + 1) { -// agentStatusChecker.check() -// if !agentStatusChecker.running { -// forceLaunchAgent() -// } -// } -// } + justUpdatedChecker.check() + Task { + await LaunchAgentController().install() + try? await Task.sleep(for: .seconds(1)) + agentStatusChecker.check() + if !agentStatusChecker.running { + forceLaunchAgent() + } + } } private func forceLaunchAgent() { // We've run setup, we didn't just update, launchd is just not doing it's thing. // Force a launch directly. - // FIXME: THIS -// LaunchAgentController().forceLaunch { _ in -// agentStatusChecker.check() -// } + Task { + _ = await LaunchAgentController().forceLaunch() + agentStatusChecker.check() + } } } diff --git a/Sources/Secretive/Preview Content/PreviewStore.swift b/Sources/Secretive/Preview Content/PreviewStore.swift index 9480c88..f9d631c 100644 --- a/Sources/Secretive/Preview Content/PreviewStore.swift +++ b/Sources/Secretive/Preview Content/PreviewStore.swift @@ -18,69 +18,69 @@ extension Preview { } -extension Preview { - - class Store: SecretStore, ObservableObject { - - let isAvailable = true - let id = UUID() - var name: String { "Preview Store" } - @Published var secrets: [Secret] = [] - - init(secrets: [Secret]) { - self.secrets.append(contentsOf: secrets) - } - - init(numberOfRandomSecrets: Int = 5) { - let new = (0.. Data { - return data - } - - func verify(signature data: Data, for signature: Data, with secret: Preview.Secret) throws -> Bool { - true - } - - func existingPersistedAuthenticationContext(secret: Preview.Secret) -> PersistedAuthenticationContext? { - nil - } - - func persistAuthentication(secret: Preview.Secret, forDuration duration: TimeInterval) throws { - } - - func reloadSecrets() { - } - - } - - class StoreModifiable: Store, SecretStoreModifiable { - override var name: String { "Modifiable Preview Store" } - - func create(name: String, requiresAuthentication: Bool) throws { - } - - func delete(secret: Preview.Secret) throws { - } - - func update(secret: Preview.Secret, name: String) throws { - } - } -} - -extension Preview { - - static func storeList(stores: [Store] = [], modifiableStores: [StoreModifiable] = []) -> SecretStoreList { - let list = SecretStoreList() - for store in stores { - list.add(store: store) - } - for storeModifiable in modifiableStores { - list.add(store: storeModifiable) - } - return list - } - -} +//extension Preview { +// +// class Store: SecretStore, ObservableObject { +// +// let isAvailable = true +// let id = UUID() +// var name: String { "Preview Store" } +// @Published var secrets: [Secret] = [] +// +// init(secrets: [Secret]) { +// self.secrets.append(contentsOf: secrets) +// } +// +// init(numberOfRandomSecrets: Int = 5) { +// let new = (0.. Data { +// return data +// } +// +// func verify(signature data: Data, for signature: Data, with secret: Preview.Secret) throws -> Bool { +// true +// } +// +// func existingPersistedAuthenticationContext(secret: Preview.Secret) -> PersistedAuthenticationContext? { +// nil +// } +// +// func persistAuthentication(secret: Preview.Secret, forDuration duration: TimeInterval) throws { +// } +// +// func reloadSecrets() { +// } +// +// } +// +// class StoreModifiable: Store, SecretStoreModifiable { +// override var name: String { "Modifiable Preview Store" } +// +// func create(name: String, requiresAuthentication: Bool) throws { +// } +// +// func delete(secret: Preview.Secret) throws { +// } +// +// func update(secret: Preview.Secret, name: String) throws { +// } +// } +//} +// +//extension Preview { +// +// static func storeList(stores: [Store] = [], modifiableStores: [StoreModifiable] = []) -> SecretStoreList { +// let list = SecretStoreList() +// for store in stores { +// list.add(store: store) +// } +// for storeModifiable in modifiableStores { +// list.add(store: storeModifiable) +// } +// return list +// } +// +//} diff --git a/Sources/Secretive/Views/ContentView.swift b/Sources/Secretive/Views/ContentView.swift index c48991c..c556e64 100644 --- a/Sources/Secretive/Views/ContentView.swift +++ b/Sources/Secretive/Views/ContentView.swift @@ -193,41 +193,41 @@ extension ContentView { } -#if DEBUG - -struct ContentView_Previews: PreviewProvider { - - private static let storeList: SecretStoreList = { - let list = SecretStoreList() - list.add(store: SecureEnclave.Store()) - list.add(store: SmartCard.Store()) - return list - }() - private static let agentStatusChecker = AgentStatusChecker() - private static let justUpdatedChecker = JustUpdatedChecker() - - @State var hasRunSetup = false - @State private var showingSetup = false - @State private var showingCreation = false - - static var previews: some View { - Group { - // Empty on modifiable and nonmodifiable - ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true)) - .environmentObject(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)])) - .environmentObject(PreviewUpdater()) - .environmentObject(agentStatusChecker) - - // 5 items on modifiable and nonmodifiable - ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true)) - .environmentObject(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()])) - .environmentObject(PreviewUpdater()) - .environmentObject(agentStatusChecker) - } - .environmentObject(agentStatusChecker) - - } -} - -#endif +//#if DEBUG +// +//struct ContentView_Previews: PreviewProvider { +// +// private static let storeList: SecretStoreList = { +// let list = SecretStoreList() +// list.add(store: SecureEnclave.Store()) +// list.add(store: SmartCard.Store()) +// return list +// }() +// private static let agentStatusChecker = AgentStatusChecker() +// private static let justUpdatedChecker = JustUpdatedChecker() +// +// @State var hasRunSetup = false +// @State private var showingSetup = false +// @State private var showingCreation = false +// +// static var previews: some View { +// Group { +// // Empty on modifiable and nonmodifiable +// ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true)) +// .environmentObject(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)])) +// .environmentObject(PreviewUpdater()) +// .environmentObject(agentStatusChecker) +// +// // 5 items on modifiable and nonmodifiable +// ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true)) +// .environmentObject(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()])) +// .environmentObject(PreviewUpdater()) +// .environmentObject(agentStatusChecker) +// } +// .environmentObject(agentStatusChecker) +// +// } +//} +// +//#endif diff --git a/Sources/Secretive/Views/CreateSecretView.swift b/Sources/Secretive/Views/CreateSecretView.swift index 4190c99..60eac1f 100644 --- a/Sources/Secretive/Views/CreateSecretView.swift +++ b/Sources/Secretive/Views/CreateSecretView.swift @@ -45,9 +45,10 @@ struct CreateSecretView: View { } func save() { - // FIXME: THIS -// try! store.create(name: name, requiresAuthentication: requiresAuthentication) - showing = false + Task { + try! await store.create(name: name, requiresAuthentication: requiresAuthentication) + showing = false + } } } @@ -231,19 +232,19 @@ struct NotificationView: View { } -#if DEBUG - -struct CreateSecretView_Previews: PreviewProvider { - - static var previews: some View { - Group { - CreateSecretView(store: Preview.StoreModifiable(), showing: .constant(true)) - AuthenticationView().environment(\.colorScheme, .dark) - AuthenticationView().environment(\.colorScheme, .light) - NotificationView().environment(\.colorScheme, .dark) - NotificationView().environment(\.colorScheme, .light) - } - } -} - -#endif +//#if DEBUG +// +//struct CreateSecretView_Previews: PreviewProvider { +// +// static var previews: some View { +// Group { +// CreateSecretView(store: Preview.StoreModifiable(), showing: .constant(true)) +// AuthenticationView().environment(\.colorScheme, .dark) +// AuthenticationView().environment(\.colorScheme, .light) +// NotificationView().environment(\.colorScheme, .dark) +// NotificationView().environment(\.colorScheme, .light) +// } +// } +//} +// +//#endif diff --git a/Sources/Secretive/Views/DeleteSecretView.swift b/Sources/Secretive/Views/DeleteSecretView.swift index d5c4e19..3be07c2 100644 --- a/Sources/Secretive/Views/DeleteSecretView.swift +++ b/Sources/Secretive/Views/DeleteSecretView.swift @@ -49,9 +49,10 @@ struct DeleteSecretView: View { } func delete() { - // FIXME: THIS -// try! store.delete(secret: secret) - dismissalBlock(true) + Task { + try! await store.delete(secret: secret) + dismissalBlock(true) + } } } diff --git a/Sources/Secretive/Views/RenameSecretView.swift b/Sources/Secretive/Views/RenameSecretView.swift index 1a2b664..0a417cb 100644 --- a/Sources/Secretive/Views/RenameSecretView.swift +++ b/Sources/Secretive/Views/RenameSecretView.swift @@ -44,8 +44,9 @@ struct RenameSecretView: View { } func rename() { - // FIXME: THIS -// try? await store.update(secret: secret, name: newName) - dismissalBlock(true) + Task { + try? await store.update(secret: secret, name: newName) + dismissalBlock(true) + } } } diff --git a/Sources/Secretive/Views/SecretDetailView.swift b/Sources/Secretive/Views/SecretDetailView.swift index aefe49d..62a77ca 100644 --- a/Sources/Secretive/Views/SecretDetailView.swift +++ b/Sources/Secretive/Views/SecretDetailView.swift @@ -47,12 +47,12 @@ struct SecretDetailView: View { } -#if DEBUG - -struct SecretDetailView_Previews: PreviewProvider { - static var previews: some View { - SecretDetailView(secret: Preview.Store(numberOfRandomSecrets: 1).secrets[0]) - } -} - -#endif +//#if DEBUG +// +//struct SecretDetailView_Previews: PreviewProvider { +// static var previews: some View { +// SecretDetailView(secret: Preview.Store(numberOfRandomSecrets: 1).secrets[0]) +// } +//} +// +//#endif