diffcrypt 0.3.0 → 0.4.1

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: 6055430f063cb4f1c161ca44b65e2d3a0a15d134546152c2e9e0b39486737f08
4
- data.tar.gz: 4332842bbef701c1b775e1de410391f07e5bf477318727e0412afb29d0ba00a5
3
+ metadata.gz: e6d985bd619146b0cede42746b62e00f7e52a01a92a8e7a79718ab0f9b80391a
4
+ data.tar.gz: d0fb2659741c498608421b741b4fa1acfbdec8f74bc7ac65425a9c97017a9342
5
5
  SHA512:
6
- metadata.gz: 5d9b0a443e3d2521ba45385a57522d289fad5c9fa88707e5d6272ac0b23dcc4ee8dee9fc6c1831794468399917dccf95747ab0ac5c391c40ebcb991bbc7ebb22
7
- data.tar.gz: '038974890091043cec270fb775b94705522445c1185fe07856d5558cbb970d96cfc86dfedfba8081f83a6ccc593e863b32df08f59a3916dc0a1c6e1fa4ceaf45'
6
+ metadata.gz: 2ba3e972200d1a4d785a9f4bdc67defc04e26d94d35421f9cc2b8a9e956b56f693e452acf0fbbb98ea7f96eb3fc6454e92dbb7d3fa825a6dc16f2882f86b12c6
7
+ data.tar.gz: d1e7c88b0a323ecb366e2a9642b45c8b60701c1492d97615773d7c12e5fe5753086b440d9bd1ccc19662ca3cb9f67de6c64e90000229ee64df73d619cc0f70f4
@@ -4,8 +4,23 @@ jobs:
4
4
  build:
5
5
  docker:
6
6
  - image: circleci/ruby:2.6.6
7
+ working_directory: /mnt/ramdisk
7
8
  steps:
8
9
  - checkout
9
10
  - run: bundle install
10
- - run: bundle exec rake test
11
- - run: bundle exec rubocop
11
+ - run:
12
+ name: Setup Code Climate test-reporter
13
+ command: |
14
+ # download test reporter as a static binary
15
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
16
+ chmod +x ./cc-test-reporter
17
+ - run:
18
+ name: rake test
19
+ command: |
20
+ ./cc-test-reporter before-build
21
+ bundle exec rake test
22
+ ./cc-test-reporter after-build --coverage-input-type lcov --exit-code $?
23
+ - run:
24
+ name: rubocop
25
+ command: bundle exec rubocop
26
+ when: always
@@ -9,8 +9,12 @@ Style/Documentation:
9
9
  Metrics/MethodLength:
10
10
  Exclude:
11
11
  - test/**/*_test.rb
12
+ TrailingCommaInArrayLiteral:
13
+ EnforcedStyleForMultiline: consistent_comma
12
14
  Style/TrailingCommaInArguments:
13
15
  EnforcedStyleForMultiline: consistent_comma
16
+ Style/AccessorGrouping:
17
+ EnforcedStyle: separated
14
18
 
15
19
  Layout/LineLength:
16
20
  Exclude:
@@ -7,6 +7,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
 
9
9
 
10
+ ## [0.4.1] - 2020-10-06
11
+
12
+ ### Fixed
13
+
14
+ - Could not initialize a new file or modify existing rails format file (Thanks @swiknaba #31)
15
+
16
+
17
+
18
+ ## [0.4.0] - 2020-10-01
19
+
20
+ ### Changed
21
+
22
+ - Encryptor can now use other ciphers than the default
23
+
24
+ ### Dependencies
25
+
26
+ - simplecov: 0.17.0 -> 0.18.0 (#20)
27
+ - rubocop: 0.88.0 -> 0.92.0 (#24)
28
+
29
+
30
+
31
+ ## [0.3.3] - 2020-07-25
32
+
33
+ ### Fixed
34
+
35
+ - Explicit FileUtils require to avoid potentially warning logs
36
+
37
+
38
+
39
+ ## [0.3.2] - 2020-07-20
40
+
41
+ ### Added
42
+
43
+ - CLI: `diffcrypt generate-key` command to generate a new key for a cipher
44
+ - Internal: Library now generates and publishes code coverage publically on Code Climate
45
+
46
+ ### Changed
47
+
48
+ - Only support ruby 2.5+ since 2.4 is no longer maintained
49
+
50
+ ### Removed
51
+
52
+ - No longer generate and store a checksum. Backwards compatible since it wasn't used
53
+
54
+
55
+
56
+ ## [0.3.1] - 2020-07-08
57
+
58
+ ### Fixed
59
+
60
+ - Thor deprecation error no longer shows on CLI failure
61
+
62
+ ### Changed
63
+
64
+ - Thor 0.20+ can now be used alongside this gem
65
+
66
+
67
+
10
68
  ## [0.3.0] - 2020-06-30
11
69
 
12
70
  ## Added
data/Gemfile CHANGED
@@ -7,4 +7,6 @@ gemspec
7
7
 
8
8
  gem 'minitest', '~> 5.0'
9
9
  gem 'rake', '~> 13.0'
10
- gem 'rubocop', '~> 0.86'
10
+ gem 'rubocop', '~> 0.92.0'
11
+ gem 'simplecov', '~> 0.19.0', require: false # CodeClimate not compatible with 0.18+ yet - https://github.com/codeclimate/test-reporter/issues/413
12
+ gem 'simplecov-lcov', '< 0.8'
data/README.md CHANGED
@@ -36,8 +36,8 @@ There are a few ways to use the library, depending on how advanced your use case
36
36
  The easiest way to get started is to use the CLI.
37
37
 
38
38
  ```shell
39
- diffcrypt decrypt -k $(cat test/fixtures/master.key) test/fixtures/example.yml.enc
40
- diffcrypt encrypt -k $(cat test/fixtures/master.key) test/fixtures/example.yml
39
+ diffcrypt decrypt -k $(cat test/fixtures/aes-128-gcm.key) test/fixtures/example.yml.enc
40
+ diffcrypt encrypt -k $(cat test/fixtures/aes-128-gcm.key) test/fixtures/example.yml
41
41
  ```
42
42
 
43
43
 
@@ -69,7 +69,7 @@ the built in encrypter. All existing `rails credentials:edit` also work with thi
69
69
  require 'diffcrypt/rails/encrypted_configuration'
70
70
  module Rails
71
71
  class Application
72
- def encrypted(path, key_path: 'config/master.key', env_key: 'RAILS_MASTER_KEY')
72
+ def encrypted(path, key_path: 'config/aes-128-gcm.key', env_key: 'RAILS_MASTER_KEY')
73
73
  Diffcrypt::Rails::EncryptedConfiguration.new(
74
74
  config_path: Rails.root.join(path),
75
75
  key_path: Rails.root.join(key_path),
@@ -83,6 +83,17 @@ end
83
83
 
84
84
 
85
85
 
86
+ ## Converting between ciphers
87
+
88
+ Sometimes you may want to rotate the cipher used on a file. You can do this programmatically using the ruby code above, or you can also chain the CLI commands like so:
89
+
90
+ ```shell
91
+ diffcrypt decrypt -k $(cat test/fixtures/aes-128-gcm.key) test/fixtures/example.yml.enc > test/fixtures/example.128.yml \
92
+ && diffcrypt encrypt --cipher aes-256-gcm -k $(cat test/fixtures/aes-256-gcm.key) test/fixtures/example.128.yml > test/fixtures/example.256.yml.enc && rm test/fixtures/example.128.yml
93
+ ```
94
+
95
+
96
+
86
97
  ## Development
87
98
 
88
99
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,17 @@
1
+ # Security Policy
2
+
3
+
4
+
5
+ ## Supported Versions
6
+
7
+ Since the internal APIs may change dramatically until v1.0, here is a list of the versions that are supported.
8
+
9
+ | Version | Supported |
10
+ | ------- | ------------------ |
11
+ | 0.3.x | :white_check_mark: |
12
+
13
+
14
+
15
+ ## Reporting a Vulnerability
16
+
17
+ Please email security@marcqualie.com to report any security issues.
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = 'Diffable encrypted configuration files that can be safely committed into a git repository'
13
13
  spec.homepage = 'https://github.com/marcqualie/diffcrypt'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
16
16
 
17
17
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
18
18
 
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  # Specify which files should be added to the gem when it is released.
24
24
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ spec.files = Dir.chdir(::File.expand_path(__dir__)) do
26
26
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
27
  end
28
28
  spec.bindir = 'bin'
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.require_paths = ['lib']
31
31
 
32
32
  spec.add_runtime_dependency 'activesupport', '~> 6.0.0'
33
- spec.add_runtime_dependency 'thor', '~> 1.0.1'
33
+ spec.add_runtime_dependency 'thor', '>= 0.20', '< 2'
34
34
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative './encryptor'
4
+ require_relative './file'
4
5
  require_relative './version'
5
6
 
6
7
  module Diffcrypt
@@ -8,17 +9,24 @@ module Diffcrypt
8
9
  desc 'decrypt <path>', 'Decrypt a file'
9
10
  method_option :key, aliases: %i[k], required: true
10
11
  def decrypt(path)
11
- ensure_file_exists(path)
12
- contents = File.read(path)
13
- puts encryptor.decrypt(contents)
12
+ file = File.new(path)
13
+ ensure_file_exists(file)
14
+ say file.decrypt(key)
14
15
  end
15
16
 
16
17
  desc 'encrypt <path>', 'Encrypt a file'
17
18
  method_option :key, aliases: %i[k], required: true
19
+ method_option :cipher, default: Encryptor::DEFAULT_CIPHER
18
20
  def encrypt(path)
19
- ensure_file_exists(path)
20
- contents = File.read(path)
21
- puts encryptor.encrypt(contents)
21
+ file = File.new(path)
22
+ ensure_file_exists(file)
23
+ say file.encrypt(key, cipher: options[:cipher])
24
+ end
25
+
26
+ desc 'generate-key', 'Generate a 32 bit key'
27
+ method_option :cipher, default: Encryptor::DEFAULT_CIPHER
28
+ def generate_key
29
+ say Encryptor.generate_key(options[:cipher])
22
30
  end
23
31
 
24
32
  desc 'version', 'Show client version'
@@ -35,8 +43,13 @@ module Diffcrypt
35
43
  @encryptor ||= Encryptor.new(key)
36
44
  end
37
45
 
38
- def ensure_file_exists(path)
39
- abort('[ERROR] File does not exist') unless File.exist?(path)
46
+ # @param [Diffcrypt::File] path
47
+ def ensure_file_exists(file)
48
+ abort('[ERROR] File does not exist') unless file.exists?
49
+ end
50
+
51
+ def self.exit_on_failure?
52
+ true
40
53
  end
41
54
  end
42
55
  end
@@ -12,15 +12,16 @@ require_relative './version'
12
12
 
13
13
  module Diffcrypt
14
14
  class Encryptor
15
- CIPHER = 'aes-128-gcm'
15
+ DEFAULT_CIPHER = 'aes-128-gcm'
16
16
 
17
- def self.generate_key
18
- SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER))
17
+ def self.generate_key(cipher = DEFAULT_CIPHER)
18
+ SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(cipher))
19
19
  end
20
20
 
21
- def initialize(key)
21
+ def initialize(key, cipher: DEFAULT_CIPHER)
22
22
  @key = key
23
- @encryptor ||= ActiveSupport::MessageEncryptor.new([key].pack('H*'), cipher: CIPHER)
23
+ @cipher = cipher
24
+ @encryptor ||= ActiveSupport::MessageEncryptor.new([key].pack('H*'), cipher: cipher)
24
25
  end
25
26
 
26
27
  # @param [String] contents The raw YAML string to be encrypted
@@ -50,8 +51,7 @@ module Diffcrypt
50
51
  data = encrypt_data contents, original_encrypted_contents
51
52
  YAML.dump(
52
53
  'client' => "diffcrypt-#{Diffcrypt::VERSION}",
53
- 'cipher' => CIPHER,
54
- 'checksum' => Digest::MD5.hexdigest(Marshal.dump(data)),
54
+ 'cipher' => @cipher,
55
55
  'data' => data,
56
56
  )
57
57
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './encryptor'
4
+
5
+ module Diffcrypt
6
+ class File
7
+ attr_reader :file
8
+
9
+ def initialize(path)
10
+ @path = ::File.absolute_path path
11
+ end
12
+
13
+ def encrypted?
14
+ to_yaml['cipher']
15
+ end
16
+
17
+ def cipher
18
+ to_yaml['cipher'] || Encryptor::DEFAULT_CIPHER
19
+ end
20
+
21
+ # @return [Boolean]
22
+ def exists?
23
+ ::File.exist?(@path)
24
+ end
25
+
26
+ # @return [String] Raw contents of the file
27
+ def read
28
+ @read ||= ::File.read(@path)
29
+ end
30
+
31
+ def encrypt(key, cipher: DEFAULT_CIPHER)
32
+ return read if encrypted?
33
+
34
+ Encryptor.new(key, cipher: cipher).encrypt(read)
35
+ end
36
+
37
+ # TODO: Add a test to verify this does descrypt properly
38
+ def decrypt(key)
39
+ return read unless encrypted?
40
+
41
+ Encryptor.new(key, cipher: cipher).decrypt(read)
42
+ end
43
+
44
+ def to_yaml
45
+ @to_yaml ||= YAML.safe_load(read)
46
+ end
47
+ end
48
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fileutils'
3
4
  require 'pathname'
4
5
  require 'tmpdir'
5
6
 
@@ -8,6 +9,8 @@ require 'active_support/core_ext/hash'
8
9
  require 'active_support/core_ext/module/delegation'
9
10
  require 'active_support/core_ext/object/inclusion'
10
11
 
12
+ require 'diffcrypt/file'
13
+
11
14
  module Diffcrypt
12
15
  module Rails
13
16
  class EncryptedConfiguration
@@ -20,13 +23,13 @@ module Diffcrypt
20
23
  delegate_missing_to :options
21
24
 
22
25
  def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:)
23
- @content_path = Pathname.new(File.absolute_path(config_path)).yield_self do |path|
26
+ @content_path = Pathname.new(::File.absolute_path(config_path)).yield_self do |path|
24
27
  path.symlink? ? path.realpath : path
25
28
  end
29
+ @diffcrypt_file = Diffcrypt::File.new(@content_path)
26
30
  @key_path = Pathname.new(key_path)
27
31
  @env_key = env_key
28
32
  @raise_if_missing_key = raise_if_missing_key
29
- @active_support_encryptor = ActiveSupport::MessageEncryptor.new([key].pack('H*'), cipher: Encryptor::CIPHER)
30
33
  end
31
34
 
32
35
  # Determines if file is using the diffable format, or still
@@ -50,7 +53,7 @@ module Diffcrypt
50
53
  deserialize(contents)
51
54
 
52
55
  IO.binwrite "#{content_path}.tmp", encrypt(contents, original_encrypted_contents)
53
- FileUtils.mv "#{content_path}.tmp", content_path
56
+ ::FileUtils.mv "#{content_path}.tmp", content_path
54
57
  end
55
58
 
56
59
  def config
@@ -72,7 +75,7 @@ module Diffcrypt
72
75
  # rubocop:disable Metrics/AbcSize
73
76
  def writing(contents)
74
77
  tmp_file = "#{Process.pid}.#{content_path.basename.to_s.chomp('.enc')}"
75
- tmp_path = Pathname.new File.join(Dir.tmpdir, tmp_file)
78
+ tmp_path = Pathname.new ::File.join(Dir.tmpdir, tmp_file)
76
79
  tmp_path.binwrite contents
77
80
 
78
81
  yield tmp_path
@@ -81,7 +84,7 @@ module Diffcrypt
81
84
 
82
85
  write(updated_contents, content_path_diffable? && content_path.binread)
83
86
  ensure
84
- FileUtils.rm(tmp_path) if tmp_path&.exist?
87
+ ::FileUtils.rm(tmp_path) if tmp_path&.exist?
85
88
  end
86
89
  # rubocop:enable Metrics/AbcSize
87
90
 
@@ -96,15 +99,24 @@ module Diffcrypt
96
99
  # @return [String]
97
100
  def decrypt(contents)
98
101
  if contents.index('---').nil?
99
- @active_support_encryptor.decrypt_and_verify contents
102
+ active_support_encryptor.decrypt_and_verify contents
100
103
  else
101
104
  encryptor.decrypt contents
102
105
  end
103
106
  end
104
107
 
108
+ # Rails applications with an existing credentials file, the inbuilt active support encryptor should be used
109
+ # @return [ActiveSupport::MessageEncryptor]
110
+ def active_support_encryptor
111
+ @active_support_encryptor ||= ActiveSupport::MessageEncryptor.new(
112
+ [key].pack('H*'),
113
+ cipher: @diffcrypt_file.cipher,
114
+ )
115
+ end
116
+
105
117
  # @return [Encryptor]
106
118
  def encryptor
107
- @encryptor ||= Encryptor.new key
119
+ @encryptor ||= Encryptor.new key, cipher: @diffcrypt_file.cipher
108
120
  end
109
121
 
110
122
  def read_env_key
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Diffcrypt
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diffcrypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc Qualie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-30 00:00:00.000000000 Z
11
+ date: 2020-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -28,16 +28,22 @@ dependencies:
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0.20'
34
+ - - "<"
32
35
  - !ruby/object:Gem::Version
33
- version: 1.0.1
36
+ version: '2'
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0.20'
44
+ - - "<"
39
45
  - !ruby/object:Gem::Version
40
- version: 1.0.1
46
+ version: '2'
41
47
  description: Diffable encrypted configuration files that can be safely committed into
42
48
  a git repository
43
49
  email:
@@ -56,6 +62,7 @@ files:
56
62
  - LICENSE.txt
57
63
  - README.md
58
64
  - Rakefile
65
+ - SECURITY.md
59
66
  - bin/console
60
67
  - bin/diffcrypt
61
68
  - bin/setup
@@ -63,8 +70,10 @@ files:
63
70
  - lib/diffcrypt.rb
64
71
  - lib/diffcrypt/cli.rb
65
72
  - lib/diffcrypt/encryptor.rb
73
+ - lib/diffcrypt/file.rb
66
74
  - lib/diffcrypt/rails/encrypted_configuration.rb
67
75
  - lib/diffcrypt/version.rb
76
+ - tmp/.keep
68
77
  homepage: https://github.com/marcqualie/diffcrypt
69
78
  licenses:
70
79
  - MIT
@@ -79,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
88
  requirements:
80
89
  - - ">="
81
90
  - !ruby/object:Gem::Version
82
- version: 2.3.0
91
+ version: 2.5.0
83
92
  required_rubygems_version: !ruby/object:Gem::Requirement
84
93
  requirements:
85
94
  - - ">="