Skip to content

Commit

Permalink
Update Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
PSchmiedmayer committed Oct 8, 2023
1 parent 522f9b6 commit 0e0ef1a
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 247 deletions.
210 changes: 35 additions & 175 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,44 @@ 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 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.
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.

# Spezi Local Storage

## Overview

The [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module enables the on-disk storage of data in mobile applications. The [`LocalStorageSetting`](https://swiftpackageindex.com/stanfordspezi/spezistorage/0.4.2/documentation/spezilocalstorage/localstoragesetting) enables configuring how data in the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module can be stored and retrieved.

The data stored can optionally be encrypted by importing the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module (see the [Spezi Secure Storage](#spezi-secure-storage) section below).

## 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 setup the core Spezi infrastructure.
You can configure the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module in the [`SpeziAppDelegate`](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/speziappdelegate).
> [!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 LocalStorage
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) class in any SwiftUI view.
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 ExampleLocalStorageView: View {
@EnvironmentObject var localStorage: LocalStorage
struct ExampleStorageView: View {
@EnvironmentObject var secureStorage: LocalStorage
@EnvironmentObject var secureStorage: SecureStorage


var body: some View {
Expand All @@ -64,185 +62,47 @@ struct ExampleLocalStorageView: View {
}
```

Alternatively it is common to use the [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module in other modules as a dependency.

## Example

### Storing data

```swift
struct Note: Codable, Equatable {
let text: String
let date: Date
}
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).

let note = Note(text: "Spezi is awesome!", date: Date())

do {
try await localStorage.store(
note,
storageKey: "MyNote",
settings: .unencrypted()
)
} catch {
// Handle storage error here
// ...
}

```
## Local Storage

### Reading stored data
The [`LocalStorage`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezilocalstorage/localstorage) module enables the on-disk storage of data in mobile applications.

```swift
do {
let storedNote: Note = try await localStorage.read(
storageKey: "MyNote",
settings: .unencrypted()
)
// Do something with `storedNote`.
} catch {
// Handle read error.
// ...
}
```
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.

### Deleting stored data

```swift
do {
try await localStorage.delete(storageKey: "MyNote")
} catch {
// Handle delete error.
// ...
}
```
- 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(_:))

# Spezi Secure Storage

## Overview
## 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.


## 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 setup the core Spezi infrastructure.
You can configure the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module in the [`SpeziAppDelegate`](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/speziappdelegate).
```swift
import Spezi
import SecureStorage


class ExampleDelegate: SpeziAppDelegate {
override var configuration: Configuration {
Configuration {
SecureStorage()
}
}
}
```

You can then use the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) class in any SwiftUI view.

```swift
struct ExampleSecureStorageView: View {
@EnvironmentObject var secureStorage: SecureStorage


var body: some View {
// ...
}
}
```

Alternatively it is common to use the [`SecureStorage`](https://swiftpackageindex.com/StanfordSpezi/SpeziStorage/documentation/spezisecurestorage) module in other modules as a dependency:

## Example

### Storing Credentials
### 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.

```swift
do {
let serverCredentials = Credentials(
username: "user",
password: "password"
)
try secureStorage.store(
credentials: serverCredentials,
server: "stanford.edu",
storageScope: .keychainSynchronizable
)
// ...
} catch {
// Handle creation error here.
// ...
}
```

### Retrieving Credentials

```swift
if let serverCredentials = secureStorage.retrieveCredentials(
"user",
server: "stanford.edu"
) {
// Use credentials here.
// ...
}
```

### Updating Credentials
- 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:))

```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.
// ...
}
```

### Deleting Credentials

```swift
do {
try secureStorage.deleteCredentials(
"user",
server: "spezi.stanford.edu"
)
} catch {
// Handle deletion error here.
// ...
}
```

### Handling Keys

Similiar 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.
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.

- [`createKey(_:size:storageScope:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/createkey(_:size:storagescope:))
- [`retrievePrivateKey(forTag:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/createkey(_:size:storagescope:))
- [`retrievePublicKey(forTag:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/retrievepublickey(fortag:))
- [`deleteKeys(forTag:)`](https://swiftpackageindex.com/stanfordspezi/spezistorage/documentation/spezisecurestorage/securestorage/deletekeys(fortag:))
- 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).

Expand Down
52 changes: 46 additions & 6 deletions Sources/SpeziLocalStorage/LocalStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<C: Encodable>(_ type: C.Type = C.self) throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpeziLocalStorage/LocalStorageError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpeziLocalStorage/LocalStorageSetting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 0e0ef1a

Please sign in to comment.