brightdigit/StealthyStash

View on GitHub
README.md

Summary

Maintainability
Test Coverage
<p align="center">
    <img alt="StealthyStash" title="StealthyStash" src="Sources/StealthyStash/Documentation.docc/Resources/SleathlyStash-Icon.png" height="125">
</p>
<h1 align="center">StealthyStash</h1>

A Swifty database interface into the Keychain Services.

[![SwiftPM](https://img.shields.io/badge/SPM-Linux%20%7C%20iOS%20%7C%20macOS%20%7C%20watchOS%20%7C%20tvOS-success?logo=swift)](https://swift.org)
[![Twitter](https://img.shields.io/badge/twitter-@brightdigit-blue.svg?style=flat)](http://twitter.com/brightdigit)
![GitHub](https://img.shields.io/github/license/brightdigit/StealthyStash)
![GitHub issues](https://img.shields.io/github/issues/brightdigit/StealthyStash)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/brightdigit/StealthyStash/StealthyStash.yml?label=actions&logo=github&?branch=main)

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbrightdigit%2FStealthyStash%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/brightdigit/StealthyStash)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbrightdigit%2FStealthyStash%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/brightdigit/StealthyStash)


[![Codecov](https://img.shields.io/codecov/c/github/brightdigit/StealthyStash)](https://codecov.io/gh/brightdigit/StealthyStash)
[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/brightdigit/StealthyStash)](https://www.codefactor.io/repository/github/brightdigit/StealthyStash)
[![codebeat badge](https://codebeat.co/badges/54695d4b-98c8-4f0f-855e-215500163094)](https://codebeat.co/projects/github-com-brightdigit-StealthyStash-main)
[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/brightdigit/StealthyStash)](https://codeclimate.com/github/brightdigit/StealthyStash)
[![Code Climate technical debt](https://img.shields.io/codeclimate/tech-debt/brightdigit/StealthyStash?label=debt)](https://codeclimate.com/github/brightdigit/StealthyStash)
[![Code Climate issues](https://img.shields.io/codeclimate/issues/brightdigit/StealthyStash)](https://codeclimate.com/github/brightdigit/StealthyStash)
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)

# Table of Contents

* [Introduction](#introduction)
   * [Requirements](#requirements)
   * [Installation](#installation)
* [Usage](#usage)
   * [Further Documentation](#further-documentation)     
* [References](#references)
* [License](#license)

# Introduction

**StealthyStash** provides an pluggable easy abstract layer for accessing Keychain data as well as an API for encoding and decoding complex data in the Keychain. 

## Requirements 

**Apple Platforms**

- Xcode 14.3.1 or later
- Swift 5.8 or later
- iOS 14 / watchOS 7 / tvOS 14 / macOS 12 or later deployment targets

**Linux**

- Ubuntu 18.04 or later
- Swift 5.8 or later

## Installation

Use the Swift Package Manager to install this library via the repository url:

```
https://github.com/brightdigit/StealthyStash.git
```

Use version up to `1.0`.

# Usage

## Accessing the Keychain like a Database

**StealthyStash** supports the adding, updating, and querying for both generic and internet passwords. To do this you need to create a ``KeychainRepository`` to access the database to.

```
let repository = KeychainRepository(
  defaultServiceName: "com.brightdigit.KeychainSyncDemo",
  defaultServerName: "com.brightdigit.KeychainSyncDemo",
  defaultAccessGroup: "MLT7M394S7.com.brightdigit.KeychainSyncDemo"
)
```

To call ``KeychainRepository.init(defaultServiceName:defaultServerName:defaultAccessGroup:defaultSynchronizable:logger:)`` you need to supply a the default ``InternetPasswordItem/server`` and ``GenericPasswordItem/service`` which is required by both types to query and create.

> You can also supply a `logger` to use for logging as well as an ``InternetPasswordItem.accessGroup`` for your ``InternetPasswordItem`` and ``GenericPasswordItem.accessGroup`` for your ``GenericPasswordItem``

To query, update, or add a new password, check out the documentation under ``StealthyRepository``.

## Using `StealthyModel` for Composite Objects

In many cases, you may want to use multiple items to store a single object such as the user's password with ``InternetPasswordItem`` as well as their token via ``GenericPasswordItem``. In this case, you'll want to use a ``StealthyModel``:

```swift
struct CompositeCredentials: StealthyModel {
  typealias QueryBuilder = CompositeCredentialsQueryBuilder

  internal init(userName: String, password: String?, token: String?) {
    self.userName = userName
    self.password = password
    self.token = token
  }

  let userName: String

  let password: String?

  let token: String?
}
```

This is the perfect use case for ``StealthyModel`` and it only requires the implementation of a ``ModelQueryBuilder`` which defines how to build the queries for creating, updating, and deleting ``StealthyModel`` objects from the keychain:

* ``ModelQueryBuilder.updates(from:to:)`` require you to build an array of ``StealthyPropertyUpdate`` object which define the previous and new properties for the Keychain. Both the previous and new are optional in case you are only adding a new item as part of the update or only removing an old item.

* ``ModelQueryBuilder.properties(from:for:)`` is for creating a new model and requires the individual ``AnyStealthyProperty`` for each item to add to the keychain.

* ``ModelQueryBuilder.model(from:)`` builds the ``StealthyModel`` based on the ``AnyStealthyProperty`` items

* ``ModelQueryBuilder.queries(from:)`` builds a query dictionary depending the ``ModelQueryBuilder.QueryType`` passed. The keys to the query dictionary will be used by ``ModelQueryBuilder.model(from:)`` to define the keys of their resulting ``AnyStealthyProperty``. If there's only one object in your app, you can define ``ModelQueryBuilder.QueryType`` as `Void`:

```
static func queries(from _: Void) -> [String: Query] {
  [
    "password": TypeQuery(type: .internet),
    "token": TypeQuery(type: .generic)
  ]
}
```

For more help, take a look at the [`Sample` projects located in the Swift Package.](https://github.com/brightdigit/StealthyStash/tree/main/Samples)

## Further Documentation

Further documentation is available at [the Swift Package Index.](https://swiftpackageindex.com/brightdigit/StealthyStash/1.0.0/documentation/stealthystash)

# References

* [Using the Keychain to Manage User Secret](https://developer.apple.com/documentation/security/keychain_services/keychain_items/using_the_keychain_to_manage_user_secrets)

# License 

This code is distributed under the MIT license. See the [LICENSE](https://github.com/brightdigit/StealthyStash/LICENSE) file for more info.