A Swifty database interface into the Keychain Services.
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.
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
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.
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
loggerto use for logging as well as anInternetPasswordItem.accessGroupfor yourInternetPasswordItemandGenericPasswordItem.accessGroupfor yourGenericPasswordItem
To query, update, or add a new password, check out the documentation under StealthyRepository.
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:
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 ofStealthyPropertyUpdateobject 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 individualAnyStealthyPropertyfor each item to add to the keychain. -
ModelQueryBuilder.model(from:)builds theStealthyModelbased on theAnyStealthyPropertyitems -
ModelQueryBuilder.queries(from:)builds a query dictionary depending theModelQueryBuilder.QueryTypepassed. The keys to the query dictionary will be used byModelQueryBuilder.model(from:)to define the keys of their resultingAnyStealthyProperty. If there's only one object in your app, you can defineModelQueryBuilder.QueryTypeasVoid:
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.
Further documentation is available at the Swift Package Index.
This code is distributed under the MIT license. See the LICENSE file for more info.