Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add first pass at Environment variable obfuscation #10

Merged
merged 2 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ By default, your `.env` file should live in the same directory as your `.xcodepr

It's sometimes helpful to commit a `.env.example` file that contains all the keys found in your environment file, but not the values, to help folks who pull down your project know which keys they need to track down.

Don't forget to add them to your .gitignore as well.
Don't forget to add them (and Environment.swift) to your .gitignore as well.

4. Create your run script

Expand Down Expand Up @@ -54,6 +54,7 @@ SteamclEnv comes with a number of flags to customize code generation:
| ------ | ------ | ---------- |
| --debug | n/a | Toggle debug mode, which prints more information out to the console while running. |
| --dev | -d | Use .env.dev rather than .env. This is superseded by --path if provided. |
| --obfuscate | -o | Obfuscates environment values. See the README for more information. |
| --output-path | -o | Path to output your file should write to, relative to your current directory. You can include a full or partial path. File name will default to Environment.swift if not provided. |
| --path | -p | Path to your environment file, relative to the current directory. This overrides --dev. |

Expand Down Expand Up @@ -91,8 +92,8 @@ Called `ci-helper`, we provide utilities to generate run scripts for Bitrise, an

### Obfuscation

https://nshipster.com/secrets/
Inspired by the folks at [NSHipster](https://nshipster.com/secrets/), this options obfuscates the values written out to your `Environment.swift` file, and provides some extra output to decode those values.

## License

Netable is available under the MIT license. See [LICENSE.md](https://github.com/steamclock/steamclenv/blob/main/LICENSE.md) for more info.
SteamclEnv is available under the MIT license. See [LICENSE.md](https://github.com/steamclock/steamclenv/blob/main/LICENSE.md) for more info.
28 changes: 22 additions & 6 deletions Sources/steamclenv/EnvironmentGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,20 @@ struct EnvironmentGenerator {
"""

let entries: [String: String]
let debug: Bool
let obfuscate: Bool

init(_ envContents: String, debug: Bool) throws {
self.debug = debug
init(_ envContents: String, obfuscate: Bool) throws {
self.obfuscate = obfuscate

let lines = envContents.components(separatedBy: .newlines)
entries = lines.reduce(into: [String: String]()) { dict, line in
let split = line.split(separator: "=")
if split.count == 2 {
let key = "\(split[0])"
let value = "\(split[1])"
if debug { Logger.shared.log("Found key: \(key)") }

Logger.shared.log("Found key: \(key)")

dict[key] = value
}
}
Expand All @@ -42,10 +44,24 @@ struct EnvironmentGenerator {
var fileContents: String {
var contents = fileHeader

entries.forEach { key, value in
contents += " static let \(key) = \"\(value)\" \n"
if obfuscate {
Logger.shared.log("Generating obfuscated Environment file...")
let obfuscator = ValueObfuscator()

contents += obfuscator.saltOutput

entries.forEach {
contents += obfuscator.obfuscated(key: $0, value: $1)
}
} else {
Logger.shared.log("Generating Environment file...")
entries.forEach { key, value in
contents += " static let \(key) = \"\(value)\" \n"
}
}

Logger.shared.log("Added \(entries.keys.count) entried to Environment 🚀")

contents += fileFooter

return contents
Expand Down
1 change: 0 additions & 1 deletion Sources/steamclenv/Logger.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//
// Logger.swift
//
//
// Created by Brendan Lensink on 2023-03-23.
//

Expand Down
54 changes: 54 additions & 0 deletions Sources/steamclenv/ValueObfuscator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// ValueObfuscator.swift
//
//
// Created by Brendan Lensink on 2023-03-23.
//

import Foundation
import os

struct ValueObfuscator {
private let salt: [UInt8]

init() {
var seed = UInt64.random(in: 0...UInt64.max)
let bytePtr = withUnsafePointer(to: &seed) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<UInt64>.size) {
UnsafeBufferPointer(start: $0, count: MemoryLayout<UInt64>.size)
}
}

self.salt = Array(bytePtr)
}

var saltOutput: String {
"""
private static let salt: [UInt8] = \(salt)

private static func decode(_ encoded: [UInt8]) -> String {
String(decoding: encoded.enumerated().map { (offset, element) in
element ^ salt[offset % salt.count]
}, as: UTF8.self
)
}\n
"""
}

func obfuscated(key: String, value: String) -> String {
"""
static var \(key): String {
let encoded: [UInt8] = \(self.encode(value))
return decode(encoded)
}\n
"""
}

private func encode(_ value: String) -> [UInt8] {
let encoded = value.enumerated().map { offset, token in
token.asciiValue! ^ salt[offset % salt.count]
}

return encoded
}
}
1 change: 0 additions & 1 deletion SteamclEnv-Example/.env.example

This file was deleted.

15 changes: 13 additions & 2 deletions SteamclEnv-Example/Environment.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
// @generated
// This file was automatically generated and should not be edited.
enum Environment {
static let API_URL = "https://google.com"
}
private static let salt: [UInt8] = [41, 149, 26, 106, 250, 201, 9, 57]

private static func decode(_ encoded: [UInt8]) -> String {
String(decoding: encoded.enumerated().map { (offset, element) in
element ^ salt[offset % salt.count]
}, as: UTF8.self
)
}
static var API_URL: String {
let encoded: [UInt8] = [65, 225, 110, 26, 137, 243, 38, 22, 78, 250, 117, 13, 150, 172, 39, 90, 70, 248]
return decode(encoded)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which ./steamclenv; then \n ./steamclenv generate\nelse\n echo \"Warning: SteamclEnv was expected to run but is not installed.\"\nfi\n";
shellScript = "if which ./steamclenv; then \n ./steamclenv generate --obfuscate\nelse\n echo \"Warning: SteamclEnv was expected to run but is not installed.\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */

Expand Down
11 changes: 0 additions & 11 deletions SteamclEnv-Example/ci_scripts/ci_pre_xcodebuild.sh

This file was deleted.