secure_credentials 0.1.1 → 0.2.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: 67f34834484a909ed1ca0cdb4da8d09a57f9c1f2381237c6a22f95081827d4c9
4
- data.tar.gz: 2da212d3f2e4941c269937cbb40484b2e27d5d38609c224ca92a3b4d1af8d258
3
+ metadata.gz: 3f105345f86816004375c9c6aec5e6d48330f14768e4da243f0f0edf0894341b
4
+ data.tar.gz: c0a64940f0b7d72c8f338797dc4d35dd1493c88f8fdb2abd733ba6d7bb152947
5
5
  SHA512:
6
- metadata.gz: b0bbf47d6d142af404268bbfe991c40e9f502dc065e780fdcf2d6fa003c7bc6eaf374ee7c2a2d9aa2d4795266e2c561641d115425ee539afce23b803b9542577
7
- data.tar.gz: a6284aa14dd2998ca6cb6ca5fdd0bab26f5274a978704cf4339fc961ddca7df780352057b612a3f12786f782f659f4d247ad748de2ede16aaf951cd1eee7146d
6
+ metadata.gz: 36475092d3f12f08d1ab749694318bafe52c88a84b873149ab51fe3e13eaddd8dea317d1c05d541ec58a692a9c984d63a33cfe01c6094f64bc1484f71f265760
7
+ data.tar.gz: 6234c6c383e3ceff2c6db4f502e11a2325d7d61c8b1511588205d50f5750bbd90ebc26da5f0d631d7b67bc7aca246914abce0a0cecf0e9dc7a0873676fcecd74
data/.gitignore CHANGED
@@ -6,6 +6,8 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /gemfiles/.bundle
10
+ /gemfiles/*.lock
9
11
  Gemfile.lock
10
12
 
11
13
  # rspec failure tracking
data/.travis.yml CHANGED
@@ -4,13 +4,9 @@ cache: bundler
4
4
  rvm:
5
5
  - 2.5
6
6
  - 2.4
7
+ gemfile:
8
+ - gemfiles/rails_5.2.gemfile
9
+ - gemfiles/rails_5.1.gemfile
7
10
 
8
11
  notifications:
9
12
  email: false
10
-
11
- # for 2.5.0 until 2.5.1 is released:
12
- # https://github.com/travis-ci/travis-ci/issues/8978
13
- # https://github.com/travis-ci/travis-ci/issues/8969#issuecomment-354135622
14
- before_install:
15
- - gem update --system
16
- - gem install bundler
data/Appraisals ADDED
@@ -0,0 +1,7 @@
1
+ appraise 'rails_5.2' do
2
+ gem 'activesupport', '~> 5.2.0'
3
+ end
4
+
5
+ appraise 'rails_5.1' do
6
+ gem 'activesupport', '~> 5.1.0'
7
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # 0.2.1
2
+ - Rails 5.1 support.
3
+
4
+ # 0.1.1
5
+ - Initial release
data/Gemfile CHANGED
@@ -5,6 +5,8 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
5
5
  # Specify your gem's dependencies in gemspec file
6
6
  gemspec
7
7
 
8
+ gem 'appraisal'
9
+
8
10
  gem 'rspec', '~> 3.7'
9
11
  gem 'rspec-its', '~> 1.2'
10
12
 
data/README.md CHANGED
@@ -4,30 +4,29 @@
4
4
  [![Code Climate](https://codeclimate.com/github/printercu/secure_credentials/badges/gpa.svg)](https://codeclimate.com/github/printercu/secure_credentials)
5
5
  [![Build Status](https://travis-ci.org/printercu/secure_credentials.svg)](https://travis-ci.org/printercu/secure_credentials)
6
6
 
7
- Makes it possible to use best of encrypted credentials
8
- and environment-dependent secrets. Sharing encryption keys with
9
- every developer in a team is a security issue, and purpose of this gem
10
- is to help you to avoid it.
11
-
12
7
  ## Rationale
13
8
 
14
9
  Rails 5.2 brings good idea of storing encrypted credentials in the repo:
15
- credentials are securely tracked in version control, less chances to face an issue
10
+ credentials are securely tracked in version control, less chance to face an issue
16
11
  during deployment, etc. However there are several drawbacks in current implementation:
17
12
 
18
13
  - It's hard to manage environment-specific credentials.
19
- For example, use some different browser api keys in development and production,
14
+ For example, to use different browser api keys in development and production,
20
15
  one is whitelisted for `locahost` and other one for app's domain.
21
16
  - In most cases it's required to share `master.key` with every developer.
22
17
  This is not acceptable for a lot of teams, and framework must serve their needs too.
23
18
 
24
19
  There are a couple ways to workaround this issues, but all of them brings
25
- unnecessary complexity. This gem takes best from new encrypted `credentials.yml.enc`
26
- and multi-environmental `secrets.yml`. It allows to use combination
20
+ unnecessary complexity. This gem takes best from new encrypted credentials (`credentials.yml.enc`)
21
+ and multi-environmental secrets (`secrets.yml`). It allows to use combination
27
22
  of encrypted and plain files for same configuration in different environments.
28
23
  For example, having encrypted `credentials.production.yml.enc` for production
29
24
  and multi-environmental `credentials.yml` for all other environments.
30
25
 
26
+ There are some other issues caused by storing `master.key` in local repo.
27
+ See this wiki page for details:<br>
28
+ [Rails 5.2 credentials are not secure](https://github.com/printercu/secure_credentials/wiki/Rails-5.2-credentials-are-not-secure).
29
+
31
30
  ## Installation
32
31
 
33
32
  Add this line to your application's Gemfile:
@@ -45,7 +44,7 @@ And then execute:
45
44
  By default this gem patches Rails::Application to make `#credentials`, `#secrets` and `#encrypted`
46
45
  use Rails-compatible wrapper around SecureCredentials::Store.
47
46
 
48
- SecureCredentials::Store provides read-write interface for YAML configuration files. It supports:
47
+ SecureCredentials::Store provides read-write access to YAML configuration files. It supports:
49
48
 
50
49
  - both encrypted and plain files,
51
50
  - both file-per-environment and multi-environment files.
@@ -65,26 +64,28 @@ Otherwise `env` is used to fetch appropriate section.
65
64
  Key for decoding encoded files can be passed:
66
65
 
67
66
  - in `key` argument;
68
- - envvar identified by `env_key`, default is to upcased basename appended with `_KEY`
67
+ - in envvar identified by `env_key`, default is to upcased basename appended with `_KEY`
69
68
  (ex., `SECRETS_KEY`);
70
69
  - in file found at `key_path`,
71
70
  by default it uses filename and replaces `.yml.enc` with `.key`
72
71
  (`secrets.production.key` for `secrets.production.yml.enc`);
73
72
  - `SecureCredentials.master_key` which is read from `config/master.key` in Rails apps.
74
73
 
75
- Use `rails encrypted path/to/file.yml.enc -k path/to/key.key` to edit encrypted files.
74
+ To edit encrypted files use `rails encrypted:edit path/to/file.yml.enc -k path/to/key.key`.
76
75
  Missing `.key` and `.yml` files are automatically created when you edit them for the first time.
77
76
 
78
77
  ## Best practices
79
78
 
80
- - __Don't keep master.key in local repo!__
79
+ - __Don't keep master.key in local working directory!__
81
80
 
82
- It's the as PIN-code written on backside of credit card.
81
+ It's like a PIN-code written on backside of credit card.
83
82
  Keep it in secure place and use it when you need to modify credentials.
84
83
 
85
- - Don't share production credentials with those who must not access them.
84
+ - Don't share production credentials with those team members who don't need to access them.
86
85
 
87
86
  Secrets get less secret every time they are shared.
87
+ It's better to share some particular keys to selected developers,
88
+ instead of giving everybody access to all keys.
88
89
 
89
90
  ## Development
90
91
 
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "rspec", "~> 3.7"
7
+ gem "rspec-its", "~> 1.2"
8
+ gem "rubocop", "~> 0.56"
9
+ gem "pry", "~> 0.11"
10
+ gem "pry-byebug", "~> 3.6"
11
+ gem "activesupport", "~> 5.1.0"
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "rspec", "~> 3.7"
7
+ gem "rspec-its", "~> 1.2"
8
+ gem "rubocop", "~> 0.56"
9
+ gem "pry", "~> 0.11"
10
+ gem "pry-byebug", "~> 3.6"
11
+ gem "activesupport", "~> 5.2.0"
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copied from activesupport 5.2
4
+ # rubocop:disable all
5
+
6
+ require "pathname"
7
+ require "active_support/message_encryptor"
8
+
9
+ module ActiveSupport
10
+ class EncryptedFile
11
+ class MissingContentError < RuntimeError
12
+ def initialize(content_path)
13
+ super "Missing encrypted content file in #{content_path}."
14
+ end
15
+ end
16
+
17
+ class MissingKeyError < RuntimeError
18
+ def initialize(key_path:, env_key:)
19
+ super \
20
+ "Missing encryption key to decrypt file with. " +
21
+ "Ask your team for your master key and write it to #{key_path} or put it in the ENV['#{env_key}']."
22
+ end
23
+ end
24
+
25
+ CIPHER = "aes-128-gcm"
26
+
27
+ def self.generate_key
28
+ SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER))
29
+ end
30
+
31
+
32
+ attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
33
+
34
+ def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:)
35
+ @content_path, @key_path = Pathname.new(content_path), Pathname.new(key_path)
36
+ @env_key, @raise_if_missing_key = env_key, raise_if_missing_key
37
+ end
38
+
39
+ def key
40
+ read_env_key || read_key_file || handle_missing_key
41
+ end
42
+
43
+ def read
44
+ if !key.nil? && content_path.exist?
45
+ decrypt content_path.binread
46
+ else
47
+ raise MissingContentError, content_path
48
+ end
49
+ end
50
+
51
+ def write(contents)
52
+ IO.binwrite "#{content_path}.tmp", encrypt(contents)
53
+ FileUtils.mv "#{content_path}.tmp", content_path
54
+ end
55
+
56
+ def change(&block)
57
+ writing read, &block
58
+ end
59
+
60
+
61
+ private
62
+ def writing(contents)
63
+ tmp_file = "#{Process.pid}.#{content_path.basename.to_s.chomp('.enc')}"
64
+ tmp_path = Pathname.new File.join(Dir.tmpdir, tmp_file)
65
+ tmp_path.binwrite contents
66
+
67
+ yield tmp_path
68
+
69
+ updated_contents = tmp_path.binread
70
+
71
+ write(updated_contents) if updated_contents != contents
72
+ ensure
73
+ FileUtils.rm(tmp_path) if tmp_path.exist?
74
+ end
75
+
76
+
77
+ def encrypt(contents)
78
+ encryptor.encrypt_and_sign contents
79
+ end
80
+
81
+ def decrypt(contents)
82
+ encryptor.decrypt_and_verify contents
83
+ end
84
+
85
+ def encryptor
86
+ @encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: CIPHER)
87
+ end
88
+
89
+
90
+ def read_env_key
91
+ ENV[env_key]
92
+ end
93
+
94
+ def read_key_file
95
+ key_path.binread.strip if key_path.exist?
96
+ end
97
+
98
+ def handle_missing_key
99
+ raise MissingKeyError, key_path: key_path, env_key: env_key if raise_if_missing_key
100
+ end
101
+ end
102
+ end
103
+
104
+ # rubocop:enable all
@@ -1,5 +1,9 @@
1
1
  require 'securerandom'
2
- require 'active_support/encrypted_file'
2
+ begin
3
+ require 'active_support/encrypted_file'
4
+ rescue LoadError
5
+ require 'secure_credentials/active_support/encrypted_file'
6
+ end
3
7
 
4
8
  module SecureCredentials
5
9
  # Wraps ActiveSupport::EncryptedFile and provides passing key as an argument.
@@ -1,3 +1,3 @@
1
1
  module SecureCredentials
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.2.1'.freeze
3
3
  end
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ['lib']
21
21
 
22
- spec.add_dependency 'activesupport', '~> 5.2'
22
+ spec.add_dependency 'activesupport', '~> 5.1'
23
23
 
24
- spec.add_development_dependency 'bundler', '~> 1.16'
24
+ spec.add_development_dependency 'bundler', '> 1.16'
25
25
  spec.add_development_dependency 'rake', '~> 10.0'
26
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secure_credentials
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Melentiev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-01 00:00:00.000000000 Z
11
+ date: 2019-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,26 +16,26 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.2'
19
+ version: '5.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.2'
26
+ version: '5.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.16'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.16'
41
41
  - !ruby/object:Gem::Dependency
@@ -64,6 +64,8 @@ files:
64
64
  - ".rspec"
65
65
  - ".rubocop.yml"
66
66
  - ".travis.yml"
67
+ - Appraisals
68
+ - CHANGELOG.md
67
69
  - Gemfile
68
70
  - README.md
69
71
  - Rakefile
@@ -71,7 +73,10 @@ files:
71
73
  - bin/git-hooks/pre-commit
72
74
  - bin/install_git_hooks
73
75
  - bin/setup
76
+ - gemfiles/rails_5.1.gemfile
77
+ - gemfiles/rails_5.2.gemfile
74
78
  - lib/secure_credentials.rb
79
+ - lib/secure_credentials/active_support/encrypted_file.rb
75
80
  - lib/secure_credentials/credentials.rb
76
81
  - lib/secure_credentials/encrypted_file.rb
77
82
  - lib/secure_credentials/no_rails_patch.rb
@@ -98,8 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
103
  - !ruby/object:Gem::Version
99
104
  version: '0'
100
105
  requirements: []
101
- rubyforge_project:
102
- rubygems_version: 2.7.6
106
+ rubygems_version: 3.0.3
103
107
  signing_key:
104
108
  specification_version: 4
105
109
  summary: Rails credentials without security issues. With environments support.