secure_yaml_2 2.0.2
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 +7 -0
- data/.github/workflows/gem-push.yml +48 -0
- data/.gitignore +13 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/README.md +105 -0
- data/Rakefile +7 -0
- data/bin/encrypt_property_for_yaml +5 -0
- data/lib/secure_yaml/cipher.rb +34 -0
- data/lib/secure_yaml/cli/property_encryption_application.rb +24 -0
- data/lib/secure_yaml/loader.rb +17 -0
- data/lib/secure_yaml/version.rb +5 -0
- data/lib/secure_yaml/yaml_decrypter.rb +27 -0
- data/lib/secure_yaml.rb +33 -0
- data/secure_yaml.gemspec +26 -0
- data/spec/fixtures/test.yml +2 -0
- data/spec/integration/secure_yaml_spec.rb +37 -0
- data/spec/secure_yaml_spec.rb +67 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/secure_yaml/cipher_spec.rb +20 -0
- data/spec/unit/secure_yaml/cli/property_encryption_application_spec.rb +30 -0
- data/spec/unit/secure_yaml/loader_spec.rb +20 -0
- data/spec/unit/secure_yaml/yaml_decrypter_spec.rb +72 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 167d84bdf5fe42049700e9d4ba54dbf21713597c16b770eaed129cf720c528b5
|
4
|
+
data.tar.gz: 2a6ac9b2a603f192daacfebd8f90f8cdf93a2bed21f4498979e0e72255368efe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4ca2685c567a395b3de60c04dd1a99a6a9640513098d2168f867a99ee15f9bdf73522453f693279097e565e31e83c62976a4701ca31b01ec1bc772af6cb2451b
|
7
|
+
data.tar.gz: b05af0c5798f12ac926c036af923099c9ce35de97fb8c6d53761642103ea39bd0b853232d68b3bdc240918866e6adc0c3905b609d7f0939b219bbd29bd40a878
|
@@ -0,0 +1,48 @@
|
|
1
|
+
name: Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ "master" ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ "master" ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
name: Build + Publish
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
permissions:
|
14
|
+
contents: read
|
15
|
+
packages: write
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v3
|
19
|
+
- name: Set up Ruby 3.2
|
20
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
21
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
22
|
+
# uses: ruby/setup-ruby@v1
|
23
|
+
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
|
24
|
+
with:
|
25
|
+
ruby-version: 3.2.2
|
26
|
+
|
27
|
+
- name: Publish to GPR
|
28
|
+
run: |
|
29
|
+
mkdir -p $HOME/.gem
|
30
|
+
touch $HOME/.gem/credentials
|
31
|
+
chmod 0600 $HOME/.gem/credentials
|
32
|
+
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
33
|
+
gem build *.gemspec
|
34
|
+
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
35
|
+
env:
|
36
|
+
GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
|
37
|
+
OWNER: ${{ github.repository_owner }}
|
38
|
+
|
39
|
+
- name: Publish to RubyGems
|
40
|
+
run: |
|
41
|
+
mkdir -p $HOME/.gem
|
42
|
+
touch $HOME/.gem/credentials
|
43
|
+
chmod 0600 $HOME/.gem/credentials
|
44
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
45
|
+
gem build *.gemspec
|
46
|
+
gem push *.gem
|
47
|
+
env:
|
48
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm ruby-3.2.2
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
### Overview
|
2
|
+
|
3
|
+
The storage of sensitive information (such as usernames and passwords) within source control is commonly avoided due to security concerns, i.e. an untrusted person gaining access to your code, would have access to your production database password.
|
4
|
+
|
5
|
+
This library attempts to address this concern by allowing sensitive information to be stored in YAML files in an encrypted form. Inspired by [Jasypt](http://www.jasypt.org/encrypting-configuration.html).
|
6
|
+
<br />
|
7
|
+
|
8
|
+
### Usage
|
9
|
+
|
10
|
+
<strong>1) Install the secure_yaml gem</strong>
|
11
|
+
|
12
|
+
```
|
13
|
+
> gem install secure_yaml
|
14
|
+
```
|
15
|
+
<br />
|
16
|
+
|
17
|
+
<strong>2) Encrypt your sensitive properties, and copy them into your YAML file</strong>
|
18
|
+
|
19
|
+
The gem provides a simple command line utility called ```encrypt_property_for_yaml``` that prints out the encrypted form of a plain text property.
|
20
|
+
|
21
|
+
```
|
22
|
+
USAGE: encrypt_property_for_yaml encrypt|decrypt <SECRET_KEY> <PROPERTY_VALUE_TO_ENCRYPT>
|
23
|
+
```
|
24
|
+
|
25
|
+
For example:
|
26
|
+
|
27
|
+
```
|
28
|
+
> encrypt_property_for_yaml abc12345678 jdbc:mysql://11.22.33.44:3306/prod
|
29
|
+
ENC(1BVzrT18dxWisIKUPkq9k0SB/aKcT70VawodxucI) <-- copy this value into your YAML file
|
30
|
+
```
|
31
|
+
|
32
|
+
When completed, your YAML file might look something like the following:
|
33
|
+
|
34
|
+
```
|
35
|
+
production:
|
36
|
+
db_adapter: mysql
|
37
|
+
db_url: ENC(1BVzrT18dxWisIKUPkq9k0SB/aKcT70VawodxucI)
|
38
|
+
db_username: ENC(4BEzrT18dxdisIKFPkw7k0SB/hKcT80VawodxuwT)
|
39
|
+
db_password: ENC(2BVzrQ79deWisIKUPkq9k8SB/aKcT74CawoExuiP)
|
40
|
+
pool: 5
|
41
|
+
timeout: 5000
|
42
|
+
|
43
|
+
```
|
44
|
+
|
45
|
+
Note:
|
46
|
+
* your YAML file can consist of a combination of plain text and encrypted property values
|
47
|
+
* the encrypted properties can be positioned within the YAML at any nested depth.
|
48
|
+
|
49
|
+
<br />
|
50
|
+
|
51
|
+
<strong>3) Supply the secret key (used by the encryption process in step 2) as an environmental property to your running app</strong>
|
52
|
+
|
53
|
+
By default, the expected name of this environmental property is 'PROPERTIES_ENCRYPTION_PASSWORD', but can be overridden if required.
|
54
|
+
|
55
|
+
```
|
56
|
+
export PROPERTIES_ENCRYPTION_PASSWORD=abc12345678; ruby app.rb
|
57
|
+
```
|
58
|
+
|
59
|
+
<strong>*** The value of the secret key must NOT be submitted to source control. Knowing the secret key allows a person to easily decrypt your properties.</strong>
|
60
|
+
<br />
|
61
|
+
<br />
|
62
|
+
|
63
|
+
<strong>4) Load and use the decrypted version of your YAML file within your app</strong>
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
require 'secure_yaml'
|
67
|
+
|
68
|
+
decrypted_yaml = SecureYaml::load(File.open('database.yml'))
|
69
|
+
|
70
|
+
# Alternatively, to override the default secret key environmental property name:
|
71
|
+
decrypted_yaml = SecureYaml::load(File.open('database.yml'), {
|
72
|
+
:secret_key_property_name => 'NEW_SECRET_KEY_PROPERTY_NAME'
|
73
|
+
})
|
74
|
+
```
|
75
|
+
|
76
|
+
<br />
|
77
|
+
<strong>4) Parse and use the decrypted version of a YAML string within your app</strong>
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
require 'secure_yaml'
|
81
|
+
|
82
|
+
decrypted_yaml = SecureYaml::parse("some correctly formatted yaml text")
|
83
|
+
```
|
84
|
+
<br />
|
85
|
+
|
86
|
+
### Customising decryption
|
87
|
+
|
88
|
+
The default decryption method applied by this library when loading a YAML file is [AES-256-CFB](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard).
|
89
|
+
However, if you wish to, you can specify your own custom decryption algorithm:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
require 'secure_yaml'
|
93
|
+
|
94
|
+
custom_decryption_algorithm = Class.new {
|
95
|
+
def self.decrypt(secret_key, encrypted_data)
|
96
|
+
"your decrypted data returned here"
|
97
|
+
end
|
98
|
+
}
|
99
|
+
|
100
|
+
decrypted_yaml = SecureYaml::load(File.open('database.yml'), {
|
101
|
+
:decryption_algorithm => custom_decryption_algorithm
|
102
|
+
})
|
103
|
+
```
|
104
|
+
|
105
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'digest/sha2'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module SecureYaml
|
6
|
+
|
7
|
+
class Cipher
|
8
|
+
|
9
|
+
def encrypt(secret_key, plain_data)
|
10
|
+
cipher = create_cipher(:encrypt, secret_key)
|
11
|
+
strip_newline_chars_from_base64(Base64.encode64(cipher.update(plain_data) + cipher.final))
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrypt(secret_key, encrypted_data)
|
15
|
+
cipher = create_cipher(:decrypt, secret_key)
|
16
|
+
cipher.update(Base64.decode64(encrypted_data)) + cipher.final
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def create_cipher(mode, secret_key)
|
22
|
+
cipher = OpenSSL::Cipher.new("AES-256-CFB")
|
23
|
+
cipher.send(mode)
|
24
|
+
cipher.key = Digest::SHA2.new(256).digest(secret_key)
|
25
|
+
cipher
|
26
|
+
end
|
27
|
+
|
28
|
+
def strip_newline_chars_from_base64(base64)
|
29
|
+
base64.gsub("\n", '')
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "secure_yaml"
|
2
|
+
|
3
|
+
module SecureYaml
|
4
|
+
|
5
|
+
class PropertyEncryptionApplication
|
6
|
+
|
7
|
+
def execute(command_line_args)
|
8
|
+
|
9
|
+
raise "USAGE: encrypt_property_for_yaml encrypt|decrypt <SECRET_KEY> <PROPERTY_VALUE_TO_ENCRYPT>" unless command_line_args.length == 3
|
10
|
+
|
11
|
+
mode = command_line_args[0]
|
12
|
+
secret_key = command_line_args[1]
|
13
|
+
plain_text = command_line_args[2]
|
14
|
+
|
15
|
+
if mode == 'encrypt'
|
16
|
+
puts "#{ENCRYPTED_PROPERTY_WRAPPER_ID}(#{Cipher.new.encrypt(secret_key, plain_text)})"
|
17
|
+
else
|
18
|
+
puts Cipher.new.decrypt(secret_key, plain_text)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'secure_yaml/yaml_decrypter'
|
2
|
+
|
3
|
+
module SecureYaml
|
4
|
+
|
5
|
+
class Loader
|
6
|
+
|
7
|
+
def initialize(yaml_decrypter)
|
8
|
+
@yaml_decrypter = yaml_decrypter
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(yaml_file)
|
12
|
+
@yaml_decrypter.decrypt(YAML::load(yaml_file, aliases: true))
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SecureYaml
|
4
|
+
|
5
|
+
class YamlDecrypter
|
6
|
+
|
7
|
+
def initialize(decryption_algorithm, secret_key)
|
8
|
+
@decryption_algorithm = decryption_algorithm
|
9
|
+
@secret_key = secret_key
|
10
|
+
end
|
11
|
+
|
12
|
+
def decrypt(yaml)
|
13
|
+
case yaml
|
14
|
+
when Hash
|
15
|
+
yaml.inject({}) {|new_hash, (key, value)| new_hash[key] = decrypt(value); new_hash}
|
16
|
+
when String
|
17
|
+
yaml.gsub(/\b#{ENCRYPTED_PROPERTY_WRAPPER_ID}\((.*)\)(?:\b|$)/) {@decryption_algorithm.decrypt(@secret_key, $1)}
|
18
|
+
when Array
|
19
|
+
yaml.map {|element| decrypt(element)}
|
20
|
+
else
|
21
|
+
yaml
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/secure_yaml.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'secure_yaml/loader'
|
2
|
+
require 'secure_yaml/cipher'
|
3
|
+
|
4
|
+
module SecureYaml
|
5
|
+
|
6
|
+
ENCRYPTED_PROPERTY_WRAPPER_ID = 'ENC'
|
7
|
+
|
8
|
+
DEFAULT_SECRET_KEY_PROP_NAME = 'PROPERTIES_ENCRYPTION_PASSWORD'
|
9
|
+
|
10
|
+
def self.load(yaml_file, opts = {})
|
11
|
+
opts[:secret_key_property_name] ||= DEFAULT_SECRET_KEY_PROP_NAME
|
12
|
+
opts[:decryption_algorithm] ||= Cipher.new
|
13
|
+
|
14
|
+
yaml_loader(opts[:decryption_algorithm], retrieve_secret_key(opts[:secret_key_property_name])).load(yaml_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse(yaml, opts = {})
|
18
|
+
load(StringIO.new(yaml), opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.retrieve_secret_key(secret_key_prop_name)
|
24
|
+
secret_key = ENV[secret_key_prop_name]
|
25
|
+
raise "#{secret_key_prop_name} env property not found" if secret_key.nil?
|
26
|
+
secret_key
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.yaml_loader(decryption_algorithm, secret_key)
|
30
|
+
Loader.new(YamlDecrypter.new(decryption_algorithm, secret_key))
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/secure_yaml.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "secure_yaml/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "secure_yaml_2"
|
7
|
+
s.version = SecureYaml::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Huw Lewis"]
|
10
|
+
s.email = ["huwtlewis@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/qmg-hlewis/secure_yaml"
|
12
|
+
s.summary = %q{encryption protection for sensitive yaml properties}
|
13
|
+
s.description = %q{encryption protection for sensitive yaml properties}
|
14
|
+
|
15
|
+
s.rubyforge_project = "secure_yaml_2"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency 'rspec', "~> 2.10"
|
22
|
+
s.add_development_dependency 'rspec-mocks', "~> 2.10"
|
23
|
+
s.add_development_dependency 'bundler', "~> 1.1"
|
24
|
+
s.add_development_dependency 'rake', "~> 0.9"
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'SecureYaml' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@secret_key = 'secret'
|
7
|
+
ENV[SecureYaml::DEFAULT_SECRET_KEY_PROP_NAME] = @secret_key
|
8
|
+
@test_yaml_file = File.open('spec/fixtures/test.yml')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should load encrypted yaml file using default decryption algorithm' do
|
12
|
+
yaml = SecureYaml::load(@test_yaml_file)
|
13
|
+
|
14
|
+
yaml.should == {'plain_prop' => '1234', 'encrypted_prop' => 'secret-text'}
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should decrypt yaml using custom decryption algorithm' do
|
18
|
+
custom_decryption_algorithm = Class.new {
|
19
|
+
def self.decrypt(secret_key, encrypted_data)
|
20
|
+
"decrypted!"
|
21
|
+
end
|
22
|
+
}
|
23
|
+
|
24
|
+
yaml = SecureYaml::load(@test_yaml_file, {:decryption_algorithm => custom_decryption_algorithm})
|
25
|
+
|
26
|
+
yaml.should == {'plain_prop' => '1234', 'encrypted_prop' => 'decrypted!'}
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should parse encrypted yaml string using default decryption algorithm' do
|
30
|
+
encrypted_yaml_str = {:plain_prop => '1234', :encrypted_prop => 'ENC(EBnrEqmvC5BbOXw=)'}.to_yaml
|
31
|
+
|
32
|
+
yaml = SecureYaml::parse(encrypted_yaml_str)
|
33
|
+
|
34
|
+
yaml.should == {:plain_prop => '1234', :encrypted_prop => 'secret-text'}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'SecureYaml' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@secret_key = 'secret key'
|
7
|
+
@yaml = {:prop => 'test'}
|
8
|
+
|
9
|
+
@default_decryption_algorithm = double(SecureYaml::Cipher)
|
10
|
+
SecureYaml::Cipher.stub(:new).and_return(@default_decryption_algorithm)
|
11
|
+
|
12
|
+
|
13
|
+
@loader = double(SecureYaml::Loader)
|
14
|
+
@yaml_decrypter = double(SecureYaml::YamlDecrypter)
|
15
|
+
SecureYaml::Loader.stub(:new).with(@yaml_decrypter).and_return(@loader)
|
16
|
+
@loader.stub(:load).and_return(@yaml)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should load encrypted yaml file' do
|
20
|
+
ENV[SecureYaml::DEFAULT_SECRET_KEY_PROP_NAME] = @secret_key
|
21
|
+
SecureYaml::YamlDecrypter.stub(:new).with(@default_decryption_algorithm, @secret_key).and_return(@yaml_decrypter)
|
22
|
+
|
23
|
+
yaml = SecureYaml::load(double(File))
|
24
|
+
|
25
|
+
yaml.should == @yaml
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should parse encrypted yaml string' do
|
29
|
+
ENV[SecureYaml::DEFAULT_SECRET_KEY_PROP_NAME] = @secret_key
|
30
|
+
SecureYaml::YamlDecrypter.stub(:new).with(@default_decryption_algorithm, @secret_key).and_return(@yaml_decrypter)
|
31
|
+
|
32
|
+
yaml = SecureYaml::parse("")
|
33
|
+
|
34
|
+
yaml.should == @yaml
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should raise error on load if secret key env property not set' do
|
38
|
+
ENV[SecureYaml::DEFAULT_SECRET_KEY_PROP_NAME] = nil
|
39
|
+
|
40
|
+
expect {SecureYaml::load(double(File))}.to raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should allow use of custom secret key property name' do
|
44
|
+
custom_secret_key_prop_name = 'CUSTOMER_SECRET_KEY_PROP_NAME'
|
45
|
+
ENV[custom_secret_key_prop_name] = @secret_key
|
46
|
+
SecureYaml::YamlDecrypter.stub(:new).with(@default_decryption_algorithm, @secret_key).and_return(@yaml_decrypter)
|
47
|
+
|
48
|
+
yaml = SecureYaml::load(double(File), {:secret_key_property_name => custom_secret_key_prop_name})
|
49
|
+
|
50
|
+
yaml.should == @yaml
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should allow use of custom decryption algorithm' do
|
54
|
+
ENV[SecureYaml::DEFAULT_SECRET_KEY_PROP_NAME] = @secret_key
|
55
|
+
custom_decryption_algorithm = Class.new {
|
56
|
+
def self.decrypt(secret_key, encrypted_data)
|
57
|
+
"decrypt data here from #{secret_key} and #{encrypted_data}"
|
58
|
+
end
|
59
|
+
}
|
60
|
+
SecureYaml::YamlDecrypter.stub(:new).with(custom_decryption_algorithm, @secret_key).and_return(@yaml_decrypter)
|
61
|
+
|
62
|
+
yaml = SecureYaml::load(double(File), {:decryption_algorithm => custom_decryption_algorithm})
|
63
|
+
|
64
|
+
yaml.should == @yaml
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Cipher' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@cipher = SecureYaml::Cipher.new
|
7
|
+
@secret_key = "abc12345678"
|
8
|
+
@plain_text = "some plain text to encrypt"
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should decrypt encrypted data' do
|
12
|
+
encrypted = @cipher.encrypt(@secret_key, @plain_text)
|
13
|
+
|
14
|
+
decrypted = @cipher.decrypt(@secret_key, encrypted)
|
15
|
+
|
16
|
+
encrypted.should_not == @plain_text
|
17
|
+
decrypted.should == @plain_text
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Property encryption command line interface' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@secret_key = 'secret key'
|
7
|
+
@plain_text = 'text to encrypt'
|
8
|
+
@encrypted_text = 'encrypted text'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should print encrypted property value for given secret key and plain text' do
|
12
|
+
cipher = double(SecureYaml::Cipher)
|
13
|
+
cipher.stub(:encrypt).with(@secret_key, @plain_text).and_return(@encrypted_text)
|
14
|
+
SecureYaml::Cipher.stub(:new).and_return(cipher)
|
15
|
+
|
16
|
+
$stdout.should_receive(:puts).with("#{SecureYaml::ENCRYPTED_PROPERTY_WRAPPER_ID}(#{@encrypted_text})")
|
17
|
+
|
18
|
+
SecureYaml::PropertyEncryptionApplication.new.execute(["encrypt", @secret_key, @plain_text])
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should raise error unless secret key and plain text have been included as command line args' do
|
22
|
+
expect {SecureYaml::PropertyEncrypterApplication.new.execute([])}.to raise_error
|
23
|
+
expect {SecureYaml::PropertyEncrypterApplication.new.execute([@secret_key])}.to raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should raise error if too many comand line args' do
|
27
|
+
expect {SecureYaml::PropertyEncryptionApplication.new.execute(["encrypt", @secret_key, @plain_text, 'unexpected'])}.to raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Loader' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@encrypted_yaml = {:prop => 'encrypted'}
|
7
|
+
@decrypted_yaml = {:prop => 'decrytped'}
|
8
|
+
@decrypter = double(SecureYaml::YamlDecrypter)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should load decrypted yaml file' do
|
12
|
+
YAML.stub(:load).and_return(@encrypted_yaml)
|
13
|
+
@decrypter.stub(:decrypt).with(@encrypted_yaml).and_return(@decrypted_yaml)
|
14
|
+
|
15
|
+
yaml = SecureYaml::Loader.new(@decrypter).load(double(File))
|
16
|
+
|
17
|
+
yaml.should == @decrypted_yaml
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Yaml decrypter' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@secret_key = 'abc12345678'
|
7
|
+
@cipher = double(SecureYaml::Cipher)
|
8
|
+
@decrypter = SecureYaml::YamlDecrypter.new(@cipher, @secret_key)
|
9
|
+
@decrypted_result = 'decrypted data'
|
10
|
+
@plain_text = 'some plain text'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should decrypt encoded values in plain strings' do
|
14
|
+
encrypted_data = 'encrypted data'
|
15
|
+
@cipher.stub(:decrypt).with(@secret_key, encrypted_data).and_return(@decrypted_result)
|
16
|
+
hash = {:encrypted_prop => "ENC(#{encrypted_data})", :plain_prop => @plain_text}
|
17
|
+
data = @decrypter.decrypt(hash.to_yaml)
|
18
|
+
YAML.load(data).should == {:encrypted_prop => @decrypted_result, :plain_prop => @plain_text}
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should decrypt only marked encrypted properties' do
|
22
|
+
encrypted_data = 'encrypted data'
|
23
|
+
@cipher.stub(:decrypt).with(@secret_key, encrypted_data).and_return(@decrypted_result)
|
24
|
+
|
25
|
+
data = @decrypter.decrypt({:encrypted_prop => "ENC(#{encrypted_data})", :plain_prop => @plain_text})
|
26
|
+
|
27
|
+
data.should == {:encrypted_prop => @decrypted_result, :plain_prop => @plain_text}
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should decrypt encrypted properties containing parentheses' do
|
31
|
+
encrypted_prop_with_param = 'encrypted )data'
|
32
|
+
@cipher.stub(:decrypt).with(@secret_key, encrypted_prop_with_param).and_return(@decrypted_result)
|
33
|
+
|
34
|
+
data = @decrypter.decrypt({:encrypted_prop => "ENC(#{encrypted_prop_with_param})"})
|
35
|
+
|
36
|
+
data.should == {:encrypted_prop => @decrypted_result}
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should ignore any encrypted properties in unexpected formats' do
|
40
|
+
unexpected_formats = {:unexpected_1 => 'ENC(text', :unexpected_2 => 'ENCtext)', :unexpected_3 => 'EN(text)'}
|
41
|
+
|
42
|
+
data = @decrypter.decrypt(unexpected_formats)
|
43
|
+
|
44
|
+
data.should == unexpected_formats
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should recursively encrypt nested properties' do
|
48
|
+
@cipher.stub(:decrypt).and_return(@decrypted_result)
|
49
|
+
|
50
|
+
data = @decrypter.decrypt({:parent_prop => {:nested_prop => 'ENC(text)', :parent_prop_2 => {:nested_prop_2 => 'ENC(text)'}}})
|
51
|
+
|
52
|
+
data.should == {:parent_prop => {:nested_prop => @decrypted_result, :parent_prop_2 => {:nested_prop_2 => @decrypted_result}}}
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should decrypt encrypted properties of array elements' do
|
56
|
+
encrypted_data = 'encrypted data'
|
57
|
+
@cipher.stub(:decrypt).and_return(@decrypted_result)
|
58
|
+
|
59
|
+
data = @decrypter.decrypt([{:encrypted_prop => "ENC(#{encrypted_data})"}])
|
60
|
+
|
61
|
+
data.should == [{:encrypted_prop => @decrypted_result}]
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should ignore any property of non-string type' do
|
65
|
+
numeric_prop = {:numeric => 1}
|
66
|
+
|
67
|
+
data = @decrypter.decrypt(numeric_prop)
|
68
|
+
|
69
|
+
data.should == numeric_prop
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: secure_yaml_2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Huw Lewis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-01-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-mocks
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
description: encryption protection for sensitive yaml properties
|
70
|
+
email:
|
71
|
+
- huwtlewis@gmail.com
|
72
|
+
executables:
|
73
|
+
- encrypt_property_for_yaml
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".github/workflows/gem-push.yml"
|
78
|
+
- ".gitignore"
|
79
|
+
- ".rvmrc"
|
80
|
+
- Gemfile
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/encrypt_property_for_yaml
|
84
|
+
- lib/secure_yaml.rb
|
85
|
+
- lib/secure_yaml/cipher.rb
|
86
|
+
- lib/secure_yaml/cli/property_encryption_application.rb
|
87
|
+
- lib/secure_yaml/loader.rb
|
88
|
+
- lib/secure_yaml/version.rb
|
89
|
+
- lib/secure_yaml/yaml_decrypter.rb
|
90
|
+
- secure_yaml.gemspec
|
91
|
+
- spec/fixtures/test.yml
|
92
|
+
- spec/integration/secure_yaml_spec.rb
|
93
|
+
- spec/secure_yaml_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
- spec/unit/secure_yaml/cipher_spec.rb
|
96
|
+
- spec/unit/secure_yaml/cli/property_encryption_application_spec.rb
|
97
|
+
- spec/unit/secure_yaml/loader_spec.rb
|
98
|
+
- spec/unit/secure_yaml/yaml_decrypter_spec.rb
|
99
|
+
homepage: https://github.com/qmg-hlewis/secure_yaml
|
100
|
+
licenses: []
|
101
|
+
metadata: {}
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubygems_version: 3.4.10
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: encryption protection for sensitive yaml properties
|
121
|
+
test_files: []
|