obfuskit 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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