arkana 1.5.0 → 2.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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/arkana/config_parser.rb +2 -0
  3. data/lib/arkana/encoder.rb +0 -1
  4. data/lib/arkana/helpers/kotlin_template_helper.rb +22 -0
  5. data/lib/arkana/helpers/swift_template_helper.rb +7 -7
  6. data/lib/arkana/kotlin_code_generator.rb +56 -0
  7. data/lib/arkana/models/arguments.rb +12 -0
  8. data/lib/arkana/models/config.rb +21 -0
  9. data/lib/arkana/models/template_arguments.rb +4 -0
  10. data/lib/arkana/models/type.rb +10 -6
  11. data/lib/arkana/swift_code_generator.rb +8 -8
  12. data/lib/arkana/templates/kotlin/arkana.kt.erb +59 -0
  13. data/lib/arkana/templates/kotlin/arkana_protocol.kt.erb +13 -0
  14. data/lib/arkana/templates/kotlin/arkana_tests.kt.erb +137 -0
  15. data/lib/arkana/templates/kotlin/build.gradle.kts.erb +18 -0
  16. data/lib/arkana/templates/readme.erb +1 -1
  17. data/lib/arkana/templates/{arkana.swift.erb → swift/arkana.swift.erb} +6 -3
  18. data/lib/arkana/templates/{arkana_protocol.swift.erb → swift/arkana_protocol.swift.erb} +2 -2
  19. data/lib/arkana/templates/{arkana_tests.swift.erb → swift/arkana_tests.swift.erb} +40 -0
  20. data/lib/arkana/templates/{interfaces_readme.erb → swift/interfaces_readme.erb} +1 -1
  21. data/lib/arkana/version.rb +1 -1
  22. data/lib/arkana.rb +15 -6
  23. metadata +17 -12
  24. data/lib/arkana/helpers/enumerable.rb +0 -16
  25. /data/lib/arkana/templates/{arkana.podspec.erb → swift/arkana.podspec.erb} +0 -0
  26. /data/lib/arkana/templates/{interfaces.podspec.erb → swift/interfaces.podspec.erb} +0 -0
  27. /data/lib/arkana/templates/{interfaces_package.swift.erb → swift/interfaces_package.swift.erb} +0 -0
  28. /data/lib/arkana/templates/{package.swift.erb → swift/package.swift.erb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb1bab49c8625e2a2bd1cb8bd378789df20767222714a950028af877a4cfeb81
4
- data.tar.gz: 9978033d03df9ea1c29528d8a506e6f82e43040c5675e81e5a84c2dc692a8b59
3
+ metadata.gz: 191140e1234c08e36b1d1bb3591bac7b77041edd8b7e00565f15480fd47bfe81
4
+ data.tar.gz: 8dd30c6bd576db0cd779b3f645cb9ec15541f5189dd71bd461c2f8895334a6e3
5
5
  SHA512:
6
- metadata.gz: 06d2d9248ba8d07e6faa667861a163599e246d61544168d7eebac39e974adf2af0ab4fdf28af7f3582727c4f304dd7d18f3692f7a5b521305865af4df7439e84
7
- data.tar.gz: 242062bff10a161e4a5734a828bcebed1694d3de700f2160720e17d87f3566c3ea68406e80f5e1c4c18a74294423df415881e0804ff75853f7ecf78eb410485a
6
+ metadata.gz: a79924122cac3f3a32e471f49218ff85227fab2898821e56436a32d6c8e7e6d8cea1af20538e71eb010383ac47cef7266964ccc1a9251ee058538227ae5a9a2d
7
+ data.tar.gz: dc8a20dfe2d1650cc14e1d3e8d24733229a795f8b6471272ff8d67cdaf72fd453925ea50d35d86386dfb1419c05fbf8910b8a7dbacbce4d80febed50883465cc
@@ -12,7 +12,9 @@ module ConfigParser
12
12
  def self.parse(arguments)
13
13
  yaml = YAML.load_file(arguments.config_filepath)
14
14
  config = Config.new(yaml)
15
+ config.include_environments(arguments.include_environments)
15
16
  config.current_flavor = arguments.flavor
17
+ config.current_lang = arguments.lang
16
18
  config.dotenv_filepath = arguments.dotenv_filepath
17
19
  UI.warn("Dotenv file was specified but couldn't be found at '#{config.dotenv_filepath}'") if config.dotenv_filepath && !File.exist?(config.dotenv_filepath)
18
20
  config
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "arkana/helpers/string"
4
- require "arkana/helpers/enumerable"
5
4
 
6
5
  # The encoder is responsible for finding the env vars for given keys, encoding them, and creating Secrets based on the generated data.
7
6
  module Encoder
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Utilities to reduce the amount of boilerplate code in `.kt.erb` template files.
4
+ module KotlinTemplateHelper
5
+ def self.kotlin_type(type)
6
+ case type
7
+ when :string then "String"
8
+ when :boolean then "Boolean"
9
+ when :integer then "Int"
10
+ else raise "Unknown variable type '#{type}' received."
11
+ end
12
+ end
13
+
14
+ def self.kotlin_decode_function(type)
15
+ case type
16
+ when :string then "decode"
17
+ when :boolean then "decodeBoolean"
18
+ when :integer then "decodeInt"
19
+ else raise "Unknown variable type '#{type}' received."
20
+ end
21
+ end
22
+ end
@@ -4,18 +4,18 @@
4
4
  module SwiftTemplateHelper
5
5
  def self.swift_type(type)
6
6
  case type
7
- when :string then "String"
8
- when :boolean then "Bool"
9
- when :integer then "Int"
10
- else raise "Unknown variable type '#{type}' received.'"
7
+ when :string then "String"
8
+ when :boolean then "Bool"
9
+ when :integer then "Int"
10
+ else raise "Unknown variable type '#{type}' received.'"
11
11
  end
12
12
  end
13
13
 
14
14
  def self.protocol_getter(declaration_strategy)
15
15
  case declaration_strategy
16
- when "lazy var" then "mutating get"
17
- when "var", "let" then "get"
18
- else raise "Unknown declaration strategy '#{declaration_strategy}' received.'"
16
+ when "lazy var" then "mutating get"
17
+ when "var", "let" then "get"
18
+ else raise "Unknown declaration strategy '#{declaration_strategy}' received.'"
19
19
  end
20
20
  end
21
21
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "fileutils"
5
+ require_relative "helpers/string"
6
+
7
+ # Responsible for generating Kotlin source and test files.
8
+ module KotlinCodeGenerator
9
+ # Generates Kotlin code and test files for the given template arguments.
10
+ def self.generate(template_arguments:, config:)
11
+ kotlin_module_dir = config.result_path
12
+ kotlin_sources_dir = File.join(kotlin_module_dir, "src", "main", config.kotlin_sources_path, config.kotlin_package_name.split("."))
13
+ kotlin_tests_dir = File.join(kotlin_module_dir, "src", "test", config.kotlin_sources_path, config.kotlin_package_name.split("."))
14
+
15
+ if config.should_generate_gradle_build_file
16
+ set_up_kotlin_module(kotlin_module_dir, template_arguments)
17
+ end
18
+
19
+ set_up_kotlin_interfaces(kotlin_sources_dir, template_arguments, config)
20
+ set_up_kotlin_classes(kotlin_sources_dir, kotlin_tests_dir, template_arguments, config)
21
+ end
22
+
23
+ def self.set_up_kotlin_module(path, template_arguments)
24
+ dirname = File.dirname(__FILE__)
25
+ sources_dir = path
26
+ readme_template = File.read("#{dirname}/templates/readme.erb")
27
+ source_template = File.read("#{dirname}/templates/kotlin/build.gradle.kts.erb")
28
+ FileUtils.mkdir_p(path)
29
+ render(readme_template, template_arguments, File.join(path, "README.md"))
30
+ render(source_template, template_arguments, File.join(sources_dir, "build.gradle.kts"))
31
+ end
32
+
33
+ def self.set_up_kotlin_interfaces(path, template_arguments, config)
34
+ dirname = File.dirname(__FILE__)
35
+ sources_dir = path
36
+ source_template = File.read("#{dirname}/templates/kotlin/arkana_protocol.kt.erb")
37
+ FileUtils.mkdir_p(path)
38
+ render(source_template, template_arguments, File.join(sources_dir, "#{config.namespace}Environment.kt"))
39
+ end
40
+
41
+ def self.set_up_kotlin_classes(sources_dir, tests_dir, template_arguments, config)
42
+ dirname = File.dirname(__FILE__)
43
+ source_template = File.read("#{dirname}/templates/kotlin/arkana.kt.erb")
44
+ tests_template = File.read("#{dirname}/templates/kotlin/arkana_tests.kt.erb")
45
+ FileUtils.mkdir_p(sources_dir)
46
+ FileUtils.mkdir_p(tests_dir) if config.should_generate_unit_tests
47
+ render(source_template, template_arguments, File.join(sources_dir, "#{config.namespace}.kt"))
48
+ render(tests_template, template_arguments, File.join(tests_dir, "#{config.namespace}Test.kt")) if config.should_generate_unit_tests
49
+ end
50
+
51
+ def self.render(template, template_arguments, destination_file)
52
+ renderer = ERB.new(template, trim_mode: ">") # Don't automatically add newlines at the end of each template tag
53
+ result = renderer.result(template_arguments.get_binding)
54
+ File.write(destination_file, result)
55
+ end
56
+ end
@@ -10,12 +10,18 @@ class Arguments
10
10
  attr_reader :dotenv_filepath
11
11
  # @returns [string]
12
12
  attr_reader :flavor
13
+ # @returns [Array<string>]
14
+ attr_reader :include_environments
15
+ # @returns [string]
16
+ attr_reader :lang
13
17
 
14
18
  def initialize
15
19
  # Default values
16
20
  @config_filepath = ".arkana.yml"
17
21
  @dotenv_filepath = ".env" if File.exist?(".env")
18
22
  @flavor = nil
23
+ @include_environments = nil
24
+ @lang = "swift"
19
25
 
20
26
  OptionParser.new do |opt|
21
27
  opt.on("-c", "--config-filepath /path/to/your/.arkana.yml", "Path to your config file. Defaults to '.arkana.yml'") do |o|
@@ -27,6 +33,12 @@ class Arguments
27
33
  opt.on("-f", "--flavor FrostedFlakes", "Flavors are useful, for instance, when generating secrets for white-label projects. See the README for more information") do |o|
28
34
  @flavor = o
29
35
  end
36
+ opt.on("-i", "--include-environments debug,release", "Optionally pass the environments that you want Arkana to generate secrets for. Useful if you only want to build a certain environment, e.g. just Debug in local machines, while only building Staging and Release in CI. Separate the keys using a comma, without spaces. When omitted, Arkana generate secrets for all environments.") do |o|
37
+ @include_environments = o.split(",")
38
+ end
39
+ opt.on("-l", "--lang kotlin", "Language to produce keys for, e.g. kotlin, swift. Defaults to 'swift'. See the README for more information") do |o|
40
+ @lang = o
41
+ end
30
42
  end.parse!
31
43
  end
32
44
  end
@@ -16,6 +16,10 @@ class Config
16
16
  attr_reader :pod_name
17
17
  # @returns [string]
18
18
  attr_reader :result_path
19
+ # @returns [string]
20
+ attr_reader :kotlin_package_name
21
+ # @returns [string]
22
+ attr_reader :kotlin_sources_path
19
23
  # @returns [string[]]
20
24
  attr_reader :flavors
21
25
  # @returns [string]
@@ -26,11 +30,17 @@ class Config
26
30
  attr_reader :package_manager
27
31
  # @returns [boolean]
28
32
  attr_reader :should_cocoapods_cross_import_modules
33
+ # @returns [boolean]
34
+ attr_reader :should_generate_gradle_build_file
35
+ # @returns [int]
36
+ attr_reader :kotlin_jvm_toolchain_version
29
37
 
30
38
  # @returns [string]
31
39
  attr_accessor :current_flavor
32
40
  # @returns [string]
33
41
  attr_accessor :dotenv_filepath
42
+ # @returns [string]
43
+ attr_accessor :current_lang
34
44
 
35
45
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
36
46
  def initialize(yaml)
@@ -42,6 +52,8 @@ class Config
42
52
  @import_name = yaml["import_name"] || default_name
43
53
  @pod_name = yaml["pod_name"] || default_name
44
54
  @result_path = yaml["result_path"] || default_name
55
+ @kotlin_package_name = yaml["kotlin_package_name"] || "com.arkanakeys"
56
+ @kotlin_sources_path = yaml["kotlin_sources_path"] || "kotlin"
45
57
  @flavors = yaml["flavors"] || []
46
58
  @swift_declaration_strategy = yaml["swift_declaration_strategy"] || "let"
47
59
  @should_generate_unit_tests = yaml["should_generate_unit_tests"]
@@ -49,6 +61,9 @@ class Config
49
61
  @package_manager = yaml["package_manager"] || "spm"
50
62
  @should_cocoapods_cross_import_modules = yaml["should_cocoapods_cross_import_modules"]
51
63
  @should_cocoapods_cross_import_modules = true if @should_cocoapods_cross_import_modules.nil?
64
+ @should_generate_gradle_build_file = yaml["should_generate_gradle_build_file"]
65
+ @should_generate_gradle_build_file = true if @should_generate_gradle_build_file.nil?
66
+ @kotlin_jvm_toolchain_version = yaml["kotlin_jvm_toolchain_version"] || 11
52
67
  end
53
68
  # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
54
69
 
@@ -63,4 +78,10 @@ class Config
63
78
  def all_keys
64
79
  global_secrets + environment_keys
65
80
  end
81
+
82
+ def include_environments(environments)
83
+ return unless environments
84
+
85
+ @environments = @environments.select { |e| environments.map(&:downcase).include?(e.downcase) }
86
+ end
66
87
  end
@@ -20,6 +20,10 @@ class TemplateArguments
20
20
  @pod_name = config.pod_name
21
21
  # The top level namespace in which the keys will be generated. Often an enum.
22
22
  @namespace = config.namespace
23
+ # Name of the kotlin package to be used for the generated code.
24
+ @kotlin_package_name = config.kotlin_package_name
25
+ # The kotlin JVM toolchain JDK version to be used in the generated build.gradle file.
26
+ @kotlin_jvm_toolchain_version = config.kotlin_jvm_toolchain_version
23
27
  # The property declaration strategy declared in the config file.
24
28
  @swift_declaration_strategy = config.swift_declaration_strategy
25
29
  # Whether unit tests should be generated.
@@ -8,12 +8,16 @@ module Type
8
8
 
9
9
  def self.new(string_value:)
10
10
  case string_value
11
- when "true", "false"
12
- BOOLEAN
13
- when /^\d+$/
14
- INTEGER
15
- else
16
- STRING
11
+ when "true", "false"
12
+ BOOLEAN
13
+ when /^\d+$/
14
+ # Handles cases like "0001" which should be interpreted as strings
15
+ return STRING if string_value.to_i.to_s != string_value
16
+ # Handle int overflow
17
+ return STRING if string_value.to_i > (2**31) - 1
18
+ INTEGER
19
+ else
20
+ STRING
17
21
  end
18
22
  end
19
23
  end
@@ -17,11 +17,11 @@ module SwiftCodeGenerator
17
17
 
18
18
  def self.set_up_interfaces_swift_package(path, template_arguments, config)
19
19
  dirname = File.dirname(__FILE__)
20
- readme_template = File.read("#{dirname}/templates/interfaces_readme.erb")
21
- package_template = File.read("#{dirname}/templates/interfaces_package.swift.erb")
22
- podspec_template = File.read("#{dirname}/templates/interfaces.podspec.erb")
20
+ readme_template = File.read("#{dirname}/templates/swift/interfaces_readme.erb")
21
+ package_template = File.read("#{dirname}/templates/swift/interfaces_package.swift.erb")
22
+ podspec_template = File.read("#{dirname}/templates/swift/interfaces.podspec.erb")
23
23
  sources_dir = File.join(path, "Sources")
24
- source_template = File.read("#{dirname}/templates/arkana_protocol.swift.erb")
24
+ source_template = File.read("#{dirname}/templates/swift/arkana_protocol.swift.erb")
25
25
  FileUtils.mkdir_p(path)
26
26
  FileUtils.mkdir_p(sources_dir)
27
27
  render(podspec_template, template_arguments, File.join(path, "#{config.pod_name.capitalize_first_letter}Interfaces.podspec")) if config.package_manager == "cocoapods"
@@ -33,12 +33,12 @@ module SwiftCodeGenerator
33
33
  def self.set_up_swift_package(path, template_arguments, config)
34
34
  dirname = File.dirname(__FILE__)
35
35
  readme_template = File.read("#{dirname}/templates/readme.erb")
36
- package_template = File.read("#{dirname}/templates/package.swift.erb")
36
+ package_template = File.read("#{dirname}/templates/swift/package.swift.erb")
37
37
  sources_dir = File.join(path, "Sources")
38
- source_template = File.read("#{dirname}/templates/arkana.swift.erb")
38
+ source_template = File.read("#{dirname}/templates/swift/arkana.swift.erb")
39
39
  tests_dir = File.join(path, "Tests") if config.should_generate_unit_tests
40
- tests_template = File.read("#{dirname}/templates/arkana_tests.swift.erb")
41
- podspec_template = File.read("#{dirname}/templates/arkana.podspec.erb")
40
+ tests_template = File.read("#{dirname}/templates/swift/arkana_tests.swift.erb")
41
+ podspec_template = File.read("#{dirname}/templates/swift/arkana.podspec.erb")
42
42
  FileUtils.mkdir_p(path)
43
43
  FileUtils.mkdir_p(sources_dir)
44
44
  FileUtils.mkdir_p(tests_dir) if config.should_generate_unit_tests
@@ -0,0 +1,59 @@
1
+ <% require "arkana/helpers/string" %>
2
+ <% require "arkana/helpers/kotlin_template_helper" %>
3
+ <% # TODO: Sort these import statements alphabetically %>
4
+ // DO NOT MODIFY
5
+ // Automatically generated by Arkana (https://github.com/rogerluan/arkana)
6
+ package <%= @kotlin_package_name %>
7
+
8
+
9
+ object <%= @namespace %> {
10
+ private val salt = listOf(<%= @salt.formatted %>)
11
+
12
+ internal fun decode(encoded: List<Int>, cipher: List<Int>): String {
13
+ val decoded = encoded.mapIndexed { index, item ->
14
+ (item xor cipher[(index % cipher.size)]).toByte()
15
+ }.toByteArray()
16
+ return decoded.toString(Charsets.UTF_8)
17
+ }
18
+
19
+ internal fun decodeInt(encoded: List<Int>, cipher: List<Int>): Int {
20
+ return decode(encoded = encoded, cipher = cipher).toInt()
21
+ }
22
+
23
+ internal fun decodeBoolean(encoded: List<Int>, cipher: List<Int>): Boolean {
24
+ return decode(encoded = encoded, cipher = cipher).toBoolean()
25
+ }
26
+
27
+ object Global {
28
+ <% @global_secrets.each_with_index do |secret, index| %>
29
+ val <%= secret.key.camel_case %>: <%= KotlinTemplateHelper.kotlin_type(secret.type) %>
30
+
31
+ get() {
32
+ val encoded = listOf(<%= secret.encoded_value %>)
33
+ return <%= KotlinTemplateHelper.kotlin_decode_function(secret.type) %>(encoded = encoded, cipher = salt)
34
+ }
35
+ <% unless index == @global_secrets.length - 1 %>
36
+
37
+ <% end %>
38
+ <% end %>
39
+ }
40
+
41
+ <% @environments.each_with_index do |environment, env_index| %>
42
+ object <%= environment %> : <%= @namespace %>Environment {
43
+ <% environment_protocol_secrets(environment).each_with_index do |secret, secret_index| %>
44
+ override val <%= secret.protocol_key.camel_case %>: <%= KotlinTemplateHelper.kotlin_type(secret.type) %>
45
+
46
+ get() {
47
+ val encoded = listOf(<%= secret.encoded_value %>)
48
+ return <%= KotlinTemplateHelper.kotlin_decode_function(secret.type) %>(encoded = encoded, cipher = salt)
49
+ }
50
+ <% unless secret_index == environment_protocol_secrets(environment).length - 1 %>
51
+
52
+ <% end %>
53
+ <% end %>
54
+ }
55
+ <% unless env_index == @environments.length - 1 %>
56
+
57
+ <% end %>
58
+ <% end %>
59
+ }
@@ -0,0 +1,13 @@
1
+ <% require "arkana/helpers/string" %>
2
+ <% require "arkana/helpers/kotlin_template_helper" %>
3
+ // DO NOT MODIFY
4
+ // Automatically generated by Arkana (https://github.com/rogerluan/arkana)
5
+ package <%= @kotlin_package_name %>
6
+
7
+
8
+ interface <%= @namespace %>Environment {
9
+ <% for secret in @environment_secrets.uniq(&:protocol_key) %>
10
+ val <%= secret.protocol_key.camel_case %>: <%= KotlinTemplateHelper.kotlin_type(secret.type) %>
11
+
12
+ <% end %>
13
+ }
@@ -0,0 +1,137 @@
1
+ <% require "arkana/helpers/string" %>
2
+ <% require "arkana/helpers/kotlin_template_helper" %>
3
+ // DO NOT MODIFY
4
+ // Automatically generated by Arkana (https://github.com/rogerluan/arkana)
5
+ package <%= @kotlin_package_name %>
6
+
7
+
8
+ import kotlin.test.Test
9
+ import kotlin.test.assertEquals
10
+ import kotlin.test.assertFalse
11
+ import kotlin.test.assertNotEquals
12
+ import kotlin.test.assertTrue
13
+
14
+ internal class <%= @namespace %>Test {
15
+ private val salt = listOf(<%= @salt.formatted %>)
16
+ private val globalSecrets = <%= @namespace %>.Global
17
+
18
+ @Test
19
+ fun test_decodeRandomHexKey_shouldDecode() {
20
+ <% hex_key = SecureRandom.hex(64) %>
21
+ <% secret = generate_test_secret(key: hex_key) %>
22
+ val encoded = listOf(<%= secret.encoded_value %>)
23
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "<%= hex_key %>")
24
+ }
25
+
26
+ @Test
27
+ fun test_decodeRandomBase64Key_shouldDecode() {
28
+ <% base64_key = SecureRandom.base64(64) %>
29
+ <% secret = generate_test_secret(key: base64_key) %>
30
+ val encoded = listOf(<%= secret.encoded_value %>)
31
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "<%= base64_key %>")
32
+ }
33
+
34
+ @Test
35
+ fun test_decodeUUIDKey_shouldDecode() {
36
+ <% uuid_key = SecureRandom.uuid %>
37
+ <% secret = generate_test_secret(key: uuid_key) %>
38
+ val encoded = listOf(<%= secret.encoded_value %>)
39
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "<%= uuid_key %>")
40
+ }
41
+
42
+ @Test
43
+ fun test_decodeTrueBoolValue_shouldDecode() {
44
+ <% bool_key = "true" %>
45
+ <% secret = generate_test_secret(key: bool_key) %>
46
+ val encoded = listOf(<%= secret.encoded_value %>)
47
+ assertTrue(<%= @namespace %>.decodeBoolean(encoded = encoded, cipher = salt))
48
+ }
49
+
50
+ @Test
51
+ fun test_decodeFalseBoolValue_shouldDecode() {
52
+ <% bool_key = "false" %>
53
+ <% secret = generate_test_secret(key: bool_key) %>
54
+ val encoded = listOf(<%= secret.encoded_value %>)
55
+ assertFalse(<%= @namespace %>.decodeBoolean(encoded = encoded, cipher = salt))
56
+ }
57
+
58
+ @Test
59
+ fun test_decodeIntValue_shouldDecode() {
60
+ <% int_key = "42" %>
61
+ <% secret = generate_test_secret(key: int_key) %>
62
+ val encoded = listOf(<%= secret.encoded_value %>)
63
+ assertEquals(<%= @namespace %>.decodeInt(encoded = encoded, cipher = salt), 42)
64
+ }
65
+
66
+ @Test
67
+ fun test_decodeIntValueWithLeadingZeroes_shouldDecodeAsString() {
68
+ <% int_with_leading_zeroes_key = "0001" %>
69
+ <% secret = generate_test_secret(key: int_with_leading_zeroes_key) %>
70
+ val encoded = listOf(<%= secret.encoded_value %>)
71
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "0001")
72
+ }
73
+
74
+ @Test
75
+ fun test_decodeMassiveIntValue_shouldDecodeAsString() {
76
+ <% int_with_massive_number_key = "92233720368547758079223372036854775807" %>
77
+ <% secret = generate_test_secret(key: int_with_massive_number_key) %>
78
+ val encoded = listOf(<%= secret.encoded_value %>)
79
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "92233720368547758079223372036854775807")
80
+ }
81
+
82
+ @Test
83
+ fun test_decodeNegativeIntValue_shouldDecodeAsString() {
84
+ <% negative_int_key = "-42" %>
85
+ <% secret = generate_test_secret(key: negative_int_key) %>
86
+ val encoded = listOf(<%= secret.encoded_value %>)
87
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "-42")
88
+ }
89
+
90
+ @Test
91
+ fun test_decodeFloatingPointValue_shouldDecodeAsString() {
92
+ <% float_key = "3.14" %>
93
+ <% secret = generate_test_secret(key: float_key) %>
94
+ val encoded = listOf(<%= secret.encoded_value %>)
95
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "3.14")
96
+ }
97
+
98
+ @Test
99
+ fun test_encodeAndDecodeValueWithDollarSign_shouldDecode() {
100
+ <% dollar_sign_key = "real_$lim_shady" %>
101
+ <% secret = generate_test_secret(key: dollar_sign_key) %>
102
+ val encoded = listOf(<%= secret.encoded_value %>)
103
+ assertEquals(<%= @namespace %>.decode(encoded = encoded, cipher = salt), "real_\$lim_shady")
104
+ }
105
+ <% if ENV["ARKANA_RUNNING_CI_INTEGRATION_TESTS"] %>
106
+
107
+ @Test
108
+ fun test_decodeEnvVarFromDotfile_withDollarSign__andEscaped_andNoQuotes_shouldDecode() {
109
+ assertEquals(globalSecrets.secretWithDollarSignEscapedAndAndNoQuotesKey, "real_\$lim_shady")
110
+ }
111
+
112
+ @Test
113
+ fun test_decodeEnvVarFromDotfile_withDollarSign__andEscaped_andDoubleQuotes_shouldDecode() {
114
+ assertEquals(globalSecrets.secretWithDollarSignEscapedAndDoubleQuoteKey, "real_\$lim_shady")
115
+ }
116
+
117
+ @Test
118
+ fun test_decodeEnvVarFromDotfile_withDollarSign__andNotEscaped_andSingleQuotes_shouldDecode() {
119
+ assertEquals(globalSecrets.secretWithDollarSignNotEscapedAndSingleQuoteKey, "real_\$lim_shady")
120
+ }
121
+
122
+ @Test
123
+ fun test_decodeEnvVarFromDotfile_withDollarSign__andNotEscaped_andDoubleQuotes_shouldDecodeWithUnexpectedValue() {
124
+ assertNotEquals(globalSecrets.secretWithDollarSignNotEscapedAndDoubleQuotesKey, "real_\$lim_shady")
125
+ }
126
+
127
+ @Test
128
+ fun test_decodeEnvVarFromDotfile_withDollarSign__andNotEscaped_andNoQuotes_shouldDecodeWithUnexpectedValue() {
129
+ assertNotEquals(globalSecrets.secretWithDollarSignNotEscapedAndNoQuotesKey, "real_\$lim_shady")
130
+ }
131
+
132
+ @Test
133
+ fun test_decodeEnvVarFromDotfile_withWeirdCharacters_shouldDecode() {
134
+ assertEquals(globalSecrets.secretWithWeirdCharactersKey, "` ~ ! @ # % ^ & * ( ) _ - + = { [ } } | : ; ' < , > . ? /")
135
+ }
136
+ <% end %>
137
+ }
@@ -0,0 +1,18 @@
1
+ // DO NOT MODIFY
2
+ // Automatically generated by Arkana (https://github.com/rogerluan/arkana)
3
+
4
+ plugins {
5
+ id("kotlin")
6
+ }
7
+
8
+ kotlin {
9
+ jvmToolchain(<%= @kotlin_jvm_toolchain_version %>)
10
+ }
11
+
12
+ tasks.test {
13
+ useJUnitPlatform()
14
+ }
15
+
16
+ dependencies {
17
+ testImplementation(kotlin("test"))
18
+ }
@@ -1,4 +1,4 @@
1
1
  # <%= @namespace %>
2
2
 
3
3
 
4
- This Package is autogenerated by [Arkana](https://github.com/rogerluan/arkana). Do not attempt to modify it manually, otherwise your changes will be overriden on the next code generation process. Please visit [Arkana](https://github.com/rogerluan/arkana) to read more.
4
+ This Package is autogenerated by [Arkana](https://github.com/rogerluan/arkana). Do not attempt to modify it manually, otherwise your changes will be overridden on the next code generation process. Please visit [Arkana](https://github.com/rogerluan/arkana) to read more.
@@ -1,5 +1,5 @@
1
- <% require 'arkana/helpers/string' %>
2
- <% require 'arkana/helpers/swift_template_helper' %>
1
+ <% require "arkana/helpers/string" %>
2
+ <% require "arkana/helpers/swift_template_helper" %>
3
3
  <% # TODO: Sort these import statements alphabetically %>
4
4
  // DO NOT MODIFY
5
5
  // Automatically generated by Arkana (https://github.com/rogerluan/arkana)
@@ -55,7 +55,7 @@ public extension <%= @namespace %> {
55
55
  }
56
56
  }
57
57
 
58
- <% for environment in @environments %>
58
+ <% @environments.each_with_index do |environment, env_index| %>
59
59
  public extension <%= @namespace %> {
60
60
  struct <%= environment %>: <%= @namespace %>EnvironmentProtocol {
61
61
  public init() {}
@@ -72,4 +72,7 @@ public extension <%= @namespace %> {
72
72
  <% end %>
73
73
  }
74
74
  }
75
+ <% unless env_index == @environments.length - 1 %>
76
+
77
+ <% end %>
75
78
  <% end %>
@@ -1,5 +1,5 @@
1
- <% require 'arkana/helpers/string' %>
2
- <% require 'arkana/helpers/swift_template_helper' %>
1
+ <% require "arkana/helpers/string" %>
2
+ <% require "arkana/helpers/swift_template_helper" %>
3
3
  // DO NOT MODIFY
4
4
  // Automatically generated by Arkana (https://github.com/rogerluan/arkana)
5
5
 
@@ -86,6 +86,46 @@ final class <%= @namespace %>Tests: XCTestCase {
86
86
  XCTAssertEqual(<%= @namespace %>.decode(encoded: encoded, cipher: salt), 42)
87
87
  }
88
88
 
89
+ func test_decodeIntValueWithLeadingZeroes_shouldDecodeAsString() {
90
+ <% int_with_leading_zeroes_key = "0001" %>
91
+ <% secret = generate_test_secret(key: int_with_leading_zeroes_key) %>
92
+ let encoded: [UInt8] = [
93
+ <%= secret.encoded_value %>
94
+
95
+ ]
96
+ XCTAssertEqual(<%= @namespace %>.decode(encoded: encoded, cipher: salt), "0001")
97
+ }
98
+
99
+ func test_decodeMassiveIntValue_shouldDecodeAsString() {
100
+ <% int_with_massive_number_key = "92233720368547758079223372036854775807" %>
101
+ <% secret = generate_test_secret(key: int_with_massive_number_key) %>
102
+ let encoded: [UInt8] = [
103
+ <%= secret.encoded_value %>
104
+
105
+ ]
106
+ XCTAssertEqual(<%= @namespace %>.decode(encoded: encoded, cipher: salt), "92233720368547758079223372036854775807")
107
+ }
108
+
109
+ func test_decodeNegativeIntValue_shouldDecodeAsString() {
110
+ <% negative_int_key = "-42" %>
111
+ <% secret = generate_test_secret(key: negative_int_key) %>
112
+ let encoded: [UInt8] = [
113
+ <%= secret.encoded_value %>
114
+
115
+ ]
116
+ XCTAssertEqual(<%= @namespace %>.decode(encoded: encoded, cipher: salt), "-42")
117
+ }
118
+
119
+ func test_decodeFloatingPointValue_shouldDecodeAsString() {
120
+ <% float_key = "3.14" %>
121
+ <% secret = generate_test_secret(key: float_key) %>
122
+ let encoded: [UInt8] = [
123
+ <%= secret.encoded_value %>
124
+
125
+ ]
126
+ XCTAssertEqual(<%= @namespace %>.decode(encoded: encoded, cipher: salt), "3.14")
127
+ }
128
+
89
129
  func test_encodeAndDecodeValueWithDollarSign_shouldDecode() {
90
130
  <% dollar_sign_key = "real_$lim_shady" %>
91
131
  <% secret = generate_test_secret(key: dollar_sign_key) %>
@@ -1,3 +1,3 @@
1
1
  # <%= @namespace %>Interfaces
2
2
 
3
- This Package was autogenerated by [Arkana](https://github.com/rogerluan/arkana). Do not attempt to modify it manually, otherwise your changes will be overriden in the next code generation process. Please visit [Arkana](https://github.com/rogerluan/arkana) to read more.
3
+ This Package was autogenerated by [Arkana](https://github.com/rogerluan/arkana). Do not attempt to modify it manually, otherwise your changes will be overridden in the next code generation process. Please visit [Arkana](https://github.com/rogerluan/arkana) to read more.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arkana
4
- VERSION = "1.5.0"
4
+ VERSION = "2.0.0"
5
5
  end
data/lib/arkana.rb CHANGED
@@ -3,9 +3,11 @@
3
3
  require_relative "arkana/config_parser"
4
4
  require_relative "arkana/encoder"
5
5
  require_relative "arkana/helpers/dotenv_helper"
6
+ require_relative "arkana/helpers/ui"
6
7
  require_relative "arkana/models/template_arguments"
7
8
  require_relative "arkana/salt_generator"
8
9
  require_relative "arkana/swift_code_generator"
10
+ require_relative "arkana/kotlin_code_generator"
9
11
  require_relative "arkana/version"
10
12
 
11
13
  # Top-level namespace for Arkana's execution entry point. When ran from CLI, `Arkana.run` is what is invoked.
@@ -30,11 +32,11 @@ module Arkana
30
32
  )
31
33
  rescue StandardError => e
32
34
  # TODO: Improve this by creating an Env/Debug helper
33
- puts("Something went wrong when parsing and encoding your secrets.")
34
- puts("Current Flavor: #{config.current_flavor}")
35
- puts("Dotenv Filepath: #{config.dotenv_filepath}")
36
- puts("Config Filepath: #{arguments.config_filepath}")
37
- raise e
35
+ UI.warn("Something went wrong when parsing and encoding your secrets.")
36
+ UI.warn("Current Flavor: #{config.current_flavor}")
37
+ UI.warn("Dotenv Filepath: #{config.dotenv_filepath}")
38
+ UI.warn("Config Filepath: #{arguments.config_filepath}")
39
+ UI.crash(e.message)
38
40
  end
39
41
  template_arguments = TemplateArguments.new(
40
42
  environment_secrets: environment_secrets,
@@ -42,7 +44,14 @@ module Arkana
42
44
  config: config,
43
45
  salt: salt,
44
46
  )
45
- SwiftCodeGenerator.generate(
47
+
48
+ generator = case config.current_lang.downcase
49
+ when "swift" then SwiftCodeGenerator
50
+ when "kotlin" then KotlinCodeGenerator
51
+ else UI.crash("Unknown output lang selected: #{config.current_lang}")
52
+ end
53
+
54
+ generator.method(:generate).call(
46
55
  template_arguments: template_arguments,
47
56
  config: config,
48
57
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arkana
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Oba
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-29 00:00:00.000000000 Z
11
+ date: 2023-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -67,10 +67,11 @@ files:
67
67
  - lib/arkana/config_parser.rb
68
68
  - lib/arkana/encoder.rb
69
69
  - lib/arkana/helpers/dotenv_helper.rb
70
- - lib/arkana/helpers/enumerable.rb
70
+ - lib/arkana/helpers/kotlin_template_helper.rb
71
71
  - lib/arkana/helpers/string.rb
72
72
  - lib/arkana/helpers/swift_template_helper.rb
73
73
  - lib/arkana/helpers/ui.rb
74
+ - lib/arkana/kotlin_code_generator.rb
74
75
  - lib/arkana/models/arguments.rb
75
76
  - lib/arkana/models/config.rb
76
77
  - lib/arkana/models/salt.rb
@@ -79,15 +80,19 @@ files:
79
80
  - lib/arkana/models/type.rb
80
81
  - lib/arkana/salt_generator.rb
81
82
  - lib/arkana/swift_code_generator.rb
82
- - lib/arkana/templates/arkana.podspec.erb
83
- - lib/arkana/templates/arkana.swift.erb
84
- - lib/arkana/templates/arkana_protocol.swift.erb
85
- - lib/arkana/templates/arkana_tests.swift.erb
86
- - lib/arkana/templates/interfaces.podspec.erb
87
- - lib/arkana/templates/interfaces_package.swift.erb
88
- - lib/arkana/templates/interfaces_readme.erb
89
- - lib/arkana/templates/package.swift.erb
83
+ - lib/arkana/templates/kotlin/arkana.kt.erb
84
+ - lib/arkana/templates/kotlin/arkana_protocol.kt.erb
85
+ - lib/arkana/templates/kotlin/arkana_tests.kt.erb
86
+ - lib/arkana/templates/kotlin/build.gradle.kts.erb
90
87
  - lib/arkana/templates/readme.erb
88
+ - lib/arkana/templates/swift/arkana.podspec.erb
89
+ - lib/arkana/templates/swift/arkana.swift.erb
90
+ - lib/arkana/templates/swift/arkana_protocol.swift.erb
91
+ - lib/arkana/templates/swift/arkana_tests.swift.erb
92
+ - lib/arkana/templates/swift/interfaces.podspec.erb
93
+ - lib/arkana/templates/swift/interfaces_package.swift.erb
94
+ - lib/arkana/templates/swift/interfaces_readme.erb
95
+ - lib/arkana/templates/swift/package.swift.erb
91
96
  - lib/arkana/version.rb
92
97
  homepage: https://github.com/rogerluan/arkana
93
98
  licenses:
@@ -112,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
117
  - !ruby/object:Gem::Version
113
118
  version: '0'
114
119
  requirements: []
115
- rubygems_version: 3.3.7
120
+ rubygems_version: 3.4.10
116
121
  signing_key:
117
122
  specification_version: 4
118
123
  summary: Store your keys and secrets away from your source code. Designed for Android
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Enumerable extensions and utilities.
4
- module Enumerable
5
- # NOTE: This is a backport of Ruby 2.7 filter_map. This method can be deleted when the minimum target Ruby version is 2.7
6
- # We're not gating against redefining the method (e.g. via `unless Enumerable.method_defined? :filter_map`) because this
7
- # would reduce the code coverage when analysing code coverage on Ruby versions >= 2.7
8
- def filter_map
9
- return to_enum(:filter_map) unless block_given?
10
-
11
- each_with_object([]) do |item, res|
12
- processed = yield(item)
13
- res << processed if processed
14
- end
15
- end
16
- end