puppet-decrypt 0.1.1 → 0.2.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.
- data/.gitignore +2 -0
- data/ChangeLog.md +10 -0
- data/Modulefile +1 -1
- data/README.md +7 -1
- data/lib/puppet-decrypt/decryptor.rb +10 -2
- data/lib/puppet-decrypt/key_loader.rb +20 -2
- data/lib/puppet-decrypt/version.rb +1 -1
- data/lib/puppet/face/crypt.rb +5 -1
- data/lib/puppet/parser/functions/decrypt.rb +7 -4
- data/lib/puppet/parser/functions/encrypt.rb +31 -0
- data/puppet-decrypt.gemspec +2 -2
- data/spec/functions/encrypt_spec.rb +63 -0
- metadata +125 -95
- checksums.yaml +0 -7
data/.gitignore
CHANGED
data/ChangeLog.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.2.0 (Aug 07, 2014)
|
2
|
+
|
3
|
+
Enhancements:
|
4
|
+
- Added an encrypt function (thanks @tioteath!)
|
5
|
+
|
6
|
+
Bugfixes:
|
7
|
+
- Fixed handling of absolute paths for to the secret key file (thanks @tioteath!)
|
8
|
+
- Removed unnecessary puts (thanks @tioteath!)
|
9
|
+
- Improved error handling (thanks @tioteath!)
|
10
|
+
|
1
11
|
## 0.1.1 (Jan 24, 2014)
|
2
12
|
|
3
13
|
Enhancements:
|
data/Modulefile
CHANGED
data/README.md
CHANGED
@@ -65,7 +65,7 @@ $ gem install encryptor
|
|
65
65
|
Puppet Decrypt can be installed with the puppet module subcommand, which is included in Puppet 2.7.14 and later.
|
66
66
|
|
67
67
|
``` shell
|
68
|
-
$ sudo puppet module install puppet_decrypt
|
68
|
+
$ sudo puppet module install devopsy-puppet_decrypt
|
69
69
|
```
|
70
70
|
The command will tell you where it is installing the module; take note:
|
71
71
|
|
@@ -119,6 +119,12 @@ In your puppet code, load the value normally and then pass it to decrypt.
|
|
119
119
|
decrypt(hiera('database_password'))
|
120
120
|
```
|
121
121
|
|
122
|
+
Or encrypt a secret passing it to encrypt, if you need to save the secret to
|
123
|
+
external storage, for example.
|
124
|
+
``` ruby
|
125
|
+
$encrypted_secret_to_save = encrypt($data)
|
126
|
+
```
|
127
|
+
|
122
128
|
### Overriding the secret key
|
123
129
|
|
124
130
|
Puppet Decrypt now supports using more than just the default secret key location. You can easily use multiple secret keys for the same project.
|
@@ -12,8 +12,16 @@ module Puppet
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def decrypt_hash(hash)
|
15
|
-
|
16
|
-
|
15
|
+
decrypt(hash['value'], hash['secretkey'] || hash['secret_key'])
|
16
|
+
end
|
17
|
+
|
18
|
+
def encrypt_hash(hash)
|
19
|
+
secret_key = hash['secretkey'] || hash['secret_key'] ||
|
20
|
+
File.join(KEY_DIR, DEFAULT_KEY)
|
21
|
+
salt = hash['salt'] || SecureRandom.base64
|
22
|
+
iv = hash['iv'] || OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
|
23
|
+
|
24
|
+
encrypt(hash['value'], secret_key, salt, iv)
|
17
25
|
end
|
18
26
|
|
19
27
|
def decrypt(value, secret_key_file)
|
@@ -1,9 +1,27 @@
|
|
1
|
+
require 'pathname'
|
1
2
|
module Puppet
|
2
3
|
module Decrypt
|
3
4
|
class KeyLoader
|
4
5
|
def load_key(secret_key_file)
|
5
|
-
|
6
|
-
|
6
|
+
|
7
|
+
# Dot not add directory if absolute path provided
|
8
|
+
if Pathname.new(secret_key_file).absolute?
|
9
|
+
full_path = secret_key_file
|
10
|
+
else
|
11
|
+
full_path = File.join(ENV['PUPPET_DECRYPT_KEYDIR'] ||
|
12
|
+
Puppet::Decrypt::Decryptor::KEY_DIR, secret_key_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Assume key file is specified as basename
|
16
|
+
if File.readable? full_path
|
17
|
+
secret_key_file = full_path
|
18
|
+
else
|
19
|
+
# Assume key file is specifed as full path
|
20
|
+
raise "Secret key file: #{secret_key_file} is not readable!" unless
|
21
|
+
File.readable? secret_key_file
|
22
|
+
end
|
23
|
+
|
24
|
+
File.open(secret_key_file, &:readline).chomp
|
7
25
|
end
|
8
26
|
end
|
9
27
|
end
|
data/lib/puppet/face/crypt.rb
CHANGED
@@ -41,6 +41,10 @@ Puppet::Face.define(:crypt, Puppet::Decrypt::VERSION) do
|
|
41
41
|
iv = options.delete(:iv) || OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
|
42
42
|
salt = options.delete(:salt) || SecureRandom.base64
|
43
43
|
secretkey = options[:secretkey]
|
44
|
+
unless secretkey.nil?
|
45
|
+
secretkey = File.expand_path(secretkey) if secretkey.start_with? '.'
|
46
|
+
end
|
47
|
+
|
44
48
|
Puppet::Decrypt::Decryptor.new(options).encrypt(plaintext_secret, secretkey, salt, iv)
|
45
49
|
end
|
46
50
|
end
|
@@ -56,4 +60,4 @@ Puppet::Face.define(:crypt, Puppet::Decrypt::VERSION) do
|
|
56
60
|
Puppet::Decrypt::Decryptor.new(options).decrypt(encrypted_secret, secretkey)
|
57
61
|
end
|
58
62
|
end
|
59
|
-
end
|
63
|
+
end
|
@@ -4,12 +4,15 @@ module Puppet::Parser::Functions
|
|
4
4
|
newfunction(:decrypt, :type => :rvalue) do |args|
|
5
5
|
options = {}
|
6
6
|
decrypt_args = {}
|
7
|
-
|
8
|
-
|
7
|
+
|
8
|
+
if args.first.is_a? String
|
9
|
+
decrypt_args['value'], decrypt_args['secret_key'] = args
|
10
|
+
elsif args.first.is_a? Hash
|
11
|
+
decrypt_args = args.first
|
9
12
|
else
|
10
|
-
|
11
|
-
puts "Using hash: #{decrypt_args}"
|
13
|
+
raise TypeError, "Expected String or Hash, given #{args.first.class}"
|
12
14
|
end
|
15
|
+
|
13
16
|
Puppet::Decrypt::Decryptor.new(options).decrypt_hash(decrypt_args)
|
14
17
|
end
|
15
18
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'puppet-decrypt'
|
2
|
+
|
3
|
+
module Puppet::Parser::Functions
|
4
|
+
newfunction(:encrypt, :type => :rvalue, :doc => <<-'DOC' ) do |args|
|
5
|
+
Encrypt data, using Decryptor.
|
6
|
+
|
7
|
+
This function expects four arguments:
|
8
|
+
- Data to encrypt.
|
9
|
+
- Secret key file path,
|
10
|
+
Puppet::Decrypt::Decryptor::DEFAULT_KEY by default.
|
11
|
+
Can be specified as basename in Puppet::Decrypt::Decryptor::KEY_DIR.
|
12
|
+
- Salt (optional), randomly generated by default.
|
13
|
+
- Initialization vector (optional), randomly generated by default,
|
14
|
+
mainly useful for tests.
|
15
|
+
DOC
|
16
|
+
|
17
|
+
encrypt_args = {}
|
18
|
+
|
19
|
+
if args.first.is_a? String
|
20
|
+
encrypt_args['value'], encrypt_args['secret_key'], encrypt_args['salt'],
|
21
|
+
encrypt_args['iv'] = args
|
22
|
+
elsif args.first.is_a? Hash
|
23
|
+
encrypt_args = args.first
|
24
|
+
else
|
25
|
+
raise TypeError, "Expected String or Hash, given #{args.first.class}"
|
26
|
+
end
|
27
|
+
|
28
|
+
Puppet::Decrypt::Decryptor.new.encrypt_hash(encrypt_args)
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/puppet-decrypt.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.description = %q{A gem for encrypting/decrypting secret values for use with Puppet}
|
12
12
|
gem.summary = %q{A shared secret strategy that works with any data source}
|
13
13
|
gem.homepage = "https://github.com/maxlinc/puppet-decrypt"
|
14
|
-
gem.required_ruby_version = '>= 1.
|
14
|
+
gem.required_ruby_version = '>= 1.8.7'
|
15
15
|
notice = """
|
16
16
|
|
17
17
|
Notice: The default master key location is now /etc/puppet-decrypt/encryptor_secret_key
|
@@ -30,7 +30,7 @@ This was done to more easily support multiple keys. If you are upgrading from a
|
|
30
30
|
gem.add_dependency('encryptor', '~> 1.3')
|
31
31
|
gem.add_development_dependency('rake')
|
32
32
|
gem.add_development_dependency('cucumber')
|
33
|
-
gem.add_development_dependency('rspec')
|
33
|
+
gem.add_development_dependency('rspec', '~> 2.14.1')
|
34
34
|
gem.add_development_dependency('rspec-puppet')
|
35
35
|
gem.add_development_dependency('puppetlabs_spec_helper')
|
36
36
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'encrypt' do
|
5
|
+
before(:all) do
|
6
|
+
mock_secret_key(Puppet::Decrypt::Decryptor::DEFAULT_FILE, 'masterkey')
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:node) { 'testhost.example.com' }
|
10
|
+
extdata_path = File.expand_path(File.join(File.dirname(__FILE__),
|
11
|
+
'../../puppet/manifests/extdata'))
|
12
|
+
|
13
|
+
let :pre_condition do
|
14
|
+
"$extlookup_datadir = '#{extdata_path}' $extlookup_precedence = ['common', 'env_vagrant']"
|
15
|
+
end
|
16
|
+
|
17
|
+
let :salt do
|
18
|
+
'test_salt'
|
19
|
+
end
|
20
|
+
|
21
|
+
let :iv do
|
22
|
+
"YS7nvbPsLP+pIJQ0waxV0w=="
|
23
|
+
end
|
24
|
+
|
25
|
+
context "unencrypted key" do
|
26
|
+
it "should encrypt plain string" do
|
27
|
+
subject.call(['blah']).should =~
|
28
|
+
Puppet::Decrypt::Decryptor::ENCRYPTED_PATTERN
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "encrypted key" do
|
33
|
+
it "should encrypt exact matches" do
|
34
|
+
subject.call(["flabberghaster", nil, salt, iv]).should ==
|
35
|
+
'ENC[WnA7ezNPSZx2S01T67TCfA==:WVM3bnZiUHNMUCtwSUpRMHdheFYwdz09:dGVzdF9zYWx0]'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with secret key file" do
|
40
|
+
it "should encrypt exact matches" do
|
41
|
+
mock_secret_key('/etc/another_key', 'anotherkey')
|
42
|
+
subject.call(['value' => 'flabberghaster', 'secretkey' =>
|
43
|
+
'/etc/another_key', 'iv' => iv, 'salt' => salt]) =~
|
44
|
+
Puppet::Decrypt::Decryptor::ENCRYPTED_PATTERN
|
45
|
+
|
46
|
+
_, iv_hash, salt_hash = Regexp.last_match[2].split(':')
|
47
|
+
strict_decode64(iv_hash).should == iv
|
48
|
+
strict_decode64(salt_hash).should == salt
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Backported for ruby 1.8.7
|
55
|
+
def strict_decode64(str)
|
56
|
+
return Base64.strict_decode64(str) if Base64.respond_to? :strict_decode64
|
57
|
+
|
58
|
+
if str.include?("\n")
|
59
|
+
raise(ArgumentError,"invalid base64")
|
60
|
+
else
|
61
|
+
Base64.decode64(str)
|
62
|
+
end
|
63
|
+
end
|
metadata
CHANGED
@@ -1,110 +1,124 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet-decrypt
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
5
11
|
platform: ruby
|
6
|
-
authors:
|
12
|
+
authors:
|
7
13
|
- mlincoln
|
8
14
|
autorequire:
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
|
18
|
+
date: 2014-08-07 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 9
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 3
|
31
|
+
version: "1.3"
|
20
32
|
type: :runtime
|
33
|
+
version_requirements: *id001
|
21
34
|
prerelease: false
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
35
|
+
name: encryptor
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
31
40
|
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
34
46
|
type: :development
|
47
|
+
version_requirements: *id002
|
35
48
|
prerelease: false
|
36
|
-
|
37
|
-
|
49
|
+
name: rake
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
38
54
|
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
|
41
|
-
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
prerelease: false
|
42
63
|
name: cucumber
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 53
|
71
|
+
segments:
|
72
|
+
- 2
|
73
|
+
- 14
|
74
|
+
- 1
|
75
|
+
version: 2.14.1
|
48
76
|
type: :development
|
77
|
+
version_requirements: *id004
|
49
78
|
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
79
|
name: rspec
|
57
|
-
|
58
|
-
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
59
84
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
62
90
|
type: :development
|
91
|
+
version_requirements: *id005
|
63
92
|
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
93
|
name: rspec-puppet
|
71
|
-
|
72
|
-
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
73
98
|
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
76
104
|
type: :development
|
105
|
+
version_requirements: *id006
|
77
106
|
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
107
|
name: puppetlabs_spec_helper
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
108
|
description: A gem for encrypting/decrypting secret values for use with Puppet
|
98
|
-
email:
|
109
|
+
email:
|
99
110
|
- max@devopsy.com
|
100
111
|
executables: []
|
112
|
+
|
101
113
|
extensions: []
|
114
|
+
|
102
115
|
extra_rdoc_files: []
|
103
|
-
|
104
|
-
|
105
|
-
-
|
106
|
-
-
|
107
|
-
-
|
116
|
+
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .rspec
|
120
|
+
- .rvmrc
|
121
|
+
- .travis.yml
|
108
122
|
- ChangeLog.md
|
109
123
|
- Gemfile
|
110
124
|
- LICENSE.txt
|
@@ -132,42 +146,57 @@ files:
|
|
132
146
|
- lib/puppet/application/crypt.rb
|
133
147
|
- lib/puppet/face/crypt.rb
|
134
148
|
- lib/puppet/parser/functions/decrypt.rb
|
149
|
+
- lib/puppet/parser/functions/encrypt.rb
|
135
150
|
- puppet-decrypt.gemspec
|
136
151
|
- spec/faces/crypt_spec.rb
|
137
152
|
- spec/functions/decrypt_spec.rb
|
153
|
+
- spec/functions/encrypt_spec.rb
|
138
154
|
- spec/puppet-decrypt/fake_key_loader.rb
|
139
155
|
- spec/spec_helper.rb
|
156
|
+
has_rdoc: true
|
140
157
|
homepage: https://github.com/maxlinc/puppet-decrypt
|
141
158
|
licenses: []
|
142
|
-
metadata: {}
|
143
|
-
post_install_message: |2+
|
144
|
-
|
145
159
|
|
160
|
+
post_install_message: |+
|
161
|
+
|
162
|
+
|
146
163
|
Notice: The default master key location is now /etc/puppet-decrypt/encryptor_secret_key
|
147
|
-
|
164
|
+
|
148
165
|
This was done to more easily support multiple keys. If you are upgrading from a version older than
|
149
166
|
0.1.0 you should move /etc/encryptor_secret_key to /etc/puppet-decrypt/encryptor_secret_key.
|
150
|
-
|
167
|
+
|
151
168
|
rdoc_options: []
|
152
|
-
|
169
|
+
|
170
|
+
require_paths:
|
153
171
|
- lib
|
154
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
155
|
-
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
none: false
|
174
|
+
requirements:
|
156
175
|
- - ">="
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
|
159
|
-
|
160
|
-
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
hash: 57
|
178
|
+
segments:
|
179
|
+
- 1
|
180
|
+
- 8
|
181
|
+
- 7
|
182
|
+
version: 1.8.7
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
+
none: false
|
185
|
+
requirements:
|
161
186
|
- - ">="
|
162
|
-
- !ruby/object:Gem::Version
|
163
|
-
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
hash: 3
|
189
|
+
segments:
|
190
|
+
- 0
|
191
|
+
version: "0"
|
164
192
|
requirements: []
|
193
|
+
|
165
194
|
rubyforge_project:
|
166
|
-
rubygems_version:
|
195
|
+
rubygems_version: 1.6.2
|
167
196
|
signing_key:
|
168
|
-
specification_version:
|
197
|
+
specification_version: 3
|
169
198
|
summary: A shared secret strategy that works with any data source
|
170
|
-
test_files:
|
199
|
+
test_files:
|
171
200
|
- features/fixtures/data/overridden_secret_key.yaml
|
172
201
|
- features/fixtures/data/simple.yaml
|
173
202
|
- features/fixtures/hiera.yaml
|
@@ -181,5 +210,6 @@ test_files:
|
|
181
210
|
- features/support/env.rb
|
182
211
|
- spec/faces/crypt_spec.rb
|
183
212
|
- spec/functions/decrypt_spec.rb
|
213
|
+
- spec/functions/encrypt_spec.rb
|
184
214
|
- spec/puppet-decrypt/fake_key_loader.rb
|
185
215
|
- spec/spec_helper.rb
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 4c098cca8fcd1228c7d2e82d7b8615f7189e77e8
|
4
|
-
data.tar.gz: b2ddb9f7aaa99af9d68812a7d86a95c7d04da32e
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: b19f454ff00dd36f2f83848c1a4be5df1ec6065b6dcd487364da4c981cce7350c6789862092df40681bcefaa2363e46ee8d4735cb751abec3b6e7400d4a6b0c2
|
7
|
-
data.tar.gz: 45b6964e742c45152804e4d6eac02324702515dcefc49ce87cf7a0eeb0268b744229ae2aec6f99b0a84ac5146de98da15519d6edb31e94c282b4af7c162f4be7
|