diffcrypt 0.4.1 → 0.5.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: e6d985bd619146b0cede42746b62e00f7e52a01a92a8e7a79718ab0f9b80391a
4
- data.tar.gz: d0fb2659741c498608421b741b4fa1acfbdec8f74bc7ac65425a9c97017a9342
3
+ metadata.gz: dacd30e3ddee50fd84847385d2cd4161645b71b1cda79566557dff60e1f15108
4
+ data.tar.gz: 648e5cf57c6b909cf84196ded1643aa41baf776b8428862d57804d6465ebb3f0
5
5
  SHA512:
6
- metadata.gz: 2ba3e972200d1a4d785a9f4bdc67defc04e26d94d35421f9cc2b8a9e956b56f693e452acf0fbbb98ea7f96eb3fc6454e92dbb7d3fa825a6dc16f2882f86b12c6
7
- data.tar.gz: d1e7c88b0a323ecb366e2a9642b45c8b60701c1492d97615773d7c12e5fe5753086b440d9bd1ccc19662ca3cb9f67de6c64e90000229ee64df73d619cc0f70f4
6
+ metadata.gz: 8c20572e67d7416fd2fac81556eadba73555959273f7ac900a2d05c82c4799135edb9940a69659eca121cddfee4dd99b3a1b94e7b5effeeea491677ae638b2b7
7
+ data.tar.gz: 7e8fe375714cdfcb730792285f648a8a7f1164fe9015b42ee06a0a592b065a576a4059ba0d338f9ec79a0749b087d186c73e1d5ba89c6cecaebb4123490eabdf
@@ -1,13 +1,39 @@
1
1
  version: 2.1
2
2
 
3
3
  jobs:
4
- build:
4
+ bundle:
5
5
  docker:
6
- - image: circleci/ruby:2.6.6
6
+ - image: circleci/ruby:2.7.1
7
7
  working_directory: /mnt/ramdisk
8
8
  steps:
9
9
  - checkout
10
- - run: bundle install
10
+ - restore_cache:
11
+ keys:
12
+ - bundler-{{ checksum "diffcrypt.gemspec" }}-{{ .Environment.CACHE_VERSION }}
13
+ - run:
14
+ name: bundle install
15
+ command: |
16
+ gem install bundler -v '2.1.4'
17
+ bundle install --path=vendor/bundle --jobs=4 --retry=3
18
+ - save_cache:
19
+ key: bundler-{{ checksum "diffcrypt.gemspec" }}-{{ .Environment.CACHE_VERSION }}
20
+ paths:
21
+ - vendor/bundle
22
+
23
+ test:
24
+ docker:
25
+ - image: circleci/ruby:2.7.1
26
+ working_directory: /mnt/ramdisk
27
+ steps:
28
+ - checkout
29
+ - restore_cache:
30
+ keys:
31
+ - bundler-{{ checksum "diffcrypt.gemspec" }}-{{ .Environment.CACHE_VERSION }}
32
+ - run:
33
+ name: bundle install
34
+ command: |
35
+ gem install bundler -v '2.1.4'
36
+ bundle install --path=vendor/bundle --jobs=4 --retry=3
11
37
  - run:
12
38
  name: Setup Code Climate test-reporter
13
39
  command: |
@@ -20,7 +46,33 @@ jobs:
20
46
  ./cc-test-reporter before-build
21
47
  bundle exec rake test
22
48
  ./cc-test-reporter after-build --coverage-input-type lcov --exit-code $?
49
+ rubocop:
50
+ docker:
51
+ - image: circleci/ruby:2.7.1
52
+ working_directory: /mnt/ramdisk
53
+ steps:
54
+ - checkout
55
+ - restore_cache:
56
+ keys:
57
+ - bundler-{{ checksum "diffcrypt.gemspec" }}-{{ .Environment.CACHE_VERSION }}
58
+ - run:
59
+ name: bundle install
60
+ command: |
61
+ gem install bundler -v '2.1.4'
62
+ bundle install --path=vendor/bundle --jobs=4 --retry=3
23
63
  - run:
24
64
  name: rubocop
25
65
  command: bundle exec rubocop
26
66
  when: always
67
+
68
+ workflows:
69
+ version: 2
70
+ all:
71
+ jobs:
72
+ - bundle
73
+ - test:
74
+ requires:
75
+ - bundle
76
+ - rubocop:
77
+ requires:
78
+ - bundle
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
2
  NewCops: enable
3
+ TargetRubyVersion: 2.6
3
4
 
4
5
  Style/ClassAndModuleChildren:
5
6
  Exclude:
@@ -9,10 +10,12 @@ Style/Documentation:
9
10
  Metrics/MethodLength:
10
11
  Exclude:
11
12
  - test/**/*_test.rb
12
- TrailingCommaInArrayLiteral:
13
+ Style/TrailingCommaInArrayLiteral:
13
14
  EnforcedStyleForMultiline: consistent_comma
14
15
  Style/TrailingCommaInArguments:
15
16
  EnforcedStyleForMultiline: consistent_comma
17
+ Style/TrailingCommaInHashLiteral:
18
+ EnforcedStyleForMultiline: consistent_comma
16
19
  Style/AccessorGrouping:
17
20
  EnforcedStyle: separated
18
21
 
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
 
9
9
 
10
+ ## [0.5.0] - 2020-12-06
11
+
12
+ ### Added
13
+
14
+ - `Diffcrypt::Rails::ApplicationHelper` to simplify integration
15
+ - `rake diffcrypt:init` command to help setup credentials
16
+
17
+ ### Changed
18
+
19
+ - Default cipher is now `aes-265-gcm`
20
+ - YAML keys are now sorted
21
+ - Improved support for rails native `aes-128-gcm` cipher
22
+ - Improved test coverage for differing ciphers
23
+
24
+
25
+
10
26
  ## [0.4.1] - 2020-10-06
11
27
 
12
28
  ### Fixed
data/Gemfile CHANGED
@@ -7,6 +7,6 @@ gemspec
7
7
 
8
8
  gem 'minitest', '~> 5.0'
9
9
  gem 'rake', '~> 13.0'
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
10
+ gem 'rubocop', '~> 1.5.2'
11
+ gem 'simplecov', '~> 0.20.0', require: false # CodeClimate not compatible with 0.18+ yet - https://github.com/codeclimate/test-reporter/issues/413
12
12
  gem 'simplecov-lcov', '< 0.8'
data/README.md CHANGED
@@ -66,17 +66,10 @@ Currently there is not native support for rails, but ActiveSupport can be monkey
66
66
  the built in encrypter. All existing `rails credentials:edit` also work with this method.
67
67
 
68
68
  ```ruby
69
- require 'diffcrypt/rails/encrypted_configuration'
69
+ # config/application.rb
70
70
  module Rails
71
71
  class Application
72
- def encrypted(path, key_path: 'config/aes-128-gcm.key', env_key: 'RAILS_MASTER_KEY')
73
- Diffcrypt::Rails::EncryptedConfiguration.new(
74
- config_path: Rails.root.join(path),
75
- key_path: Rails.root.join(key_path),
76
- env_key: env_key,
77
- raise_if_missing_key: config.require_master_key,
78
- )
79
- end
72
+ include Diffcrypt::Rails::ApplicationHelper
80
73
  end
81
74
  end
82
75
  ```
data/Rakefile CHANGED
@@ -8,5 +8,7 @@ Rake::TestTask.new(:test) do |t|
8
8
  t.libs << 'lib'
9
9
  t.test_files = FileList['test/**/*_test.rb']
10
10
  end
11
-
12
11
  task default: :test
12
+
13
+ path = File.expand_path(__dir__)
14
+ Dir.glob("#{path}/lib/diffcrypt/tasks/**/*.rake").sort.each { |f| load f }
@@ -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.5.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
16
16
 
17
17
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
18
18
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'diffcrypt/encryptor'
4
4
  require 'diffcrypt/version'
5
+ require 'diffcrypt/railtie' if defined?(Rails)
5
6
 
6
7
  module Diffcrypt
7
8
  class Error < StandardError; end
@@ -12,7 +12,7 @@ require_relative './version'
12
12
 
13
13
  module Diffcrypt
14
14
  class Encryptor
15
- DEFAULT_CIPHER = 'aes-128-gcm'
15
+ DEFAULT_CIPHER = 'aes-256-gcm'
16
16
 
17
17
  def self.generate_key(cipher = DEFAULT_CIPHER)
18
18
  SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(cipher))
@@ -47,11 +47,11 @@ module Diffcrypt
47
47
  # @param [String] contents The raw YAML string to be encrypted
48
48
  # @param [String, nil] original_encrypted_contents The original (encrypted) content to determine which keys have changed
49
49
  # @return [String]
50
- def encrypt(contents, original_encrypted_contents = nil)
50
+ def encrypt(contents, original_encrypted_contents = nil, cipher: nil)
51
51
  data = encrypt_data contents, original_encrypted_contents
52
52
  YAML.dump(
53
53
  'client' => "diffcrypt-#{Diffcrypt::VERSION}",
54
- 'cipher' => @cipher,
54
+ 'cipher' => cipher || @cipher,
55
55
  'data' => data,
56
56
  )
57
57
  end
@@ -86,7 +86,7 @@ module Diffcrypt
86
86
  key_changed ? encrypt_string(value) : original_encrypted_value
87
87
  end
88
88
  end
89
- data
89
+ data.sort.to_h
90
90
  end
91
91
  # rubocop:enable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity
92
92
 
@@ -14,7 +14,10 @@ module Diffcrypt
14
14
  to_yaml['cipher']
15
15
  end
16
16
 
17
+ # Determines the cipher to use for encryption/decryption
17
18
  def cipher
19
+ return 'aes-128-gcm' if format == 'activesupport'
20
+
18
21
  to_yaml['cipher'] || Encryptor::DEFAULT_CIPHER
19
22
  end
20
23
 
@@ -23,11 +26,33 @@ module Diffcrypt
23
26
  ::File.exist?(@path)
24
27
  end
25
28
 
29
+ # Determines the format to be used for encryption
30
+ # @return [String] diffcrypt|activesupport
31
+ def format
32
+ return 'diffcrypt' if read == ''
33
+ return 'diffcrypt' if read.index('---')&.zero?
34
+
35
+ 'activesupport'
36
+ end
37
+
26
38
  # @return [String] Raw contents of the file
27
39
  def read
40
+ return '' unless ::File.exist?(@path)
41
+
28
42
  @read ||= ::File.read(@path)
43
+ @read
44
+ end
45
+
46
+ # Save the encrypted contents back to disk
47
+ # @return [Boolean] True is file save was successful
48
+ def write(key, data, cipher: nil)
49
+ cipher ||= self.cipher
50
+ yaml = ::YAML.dump(data)
51
+ contents = Encryptor.new(key, cipher: cipher).encrypt(yaml)
52
+ ::File.write(@path, contents)
29
53
  end
30
54
 
55
+ # TODO: This seems useless, figure out what's up
31
56
  def encrypt(key, cipher: DEFAULT_CIPHER)
32
57
  return read if encrypted?
33
58
 
@@ -42,7 +67,7 @@ module Diffcrypt
42
67
  end
43
68
 
44
69
  def to_yaml
45
- @to_yaml ||= YAML.safe_load(read)
70
+ @to_yaml ||= YAML.safe_load(read) || {}
46
71
  end
47
72
  end
48
73
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './encrypted_configuration'
4
+
5
+ module Diffcrypt
6
+ module Rails
7
+ module ApplicationHelper
8
+ def encrypted(path, key_path: 'config/master.key', env_key: 'RAILS_MASTER_KEY')
9
+ config_path, key_path = resolve_encrypted_paths(path, key_path)
10
+
11
+ Diffcrypt::Rails::EncryptedConfiguration.new(
12
+ config_path: config_path,
13
+ key_path: key_path,
14
+ env_key: env_key,
15
+ raise_if_missing_key: config.require_master_key,
16
+ )
17
+ end
18
+
19
+ protected
20
+
21
+ def resolve_encrypted_paths(config_path, key_path)
22
+ config_path_abs = ::Rails.root.join(config_path)
23
+ key_path_abs = ::Rails.root.join(key_path)
24
+
25
+ # We always want to use `config/credentials/[environment]` for consistency
26
+ # If the master credentials do not exist, and a user has not specificed an environment, default to development
27
+ if config_path == 'config/credentials.yml.enc' && ::File.exist?(config_path_abs.to_s) == false
28
+ config_path_abs = ::Rails.root.join('config/credentials/development.yml.enc')
29
+ key_path_abs = ::Rails.root.join('config/credentials/development.key')
30
+ end
31
+
32
+ [
33
+ config_path_abs,
34
+ key_path_abs,
35
+ ]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -88,6 +88,13 @@ module Diffcrypt
88
88
  end
89
89
  # rubocop:enable Metrics/AbcSize
90
90
 
91
+ # Standard rails credentials encrypt the entire file. We need to detect this to use the correct
92
+ # data interface
93
+ # @return [Boolean]
94
+ def rails_native_credentials?(contents)
95
+ contents.index('---').nil?
96
+ end
97
+
91
98
  # @param [String] contents The new content to be encrypted
92
99
  # @param [String] diff_against The original (encrypted) content to determine which keys have changed
93
100
  # @return [String] Encrypted content to commit
@@ -98,7 +105,7 @@ module Diffcrypt
98
105
  # @param [String] contents
99
106
  # @return [String]
100
107
  def decrypt(contents)
101
- if contents.index('---').nil?
108
+ if rails_native_credentials?(contents)
102
109
  active_support_encryptor.decrypt_and_verify contents
103
110
  else
104
111
  encryptor.decrypt contents
@@ -110,7 +117,7 @@ module Diffcrypt
110
117
  def active_support_encryptor
111
118
  @active_support_encryptor ||= ActiveSupport::MessageEncryptor.new(
112
119
  [key].pack('H*'),
113
- cipher: @diffcrypt_file.cipher,
120
+ cipher: 'aes-128-gcm',
114
121
  )
115
122
  end
116
123
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'diffcrypt/rails/application_helper'
4
+
5
+ module Diffcrypt
6
+ class Railtie < ::Rails::Railtie
7
+ railtie_name :diffcrypt
8
+
9
+ rake_tasks do
10
+ path = ::File.expand_path(__dir__)
11
+ ::Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :diffcrypt do
4
+ desc 'Initialize credentials for all environments'
5
+ task :init, %i[environments] do |_t, args|
6
+ args.with_defaults(
7
+ environments: 'development,test,staging,production',
8
+ )
9
+ environments = args.environments.split(',')
10
+
11
+ environments.each do |environment|
12
+ key_path = Rails.root.join('config', 'credentials', "#{environment}.key")
13
+ file_path = Rails.root.join('config', 'credentials', "#{environment}.yml.enc")
14
+ gitignore_path = Rails.root.join('.gitignore')
15
+ next if File.exist?(file_path) || File.exist?(key_path)
16
+
17
+ # Generate a new key
18
+ key = Diffcrypt::Encryptor.generate_key
19
+ key_dir = File.dirname(key_path)
20
+ Dir.mkdir(key_dir) unless Dir.exist?(key_dir)
21
+ ::File.write(key_path, key)
22
+
23
+ # Encrypt default contents
24
+ file = Diffcrypt::File.new(file_path)
25
+ data = {
26
+ 'secret_key_base' => SecureRandom.hex(32),
27
+ }
28
+ file.write(key, data)
29
+
30
+ # Ensure .key files are always ignored
31
+ ::File.open(gitignore_path, 'a') do |f|
32
+ f.write("\nconfig/credentials/*.key")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Diffcrypt
4
- VERSION = '0.4.1'
4
+ VERSION = '0.5.0'
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.4.1
4
+ version: 0.5.0
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-10-06 00:00:00.000000000 Z
11
+ date: 2020-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -71,7 +71,10 @@ files:
71
71
  - lib/diffcrypt/cli.rb
72
72
  - lib/diffcrypt/encryptor.rb
73
73
  - lib/diffcrypt/file.rb
74
+ - lib/diffcrypt/rails/application_helper.rb
74
75
  - lib/diffcrypt/rails/encrypted_configuration.rb
76
+ - lib/diffcrypt/railtie.rb
77
+ - lib/diffcrypt/tasks/rails.rake
75
78
  - lib/diffcrypt/version.rb
76
79
  - tmp/.keep
77
80
  homepage: https://github.com/marcqualie/diffcrypt
@@ -88,7 +91,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
91
  requirements:
89
92
  - - ">="
90
93
  - !ruby/object:Gem::Version
91
- version: 2.5.0
94
+ version: 2.6.0
92
95
  required_rubygems_version: !ruby/object:Gem::Requirement
93
96
  requirements:
94
97
  - - ">="