Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/vdka/SecretsManager

A Swift Package to generate and use encrypted secrets in your app
https://github.com/vdka/SecretsManager

plugin secret-management secrets secrets-management secrets-manager swift swift-package-manager swift-package-manager-plugin swift-package-plugin

Last synced: 2 months ago
JSON representation

A Swift Package to generate and use encrypted secrets in your app

Lists

README

        

# SecretsManager

Effortless Secrets Management for Swift projects using Code Generation.
A simpler approach than using GYB files as outlined by the [NSHipster article](https://nshipster.com/secrets/#cosmic-brain-obfuscate-secrets-using-code-generation)
on Secret Management on iOS using Swift Build Tool Plugin (Swift 5.6+).

## Features

- Provides a convenient way to keep secrets out of source code
- Encrypts Secrets when they are at rest in your applications binary
- Provides convenient access through global `Secrets`
- Run as manual Script, SPM plugin or Xcode plugin
- Less than 250 lines of Swift

## Usage

Use a `.env` bash script to export Secrets you want available to your source code.

```bash
#prefix ORG

export ORG_API_CLIENT_SECRET=hrFL6LpsGQPsEQdipfTSlosI6topYTfhLNCfIvbfUz5r6nc72DMRbLL3msjuAFnY
export ORG_ANALYTICS_KEY=dak37Qv5KGwNsQxVJxjJY2OtbUnGKXlm3mkDApSRfrAsTHQdFRSEfrA9yin5T4YT
export ORG_BACKEND_KEY='KwphtrRhgOXcRd=p!73QnrQLuOj=rx8edJhMy52sWeQPKMxOxA8hNcDrG9=XRvAw'
export ORG_LOGGER_KEY='oW7YQKg2eNcVjzRdmCtmgCCSBp2dpJlL5NC-Pj!asS5XdPG/--R2hE?/=I/TlotP'
```

Using this plugin the following Swift code is generated and available directly to your targets
source code, no need for an import.

```swift
// This file is automatically generated

import struct Foundation.Data

private func secret(_ secret: String) -> String {
let data = Data(base64Encoded: secret)
guard let data else {
fatalError("Failed to decode a secret!")
}

func decrypt(_ data: Data) -> String {
let key = Data(base64Encoded: "JbiOFqC+jH3l8pwCLE4Nca4f19M7YAbeTUo7rhnSSG7ctZMlc+dg5FI9o3zrSbCgFLtDd0uC9EcCC+jd6hlVDA==")!
var output: [UTF8.CodeUnit] = []
for (offset, ch) in data.enumerated() {
output.append(ch ^ key[offset % key.count])
}
return String(bytes: output, encoding: .utf8)!
}

return decrypt(data)
}

enum Secrets {
static let apiClientSecret = secret("TcrIWpby/A6io8xxaR9pGN55g4BXD3WXez5U3kCGLgaQ+9BDOpECggdHlg7dJ9OXJv8OJSnOuHRveIKoq187VQ==")
static let analyticsKey = secret("QdnlJZfv+kiutetMXx91J+RnvZliUkmqLx9V6VKKJAPv2PhhMpcztjRP4g+/AeHEUukQMi3wtX57Yobovi0MWA==")
static let backendKey = secret("bs/+ftTM3hWCvcRhfiowAY8o5IJVEleSOAVRk2uqcAu4//toCtJSlwVY8iygBMjvbPp7HwXhsDVFMtWFuG8Uew==")
static let loggerKey = secret("Su+5T/H160+AvP9URjRfFcNco75cI0WNDzoJymmYJCLp+9AII41BhSFuliSPGfePOZYRRSPHy2g/QseJhnYhXA==")
}
```

## Setup

> Requires Swift 5.6 (Xcode 13.3+)

Create a `.env` file in your root directory (alongside `Package.swift` or your `*.xcodeproj`).
You can define a prefix to strip from all your exported keys with `#prefix`. See [Usage](#usage)
for an example `.env` file.

### Xcode Projects
> [Visual Guide](https://github.com/vdka/SecretsManager/wiki/Xcode-Integration)

1. Add SecretsManager package
- When prompted to **Choose Package Products for SecretsManager** don't select any products
2. In **Targets > Build Phases** add `SecretsManagerPlugin` to **Run Build Tool Plug-ins**
3. Build, triggering a prompt to trust the plugin
- From the issue navigator you can goto the plugin and read the source code before trusting

### Swift Package Manager

Add the following to your `Package.swift` files dependencies array:
```swift
.package(url: "https://github.com/vdka/SecretsManager.git", from: "1.0.0"),
```

And to the targets Secrets should be available to, after their `dependencies`:
```swift
plugins: [
.plugin(name: "SecretsManagerPlugin", package: "SecretsManager"),
]
```

### Xcode Cloud

When running in Xcode cloud you will want the secret values to come from the actual environment. In
order to tell the plugin which keys to read from the environment from you can create a `.env` file
that exports only the keys without associated values.

```bash
#prefix ORG

export ORG_API_CLIENT_SECRET
export ORG_ANALYTICS_KEY
export ORG_BACKEND_KEY
export ORG_LOGGER_KEY
```

## Security

This package doesn't aim to keep your Secrets safe from intentional attacks. It's aim is to make it
convenient to adopt best practice Secrets Management in Swift projects. It does this by ensuring
keeping your secrets out of your Source Code doesn't sacrifice usability, and that when compiled
into your application, they are not stored in plaintext. Remember
[Client Secrecy is Impossible](https://nshipster.com/secrets/#universe-brain-client-secrecy-is-impossible).