From 58f79a21291da6d2d2193275486fa3c69b4f31fa Mon Sep 17 00:00:00 2001 From: Vishnu Ravi Date: Sun, 8 Oct 2023 15:17:03 -0400 Subject: [PATCH] Update Documentation in Conformance to the Documentation Guide (#14) # Update Documentation in Conformance to the Documentation Guide ## :recycle: Current situation & Problem Addresses issue #11. ## :pencil: Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md): - [X] I agree to follow the [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md). --------- Co-authored-by: Paul Schmiedmayer --- README.md | 88 ++++++++++++++- Sources/SpeziLocalStorage/LocalStorage.swift | 52 +++++++-- .../SpeziLocalStorage/LocalStorageError.swift | 2 +- .../LocalStorageSetting.swift | 2 +- .../SpeziLocalStorage.md | 85 +++++++++------ Sources/SpeziSecureStorage/Credentials.swift | 4 +- .../SpeziSecureStorage/SecureStorage.swift | 70 +++++++++++- .../SecureStorageError.swift | 6 +- .../SecureStorageScope.swift | 2 +- .../SpeziSecureStorage.md | 100 +++++++++++++----- 10 files changed, 337 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index b983bcc..c5bfadb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,93 @@ SPDX-License-Identifier: MIT [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FStanfordSpezi%2FSpeziStorage%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FStanfordSpezi%2FSpeziStorage%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage) -The Spezi Storage module enables an encrypted storage of information, credentials, and keys. +The Spezi Storage module consists of two sub-modules that enable on-disk storage of information. +The [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module can be used to store information that does not need to be encrypted. +Credentials, keys, and other sensitive information that needs to be encrypted may be stored by using the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module. + + +## Setup + +You need to add the Spezi Storage Swift package to +[your app in Xcode](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#) or +[Swift package](https://developer.apple.com/documentation/xcode/creating-a-standalone-swift-package-with-xcode#Add-a-dependency-on-another-Swift-package). + +> [!IMPORTANT] +> If your application is not yet configured to use Spezi, follow the [Spezi setup article](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/setup) to set up the core Spezi infrastructure. + +You can configure the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) or [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module in the [`SpeziAppDelegate`](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/speziappdelegate). +```swift +import Spezi +import SpeziLocalStorage +import SpeziSecureStorage + + +class ExampleDelegate: SpeziAppDelegate { + override var configuration: Configuration { + Configuration { + LocalStorage() + SecureStorage() + // ... + } + } +} +``` + +You can then use the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) or [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) class in any SwiftUI view. + +```swift +struct ExampleStorageView: View { + @EnvironmentObject var secureStorage: LocalStorage + @EnvironmentObject var secureStorage: SecureStorage + + + var body: some View { + // ... + } +} +``` + +Alternatively, it is common to use the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) or [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module in other modules as a dependency: [Spezi component dependencies](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/component#Dependencies). + + +## Local Storage + +The [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module enables the on-disk storage of data in mobile applications. + +The [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module defaults to storing data encrypted supported by the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module. +The [`LocalStorageSetting`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstoragesetting) enables configuring how data in the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module can be stored and retrieved. + +- Store or update new elements: [`store(_:storageKey:settings:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage/store(_:storagekey:settings:)) +- Retrieve existing elements: [`read(_:storageKey:settings:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage/read(_:storagekey:settings:)) +- Delete existing elements: [`delete(_:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage/delete(_:)) + + +## Secure Storage + +The [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module allows for the encrypted storage of small chunks of sensitive user data, such as usernames and passwords for internet services, using Apple's [Keychain documentation](https://developer.apple.com/documentation/security/keychain_services/keychain_items/using_the_keychain_to_manage_user_secrets). + +Credentials can be stored in the Secure Enclave (if available) or the Keychain. Credentials stored in the Keychain can be made synchronizable between different instances of user devices. + +### Handling Credentials + +Use the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module to store a set of [`Credentials`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/credentials) instances in the Keychain associated with a server that is synchronizable between different devices. + +- Store new credentials: [`store(credentials:server:removeDuplicate:storageScope:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/store(credentials:server:removeduplicate:storagescope:)) +- Retrieve existing credentials: [`retrieveCredentials(_:server:accessGroup:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/retrievecredentials(_:server:accessgroup:)) +- Retrieve all matching existing credentials: [`retrieveAllCredentials(forServer:accessGroup:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/retrieveallcredentials(forserver:accessgroup:)) +- Update existing credentials: [`updateCredentials(_:server:newCredentials:newServer:removeDuplicate:storageScope:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/updatecredentials(_:server:newcredentials:newserver:removeduplicate:storagescope:)) +- Delete existing credentials: [`deleteCredentials(_:server:accessGroup:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/deletecredentials(_:server:accessgroup:)) +- Delete all matching existing credentials: [`deleteAllCredentials(itemTypes:accessGroup:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/deleteallcredentials(itemtypes:accessgroup:)) + + +### Handling Keys + +Similar to [`Credentials`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/credentials) instances, you can also use the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module to interact with keys. + +- Create new keys: [`createKey(_:size:storageScope:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/createkey(_:size:storagescope:)) +- Retrieve existing public keys: [`retrievePublicKey(forTag:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/retrievepublickey(fortag:)) +- Retrieve existing private keys: [`retrievePrivateKey(forTag:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/retrieveprivatekey(fortag:)) +- Delete existing keys: [`deleteKeys(forTag:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/deletekeys(fortag:)) For more information, please refer to the [API documentation](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation). diff --git a/Sources/SpeziLocalStorage/LocalStorage.swift b/Sources/SpeziLocalStorage/LocalStorage.swift index 640d6e9..d257d76 100644 --- a/Sources/SpeziLocalStorage/LocalStorage.swift +++ b/Sources/SpeziLocalStorage/LocalStorage.swift @@ -15,9 +15,9 @@ import SpeziSecureStorage /// The ``LocalStorage/`` module enables the on-disk storage of data in mobile applications. /// The module relies on the `SecureStorage` module to enable an encrypted on-disk storage as defined by the ``LocalStorageSetting`` configuration. /// -/// Use ``LocalStorage/LocalStorage/store(_:storageKey:settings:)`` to store elements on disk and define the settings using a ``LocalStorageSetting`` instance. +/// Use ``LocalStorage/store(_:storageKey:settings:)`` to store elements on disk and define the settings using a ``LocalStorageSetting`` instance. /// -/// Use ``LocalStorage/LocalStorage/read(_:storageKey:settings:)`` to read elements on disk which are decoded as define by passed in ``LocalStorageSetting`` instance. +/// Use ``LocalStorage/read(_:storageKey:settings:)`` to read elements on disk which are decoded as define by passed in ``LocalStorageSetting`` instance. public final class LocalStorage: Module, DefaultInitializable { private let encryptionAlgorithm: SecKeyAlgorithm = .eciesEncryptionCofactorX963SHA256AESGCM @Dependency private var secureStorage = SecureStorage() @@ -43,7 +43,23 @@ public final class LocalStorage: Module, DefaultInitializable { public required init() {} - /// Use ``LocalStorage/LocalStorage/store(_:storageKey:settings:)`` to store elements on disk and define the settings using a ``LocalStorageSetting`` instance. + /// Store elements on disk and define the settings using a ``LocalStorageSetting`` instance. + /// + /// ```swift + /// struct Note: Codable, Equatable { + /// let text: String + /// let date: Date + /// } + /// + /// let note = Note(text: "Spezi is awesome!", date: Date()) + /// + /// do { + /// try await localStorage.store(note) + /// } catch { + /// // Handle storage errors ... + /// } + /// ``` + /// /// - Parameters: /// - element: The element that should be stored conforming to `Encodable` /// - storageKey: An optional storage key to identify the file. @@ -100,7 +116,17 @@ public final class LocalStorage: Module, DefaultInitializable { } - /// Use ``LocalStorage/LocalStorage/read(_:storageKey:settings:)`` to read elements on disk which are decoded as defined by passed in ``LocalStorageSetting`` instance. + /// Read elements on disk which are decoded as defined by passed in ``LocalStorageSetting`` instance. + /// + /// ```swift + /// do { + /// let storedNote: Note = try await localStorage.read() + /// // Do something with `storedNote`. + /// } catch { + /// // Handle read errors ... + /// } + /// ``` + /// /// - Parameters: /// - storageKey: An optional storage key to identify the file. /// - settings: The ``LocalStorageSetting``s used to retrieve the file on disk. @@ -131,14 +157,28 @@ public final class LocalStorage: Module, DefaultInitializable { } - /// Use ``LocalStorage/LocalStorage/delete(storageKey:)`` to deletes a file stored on disk identified by the `storageKey`. + /// Deletes a file stored on disk identified by the `storageKey`. + /// + /// ```swift + /// do { + /// try await localStorage.delete(storageKey: "MyNote") + /// } catch { + /// // Handle delete errors ... + /// } + /// ``` + /// + /// Use ``delete(_:)`` as an automatically define the `storageKey` if the type conforms to `Encodable`. + /// /// - Parameters: /// - storageKey: An optional storage key to identify the file. public func delete(storageKey: String) throws { try delete(String.self, storageKey: storageKey) } - /// Use ``LocalStorage/LocalStorage/delete(storageKey:)`` to deletes a file stored on disk defined by a `Decodable` type that is used to derive the storage key. + /// Deletes a file stored on disk defined by a `Decodable` type that is used to derive the storage key. + /// + /// Use ``delete(storageKey:)`` to manually define the storage key. + /// /// - Parameters: /// - type: The `Decodable` type that is used to derive the storage key from. public func delete(_ type: C.Type = C.self) throws { diff --git a/Sources/SpeziLocalStorage/LocalStorageError.swift b/Sources/SpeziLocalStorage/LocalStorageError.swift index 6ba947d..3db4413 100644 --- a/Sources/SpeziLocalStorage/LocalStorageError.swift +++ b/Sources/SpeziLocalStorage/LocalStorageError.swift @@ -7,7 +7,7 @@ // -/// An error thrown by the ``LocalStorage/LocalStorage`` module. +/// An error thrown by the ``LocalStorage`` module. enum LocalStorageError: Error { /// Encryption of the file was not possible, did not store the data on disk. case encyptionNotPossible diff --git a/Sources/SpeziLocalStorage/LocalStorageSetting.swift b/Sources/SpeziLocalStorage/LocalStorageSetting.swift index 4cf2a7d..6a20f6c 100644 --- a/Sources/SpeziLocalStorage/LocalStorageSetting.swift +++ b/Sources/SpeziLocalStorage/LocalStorageSetting.swift @@ -11,7 +11,7 @@ import Spezi import SpeziSecureStorage -/// The ``LocalStorageSetting`` enables configuring how data in the ``LocalStorage/LocalStorage`` module can be stored and retrieved. +/// The ``LocalStorageSetting`` enables configuring how data in the ``LocalStorage`` module can be stored and retrieved. public enum LocalStorageSetting { /// Unencrypted case unencrypted(excludedFromBackup: Bool = true) diff --git a/Sources/SpeziLocalStorage/SpeziLocalStorage.docc/SpeziLocalStorage.md b/Sources/SpeziLocalStorage/SpeziLocalStorage.docc/SpeziLocalStorage.md index 1b4f6cb..6dac2a5 100644 --- a/Sources/SpeziLocalStorage/SpeziLocalStorage.docc/SpeziLocalStorage.md +++ b/Sources/SpeziLocalStorage/SpeziLocalStorage.docc/SpeziLocalStorage.md @@ -10,37 +10,45 @@ SPDX-License-Identifier: MIT --> -Store data on-disk. +Store data encryped on-disk. ## Overview -The ``LocalStorage`` module enables the on-disk storage of data in mobile applications. The ``LocalStorageSetting`` enables configuring how data in the ``LocalStorage`` module can be stored and retrieved. +The ``LocalStorage`` module enables the on-disk storage of data in mobile applications. -The data stored can optionally be encrypted by importing the `SecureStorage` module. +The ``LocalStorage`` module defaults to storing data encrypted supported by the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module. +The ``LocalStorageSetting`` enables configuring how data in the ``LocalStorage`` module can be stored and retrieved. -## Add the LocalStorage Module +## Setup -You can configure the ``LocalStorage/LocalStorage`` module in the `SpeziAppDelegate`. +You need to add the Spezi Storage Swift package to +[your app in Xcode](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#) or +[Swift package](https://developer.apple.com/documentation/xcode/creating-a-standalone-swift-package-with-xcode#Add-a-dependency-on-another-Swift-package). + +> Important: If your application is not yet configured to use Spezi, follow the [Spezi setup article](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/setup) to set up the core Spezi infrastructure. + +You can configure the ``LocalStorage`` module in the [`SpeziAppDelegate`](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/speziappdelegate). ```swift import Spezi -import LocalStorage +import SpeziLocalStorage class ExampleDelegate: SpeziAppDelegate { override var configuration: Configuration { Configuration { LocalStorage() + // ... } } } ``` -You can then use the ``LocalStorage/LocalStorage`` class in any SwiftUI view. +You can then use the ``LocalStorage`` class in any SwiftUI view. ```swift -struct ExampleLocalStorageView: View { +struct ExampleStorageView: View { @EnvironmentObject var localStorage: LocalStorage @@ -50,13 +58,17 @@ struct ExampleLocalStorageView: View { } ``` -Alternatively it is common to use the ``LocalStorage/LocalStorage`` component in other components as a dependency. +Alternatively, it is common to use the ``LocalStorage`` module in other modules as a dependency: [Spezi component dependencies](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/component#Dependencies). + ## Use the LocalStorage Module -### Storing data +You can use the ``LocalStorage`` module to store, update, retrieve, and delete element conforming to [`Codable`](https://developer.apple.com/documentation/swift/codable). + + +### Storing & Update Data -Use the ``LocalStorage/LocalStorage`` component to store data that conforms to `Encodable`. +The ``LocalStorage`` module enables the storage and update of elements conforming to [`Codable`](https://developer.apple.com/documentation/swift/codable). ```swift struct Note: Codable, Equatable { @@ -67,44 +79,55 @@ struct Note: Codable, Equatable { let note = Note(text: "Spezi is awesome!", date: Date()) do { - try await localStorage.store( - note, - storageKey: "MyNote", - settings: .unencrypted() - ) + try await localStorage.store(note) } catch { - // Handle storage error here - // ... + // Handle storage errors ... } - ``` -### Reading stored data +See ``LocalStorage/store(_:storageKey:settings:)`` for more details. + + + +### Read Data -Use the ``LocalStorage/LocalStorage`` component to read previously stored data. +The ``LocalStorage`` module enables the retrieval of elements conforming to [`Codable`](https://developer.apple.com/documentation/swift/codable). ```swift do { - let storedNote: Note = try await localStorage.read( - storageKey: "MyNote", - settings: .unencrypted() - ) + let storedNote: Note = try await localStorage.read() // Do something with `storedNote`. } catch { - // Handle read error. - // ... + // Handle read errors ... } ``` -### Deleting stored data +See ``LocalStorage/read(_:storageKey:settings:)`` for more details. -Use the ``LocalStorage/LocalStorage`` component to delete previously stored data. + +### Deleting Element + +The ``LocalStorage`` module enables the deletion of a previously stored elements. ```swift do { try await localStorage.delete(storageKey: "MyNote") } catch { - // Handle delete error. - // ... + // Handle delete errors ... } ``` + +See ``LocalStorage/delete(_:)`` or ``LocalStorage/delete(storageKey:)`` for more details. + + +## Topics + +### LocalStorage + +- ``LocalStorage`` +- ``LocalStorageSetting`` +- ``LocalStorage/store(_:storageKey:settings:)`` +- ``LocalStorage/read(_:storageKey:settings:)`` +- ``LocalStorage/delete(storageKey:)`` +- ``LocalStorage/delete(_:)`` + diff --git a/Sources/SpeziSecureStorage/Credentials.swift b/Sources/SpeziSecureStorage/Credentials.swift index db721c0..e5e3883 100644 --- a/Sources/SpeziSecureStorage/Credentials.swift +++ b/Sources/SpeziSecureStorage/Credentials.swift @@ -7,7 +7,7 @@ // -/// Credentials that can be stored, updated, deleted, and retrieved from a ``SecureStorage/SecureStorage`` module. +/// Credentials that can be stored, updated, deleted, and retrieved from a ``SecureStorage`` module. public struct Credentials: Equatable, Identifiable { /// The username public var username: String @@ -21,7 +21,7 @@ public struct Credentials: Equatable, Identifiable { } - /// Credentials that can be stored, updated, deleted, and retrieved from a ``SecureStorage/SecureStorage`` module. + /// Credentials that can be stored, updated, deleted, and retrieved from a ``SecureStorage`` module. /// - Parameters: /// - username: The username /// - password: The password associated to the ``Credentials/username`` diff --git a/Sources/SpeziSecureStorage/SecureStorage.swift b/Sources/SpeziSecureStorage/SecureStorage.swift index 410a9ae..1611960 100644 --- a/Sources/SpeziSecureStorage/SecureStorage.swift +++ b/Sources/SpeziSecureStorage/SecureStorage.swift @@ -14,11 +14,11 @@ import Spezi import XCTRuntimeAssertions -/// The ``SecureStorage/SecureStorage`` serves as a reusable `Module` that can be used to store small chunks of data such as credentials and keys. +/// The ``SecureStorage`` serves as a reusable `Module` that can be used to store small chunks of data such as credentials and keys. /// /// The storing of credentials and keys follows the Keychain documentation provided by Apple: https://developer.apple.com/documentation/security/keychain_services/keychain_items/using_the_keychain_to_manage_user_secrets. public final class SecureStorage: Module, DefaultInitializable { - /// The ``SecureStorage/SecureStorage`` serves as a reusable `Module` that can be used to store store small chunks of data such as credentials and keys. + /// The ``SecureStorage`` serves as a reusable `Module` that can be used to store store small chunks of data such as credentials and keys. /// /// The storing of credentials and keys follows the Keychain documentation provided by Apple: /// https://developer.apple.com/documentation/security/keychain_services/keychain_items/using_the_keychain_to_manage_user_secrets. @@ -130,6 +130,27 @@ public final class SecureStorage: Module, DefaultInitializable { // MARK: - Credentials Handling /// Stores credentials in the Keychain. + /// + /// ```swift + /// do { + /// let serverCredentials = Credentials( + /// username: "user", + /// password: "password" + /// ) + /// try secureStorage.store( + /// credentials: serverCredentials, + /// server: "stanford.edu", + /// storageScope: .keychainSynchronizable + /// ) + /// + /// // ... + /// + /// } catch { + /// // Handle creation error here. + /// // ... + /// } + /// ``` + /// /// - Parameters: /// - credentials: The ``Credentials`` stored in the Keychain. /// - server: The server associated with the credentials. @@ -168,6 +189,21 @@ public final class SecureStorage: Module, DefaultInitializable { } /// Delete existing credentials stored in the Keychain. + /// + /// ```swift + /// do { + /// try secureStorage.deleteCredentials( + /// "user", + /// server: "spezi.stanford.edu" + /// ) + /// } catch { + /// // Handle deletion error here. + /// // ... + /// } + /// ``` + /// + /// Use to ``deleteAllCredentials(itemTypes:accessGroup:)`` delete all existing credentials stored in the Keychain. + /// /// - Parameters: /// - username: The username associated with the credentials. /// - server: The server associated with the credentials. @@ -200,6 +236,25 @@ public final class SecureStorage: Module, DefaultInitializable { } /// Update existing credentials found in the Keychain. + /// + /// ```swift + /// do { + /// let newCredentials = Credentials( + /// username: "user", + /// password: "newPassword" + /// ) + /// try secureStorage.updateCredentials( + /// "user", + /// server: "stanford.edu", + /// newCredentials: newCredentials, + /// newServer: "spezi.stanford.edu" + /// ) + /// } catch { + /// // Handle update error here. + /// // ... + /// } + /// ``` + /// /// - Parameters: /// - username: The username associated with the old credentials. /// - server: The server associated with the old credentials. @@ -222,6 +277,17 @@ public final class SecureStorage: Module, DefaultInitializable { } /// Retrieve existing credentials stored in the Keychain. + /// + /// ```swift + /// guard let serverCredentials = secureStorage.retrieveCredentials("user", server: "stanford.edu") else { + /// // Handle errors here. + /// } + /// + /// // Use the credentials + /// ``` + /// + /// Use ``retrieveAllCredentials(forServer:accessGroup:)`` to retrieve all existing credentials stored in the Keychain for a specific server. + /// /// - Parameters: /// - username: The username associated with the credentials. /// - server: The server associated with the credentials. diff --git a/Sources/SpeziSecureStorage/SecureStorageError.swift b/Sources/SpeziSecureStorage/SecureStorageError.swift index 502ab4c..d0ab070 100644 --- a/Sources/SpeziSecureStorage/SecureStorageError.swift +++ b/Sources/SpeziSecureStorage/SecureStorageError.swift @@ -10,7 +10,7 @@ import CryptoKit import Security -/// An `Error` thrown by the ``SecureStorage/SecureStorage`` module. +/// An `Error` thrown by the ``SecureStorage`` module. public enum SecureStorageError: Error { /// Creation of a new element failed with a `CFError`. case createFailed(CFError? = nil) @@ -26,8 +26,8 @@ public enum SecureStorageError: Error { /// for more information about KeyChain access groups. /// Remove the ``SecureStorageScope``'s `accessGroup` configuration value if you do not intend to use KeyChain access groups. case missingEntitlement - /// The ``SecureStorage/SecureStorage`` is unable to decode the information obtained into a credentials. + /// The ``SecureStorage`` is unable to decode the information obtained into a credentials. case unexpectedCredentialsData - /// The ``SecureStorage/SecureStorage`` encountered a Keychain error when interacting with the Keychain. + /// The ``SecureStorage`` encountered a Keychain error when interacting with the Keychain. case keychainError(status: OSStatus) } diff --git a/Sources/SpeziSecureStorage/SecureStorageScope.swift b/Sources/SpeziSecureStorage/SecureStorageScope.swift index 74b7267..7a4b9e4 100644 --- a/Sources/SpeziSecureStorage/SecureStorageScope.swift +++ b/Sources/SpeziSecureStorage/SecureStorageScope.swift @@ -9,7 +9,7 @@ import Security -/// The ``SecureStorageScope`` defines how secure data is stored by the ``SecureStorage/SecureStorage`` component. +/// The ``SecureStorageScope`` defines how secure data is stored by the ``SecureStorage`` component. public enum SecureStorageScope: Equatable, Identifiable { /// Store the element in the Secure Enclave case secureEnclave(userPresence: Bool = false) diff --git a/Sources/SpeziSecureStorage/SpeziSecureStorage.docc/SpeziSecureStorage.md b/Sources/SpeziSecureStorage/SpeziSecureStorage.docc/SpeziSecureStorage.md index cfafb0a..4487f4c 100644 --- a/Sources/SpeziSecureStorage/SpeziSecureStorage.docc/SpeziSecureStorage.md +++ b/Sources/SpeziSecureStorage/SpeziSecureStorage.docc/SpeziSecureStorage.md @@ -12,6 +12,7 @@ SPDX-License-Identifier: MIT Securely store small chunks of data, such as credentials and keys. + ## Overview The ``SecureStorage`` module allows for the encrypted storage of small chunks of sensitive user data, such as usernames and passwords for internet services, using Apple's [Keychain documentation](https://developer.apple.com/documentation/security/keychain_services/keychain_items/using_the_keychain_to_manage_user_secrets). @@ -19,27 +20,35 @@ The ``SecureStorage`` module allows for the encrypted storage of small chunks of Credentials can be stored in the Secure Enclave (if available) or the Keychain. Credentials stored in the Keychain can be made synchronizable between different instances of user devices. -## Add the Secure Storage Component +## Setup + +You need to add the Spezi Storage Swift package to +[your app in Xcode](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#) or +[Swift package](https://developer.apple.com/documentation/xcode/creating-a-standalone-swift-package-with-xcode#Add-a-dependency-on-another-Swift-package). + +> Important: If your application is not yet configured to use Spezi, follow the [Spezi setup article](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/setup) to set up the core Spezi infrastructure. + +You can configure the ``SecureStorage`` module in the [`SpeziAppDelegate`](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/speziappdelegate). -You can configure the ``SecureStorage/SecureStorage`` component in the `SpeziAppDelegate`. ```swift import Spezi -import SecureStorage +import SpeziSecureStorage class ExampleDelegate: SpeziAppDelegate { override var configuration: Configuration { Configuration { SecureStorage() + // ... } } } ``` -You can then use the ``SecureStorage/SecureStorage`` class in any SwiftUI view. +You can then use the ``SecureStorage`` class in any SwiftUI view. ```swift -struct ExampleSecureStorageView: View { +struct ExampleStorageView: View { @EnvironmentObject var secureStorage: SecureStorage @@ -49,28 +58,30 @@ struct ExampleSecureStorageView: View { } ``` -Alternatively it is common to use the ``SecureStorage/SecureStorage`` component in other components as a dependency: +Alternatively, it is common to use the ``SecureStorage`` module in other modules as a dependency: [Spezi component dependencies](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/component#Dependencies). -## Use the ``SecureStorage/SecureStorage`` component. -You can use the ``SecureStorage/SecureStorage`` component to store, update, retrieve, and delete credentials and keys. +## Use the SecureStorage Module + +You can use the ``SecureStorage`` module to store, update, retrieve, and delete credentials and keys. ### Storing Credentials -Use the ``SecureStorage/SecureStorage`` component to store a set of ``Credentials`` instances in the Keychain associated with a server that is synchronizable between different devices. +The ``SecureStorage`` module enables the storage of credentials in the Keychain. ```swift do { let serverCredentials = Credentials( - username: "user", + username: "user", password: "password" ) try secureStorage.store( - credentials: serverCredentials, + credentials: serverCredentials, server: "stanford.edu", storageScope: .keychainSynchronizable ) + // ... } catch { // Handle creation error here. @@ -78,23 +89,28 @@ do { } ``` +See ``SecureStorage/store(credentials:server:removeDuplicate:storageScope:)`` for more details. + + + ### Retrieving Credentials -The ``SecureStorage/SecureStorage`` component enables the retrieval of a previously stored set of credentials. +The ``SecureStorage`` module enables the retrieval of existing credentials stored in the Keychain. ```swift -if let serverCredentials = secureStorage.retrieveCredentials( - "user", - server: "stanford.edu" -) { - // Use credentials here. - // ... +guard let serverCredentials = secureStorage.retrieveCredentials("user", server: "stanford.edu") else { + // Handle errors here. } + +// Use the credentials ``` +See ``SecureStorage/retrieveCredentials(_:server:accessGroup:)`` or ``SecureStorage/retrieveAllCredentials(forServer:accessGroup:)`` for more details. + + ### Updating Credentials -The ``SecureStorage/SecureStorage`` component enables the update of a previously stored set of credentials. +The ``SecureStorage`` module enables the update of existing credentials found in the Keychain. ```swift do { @@ -114,14 +130,17 @@ do { } ``` +See ``SecureStorage/updateCredentials(_:server:newCredentials:newServer:removeDuplicate:storageScope:)`` for more details. + + ### Deleting Credentials -The ``SecureStorage/SecureStorage`` component enables the deletion of a previously stored set of credentials. +The ``SecureStorage`` module enables the deletion of a previously stored set of credentials. ```swift do { try secureStorage.deleteCredentials( - "user", + "user", server: "spezi.stanford.edu" ) } catch { @@ -130,11 +149,40 @@ do { } ``` +See ``SecureStorage/deleteCredentials(_:server:accessGroup:)`` or ``SecureStorage/deleteAllCredentials(itemTypes:accessGroup:)`` for more details. + + ### Handeling Keys -Similiar to ``Credentials`` instances, you can also use the ``SecureStorage`` component to interact with keys. +Similiar to ``Credentials`` instances, you can also use the ``SecureStorage`` module to interact with keys. + +- ``SecureStorage/createKey(_:size:storageScope:)`` +- ``SecureStorage/retrievePublicKey(forTag:)`` +- ``SecureStorage/retrievePrivateKey(forTag:)`` +- ``SecureStorage/deleteKeys(forTag:)`` + + +## Topics + +### Secure Storage +- ``SecureStorage`` +- ``SecureStorageError`` +- ``SecureStorageScope`` + +### Handling Credentials + +- ``Credentials`` +- ``SecureStorage/store(credentials:server:removeDuplicate:storageScope:)`` +- ``SecureStorage/retrieveCredentials(_:server:accessGroup:)`` +- ``SecureStorage/retrieveAllCredentials(forServer:accessGroup:)`` +- ``SecureStorage/updateCredentials(_:server:newCredentials:newServer:removeDuplicate:storageScope:)`` +- ``SecureStorage/deleteCredentials(_:server:accessGroup:)`` +- ``SecureStorage/deleteAllCredentials(itemTypes:accessGroup:)`` +- ``SecureStorageItemTypes`` + +### Handling Keys -- ``SecureStorage/SecureStorage/createKey(_:size:storageScope:)`` -- ``SecureStorage/SecureStorage/retrievePrivateKey(forTag:)`` -- ``SecureStorage/SecureStorage/retrievePublicKey(forTag:)`` -- ``SecureStorage/SecureStorage/deleteKeys(forTag:)`` +- ``SecureStorage/createKey(_:size:storageScope:)`` +- ``SecureStorage/retrievePublicKey(forTag:)`` +- ``SecureStorage/retrievePrivateKey(forTag:)`` +- ``SecureStorage/deleteKeys(forTag:)``