obfuskit 0.2.1 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f13c1d6e89c565ef55077edab6aeadaf16396a142887df8ccb8fc9e4c1939177
4
- data.tar.gz: 281bc1d8a5517df52e6f71af31edd5430d52abc5f1a01e953b431c3c5f8f4cee
3
+ metadata.gz: 07c3f052a3c4ff566890a9cb72099b7f2cc9f6eab79a865b58e2de901d0963c5
4
+ data.tar.gz: 93b42f3091775a71366b4f70e93ef42114f08f5eddcd0275225f0e0d14f99464
5
5
  SHA512:
6
- metadata.gz: 30d4652e43f1440ffc36b7c90541523719d0f7bb21f8d5d405571b1021f7f763ad6f4963ad2fb8e44532af1e47a9d72da547464b028369351aa512a955982532
7
- data.tar.gz: 7fe5c1cfe3eaaf5ff2a11d0fd8d40d023bf4ccf6f8a2aefee2d77288437161e8975651697ee60ca1e5bbf2930a98e5328512cf2dafba34e08eb49ed107612561
6
+ metadata.gz: 337aaf034bf4afb7d41168254472376646876aa0e30ee609256f94c3cdf7c0974e83a2853f383bcfea719aceab0c5b2cde17bf8c90e1206a9dd78329b3caae1f
7
+ data.tar.gz: 83047860687ac6ab90b77958495deb0c06f20f676730a5d53199798340ef0b0102795fe065c6ef9696183435acd29c59e936363a60505c5c1d898d390aecf3a9
data/README.md CHANGED
@@ -1,22 +1,41 @@
1
1
  # ObfusKit
2
-
3
- ObfusKit is a ruby script to generate obfuscated secrets for `Swift` and `Kotlin`.
2
+ ObfusKit is a ruby script that generates obfuscated secrets for `Swift` and `Kotlin`.
4
3
 
5
4
  ## Installation and usage
6
5
 
7
6
  Install the latest version of the gem using:
8
7
 
9
- ```
8
+ ```sh
10
9
  gem install obfuskit
11
10
  ```
12
11
 
13
- To generate Swift code run the following command:
12
+ Call `obfuskit -h` for help.
14
13
 
15
14
  ```sh
16
- obfuskit swift SECRET_1 SECRET_2 > generated.swift
15
+ Usage: obfuskit [options]
16
+
17
+ Specific options:
18
+ -l, --language [LANGUAGE] Output language (swift, kotlin). Kotlin requires a package parameter.
19
+ -k SECRET_1,SECRET_2,SECRET_3, List of environment variable keys
20
+ --keys
21
+ -p, --package [PACKAGE] Package name for Kotlin
22
+ -t, --type [TYPE] Output type name. Defaults to `ObfusKit`
23
+ -e, --env [PATH] Path to an alternative .env file
24
+
25
+ Common options:
26
+ -h, --help Show this message
27
+ -v, --version Show version
17
28
  ```
18
29
 
19
- It will will create the file `generated.swift` containing an obfuscated version of the environment variables `SECRET_1` and `SECRET_2`.
30
+ ### Swift
31
+
32
+ To generate Swift code, run the following command:
33
+
34
+ ```sh
35
+ obfuskit -l swift -k SECRET_1,SECRET_2 > generated.swift
36
+ ```
37
+
38
+ It will create the file `generated.swift` containing an obfuscated version of the environment variables `SECRET_1` and `SECRET_2`.
20
39
  This file should be excluded from the git repository and generated at build time.
21
40
  The obfuscation salt is regenerated for each run.
22
41
 
@@ -30,14 +49,15 @@ enum ObfusKit {
30
49
  private class _3f3eccd2e5ea46b39738e5502bda6bef { }
31
50
  private static let _o = O(String(describing: _3f3eccd2e5ea46b39738e5502bda6bef.self))
32
51
  }
33
-
34
- struct O { private let c: [UInt8]; private let l: Int; init(_ s: String) { self.init([UInt8](s.utf8)) }; init(_ c: [UInt8]) { self.c = c; l = c.count }; @inline(__always) func o(_ v: String) -> [UInt8] { [UInt8](v.utf8).enumerated().map { $0.element ^ c[$0.offset % l] } }; @inline(__always) func r(_ value: [UInt8]) -> String { String(bytes: value.enumerated().map { $0.element ^ c[$0.offset % l] }, encoding: .utf8) ?? "" } }
52
+ // ...
35
53
  ```
36
54
 
37
- The same concept applies for the `kotlin` language using:
55
+ ### Kotlin
56
+
57
+ The same concept applies to the Kotlin language using:
38
58
 
39
59
  ```sh
40
- obfuskit kotlin com.myapp.configuration.environment SECRET_1 SECRET_2 > generated.kt
60
+ obfuskit -l kotlin -p com.myapp.configuration.environment -k SECRET_1,SECRET_2 > generated.kt
41
61
  ```
42
62
  It will create the Kotlin version `generated.kt`.
43
63
 
@@ -51,15 +71,31 @@ object ObfusKit {
51
71
  val SECRET_1: String = _o.r(byteArrayOf(30, 116, 118, 115, 119, 119, 116))
52
72
  val SECRET_2: String = _o.r(byteArrayOf(24, 112, 112, 115, 113, 115, 114))
53
73
  }
74
+ // ...
75
+ ```
76
+
77
+ #### Android Code shrinking and Obfuscation
78
+ Proguard/R8 changes class names and method names. This will break revealing secrets at run time.
79
+ To prevent this, add the according rules to your `proguard-rules.pro` file or use the `--keep-annotation` parameter to inject a custom annotation like `@androidx.annotation.Keep` into the generated code.
54
80
 
55
- class O{private val a:ByteArray;private val b:Int;constructor(s:String){a=s.toByteArray(Charsets.UTF_8);b=a.size};fun o(v:String):ByteArray{val d=v.toByteArray(Charsets.UTF_8);return ByteArray(d.size){i->(d[i].toInt() xor a[i%b].toInt()).toByte()}};fun r(value:ByteArray):String{return String(ByteArray(value.size){i->(value[i].toInt() xor a[i%b].toInt()).toByte()},Charsets.UTF_8)}}
81
+ For example:
56
82
 
83
+ ```sh
84
+ obfuskit -l kotlin -p com.myapp.configuration.environment -k SECRET_1,SECRET_2 --keep-annotation @androidx.annotation.Keep > generated.kt
85
+ ```
86
+
87
+ ### Use a custom .env file location
88
+
89
+ Use the `-e` option to define the path to a different `.env` file, e.g., if you want to reuse the `fastlane/.env` file.
90
+
91
+ ```sh
92
+ obfuskit -l swift -k SECRET_3,SECRET_4 -e fastlane/.env > generated.swift
57
93
  ```
58
94
 
59
95
  ## Features
60
96
  - [x] Generate Swift
61
97
  - [x] Generate Kotlin
62
- - [x] Read secrets from the Environment
98
+ - [x] Read Secrets from the Environment
63
99
  - [x] Add dynamic salt for obfuscation
64
100
  - [x] Support for .env files
65
101
  - [x] Use template engine for code generation
@@ -1,79 +1,62 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative 'obfuscator'
3
+ require_relative 'options_parser'
3
4
  require 'securerandom'
4
5
  require 'dotenv'
5
6
  require 'erb'
6
-
7
- module Language
8
- SWIFT = "Swift"
9
- KOTLIN = "Kotlin"
10
- end
7
+ require 'optparse'
11
8
 
12
9
  module Obfuskit
13
10
 
14
11
  class Generator
15
12
 
16
- def generate()
13
+ def generate
17
14
 
18
- Dotenv.load
19
- args = ARGV
20
- language_key = args.shift.downcase
15
+ parser = OptionsParser.new
16
+ options = parser.parse(ARGV)
21
17
 
22
- language_map = {
23
- "swift" => Language::SWIFT,
24
- "kotlin" => Language::KOTLIN,
25
- "kt" => Language::KOTLIN
26
- }
18
+ Dotenv.load(options.dot_env_file_path)
27
19
 
28
- if language_key != nil && language_map.key?(language_key)
20
+ if !options.output_language.nil? && options.env_var_keys.length.positive?
29
21
 
30
22
  salt = SecureRandom.uuid.to_s.gsub("-", "")
31
23
  obfuscator = Obfuscator.new("_" + salt)
32
24
 
33
- case language_map[language_key]
34
- when Language::SWIFT
35
- puts generate_swift(args, obfuscator)
25
+ values = obfuscated_values_from_env(options.env_var_keys, obfuscator)
26
+
27
+ if options.output_language == :swift
28
+ puts generate_with_template("swift", values, nil, options.output_type_name, obfuscator, options.keep_annotation)
29
+
30
+ elsif options.output_language == :kotlin && !options.package_name.nil?
31
+ puts generate_with_template("kotlin", values, options.package_name, options.output_type_name, obfuscator, options.keep_annotation)
36
32
 
37
- when Language::KOTLIN
38
- puts generate_kotlin(args, obfuscator)
33
+ else
34
+ STDERR.puts parser.parse(%w[--help])
39
35
  end
40
36
 
41
37
  else
42
- STDERR.puts "Please specify a valid language."
38
+ STDERR.puts parser.parse(%w[--help])
43
39
  end
44
40
  end
45
41
 
46
42
  private
47
43
 
48
- def generate_swift(args, obfuscator)
49
- values = obfuscated_values_from_env(args, obfuscator)
50
- generate_with_template("swift", values, nil, obfuscator)
51
- end
52
-
53
- def generate_kotlin(args, obfuscator)
54
- package = args.shift
55
- if package == nil
56
- STDERR.puts "No package name provided."
57
- else
58
- values = obfuscated_values_from_env(args, obfuscator)
59
- generate_with_template("kotlin", values, package, obfuscator)
60
- end
61
- end
62
-
63
44
  def obfuscated_values_from_env(args, obfuscator)
64
- args.map { |name|
65
- ENV[name] != nil ? [name, obfuscator.obfuscate(ENV[name])] : nil
66
- }.compact.to_h
45
+ args.map do |name|
46
+ !ENV[name].nil? ? [name, obfuscator.obfuscate(ENV[name])] : nil
47
+ end.compact.to_h
67
48
  end
68
49
 
69
- def generate_with_template(template_name, values, package, obfuscator)
50
+ def generate_with_template(template_name, values, package, type_name, obfuscator, keep_annotation)
70
51
  file = File.expand_path("templates/#{template_name}.erb", __dir__)
71
52
  template = ERB.new(File.read(file), trim_mode: "-")
72
53
  template.result_with_hash(
73
54
  values: values,
74
55
  package: package,
75
- salt: obfuscator.salt
76
- )
56
+ type_name: type_name,
57
+ salt: obfuscator.salt,
58
+ keep_annotation: keep_annotation
59
+ )
77
60
  end
78
61
 
79
62
  end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+ require 'optparse'
3
+
4
+ class OptionsParser
5
+ class ScriptOptions
6
+
7
+ attr_accessor :output_language, :env_var_keys, :package_name, :output_type_name, :dot_env_file_path, :keep_annotation
8
+
9
+ def initialize
10
+ self.output_language = nil
11
+ self.env_var_keys = []
12
+ self.package_name = nil
13
+ self.output_type_name = "ObfusKit"
14
+ self.dot_env_file_path = ".env"
15
+ self.keep_annotation = nil
16
+ end
17
+
18
+ def define_options(parser)
19
+ parser.banner = "Usage: obfuskit [options]"
20
+ parser.separator ""
21
+ parser.separator "Specific options:"
22
+
23
+ # add additional options
24
+ output_language_option(parser)
25
+ env_var_keys_option(parser)
26
+ package_name_option(parser)
27
+ output_type_name_option(parser)
28
+ dot_env_file_path_options(parser)
29
+ keep_annotation_options(parser)
30
+
31
+ parser.separator ""
32
+ parser.separator "Common options:"
33
+ # No argument, shows at tail. This will print an options summary.
34
+ # Try it and see!
35
+ parser.on_tail("-h", "--help", "Show this message") do
36
+ puts parser
37
+ exit
38
+ end
39
+
40
+ # Another typical switch to print the version.
41
+ parser.on_tail("-v", "--version", "Show version") do
42
+ puts Obfuskit::VERSION
43
+ exit
44
+ end
45
+
46
+ end
47
+
48
+ private
49
+
50
+ def output_language_option(parser)
51
+ parser.on("-l", "--language [LANGUAGE]", [:swift, :kotlin],
52
+ "Output language (swift, kotlin). Kotlin requires a package parameter.") do |t|
53
+ self.output_language = t
54
+ end
55
+ end
56
+
57
+ def env_var_keys_option(parser)
58
+ parser.on("-k", "--keys SECRET_1,SECRET_2,SECRET_3", Array, "List of environment variable keys") do |list|
59
+ self.env_var_keys = list
60
+ end
61
+ end
62
+
63
+ def package_name_option(parser)
64
+ parser.on("-p", "--package [PACKAGE]", "Package name for Kotlin") do |value|
65
+ self.package_name = value
66
+ end
67
+ end
68
+
69
+ def output_type_name_option(parser)
70
+ parser.on("-t", "--type [TYPE]", "Output type name. Defaults to `ObfusKit`") do |value|
71
+ self.output_type_name = value
72
+ end
73
+ end
74
+
75
+ def dot_env_file_path_options(parser)
76
+ parser.on("-e", "--env [PATH]", "Path to an alternative .env file") do |value|
77
+ self.dot_env_file_path = value
78
+ end
79
+ end
80
+
81
+ def keep_annotation_options(parser)
82
+ parser.on("--keep-annotation [Annotation]", "Annotation to prevent key class obfuscation. e.g. @androidx.annotation.Kee
83
+ ") do |value|
84
+ self.keep_annotation = value
85
+ end
86
+ end
87
+ end
88
+
89
+ #
90
+ # Return a structure describing the options.
91
+ #
92
+ def parse(args)
93
+ # The options specified on the command line will be collected in
94
+ # *options*.
95
+
96
+ @options = ScriptOptions.new
97
+ OptionParser.new do |parser|
98
+ @options.define_options(parser)
99
+ parser.parse!(args)
100
+ end
101
+ @options
102
+ end
103
+
104
+ attr_reader :parser, :options
105
+ end # class OptionsParser
@@ -1,7 +1,8 @@
1
1
  package <%= package %>
2
2
 
3
- public object ObfusKit {
3
+ public object <%= type_name %> {
4
4
  private val _o = O(<%= salt %>::class.java.simpleName)
5
+ <%= keep_annotation unless keep_annotation.nil? %>
5
6
  private class <%= salt %>
6
7
 
7
8
  <% values.each do |name, values| -%>
@@ -1,6 +1,6 @@
1
1
  import Foundation
2
2
 
3
- public enum ObfusKit {
3
+ public enum <%= type_name %> {
4
4
  <% values.each do |name, values| -%>
5
5
  public static let <%= name %>: String = _o.r([<%= values.map { |i| i.to_s }.join(', ') %>])
6
6
  <% end -%>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Obfuskit
4
- VERSION = "0.2.1"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -3,9 +3,9 @@ module Obfuskit
3
3
  def generate: -> void
4
4
 
5
5
  private
6
- def generate_kotlin: ([String], Obfuscator) -> String
7
- def generate_swift: ([String], Obfuscator) -> String
6
+ def generate_kotlin: ([String], String, Obfuscator) -> String
7
+ def generate_swift: ([String], String, Obfuscator) -> String
8
8
  def obfuscated_values_from_env: ([String], Obfuscator) -> Hash[String, [Integer]]
9
- def generate_with_template: (String, Hash[String, [Integer]], String, Obfuscator) -> String
9
+ def generate_with_template: (String, Hash[String, [Integer]], String?, String, Obfuscator) -> String
10
10
  end
11
11
  end
@@ -0,0 +1,6 @@
1
+ class OptionsParser
2
+ attr_reader options: ScriptOptions
3
+ attr_reader parser: OptionsParser
4
+
5
+ def parse: -> ScriptOptions
6
+ end
@@ -0,0 +1,22 @@
1
+ module OptionsParser
2
+ class ScriptOptions
3
+ attr_accessor dot_env_file_path: String
4
+ attr_accessor dot_env_file_paths: [String]
5
+ attr_accessor env_var_keys: [String]
6
+ attr_accessor keep_annotation: String?
7
+ attr_accessor output_language: String?
8
+ attr_accessor output_type_name: String
9
+ attr_accessor package_name: String?
10
+
11
+ def define_options: -> void
12
+
13
+ private
14
+
15
+ def dot_env_file_path_options: -> OptionParser
16
+ def env_var_keys_option: -> OptionParser
17
+ def keep_annotation_options: -> OptionParser
18
+ def output_language_option: -> OptionParser
19
+ def output_type_name_option: -> OptionParser
20
+ def package_name_option: -> OptionParser
21
+ end
22
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obfuskit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Gratzer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-19 00:00:00.000000000 Z
11
+ date: 2024-04-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Generate Swift and Kotlin files with obfuscated environment variables.
14
14
  email: mgratzer@gmail.com
@@ -23,13 +23,15 @@ files:
23
23
  - exe/obfuskit
24
24
  - lib/obfuskit/generator.rb
25
25
  - lib/obfuskit/obfuscator.rb
26
+ - lib/obfuskit/options_parser.rb
26
27
  - lib/obfuskit/templates/kotlin.erb
27
28
  - lib/obfuskit/templates/swift.erb
28
29
  - lib/obfuskit/version.rb
29
- - obfuskit.gemspec
30
30
  - sig/obfuskit.rbs
31
31
  - sig/obfuskit/generator.rbs
32
32
  - sig/obfuskit/obfuscator.rbs
33
+ - sig/obfuskit/options_parser.rbs
34
+ - sig/options_parser/script_options.rbs
33
35
  homepage: https://github.com/mgratzer/obfuskit
34
36
  licenses:
35
37
  - MIT
data/obfuskit.gemspec DELETED
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/obfuskit/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "obfuskit"
7
- s.version = Obfuskit::VERSION
8
- s.summary = "Environment variable obfuscation for Swift and Kotlin."
9
- s.description = "Generate Swift and Kotlin files with obfuscated environment variables."
10
- s.authors = ["Martin Gratzer"]
11
- s.email = "mgratzer@gmail.com"
12
- s.homepage =
13
- "https://github.com/mgratzer/obfuskit"
14
- s.license = "MIT"
15
- s.executables << "obfuskit"
16
- s.required_ruby_version = ">= 3.0.0"
17
- s.metadata["homepage_uri"] = s.homepage
18
-
19
- # Specify which files should be added to the gem when it is released.
20
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
- s.files = Dir.chdir(__dir__) do
22
- `git ls-files -z`.split("\x0").reject do |f|
23
- (File.expand_path(f) == __FILE__) ||
24
- f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
25
- end
26
- end
27
- s.bindir = "exe"
28
- s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
- s.require_paths = ["lib"]
30
- end