secure-keys 1.1.3 → 1.1.4
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 +4 -4
- data/README.md +58 -12
- data/bin/secure-keys +1 -1
- data/lib/core/console/arguments/handler.rb +20 -4
- data/lib/core/console/arguments/parser.rb +12 -4
- data/lib/core/console/arguments/xcframework/handler.rb +23 -0
- data/lib/core/console/arguments/xcframework/parser.rb +42 -0
- data/lib/core/console/logger.rb +1 -1
- data/lib/core/environment/ci.rb +1 -10
- data/lib/core/generator.rb +81 -0
- data/lib/core/globals/globals.rb +36 -6
- data/lib/core/utils/extensions/kernel.rb +13 -0
- data/lib/core/utils/extensions/string/camelize.rb +11 -0
- data/lib/core/utils/extensions/string/to_bool.rb +16 -0
- data/lib/core/utils/swift/writer.rb +81 -52
- data/lib/core/utils/swift/xcframework.rb +22 -2
- data/lib/core/utils/swift/xcodeproj.rb +70 -4
- data/lib/keys.rb +9 -75
- data/lib/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdab80c05ee6ac029d64ec53aef700bc77e9126398f886f6fc7e0ae529297535
|
4
|
+
data.tar.gz: 38176c478f562dfcacd51e62b051f49705cec3cc66a586e20487038965a9976e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77e197f322a085f56ce57eef897fdcc156c2c5fe3be9decd1464b396080cfbab2acb39def1787c872b7980c8fb6b9530b6487ccbd2b8b87e93beff57a64f1d51
|
7
|
+
data.tar.gz: ffc4ba7aedeff64d0d30f214564b2ec48f4658d4a5eef8e428877b7d98ab896d5a108e0a9e50bdd9668cfa62496d0b9929b6efab50f42814ff4ae1871dc22b14
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
<div style="display: flex; gap: 10px; padding-bottom: 20px;">
|
2
|
-
<img src="https://img.shields.io/badge/version-1.1.
|
2
|
+
<img src="https://img.shields.io/badge/version-1.1.4-cyan" alt="SecureKeys version">
|
3
3
|
|
4
4
|
<img src="https://img.shields.io/badge/iOS-^13.0-blue" alt="iOS version 13.0">
|
5
5
|
|
@@ -137,13 +137,13 @@ secure-keys --help
|
|
137
137
|
|
138
138
|
Usage: secure-keys [--options]
|
139
139
|
|
140
|
-
-h, --help
|
141
|
-
--
|
142
|
-
-d, --delimiter DELIMITER
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
-
|
140
|
+
-h, --help Use the provided commands to select the params
|
141
|
+
--xcframework Add the xcframework to the target
|
142
|
+
-d, --delimiter DELIMITER The delimiter to use for the key access (default: ",")
|
143
|
+
--[no-]generate Generate the SecureKeys.xcframework
|
144
|
+
-i, --identifier IDENTIFIER The identifier to use for the key access (default: "secure-keys")
|
145
|
+
--verbose Enable verbose mode (default: false)
|
146
|
+
-v, --version Show the secure-keys version
|
147
147
|
```
|
148
148
|
|
149
149
|
To avoid defining the `SECURE_KEYS_IDENTIFIER` and `SECURE_KEYS_DELIMITER` env variables, you can use the `--identifier` and `--delimiter` options.
|
@@ -188,22 +188,68 @@ let apiKey: String = .key(for: .apiKey)
|
|
188
188
|
|
189
189
|
### Automatically
|
190
190
|
|
191
|
-
|
191
|
+
> [!IMPORTANT]
|
192
|
+
> You can see more information about the command using the `--help` option.
|
193
|
+
|
194
|
+
```bash
|
195
|
+
secure-keys --xcframework --help
|
196
|
+
|
197
|
+
# Output
|
198
|
+
Usage: secure-keys --xcframework [--options]
|
199
|
+
|
200
|
+
-h, --help Use the provided commands to select the params
|
201
|
+
--[no-]add Add the SecureKeys XCFramework to the Xcode project (default: true)
|
202
|
+
-t, --target TARGET The target to add the xcframework
|
203
|
+
-r, --replace Replace the existing xcframework in the Xcode project (default: false)
|
204
|
+
-x, --xcodeproj XCODEPROJ The Xcode project path (default: the first found Xcode project)
|
205
|
+
```
|
206
|
+
|
207
|
+
From the `secure-keys` command, you can use the `--xcframework` option to add the `SecureKeys.xcframework` to the iOS project.
|
208
|
+
|
209
|
+
```bash
|
210
|
+
secure-keys --xcframework --target "YourTargetName" --add
|
211
|
+
```
|
212
|
+
|
213
|
+
If you want to add the `SecureKeys.xcframework` to an iOS that already contains the `SecureKeys` source code, you can use the `--replace` option.
|
214
|
+
|
215
|
+
```bash
|
216
|
+
secure-keys --xcframework --target "YourTargetName" --replace
|
217
|
+
```
|
218
|
+
|
219
|
+
> [!IMPORTANT]
|
220
|
+
> If you don't need to generate the `SecureKeys.xcframework` every time, you can use the `--no-generate` option.
|
192
221
|
|
193
222
|
```bash
|
194
|
-
secure-keys --
|
223
|
+
secure-keys --no-generate --xcframework --target "YourTargetName"
|
195
224
|
```
|
196
225
|
|
197
226
|
Also, you can specify your Xcode project path using the `--xcodeproj` option.
|
198
227
|
|
199
228
|
```bash
|
200
|
-
secure-keys --
|
229
|
+
secure-keys --xcframework --target "YourTargetName" --xcodeproj "/path/to/your/project.xcodeproj"
|
201
230
|
```
|
202
231
|
|
203
232
|
> [!IMPORTANT]
|
204
233
|
> By default, the xcodeproj path would be the first found Xcode project.
|
205
234
|
|
206
|
-
|
235
|
+
If you don't want to use the CLI options, you can configure some env variable to interact with the `secure-keys` command.
|
236
|
+
|
237
|
+
```bash
|
238
|
+
# e.g (Large version)
|
239
|
+
export SECURE_KEYS_XCFRAMEWORK_TARGET="YourTargetName"
|
240
|
+
export SECURE_KEYS_XCFRAMEWORK_ADD=true
|
241
|
+
export SECURE_KEYS_XCFRAMEWORK_REPLACE=true
|
242
|
+
export SECURE_KEYS_XCFRAMEWORK_XCODEPROJ="/path/to/your/project.xcodeproj"
|
243
|
+
|
244
|
+
# e.g (Short version)
|
245
|
+
export XCFRAMEWORK_TARGET="YourTargetName"
|
246
|
+
export XCFRAMEWORK_ADD=true
|
247
|
+
export XCFRAMEWORK_REPLACE=true
|
248
|
+
export XCFRAMEWORK_XCODEPROJ="/path/to/your/project.xcodeproj"
|
249
|
+
|
250
|
+
# Run the command
|
251
|
+
secure-keys --xcframework
|
252
|
+
```
|
207
253
|
|
208
254
|
### Manually
|
209
255
|
|
data/bin/secure-keys
CHANGED
@@ -10,21 +10,37 @@ module SecureKeys
|
|
10
10
|
# Configure the default arguments
|
11
11
|
@arguments = {
|
12
12
|
delimiter: nil,
|
13
|
+
generate: true,
|
13
14
|
identifier: nil,
|
14
|
-
target: nil,
|
15
15
|
verbose: false,
|
16
|
-
xcodeproj: nil,
|
17
16
|
}
|
18
17
|
|
19
18
|
# Fetch the argument value by key
|
20
19
|
# from CLI arguments or environment variables
|
21
20
|
#
|
22
|
-
# @param key [Symbol] the argument key
|
21
|
+
# @param key [Array|Symbol] the argument key
|
23
22
|
# @param default [String] the default value
|
24
23
|
#
|
25
24
|
# @return [String] the argument value
|
26
25
|
def self.fetch(key:, default: nil)
|
27
|
-
|
26
|
+
keys = Array(key).map(&:to_sym)
|
27
|
+
joined_keys = keys.join('_').upcase
|
28
|
+
@arguments.dig(*keys) || ENV["SECURE_KEYS_#{joined_keys}"] || ENV[joined_keys] || default
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set the value of the key
|
32
|
+
# @param key [Symbol] the key to be updated
|
33
|
+
# @param value [String] the value to be updated
|
34
|
+
def self.set(key:, value:)
|
35
|
+
@arguments[key.to_sym] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
# Append the argument value by key
|
39
|
+
# @param key [Symbol] the argument key
|
40
|
+
# @param value [String] the argument value
|
41
|
+
def self.deep_merge(key:, value:)
|
42
|
+
@arguments[key.to_sym] ||= {} # Initialize the key if it doesn't exist
|
43
|
+
@arguments[key.to_sym].merge!(value)
|
28
44
|
end
|
29
45
|
end
|
30
46
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'optparse'
|
4
4
|
require_relative '../../globals/globals'
|
5
5
|
require_relative './handler'
|
6
|
+
require_relative './xcframework/parser'
|
6
7
|
|
7
8
|
module SecureKeys
|
8
9
|
module Core
|
@@ -16,7 +17,8 @@ module SecureKeys
|
|
16
17
|
|
17
18
|
# Configure the arguement parser
|
18
19
|
configure!
|
19
|
-
|
20
|
+
order!(into: Handler.arguments)
|
21
|
+
configure_sub_arguments
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
@@ -28,10 +30,12 @@ module SecureKeys
|
|
28
30
|
exit(0)
|
29
31
|
end
|
30
32
|
|
31
|
-
on('--
|
32
|
-
|
33
|
+
on('--xcframework', 'Add the xcframework to the target') do
|
34
|
+
XCFramework::Parser.new
|
33
35
|
end
|
36
|
+
|
34
37
|
on('-d', '--delimiter DELIMITER', String, "The delimiter to use for the key access (default: \"#{Globals.default_key_delimiter}\")")
|
38
|
+
on('--[no-]generate', TrueClass, 'Generate the SecureKeys.xcframework')
|
35
39
|
on('-i', '--identifier IDENTIFIER', String, "The identifier to use for the key access (default: \"#{Globals.default_key_access_identifier}\")")
|
36
40
|
on('--verbose', TrueClass, 'Enable verbose mode (default: false)')
|
37
41
|
|
@@ -39,7 +43,11 @@ module SecureKeys
|
|
39
43
|
puts "secure-keys version: v#{SecureKeys::VERSION}"
|
40
44
|
exit(0)
|
41
45
|
end
|
42
|
-
|
46
|
+
end
|
47
|
+
|
48
|
+
# Configure the sub arguments
|
49
|
+
def configure_sub_arguments
|
50
|
+
Handler.set(key: :xcframework, value: XCFramework::Handler.arguments)
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SecureKeys
|
2
|
+
module Core
|
3
|
+
module Console
|
4
|
+
module Argument
|
5
|
+
module XCFramework
|
6
|
+
class Handler
|
7
|
+
class << self
|
8
|
+
attr_reader :arguments
|
9
|
+
end
|
10
|
+
|
11
|
+
# Configure the default arguments
|
12
|
+
@arguments = {
|
13
|
+
add: true,
|
14
|
+
replace: false,
|
15
|
+
target: nil,
|
16
|
+
xcodeproj: nil,
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require_relative '../../../globals/globals'
|
5
|
+
require_relative './handler'
|
6
|
+
|
7
|
+
module SecureKeys
|
8
|
+
module Core
|
9
|
+
module Console
|
10
|
+
module Argument
|
11
|
+
module XCFramework
|
12
|
+
class Parser < OptionParser
|
13
|
+
# Initialize the argument parser with the default options
|
14
|
+
def initialize
|
15
|
+
super('Usage: secure-keys --xcframework [--options]')
|
16
|
+
separator('')
|
17
|
+
|
18
|
+
# Configure the arguement parser
|
19
|
+
configure!
|
20
|
+
order!(into: Handler.arguments)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Configure the argument parser
|
26
|
+
def configure!
|
27
|
+
on('-h', '--help', 'Use the provided commands to select the params') do
|
28
|
+
puts self
|
29
|
+
exit(0)
|
30
|
+
end
|
31
|
+
|
32
|
+
on('--[no-]add', TrueClass, 'Add the SecureKeys XCFramework to the Xcode project (default: true)')
|
33
|
+
on('-t', '--target TARGET', String, 'The target to add the xcframework')
|
34
|
+
on('-r', '--replace', TrueClass, 'Replace the existing xcframework in the Xcode project (default: false)')
|
35
|
+
on('-x', '--xcodeproj XCODEPROJ', String, 'The Xcode project path (default: the first found Xcode project)')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/core/console/logger.rb
CHANGED
@@ -54,7 +54,7 @@ module SecureKeys
|
|
54
54
|
# Log a verbose message
|
55
55
|
# @param message [String] the message to log
|
56
56
|
def verbose(message:)
|
57
|
-
logger.debug(message.to_s) if
|
57
|
+
logger.debug(message.to_s) if Globals.verbose?
|
58
58
|
end
|
59
59
|
|
60
60
|
# Crash the terminal with a message
|
data/lib/core/environment/ci.rb
CHANGED
@@ -8,19 +8,10 @@ module SecureKeys
|
|
8
8
|
# @param key [String] the key of the environment variable to fetch
|
9
9
|
# @return [String] the value of the environment variable
|
10
10
|
def fetch(key:)
|
11
|
-
ENV[
|
11
|
+
ENV[key]
|
12
12
|
rescue StandardError
|
13
13
|
puts "❌ Error fetching the key: #{key} from ENV variables"
|
14
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
15
|
end
|
25
16
|
end
|
26
17
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative './globals/globals'
|
4
|
+
require_relative './environment/ci'
|
5
|
+
require_relative './environment/keychain'
|
6
|
+
require_relative './utils/swift/writer'
|
7
|
+
require_relative './utils/swift/package'
|
8
|
+
require_relative './utils/swift/swift'
|
9
|
+
require_relative './utils/swift/xcframework'
|
10
|
+
require_relative './utils/openssl/cipher'
|
11
|
+
|
12
|
+
module SecureKeys
|
13
|
+
module Core
|
14
|
+
class Generator
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :cipher, :secrets_source, :secret_keys, :mapped_keys, :xcframework
|
18
|
+
|
19
|
+
public
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
# Configure cipher
|
23
|
+
self.cipher = OpenSSL::Cipher.new
|
24
|
+
self.secrets_source = Globals.secret_keys_source
|
25
|
+
|
26
|
+
# Define the keys that we want to map
|
27
|
+
self.secret_keys = secrets_source.fetch(key: Globals.key_access_identifier)
|
28
|
+
.to_s
|
29
|
+
.split(Globals.key_delimiter)
|
30
|
+
.map(&:strip)
|
31
|
+
|
32
|
+
# Add the keys that we want to map
|
33
|
+
self.mapped_keys = secret_keys.map do |key|
|
34
|
+
encrypted_data = cipher.encrypt(value: secrets_source.fetch(key:))
|
35
|
+
{ name: key.camelize, **encrypted_data }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Configure the XCFramework
|
39
|
+
self.xcframework = Swift::XCFramework.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate
|
43
|
+
if Globals.generate_xcframework?
|
44
|
+
pre_actions
|
45
|
+
generate_swift_package
|
46
|
+
write_keys
|
47
|
+
xcframework.generate
|
48
|
+
end
|
49
|
+
|
50
|
+
xcframework.configure_xcframework_to_xcodeproj
|
51
|
+
post_actions if Globals.generate_xcframework?
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def generate_swift_package
|
57
|
+
package = Swift::Package.new
|
58
|
+
package.generate
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_keys
|
62
|
+
writer = Swift::Writer.new(mapped_keys:,
|
63
|
+
secure_key_bytes: cipher.secure_key_bytes)
|
64
|
+
writer.write
|
65
|
+
end
|
66
|
+
|
67
|
+
def pre_actions
|
68
|
+
# Remove the keys directory
|
69
|
+
system("rm -rf #{Swift::KEYS_DIRECTORY}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def post_actions
|
73
|
+
# Remove the keys directory
|
74
|
+
system("rm -rf #{Swift::SWIFT_PACKAGE_DIRECTORY}")
|
75
|
+
|
76
|
+
# Remove the build directory
|
77
|
+
system("rm -rf #{Swift::KEYS_DIRECTORY}/#{Swift::BUILD_DIRECTORY}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/core/globals/globals.rb
CHANGED
@@ -15,7 +15,7 @@ module SecureKeys
|
|
15
15
|
|
16
16
|
# Check for Jenkins, Travis CI, ... environment variables
|
17
17
|
%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|
|
18
|
-
ENV[current].to_s.
|
18
|
+
ENV[current].to_s.to_boolean
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -28,17 +28,39 @@ module SecureKeys
|
|
28
28
|
# Check if the current instance is verbose
|
29
29
|
# @return [Bool] true if the current instance is verbose
|
30
30
|
def verbose?
|
31
|
-
Core::Console::Argument::Handler.fetch(key: :verbose
|
32
|
-
default: ENV.fetch('VERBOSE', false))
|
31
|
+
Core::Console::Argument::Handler.fetch(key: :verbose)
|
33
32
|
.to_s
|
34
|
-
.
|
35
|
-
|
33
|
+
.to_boolean
|
34
|
+
end
|
35
|
+
|
36
|
+
# Check if the SecureKeys XCFramework should be generated
|
37
|
+
# @return [Bool] true if the SecureKeys XCFramework should be generated
|
38
|
+
def generate_xcframework?
|
39
|
+
Core::Console::Argument::Handler.fetch(key: :generate)
|
40
|
+
.to_s
|
41
|
+
.to_boolean
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check if the SecureKeys XCFramework should be replaced
|
45
|
+
# @return [Bool] true if the SecureKeys XCFramework should be replaced
|
46
|
+
def replace_xcframework?
|
47
|
+
Core::Console::Argument::Handler.fetch(key: %i[xcframework replace])
|
48
|
+
.to_s
|
49
|
+
.to_boolean
|
50
|
+
end
|
51
|
+
|
52
|
+
# Check if the SecureKeys XCFramework should be added
|
53
|
+
# @return [Bool] true if the SecureKeys XCFramework should be added
|
54
|
+
def add_xcframework?
|
55
|
+
Core::Console::Argument::Handler.fetch(key: %i[xcframework add])
|
56
|
+
.to_s
|
57
|
+
.to_boolean
|
36
58
|
end
|
37
59
|
|
38
60
|
# Returns the Xcode project path
|
39
61
|
# @return [String] Xcode project path
|
40
62
|
def xcodeproj_path
|
41
|
-
Core::Console::Argument::Handler.fetch(key:
|
63
|
+
Core::Console::Argument::Handler.fetch(key: %i[xcframework xcodeproj],
|
42
64
|
default: Dir.glob('**/*.xcodeproj').first)
|
43
65
|
end
|
44
66
|
|
@@ -48,6 +70,14 @@ module SecureKeys
|
|
48
70
|
Dir.glob("**/#{Swift::KEYS_DIRECTORY}/#{Swift::XCFRAMEWORK_DIRECTORY}").first
|
49
71
|
end
|
50
72
|
|
73
|
+
# Determine the secret keys source based on the environment
|
74
|
+
# @return [Object] secret keys source
|
75
|
+
def secret_keys_source
|
76
|
+
return SecureKeys::Core::Environment::CI.new if ci?
|
77
|
+
|
78
|
+
SecureKeys::Core::Environment::Keychain.new
|
79
|
+
end
|
80
|
+
|
51
81
|
# Returns the supported iOS platforms
|
52
82
|
# @return [Array] supported iOS platforms
|
53
83
|
def ios_platforms
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative './string/to_bool'
|
2
|
+
require_relative './string/camelize'
|
3
|
+
|
4
|
+
module Kernel
|
5
|
+
include BooleanCasting
|
6
|
+
include Camelize
|
7
|
+
|
8
|
+
String.include(BooleanCasting)
|
9
|
+
String.singleton_class.include(BooleanCasting)
|
10
|
+
|
11
|
+
String.include(Camelize)
|
12
|
+
String.singleton_class.include(Camelize)
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Adds some useful methods to the String class
|
2
|
+
module Camelize
|
3
|
+
# Convert a string to camel case format
|
4
|
+
# @return [String] the camel case formatted string
|
5
|
+
def camelize
|
6
|
+
words = split(/(?<=[a-z])(?=[A-Z])|[-_\s]+/) # Split at lowercase-to-uppercase transitions or explicit separators
|
7
|
+
.map(&:downcase) # Convert everything to lowercase for consistency
|
8
|
+
|
9
|
+
words.map.with_index { |word, index| index.zero? ? word : word.capitalize }.join
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Adds some useful methods to the String class
|
2
|
+
module BooleanCasting
|
3
|
+
# Casts a string to a boolean
|
4
|
+
# @return [Boolean] the boolean value of the string
|
5
|
+
def to_bool
|
6
|
+
return self if [true, false].include?(self)
|
7
|
+
return false if nil? || empty?
|
8
|
+
return false if self =~ /^(false|f|no|n|0)$/i
|
9
|
+
return true if self =~ /^(true|t|yes|y|1)$/i
|
10
|
+
|
11
|
+
# If the string is not a boolean, return false by default
|
12
|
+
false
|
13
|
+
end
|
14
|
+
alias to_b to_bool
|
15
|
+
alias to_boolean to_bool
|
16
|
+
end
|
@@ -30,8 +30,6 @@ module SecureKeys
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
private
|
34
|
-
|
35
33
|
# Generate the formatted keys content using Swift code format
|
36
34
|
# @return [String] The formatted keys content
|
37
35
|
def formatted_keys
|
@@ -44,7 +42,7 @@ module SecureKeys
|
|
44
42
|
/// The decrypted value of the key
|
45
43
|
public var decryptedValue: String {
|
46
44
|
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
|
45
|
+
#{mapped_keys.map { |key| switch_case_key_declaration_template(name: key[:name], value: key[:value], iv: key[:iv], tag: key[:tag]) }.join("\t\t")}
|
48
46
|
case .unknown: fatalError("Unknown key \\(rawValue)")
|
49
47
|
}
|
50
48
|
}
|
@@ -61,25 +59,7 @@ module SecureKeys
|
|
61
59
|
import Foundation
|
62
60
|
import CryptoKit
|
63
61
|
|
64
|
-
|
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: SecureKey) -> 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: SecureKey) -> String { key.decryptedValue }
|
62
|
+
#{key_swift_global_helper_functions}
|
83
63
|
|
84
64
|
// MARK: - SecureKey enum
|
85
65
|
|
@@ -92,50 +72,95 @@ module SecureKeys
|
|
92
72
|
#{content}
|
93
73
|
}
|
94
74
|
|
95
|
-
|
75
|
+
#{key_array_decrypt_swift_extension}
|
96
76
|
|
97
|
-
|
98
|
-
extension Array where Element == UInt8 {
|
77
|
+
#{key_string_swift_extension}
|
99
78
|
|
100
|
-
|
79
|
+
// swiftlint:enable all
|
80
|
+
SWIFT
|
81
|
+
end
|
101
82
|
|
102
|
-
|
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
|
-
}
|
83
|
+
private
|
113
84
|
|
114
|
-
|
85
|
+
# Generate the key global helper functions
|
86
|
+
# @return [String] The key global helper functions
|
87
|
+
def key_swift_global_helper_functions
|
88
|
+
<<~SWIFT
|
89
|
+
// MARK: - Global methods
|
90
|
+
|
91
|
+
/// Fetch the decrypted value of the key
|
92
|
+
///
|
93
|
+
/// - Parameter:
|
94
|
+
/// - key: The key to fetch the decrypted value for
|
95
|
+
///
|
96
|
+
/// - Returns: The decrypted value of the key
|
97
|
+
@available(iOS 13.0, *)
|
98
|
+
public func key(for key: SecureKey) -> String { key.decryptedValue }
|
99
|
+
|
100
|
+
/// Fetch the decrypted value of the key
|
101
|
+
///
|
102
|
+
/// - Parameter:
|
103
|
+
/// - key: The key to fetch the decrypted value for
|
104
|
+
///
|
105
|
+
/// - Returns: The decrypted value of the key
|
106
|
+
@available(iOS 13.0, *)
|
107
|
+
public func key(_ key: SecureKey) -> String { key.decryptedValue }
|
108
|
+
SWIFT
|
109
|
+
end
|
115
110
|
|
116
|
-
|
117
|
-
|
111
|
+
# Generate the key array decrypt extension
|
112
|
+
# @return [String] The key array decrypt extension
|
113
|
+
def key_array_decrypt_swift_extension
|
114
|
+
<<~SWIFT
|
115
|
+
// MARK: - Decrypt keys from array extension
|
116
|
+
|
117
|
+
@available(iOS 13.0, *)
|
118
|
+
extension Array where Element == UInt8 {
|
119
|
+
|
120
|
+
// MARK: - Methods
|
121
|
+
|
122
|
+
func decrypt(key: [UInt8], iv: [UInt8], tag: [UInt8]) -> String {
|
123
|
+
guard let sealedBox = try? AES.GCM.SealedBox(nonce: AES.GCM.Nonce(data: Data(iv)),
|
124
|
+
ciphertext: Data(self),
|
125
|
+
tag: Data(tag)),
|
126
|
+
let decryptedData = try? AES.GCM.open(sealedBox, using: SymmetricKey(data: Data(key))),
|
127
|
+
let decryptedKey = String(data: decryptedData, encoding: .utf8) else {
|
128
|
+
fatalError("Failed to decrypt the key")
|
129
|
+
}
|
130
|
+
return decryptedKey
|
131
|
+
}
|
132
|
+
}
|
133
|
+
SWIFT
|
134
|
+
end
|
135
|
+
|
136
|
+
# Generate the key string extension
|
137
|
+
# @return [String] The key string extension
|
138
|
+
def key_string_swift_extension
|
139
|
+
<<~SWIFT
|
140
|
+
// MARK: - String extension for secure keys
|
118
141
|
|
119
|
-
|
142
|
+
@available(iOS 13.0, *)
|
143
|
+
extension String {
|
120
144
|
|
121
|
-
|
122
|
-
public var secretKey: SecureKey { SecureKey(rawValue: self) ?? .unknown }
|
145
|
+
// MARK: - Methods
|
123
146
|
|
124
|
-
|
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: SecureKey) -> String { key.decryptedValue }
|
131
|
-
}
|
147
|
+
/// Fetch the key from the secure keys enum
|
148
|
+
public var secretKey: SecureKey { SecureKey(rawValue: self) ?? .unknown }
|
132
149
|
|
133
|
-
|
150
|
+
/// Fetch the decrypted value of the key
|
151
|
+
///
|
152
|
+
/// - Parameters:
|
153
|
+
/// - key: The key to fetch the decrypted value for
|
154
|
+
///
|
155
|
+
/// - Returns: The decrypted value of the key
|
156
|
+
public static func key(for key: SecureKey) -> String { key.decryptedValue }
|
157
|
+
}
|
134
158
|
SWIFT
|
135
159
|
end
|
136
160
|
|
137
161
|
# Generate the case key declaration template
|
138
162
|
# @param name [String] The name of the key
|
163
|
+
# @return [String] The case key declaration template
|
139
164
|
def case_key_declaration_template(name:)
|
140
165
|
<<~SWIFT
|
141
166
|
case #{name}
|
@@ -144,6 +169,10 @@ module SecureKeys
|
|
144
169
|
|
145
170
|
# Generate the switch case key declaration template
|
146
171
|
# @param name [String] The name of the key
|
172
|
+
# @param value [String] The value of the key
|
173
|
+
# @param iv [String] The IV of the key
|
174
|
+
# @param tag [String] The tag of the key
|
175
|
+
# @return [String] The switch case key declaration template
|
147
176
|
def switch_case_key_declaration_template(name:, value:, iv:, tag:) # rubocop:disable Naming/MethodParameterName
|
148
177
|
<<~SWIFT
|
149
178
|
case .#{name}: #{value}.decrypt(key: #{secure_key_bytes}, iv: #{iv}, tag: #{tag})
|
@@ -22,7 +22,12 @@ module SecureKeys
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
generate_key_xcframework
|
25
|
-
|
25
|
+
end
|
26
|
+
|
27
|
+
# Configure the XCFramework to the Xcode project
|
28
|
+
def configure_xcframework_to_xcodeproj
|
29
|
+
remove_xcframework_from_xcodeproj_target_if_needed if Globals.replace_xcframework?
|
30
|
+
add_xcframework_to_xcodeproj_target_if_needed if Globals.replace_xcframework? || Globals.add_xcframework?
|
26
31
|
end
|
27
32
|
|
28
33
|
private
|
@@ -85,7 +90,7 @@ module SecureKeys
|
|
85
90
|
# Add the XCFramework to the Xcode project target if needed
|
86
91
|
# @param target_name [String] The target name to add the XCFramework
|
87
92
|
def add_xcframework_to_xcodeproj_target_if_needed(target_name: nil)
|
88
|
-
target_name ||= Core::Console::Argument::Handler.fetch(key:
|
93
|
+
target_name ||= Core::Console::Argument::Handler.fetch(key: %i[xcframework target])
|
89
94
|
return if target_name.to_s.empty?
|
90
95
|
|
91
96
|
Core::Console::Logger.important(message: "Adding the XCFramework to the target '#{target_name}'")
|
@@ -97,6 +102,21 @@ module SecureKeys
|
|
97
102
|
xcodeproj.save
|
98
103
|
Core::Console::Logger.success(message: "The XCFramework was added to the target '#{target_name}'")
|
99
104
|
end
|
105
|
+
|
106
|
+
# Remove the XCFramework from the Xcode project target if needed
|
107
|
+
# @param target_name [String] The target name to remove the XCFramework
|
108
|
+
def remove_xcframework_from_xcodeproj_target_if_needed(target_name: nil)
|
109
|
+
target_name ||= Core::Console::Argument::Handler.fetch(key: %i[xcframework target])
|
110
|
+
return if target_name.to_s.empty?
|
111
|
+
|
112
|
+
Core::Console::Logger.important(message: "Removing the XCFramework from the target '#{target_name}'")
|
113
|
+
xcodeproj = Xcodeproj.xcodeproj
|
114
|
+
xcodeproj_target = Xcodeproj.xcodeproj_target_by_target_name(xcodeproj:, target_name:)
|
115
|
+
Xcodeproj.remove_xcframework(xcodeproj:, xcodeproj_target:, xcframework_path: Xcodeproj.xcframework_relative_path)
|
116
|
+
|
117
|
+
xcodeproj.save
|
118
|
+
Core::Console::Logger.success(message: "The XCFramework was removed from the target '#{target_name}'")
|
119
|
+
end
|
100
120
|
end
|
101
121
|
end
|
102
122
|
end
|
@@ -42,14 +42,27 @@ module SecureKeys
|
|
42
42
|
# Get the Xcodeproj
|
43
43
|
# @return [Xcodeproj] The Xcodeproj
|
44
44
|
def xcodeproj
|
45
|
-
::Xcodeproj::Project.open(
|
45
|
+
::Xcodeproj::Project.open(Globals.xcodeproj_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Remove all references to SecureKeys.xcframework from the Xcodeproj
|
49
|
+
# @param xcodeproj [Xcodeproj::Project] The Xcodeproj to remove the XCFramework
|
50
|
+
# @param xcodeproj_target [Xcodeproj::Project::Object::PBXNativeTarget] The target where the XCFramework is linked
|
51
|
+
# @param xcframework_path [String] The XCFramework path to remove
|
52
|
+
def remove_xcframework(xcodeproj:, xcodeproj_target:, xcframework_path:)
|
53
|
+
xcframework_filename = File.basename(xcframework_path)
|
54
|
+
|
55
|
+
remove_xcframework_from_build_phase(xcodeproj_target:, xcframework_filename:)
|
56
|
+
remove_xcframework_file_references(xcodeproj:, xcframework_filename:)
|
57
|
+
remove_xcframework_from_groups(xcodeproj:, xcframework_filename:)
|
58
|
+
remove_xcframework_from_search_paths(xcodeproj_target:, xcframework_filename:)
|
46
59
|
end
|
47
60
|
|
48
61
|
# Get the XCFramework relative path
|
49
62
|
# @return [Pathname] The XCFramework relative path
|
50
63
|
def xcframework_relative_path
|
51
|
-
Pathname.new(
|
52
|
-
.relative_path_from(Pathname.new(
|
64
|
+
Pathname.new(Globals.secure_keys_xcframework_path)
|
65
|
+
.relative_path_from(Pathname.new(Globals.xcodeproj_path).dirname)
|
53
66
|
end
|
54
67
|
|
55
68
|
# Check if the Xcode project has the secure keys XCFramework
|
@@ -60,10 +73,63 @@ module SecureKeys
|
|
60
73
|
target.frameworks_build_phase.files.any? do |file|
|
61
74
|
return false if file.file_ref.nil?
|
62
75
|
|
63
|
-
file.file_ref.path.include?(
|
76
|
+
file.file_ref.path.include?(Globals.secure_keys_xcframework_path)
|
64
77
|
end
|
65
78
|
end
|
66
79
|
end
|
80
|
+
|
81
|
+
# Remove the XCFramework from the "Link Binary With Libraries" build phase
|
82
|
+
# @param xcodeproj_target [Xcodeproj::Project::Object::PBXNativeTarget] The target where the XCFramework is linked
|
83
|
+
# @param xcframework_filename [String] The XCFramework filename to remove
|
84
|
+
def remove_xcframework_from_build_phase(xcodeproj_target:, xcframework_filename:)
|
85
|
+
build_phase_files = xcodeproj_target.frameworks_build_phase.files.select do |file|
|
86
|
+
file.file_ref&.path&.include?(xcframework_filename)
|
87
|
+
end
|
88
|
+
|
89
|
+
build_phase_files.each do |file|
|
90
|
+
file.remove_from_project
|
91
|
+
Core::Console::Logger.verbose(message: "Removed #{xcframework_filename} from Link Binary With Libraries in target #{xcodeproj_target.name}")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Remove the XCFramework from the file references
|
96
|
+
# @param xcodeproj [Xcodeproj::Project] The Xcodeproj to remove the XCFramework
|
97
|
+
# @param xcframework_filename [String] The XCFramework filename to remove
|
98
|
+
def remove_xcframework_file_references(xcodeproj:, xcframework_filename:)
|
99
|
+
file_references = xcodeproj.files.select { |file| file.path&.include?(xcframework_filename) }
|
100
|
+
file_references.each do |file_ref|
|
101
|
+
file_ref.remove_from_project
|
102
|
+
Core::Console::Logger.verbose(message: "Removed #{xcframework_filename} file reference")
|
103
|
+
end
|
104
|
+
|
105
|
+
# Ensure no orphaned references remain
|
106
|
+
xcodeproj.objects.select { |obj| obj.isa == 'PBXFileReference' && obj.path&.include?(xcframework_filename) }.each(&:remove_from_project)
|
107
|
+
xcodeproj.objects.select { |obj| obj.isa == 'PBXBuildFile' && obj.file_ref&.path&.include?(xcframework_filename) }.each(&:remove_from_project)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Remove the XCFramework from groups (e.g., Frameworks Group)
|
111
|
+
# @param xcodeproj [Xcodeproj::Project] The Xcodeproj to remove the XCFramework
|
112
|
+
# @param xcframework_filename [String] The XCFramework filename to remove
|
113
|
+
def remove_xcframework_from_groups(xcodeproj:, xcframework_filename:)
|
114
|
+
frameworks_group = xcodeproj.frameworks_group
|
115
|
+
group_references = frameworks_group.files.select { |file| file.path&.include?(xcframework_filename) }
|
116
|
+
|
117
|
+
group_references.each do |file_ref|
|
118
|
+
frameworks_group.remove_reference(file_ref)
|
119
|
+
Core::Console::Logger.verbose(message: "Removed #{xcframework_filename} from Frameworks group")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Remove the XCFramework from FRAMEWORK_SEARCH_PATHS
|
124
|
+
# @param xcodeproj_target [Xcodeproj::Project::Object::PBXNativeTarget] The target where the XCFramework is linked
|
125
|
+
# @param xcframework_filename [String] The XCFramework filename to remove
|
126
|
+
def remove_xcframework_from_search_paths(xcodeproj_target:, xcframework_filename:)
|
127
|
+
xcodeproj_target.build_configurations.each do |config|
|
128
|
+
framework_search_paths = config.build_settings['FRAMEWORK_SEARCH_PATHS'] || []
|
129
|
+
new_search_paths = framework_search_paths.reject { |path| path.include?(xcframework_filename) }
|
130
|
+
config.build_settings['FRAMEWORK_SEARCH_PATHS'] = new_search_paths unless framework_search_paths == new_search_paths
|
131
|
+
end
|
132
|
+
end
|
67
133
|
end
|
68
134
|
end
|
69
135
|
end
|
data/lib/keys.rb
CHANGED
@@ -1,84 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require_relative './core/utils/extensions/kernel'
|
4
|
+
require_relative './core/generator'
|
3
5
|
require_relative './core/globals/globals'
|
4
|
-
require_relative './core/
|
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'
|
6
|
+
require_relative './core/console/logger'
|
11
7
|
require_relative './core/console/arguments/parser'
|
8
|
+
require_relative './core/utils/swift/xcframework'
|
12
9
|
|
13
10
|
module SecureKeys
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
attr_accessor :cipher, :secrets_source, :secret_keys, :mapped_keys
|
18
|
-
|
19
|
-
public
|
20
|
-
|
21
|
-
def initialize
|
22
|
-
# Configure the argument parser
|
23
|
-
SecureKeys::Core::Console::Argument::Parser.new
|
24
|
-
|
25
|
-
puts "🔔 You're using a custom delimiter '#{SecureKeys::Globals.key_delimiter}'" unless SecureKeys::Globals.key_delimiter.eql?(SecureKeys::Globals.default_key_delimiter)
|
26
|
-
puts "🔔 You're using a custom key access identifier '#{SecureKeys::Globals.key_access_identifier}'" unless SecureKeys::Globals.key_access_identifier.eql?(SecureKeys::Globals.default_key_access_identifier)
|
27
|
-
|
28
|
-
# Configure cipher
|
29
|
-
self.cipher = SecureKeys::OpenSSL::Cipher.new
|
30
|
-
|
31
|
-
# Configure the secret source based on the environment
|
32
|
-
if SecureKeys::Globals.ci?
|
33
|
-
self.secrets_source = SecureKeys::Core::Environment::CI.new
|
34
|
-
else
|
35
|
-
self.secrets_source = SecureKeys::Core::Environment::Keychain.new
|
36
|
-
end
|
37
|
-
|
38
|
-
# Define the keys that we want to map
|
39
|
-
self.secret_keys = secrets_source.fetch(key: SecureKeys::Globals.key_access_identifier)
|
40
|
-
.to_s
|
41
|
-
.split(SecureKeys::Globals.key_delimiter)
|
42
|
-
.map(&:strip)
|
43
|
-
|
44
|
-
# Add the keys that we want to map
|
45
|
-
self.mapped_keys = secret_keys.map do |key|
|
46
|
-
encrypted_data = cipher.encrypt(value: secrets_source.fetch(key:))
|
47
|
-
# Convert the first key chart to downcase
|
48
|
-
key[0] = key[0].downcase
|
49
|
-
{ name: key, **encrypted_data }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def setup
|
54
|
-
pre_actions
|
55
|
-
|
56
|
-
package = SecureKeys::Swift::Package.new
|
57
|
-
package.generate
|
58
|
-
|
59
|
-
writer = SecureKeys::Swift::Writer.new(mapped_keys: mapped_keys,
|
60
|
-
secure_key_bytes: cipher.secure_key_bytes)
|
61
|
-
writer.write
|
62
|
-
|
63
|
-
xcframework = SecureKeys::Swift::XCFramework.new
|
64
|
-
xcframework.generate
|
65
|
-
|
66
|
-
post_actions
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def pre_actions
|
72
|
-
# Remove the keys directory
|
73
|
-
system("rm -rf #{SecureKeys::Swift::KEYS_DIRECTORY}")
|
74
|
-
end
|
75
|
-
|
76
|
-
def post_actions
|
77
|
-
# Remove the keys directory
|
78
|
-
system("rm -rf #{SecureKeys::Swift::SWIFT_PACKAGE_DIRECTORY}")
|
11
|
+
def self.run
|
12
|
+
# Configure the argument parser
|
13
|
+
Core::Console::Argument::Parser.new
|
79
14
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
15
|
+
# Generate the keys
|
16
|
+
Core::Generator.new.generate
|
83
17
|
end
|
84
18
|
end
|
data/lib/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
module SecureKeys
|
4
|
-
VERSION = '1.1.
|
4
|
+
VERSION = '1.1.4'.freeze
|
5
5
|
SUMMARY = 'Secure Keys is a simple tool for managing your secret keys'.freeze
|
6
6
|
DESCRIPTION = 'Secure Keys is a simple tool to manage your secret keys in your iOS project'.freeze
|
7
7
|
HOMEPAGE_URI = 'https://github.com/derian-cordoba/secure-keys'.freeze
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secure-keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derian Córdoba
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -230,11 +230,17 @@ extra_rdoc_files: []
|
|
230
230
|
files:
|
231
231
|
- "./lib/core/console/arguments/handler.rb"
|
232
232
|
- "./lib/core/console/arguments/parser.rb"
|
233
|
+
- "./lib/core/console/arguments/xcframework/handler.rb"
|
234
|
+
- "./lib/core/console/arguments/xcframework/parser.rb"
|
233
235
|
- "./lib/core/console/logger.rb"
|
234
236
|
- "./lib/core/console/shell.rb"
|
235
237
|
- "./lib/core/environment/ci.rb"
|
236
238
|
- "./lib/core/environment/keychain.rb"
|
239
|
+
- "./lib/core/generator.rb"
|
237
240
|
- "./lib/core/globals/globals.rb"
|
241
|
+
- "./lib/core/utils/extensions/kernel.rb"
|
242
|
+
- "./lib/core/utils/extensions/string/camelize.rb"
|
243
|
+
- "./lib/core/utils/extensions/string/to_bool.rb"
|
238
244
|
- "./lib/core/utils/openssl/cipher.rb"
|
239
245
|
- "./lib/core/utils/swift/package.rb"
|
240
246
|
- "./lib/core/utils/swift/swift.rb"
|