secure-keys 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e1c55d0d0f427de2248176c7b637d099d707c49802d6e3ef2b726e0d3e2383a8
4
+ data.tar.gz: 6cbc1fcdc0a67dce1101ef372849d11f19e1ce07bd48ac52d9c3c34cf2188fed
5
+ SHA512:
6
+ metadata.gz: 2a8e5c02474072f96dd7da0b61db861c313d8575e2bca0f42c57576f3081b58b7095fb47e17db01eff9ea5b756fac0be1e7d33351e5e4a143110640850fc6e69
7
+ data.tar.gz: f10ab748b3c5a74d4ef3b562ae555f5f6e1e93064fe25dc8a23fcfd185ab51baa08e148169a216d5694007ed8ddc0a760037d0b8c81b1233a4c9083a37ab515a
data/README.md ADDED
@@ -0,0 +1,193 @@
1
+ <div style="display: flex; gap: 10px; padding-bottom: 20px;">
2
+ <img src="https://img.shields.io/badge/version-1.0.0-cyan" alt="Keys Version 1.0.0">
3
+
4
+ <img src="https://img.shields.io/badge/iOS-^13.0-blue" alt="iOS version 13.0">
5
+
6
+ <img src="https://img.shields.io/badge/Ruby-^3.3.6-red" alt="Ruby version 3.3.6">
7
+
8
+ </div>
9
+
10
+ # Secure Key Generator for iOS projects
11
+
12
+ Utility to generate a `xcframework` for handling secure keys in iOS projects.
13
+
14
+ ### Prerequisites
15
+
16
+ - Ruby 3.3.6 or higher
17
+ - iOS 13.0 or higher
18
+
19
+ ### Installation
20
+
21
+ Install gems using bundler
22
+
23
+ ```bash
24
+ bundle install
25
+ ```
26
+
27
+ If you don't have bundler installed, you can install it using:
28
+
29
+ ```bash
30
+ gem install bundler
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ As first step, you need to determine the keys that you want to use in your iOS project. You can define the keys from Keychain or env variables.
36
+
37
+ The source is determined by the current platform **local or CI / cloud** using the `CI` environment variable.
38
+
39
+ If the `CI` environment variable is set to `true`, the keys are read from the environment variables. Otherwise, the keys are read from the Keychain.
40
+
41
+ You can configure your keys like this:
42
+
43
+ ### From Keychain
44
+
45
+ 1. You need to define the `secure-keys` record in the Keychain with the key name and the key value.
46
+
47
+ The value for this key should be all the key names separated by a comma.
48
+
49
+ ```bash
50
+ security add-generic-password -a "secure-keys" -s "secure-keys" -w "githubToken,apiKey"
51
+ ```
52
+
53
+ If you want to use another keychain identifier, you can define an env variable named `SECURE_KEYS_IDENTIFIER` to set the keychain identifier.
54
+
55
+ ```bash
56
+ export SECURE_KEYS_IDENTIFIER="your-keychain-identifier"
57
+
58
+ security add-generic-password -a "$SECURE_KEYS_IDENTIFIER" -s "$SECURE_KEYS_IDENTIFIER" -w "githubToken,apiKey"
59
+ ```
60
+
61
+ 2. You can add new keys using the `security` command.
62
+
63
+ ```bash
64
+ security add-generic-password -a "secure-keys" -s "apiKey" -w "your-api-key"
65
+ ```
66
+
67
+ Using custom keychain identifier:
68
+
69
+ ```bash
70
+ security add-generic-password -a "$SECURE_KEYS_IDENTIFIER" -s "apiKey" -w "your-api-key"
71
+ ```
72
+
73
+ ### Environment variables
74
+
75
+ 1. You can define the keys in the `.env` file or export the keys as environment variables.
76
+
77
+ ```bash
78
+ export SECURE_KEYS_IDENTIFIER="github-token,api_key,firebaseToken"
79
+
80
+ export GITHUB_TOKEN="your-github-token"
81
+ export API_KEY="your-api-key"
82
+ export FIREBASETOKEN="your-firebase-token"
83
+ ```
84
+
85
+ > The key names are formatted in uppercase and replace the `-` with `_`.
86
+
87
+ > [!IMPORTANT]
88
+ > If you want to use another demiliter, you can define an env variable named `SECURE_KEYS_DELIMITER` to set the delimiter.
89
+
90
+ ```bash
91
+ export SECURE_KEYS_DELIMITER="|"
92
+
93
+ export SECURE_KEYS_IDENTIFIER="github-token|api_key|firebaseToken"
94
+ ```
95
+
96
+ ### Ruby script
97
+
98
+ To generate the `Keys.xcframework` use the `keys.rb` script with:
99
+
100
+ ```bash
101
+ bundle exec ruby ./bin/keys.rb
102
+ ```
103
+
104
+ ### iOS project
105
+
106
+ Within the iOS project, you can use the `Keys` target dependency like:
107
+
108
+ ```swift
109
+ import Keys
110
+
111
+ // Using key directly in the code
112
+ let apiKey = Keys.apiKey.decryptedValue
113
+
114
+ // Using key from `Key` enum
115
+ let someKey: String = key(for: .someKey)
116
+
117
+ // Alternative way to use key from `Key` enum
118
+ let someKey: String = key(.someKey)
119
+
120
+ // Using raw value from `Key` enum
121
+ let apiKey: Keys = "apiKey".secretKey
122
+
123
+ // Using raw value from `Key` enum with decrypted value
124
+ let apiKey: String = "apiKey".secretKey.decryptedValue
125
+
126
+ // Using `key` method to get the key
127
+ let apiKey: String = .key(for: .apiKey)
128
+ ```
129
+
130
+ ## How to install the `Keys.xcframework` in the iOS project
131
+
132
+ 1. From the iOS project, click on the project target, select the `General` tab, and scroll down to the `Frameworks, Libraries, and Embedded Content` section.
133
+
134
+ ![Project Target](/docs/assets/add-xcframework-to-ios-project/first-step.png)
135
+
136
+ 2. Click on the `Add Other...` button and click on the `Add Files...` option.
137
+
138
+ ![Add Files](/docs/assets/add-xcframework-to-ios-project/second-step.png)
139
+
140
+ 3. Navigate to the `keys` directory and select the `Keys.xcframework` folder.
141
+
142
+ ![Select Keys.xcframework](/docs/assets/add-xcframework-to-ios-project/third-step.png)
143
+
144
+ > Now the `Keys.xcframework` is added to the iOS project.
145
+
146
+ ![Select Keys.xcframework](/docs/assets/add-xcframework-to-ios-project/third-step-result.png)
147
+
148
+ 4. Click on the `Build settings` tab and search for the `Search Paths` section.
149
+
150
+ ![Search Paths](/docs/assets/add-xcframework-to-ios-project/fourth-step.png)
151
+
152
+ > Add the path to the `Keys.xcframework` in the `Framework Search Paths` section.
153
+
154
+ ```bash
155
+ $(inherited)
156
+ $(SRCROOT)/.keys
157
+ ```
158
+
159
+ ## How it works
160
+
161
+ The process when the script is executed is:
162
+
163
+ 1. Create a `.keys` directory.
164
+ 2. Create a temporary `Swift Package` in the `.keys` directory.
165
+ 3. Copy the `Keys` source code to the temporary `Swift Package`.
166
+
167
+ ```swift
168
+ public enum Keys {
169
+
170
+ // MARK: - Cases
171
+
172
+ case apiKey
173
+ case someKey
174
+ case unknown
175
+
176
+ // MARK: - Properties
177
+
178
+ /// The decrypted value of the key
179
+ public var decryptedValue: String {
180
+ switch self {
181
+ case .apiKey: [1, 2, 4].decrypt(key: [248, 53, 26], iv: [148, 55, 47], tag: [119, 81])
182
+ case .someKey: [1, 2, 4].decrypt(key: [248, 53, 26], iv: [148, 55, 47], tag: [119, 81])
183
+ case .unknown: fatalError("Unknown key \(rawValue)")
184
+ }
185
+ }
186
+ }
187
+ ```
188
+ 4. Generate the `Keys.xcframework` using the temporary `Swift Package`.
189
+ 5. Remove the temporary `Swift Package`.
190
+
191
+ ## License
192
+
193
+ This project is licensed under the MIT [License](LICENSE).
data/bin/keys.rb ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require_relative '../lib/keys'
5
+
6
+ # Generate the keys
7
+ Keys::Generator.new.setup
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Keys
4
+ module Core
5
+ module Environment
6
+ class CI
7
+ # Fetches the value of the environment variable with the given key.
8
+ # @param key [String] the key of the environment variable to fetch
9
+ # @return [String] the value of the environment variable
10
+ def fetch(key:)
11
+ ENV[formatted_key(key:)]
12
+ rescue StandardError
13
+ puts "❌ Error fetching the key: #{key} from ENV variables"
14
+ end
15
+
16
+ private
17
+
18
+ # Formats the key to match the format of the environment variables.
19
+ # @param key [String] the key to format
20
+ # @return [String] the formatted key
21
+ def formatted_key(key:)
22
+ key.gsub('-', '_').uppercase
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'osx_keychain'
4
+
5
+ module Keys
6
+ module Core
7
+ module Environment
8
+ class Keychain
9
+ private
10
+
11
+ attr_accessor :keychain
12
+
13
+ public
14
+
15
+ def initialize
16
+ self.keychain = OSXKeychain.new
17
+ end
18
+
19
+ # Fetches the value of the keychain access item with the given key.
20
+ # @param key [String] the key of the keychain access item to fetch
21
+ # @return [String] the value of the keychain access item
22
+ def fetch(key:)
23
+ keychain[key, Keys::Globals.key_access_identifier]
24
+ rescue StandardError
25
+ puts "❌ Error fetching the key: #{key} from Keychain."
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Keys
4
+ module Globals
5
+ module_function
6
+
7
+ # Source: https://github.com/fastlane/fastlane/blob/b626fb18597eee88de0e08beba77070e2fecc299/fastlane_core/lib/fastlane_core/helper.rb#L73
8
+ # Check if the current build is running on a CI
9
+ # @return [Bool] true if the current build is running on a CI
10
+ def ci?
11
+ return true if circle_ci?
12
+
13
+ # Check for Jenkins, Travis CI, ... environment variables
14
+ %w[JENKINS_HOME JENKINS_URL TRAVIS CI APPCENTER_BUILD_ID TEAMCITY_VERSION GO_PIPELINE_NAME bamboo_buildKey GITLAB_CI XCS TF_BUILD GITHUB_ACTION GITHUB_ACTIONS BITRISE_IO BUDDY CODEBUILD_BUILD_ARN].any? do |current|
15
+ ENV[current].to_s.eql?('true')
16
+ end
17
+ end
18
+
19
+ # Check if the current build is running on CircleCI
20
+ # @return [Bool] true if the current build is running on CircleCI
21
+ def circle_ci?
22
+ ENV.key?('CIRCLECI')
23
+ end
24
+
25
+ # Returns the supported iOS platforms
26
+ # @return [Array] supported iOS platforms
27
+ def ios_platforms
28
+ [
29
+ {
30
+ name: 'iOS Simulator',
31
+ path: 'iphonesimulator'
32
+ },
33
+ {
34
+ name: 'iOS',
35
+ path: 'iphoneos'
36
+ }
37
+ ]
38
+ end
39
+
40
+ # Returns the identifier to get all the key names
41
+ # @return [String] key access identifier
42
+ def key_access_identifier
43
+ ENV['SECURE_KEYS_IDENTIFIER'] || default_key_access_identifier
44
+ end
45
+
46
+ # Returns the default key access identifier
47
+ # @return [String] default key access identifier
48
+ def default_key_access_identifier
49
+ 'secure-keys'
50
+ end
51
+
52
+ # Returns the keys delimiter
53
+ # @return [String] keys delimiter
54
+ def key_delimiter
55
+ ENV['SECURE_KEYS_DELIMITER'] || default_key_delimiter
56
+ end
57
+
58
+ # Returns the default keys delimiter
59
+ # @return [String] default keys delimiter
60
+ def default_key_delimiter
61
+ ','
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'openssl'
4
+ require 'base64'
5
+ require 'securerandom'
6
+
7
+ module Keys
8
+ module OpenSSL
9
+ class Cipher
10
+ private
11
+
12
+ attr_accessor :secure_key, :cipher
13
+
14
+ public
15
+
16
+ # Initialize the cipher with a random generated key
17
+ # and the aes-256-gcm algorithm
18
+ # @param bytes [Integer] the number of bytes to generate the key
19
+ def initialize(bytes: 32)
20
+ self.secure_key = SecureRandom.random_bytes(bytes)
21
+ self.cipher = ::OpenSSL::Cipher.new('aes-256-gcm').encrypt
22
+
23
+ # Configure the cipher key using the random generated key
24
+ cipher.key = secure_key
25
+ end
26
+
27
+ # Encrypt a value using the cipher
28
+ # @param value [String] the value to encrypt
29
+ # @return [Hash] the encrypted value, the iv and the tag
30
+ def encrypt(value:)
31
+ iv = cipher.random_iv
32
+ encrypted_value = cipher.update(value) + cipher.final
33
+ tag = cipher.auth_tag
34
+
35
+ { iv: iv.bytes, value: encrypted_value.bytes, tag: tag.bytes }
36
+ end
37
+
38
+ # Fetch the bytes of the secure key
39
+ # @return [Array] the bytes of the secure key
40
+ def secure_key_bytes
41
+ secure_key.bytes
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative './swift'
4
+
5
+ module Keys
6
+ module Swift
7
+ class Package
8
+ # Generate the Swift Package using the configured path
9
+ def generate
10
+ command = <<~BASH
11
+ rm -rf #{SWIFT_PACKAGE_DIRECTORY} &&
12
+ mkdir -p #{SWIFT_PACKAGE_DIRECTORY} &&
13
+ cd #{SWIFT_PACKAGE_DIRECTORY} &&
14
+ swift package init --name #{SWIFT_PACKAGE_NAME} --type library
15
+ BASH
16
+
17
+ system(command)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Keys
4
+ module Swift
5
+ # Constants
6
+
7
+ # The name of the directory that contains the keys
8
+ KEYS_DIRECTORY = '.keys'.freeze
9
+
10
+ # The name of the directory that contains the generated build
11
+ BUILD_DIRECTORY = 'Build'.freeze
12
+
13
+ # The name of the Swift Package
14
+ SWIFT_PACKAGE_NAME = 'Keys'.freeze
15
+
16
+ # The name of the directory that contains the generated Swift package
17
+ SWIFT_PACKAGE_DIRECTORY = "#{KEYS_DIRECTORY}/Package".freeze
18
+
19
+ # The name of the directory that contains the generated xcframework
20
+ XCFRAMEWORK_DIRECTORY = "#{SWIFT_PACKAGE_NAME}.xcframework".freeze
21
+ end
22
+ end
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+ # rubocop:disable Layout/HeredocIndentation
3
+
4
+ require_relative './swift'
5
+
6
+ module Keys
7
+ module Swift
8
+ class Writer
9
+ private
10
+
11
+ attr_accessor :mapped_keys, :secure_key_bytes, :key_file, :key_directory
12
+
13
+ public
14
+
15
+ # Initialize the writer with the mapped keys and the secure key bytes
16
+ # @param mapped_keys [Array<Hash>] The mapped keys
17
+ # @param secure_key_bytes [Array<UInt8>] The secure key bytes
18
+ def initialize(mapped_keys:, secure_key_bytes:)
19
+ self.mapped_keys = mapped_keys
20
+ self.secure_key_bytes = secure_key_bytes
21
+ self.key_file = "#{SWIFT_PACKAGE_NAME}.swift"
22
+ self.key_directory = "#{SWIFT_PACKAGE_DIRECTORY}/Sources/#{SWIFT_PACKAGE_NAME}"
23
+ end
24
+
25
+ # Write the keys to the file
26
+ def write
27
+ # Write the file
28
+ File.open("#{key_directory}/#{key_file}", 'w') do |file|
29
+ file.write(key_swift_file_template(content: formatted_keys))
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # Generate the formatted keys content using Swift code format
36
+ # @return [String] The formatted keys content
37
+ def formatted_keys
38
+ <<~SWIFT
39
+ #{mapped_keys.map { |key| case_key_declaration_template(name: key[:name]) }.join("\t")}
40
+ case unknown
41
+
42
+ // MARK: - Properties
43
+
44
+ /// The decrypted value of the key
45
+ public var decryptedValue: String {
46
+ switch self {
47
+ #{mapped_keys.map { |key| switch_case_key_declaration_template(name: key[:name], value: key[:value], iv: key[:iv], tag: key[:tag]) }.join("\t\t\t")}
48
+ case .unknown: fatalError("Unknown key \\(rawValue)")
49
+ }
50
+ }
51
+ SWIFT
52
+ end
53
+
54
+ # Generate the Swift file template
55
+ # @param content [String] The content of the file
56
+ # @return [String] The Swift file template
57
+ def key_swift_file_template(content:)
58
+ <<~SWIFT
59
+ // swiftlint:disable all
60
+
61
+ import Foundation
62
+ import CryptoKit
63
+
64
+ // MARK: - Global methods
65
+
66
+ /// Fetch the decrypted value of the key
67
+ ///
68
+ /// - Parameter:
69
+ /// - key: The key to fetch the decrypted value for
70
+ ///
71
+ /// - Returns: The decrypted value of the key
72
+ @available(iOS 13.0, *)
73
+ public func key(for key: Keys) -> String { key.decryptedValue }
74
+
75
+ /// Fetch the decrypted value of the key
76
+ ///
77
+ /// - Parameter:
78
+ /// - key: The key to fetch the decrypted value for
79
+ ///
80
+ /// - Returns: The decrypted value of the key
81
+ @available(iOS 13.0, *)
82
+ public func key(_ key: Keys) -> String { key.decryptedValue }
83
+
84
+ // MARK: - Keys enum
85
+
86
+ /// Keys is a class that contains all the keys that are used in the application.
87
+ @available(iOS 13.0, *)
88
+ public enum Keys: String {
89
+
90
+ // MARK: - Cases
91
+
92
+ #{content}
93
+ }
94
+
95
+ // MARK: - Decrypt keys from array extension
96
+
97
+ @available(iOS 13.0, *)
98
+ extension Array where Element == UInt8 {
99
+
100
+ // MARK: - Methods
101
+
102
+ func decrypt(key: [UInt8], iv: [UInt8], tag: [UInt8]) -> String {
103
+ guard let sealedBox = try? AES.GCM.SealedBox(nonce: AES.GCM.Nonce(data: Data(iv)),
104
+ ciphertext: Data(self),
105
+ tag: Data(tag)),
106
+ let decryptedData = try? AES.GCM.open(sealedBox, using: SymmetricKey(data: Data(key))),
107
+ let decryptedKey = String(data: decryptedData, encoding: .utf8) else {
108
+ fatalError("Failed to decrypt the key")
109
+ }
110
+ return decryptedKey
111
+ }
112
+ }
113
+
114
+ // MARK: - String extension for keys
115
+
116
+ @available(iOS 13.0, *)
117
+ extension String {
118
+
119
+ // MARK: - Methods
120
+
121
+ /// Fetch the key from the keys enum
122
+ public var secretKey: Keys { Keys(rawValue: self) ?? .unknown }
123
+
124
+ /// Fetch the decrypted value of the key
125
+ ///
126
+ /// - Parameters:
127
+ /// - key: The key to fetch the decrypted value for
128
+ ///
129
+ /// - Returns: The decrypted value of the key
130
+ public static func key(for key: Keys) -> String { key.decryptedValue }
131
+ }
132
+
133
+ // swiftlint:enable all
134
+ SWIFT
135
+ end
136
+
137
+ # Generate the case key declaration template
138
+ # @param name [String] The name of the key
139
+ def case_key_declaration_template(name:)
140
+ <<~SWIFT
141
+ case #{name}
142
+ SWIFT
143
+ end
144
+
145
+ # Generate the switch case key declaration template
146
+ # @param name [String] The name of the key
147
+ def switch_case_key_declaration_template(name:, value:, iv:, tag:) # rubocop:disable Naming/MethodParameterName
148
+ <<~SWIFT
149
+ case .#{name}: #{value}.decrypt(key: #{secure_key_bytes}, iv: #{iv}, tag: #{tag})
150
+ SWIFT
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ # rubocop:enable Layout/HeredocIndentation
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative './swift'
4
+ require_relative '../../globals/globals'
5
+
6
+ module Keys
7
+ module Swift
8
+ class XCFramework
9
+ # Generate the XCFramework from the Swift package
10
+ def generate
11
+ # TODO: Add support for multiple platforms
12
+ # Currently this is failling with the following error:
13
+ # "library with the identifier 'ios-arm64' already exists."
14
+ %w[Release].each do |configuration|
15
+ Keys::Globals.ios_platforms.each do |platform|
16
+ generate_key_modules(configuration:, platform:)
17
+ generate_key_libraries(configuration:, platform: platform[:path])
18
+ end
19
+ end
20
+ generate_key_xcframework
21
+ end
22
+
23
+ private
24
+
25
+ # Generate the Swift package modules
26
+ # @param configuration [String] The configuration to build
27
+ # @param platform [Hash] The platform to build
28
+ def generate_key_modules(configuration:, platform:)
29
+ command = <<~BASH
30
+ cd #{SWIFT_PACKAGE_DIRECTORY} &&
31
+ xcodebuild -scheme #{SWIFT_PACKAGE_NAME} \
32
+ -sdk #{platform[:path]} \
33
+ -destination generic/platform="#{platform[:name]}" \
34
+ -configuration #{configuration} \
35
+ ARCHS="arm64" BUILD_DIR="../#{BUILD_DIRECTORY}"
36
+ BASH
37
+
38
+ system(command)
39
+ end
40
+
41
+ # Generate the Swift package libraries
42
+ # @param configuration [String] The configuration to build
43
+ # @param platform [String] The platform to build
44
+ def generate_key_libraries(configuration:, platform:)
45
+ command = <<~BASH
46
+ cd #{KEYS_DIRECTORY} &&
47
+ ar -crs #{BUILD_DIRECTORY}/#{configuration}-#{platform}/libKeys.a \
48
+ #{BUILD_DIRECTORY}/#{configuration}-#{platform}/Keys.o
49
+ BASH
50
+
51
+ system(command)
52
+ end
53
+
54
+ # Generate the XCFramework from the Swift package libraries
55
+ def generate_key_xcframework
56
+ command = <<~BASH
57
+ cd #{KEYS_DIRECTORY} &&
58
+ xcodebuild -create-xcframework \
59
+ #{xcframework_library_command} \
60
+ -allow-internal-distribution \
61
+ -output #{XCFRAMEWORK_DIRECTORY}
62
+ BASH
63
+
64
+ system(command)
65
+ end
66
+
67
+ # Generate the XCFramework library command
68
+ # @return [String] The XCFramework library command
69
+ def xcframework_library_command
70
+ # TODO: Add support for multiple platforms
71
+ # Currently this is failling with the following error:
72
+ # "library with the identifier 'ios-arm64' already exists."
73
+ %w[Release].map do |configuration|
74
+ Keys::Globals.ios_platforms.map do |platform|
75
+ "-library #{BUILD_DIRECTORY}/#{configuration}-#{platform[:path]}/libKeys.a"
76
+ end.join(' ')
77
+ end.join(' ')
78
+ end
79
+ end
80
+ end
81
+ end
data/lib/keys.rb ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative './core/globals/globals'
4
+ require_relative './core/environment/ci'
5
+ require_relative './core/environment/keychain'
6
+ require_relative './core/utils/swift/writer'
7
+ require_relative './core/utils/swift/package'
8
+ require_relative './core/utils/swift/swift'
9
+ require_relative './core/utils/swift/xcframework'
10
+ require_relative './core/utils/openssl/cipher'
11
+
12
+ module Keys
13
+ class Generator
14
+ private
15
+
16
+ attr_accessor :cipher, :secrets_source, :secret_keys, :mapped_keys
17
+
18
+ public
19
+
20
+ def initialize
21
+ # If the secure keys identifier is not set, set it to 'secure-keys'
22
+ ENV['SECURE_KEYS_IDENTIFIER'] = 'secure-keys' unless ENV.key?('SECURE_KEYS_IDENTIFIER')
23
+
24
+ puts "🔔 You're using a custom delimiter '#{Keys::Globals.key_delimiter}'" unless Keys::Globals.key_delimiter.eql?(Keys::Globals.default_key_delimiter)
25
+ puts "🔔 You're using a custom key access identifier '#{Keys::Globals.key_access_identifier}'" unless Keys::Globals.key_access_identifier.eql?(Keys::Globals.default_key_access_identifier)
26
+
27
+ # Configure cipher
28
+ self.cipher = Keys::OpenSSL::Cipher.new
29
+
30
+ # Configure the secret source based on the environment
31
+ if Keys::Globals.ci?
32
+ self.secrets_source = Keys::Core::Environment::CI.new
33
+ else
34
+ self.secrets_source = Keys::Core::Environment::Keychain.new
35
+ end
36
+
37
+ # Define the keys that we want to map
38
+ self.secret_keys = secrets_source.fetch(key: Keys::Globals.key_access_identifier)
39
+ .to_s
40
+ .split(Keys::Globals.key_delimiter)
41
+ .map(&:strip)
42
+
43
+ # Add the keys that we want to map
44
+ self.mapped_keys = secret_keys.map do |key|
45
+ encrypted_data = cipher.encrypt(value: secrets_source.fetch(key:))
46
+ # Convert the first key chart to downcase
47
+ key[0] = key[0].downcase
48
+ { name: key, **encrypted_data }
49
+ end
50
+ end
51
+
52
+ def setup
53
+ pre_actions
54
+
55
+ package = Keys::Swift::Package.new
56
+ package.generate
57
+
58
+ writer = Keys::Swift::Writer.new(mapped_keys: mapped_keys,
59
+ secure_key_bytes: cipher.secure_key_bytes)
60
+ writer.write
61
+
62
+ xcframework = Keys::Swift::XCFramework.new
63
+ xcframework.generate
64
+
65
+ post_actions
66
+ end
67
+
68
+ private
69
+
70
+ def pre_actions
71
+ # Remove the keys directory
72
+ system("rm -rf #{Keys::Swift::KEYS_DIRECTORY}")
73
+ end
74
+
75
+ def post_actions
76
+ # Remove the keys directory
77
+ system("rm -rf #{Keys::Swift::SWIFT_PACKAGE_DIRECTORY}")
78
+
79
+ # Remove the build directory
80
+ system("rm -rf #{Keys::Swift::KEYS_DIRECTORY}/#{Keys::Swift::BUILD_DIRECTORY}")
81
+ end
82
+ end
83
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Keys
4
+ VERSION = '1.0.0'.freeze
5
+ SUMMARY = 'Keys is a simple tool for managing your secret keys'.freeze
6
+ DESCRIPTION = 'Keys is a simple tool to manage your secret keys in iOS your project'.freeze
7
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: secure-keys
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Derian Córdoba
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: digest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.10.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.10.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: osx_keychain
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.0.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.71.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.71.2
83
+ description: Keys is a simple tool to manage your secret keys in iOS your project
84
+ email:
85
+ - derianricardo451@gmail.com
86
+ executables:
87
+ - keys.rb
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - "./lib/core/environment/ci.rb"
92
+ - "./lib/core/environment/keychain.rb"
93
+ - "./lib/core/globals/globals.rb"
94
+ - "./lib/core/utils/openssl/cipher.rb"
95
+ - "./lib/core/utils/swift/package.rb"
96
+ - "./lib/core/utils/swift/swift.rb"
97
+ - "./lib/core/utils/swift/writer.rb"
98
+ - "./lib/core/utils/swift/xcframework.rb"
99
+ - "./lib/keys.rb"
100
+ - "./lib/version.rb"
101
+ - README.md
102
+ - bin/keys.rb
103
+ homepage: https://github.com/DerianCordobaPerez/secure-keys-generator
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '3.3'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubygems_version: 3.5.22
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: Keys is a simple tool for managing your secret keys
126
+ test_files: []