dry-credentials 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 24deb6ca2d926a11c530c6e81821af802fe1ac36e4fafb8c2273619afdd4ff8e
4
+ data.tar.gz: 5be212ecb261ab3134b80f14d93a8ca9b7492be642b7a129b16239b0b727410f
5
+ SHA512:
6
+ metadata.gz: a4e0f03fa13561dbc97b110b2d3f660889f0fe76d98615b981af07bf5b44481669f9b176692f77508d71d3629a8cf05c98262601cef5db4a5ee04b0d04de158a
7
+ data.tar.gz: a0258c2537012e92dfa82ec88d1881a740d04eb9fae617fbafc79a3dabb9e0ff526e51856218a0316c5d99a1c357edb681d404cd2f831f7f79e183659de2dde3
checksums.yaml.gz.sig ADDED
Binary file
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ ## Main
2
+
3
+ Nothing so far
4
+
5
+ ## 0.1.0
6
+
7
+ #### Initial implementation
8
+
9
+ * Require Ruby 3.0 or newer
10
+ * Class mixin featuring the `credentials` macro:
11
+ * Block to change (default) settings such as the cipher
12
+ * Bang method to edit or reload credentials
13
+ * Arbitrary method chain to query credentials
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sven Schwyn
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,167 @@
1
+ [![Version](https://img.shields.io/gem/v/dry-credentials.svg?style=flat)](https://rubygems.org/gems/dry-credentials)
2
+ [![Tests](https://img.shields.io/github/actions/workflow/status/svoop/dry-credentials/test.yml?style=flat&label=tests)](https://github.com/svoop/dry-credentials/actions?workflow=Test)
3
+ [![Code Climate](https://img.shields.io/codeclimate/maintainability/svoop/dry-credentials.svg?style=flat)](https://codeclimate.com/github/svoop/dry-credentials/)
4
+ [![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera)
5
+
6
+ # Dry::Credentials
7
+
8
+ Manage and deploy secrets (access keys, API tokens etc) in encrypted files which can safely be committed to the code repository. To decrypt and and use them, only one environment variable containing the corresponding key is required.
9
+
10
+ While similar in purpose to ActiveSupport::EncryptedConfiguration, this lightweight implementation doesn't introduce any dependencies.
11
+
12
+ * [Homepage](https://github.com/svoop/dry-credentials)
13
+ * [API](https://www.rubydoc.info/gems/dry-credentials)
14
+ * Author: [Sven Schwyn - Bitcetera](https://bitcetera.com)
15
+
16
+ ## Install
17
+
18
+ ### Security
19
+
20
+ This gem is [cryptographically signed](https://guides.rubygems.org/security/#using-gems) in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:
21
+
22
+ ```
23
+ gem cert --add <(curl -Ls https://raw.github.com/svoop/dry-credentials/main/certs/svoop.pem)
24
+ ```
25
+
26
+ ### Bundler
27
+
28
+ Add the following to the <tt>Gemfile</tt> or <tt>gems.rb</tt> of your [Bundler](https://bundler.io) powered Ruby project:
29
+
30
+ ```ruby
31
+ gem 'dry-credentials'
32
+ ```
33
+
34
+ And then install the bundle:
35
+
36
+ ```
37
+ bundle install --trust-policy MediumSecurity
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Extend any class with `Dry::Credentials` to use the [default settings](#defaults):
43
+
44
+ ```ruby
45
+ class App
46
+ extend Dry::Credentials
47
+ end
48
+ ```
49
+
50
+ The `credentials` macro allows you to tweak the settings:
51
+
52
+ ```ruby
53
+ class App
54
+ extend Dry::Credentials
55
+
56
+ credentials do
57
+ env "sandbox"
58
+ dir "/path/to/credentials"
59
+ end
60
+ end
61
+ ```
62
+
63
+ ⚠️ The `dir` must exist and have the proper permissions set.
64
+
65
+ Now initialize the credentials for this `env`:
66
+
67
+ ```ruby
68
+ App.credentials.edit!
69
+ ```
70
+
71
+ It creates `/path/to/credentials/sandbox.yml.enc` (where the encrypted credentials are stored) and opens this file using your favourite editor as per the `EDITOR` environment variable.
72
+
73
+ For the sake of this example, let's assume you paste the following credentials:
74
+
75
+ ```yml
76
+ otp:
77
+ secret_key: ZcikLNiUQoqOo594oH2eqw04HPclhjkpgvpBik/40oU=
78
+ salt: 583506a49c71724a9f085bf2e70362df9d973f08d6575191cab6a177dfb872c6
79
+ meta:
80
+ realm: main
81
+ ```
82
+
83
+ When you close the editor, the credentials are encrypted and stored. This first time only, the key to encrypt and decrypt is printed to STDOUT:
84
+
85
+ ```
86
+ SANDBOX_CREDENTIALS_KEY=68656973716a4e706e336733377245732b6e77584c6c772b5432446532456f674767664271374a623876383d
87
+ ```
88
+
89
+ ⚠️ In case you've entered invalid YAML, a warning will be printed and the editor reopens immediately.
90
+
91
+ To decrypt the credentials and use them in your app, you have to set just this one environment variable containing the key, in this case:
92
+
93
+ ```sh
94
+ export SANDBOX_CREDENTIALS_KEY=68656973716a4e706e336733377245732b6e77584c6c772b5432446532456f674767664271374a623876383d
95
+ ```
96
+
97
+ With this in place, you can use the decrypted credentials anywhere in your app:
98
+
99
+ ```ruby
100
+ App.credentials.otp.secret_key
101
+ # => "ZcikLNiUQoqOo594oH2eqw04HPclhjkpgvpBik/40oU="
102
+
103
+ App.credentials.otp.meta.realm
104
+ # => "main"
105
+ ```
106
+
107
+ ## Environments
108
+
109
+ Credentials are isolated into environments which most likely will, but don't necessarily have to align with the environments of the app framework you're using.
110
+
111
+ By default, the current environment is read from `RACK_ENV`.
112
+
113
+ ⚠️ For safety reasons, don't share the same key across multiple environments!
114
+
115
+ ## Reload Credentials
116
+
117
+ The credentials are lazy loaded when queried for the first time. After that, changes in the encrypted credentials files are not taken into account at runtime for efficiency reasons.
118
+
119
+ However, you can schedule a reload:
120
+
121
+ ```ruby
122
+ App.credentials.reload!
123
+ ```
124
+
125
+ The reload is not done immediately but the next time credentials are queried.
126
+
127
+ ## Edit Credentials
128
+
129
+ This gem does not provide any CLI tools to edit the credentials. You should integrate it into your app instead e.g. with a Rake task or an extension to the CLI tool of the app framework you're using.
130
+
131
+ You can explicitly pass the environment to edit:
132
+
133
+ ```ruby
134
+ App.credentials.edit! "production"
135
+ ```
136
+
137
+ Editing credentials implicitly schedules a `reload!`.
138
+
139
+ ## Settings
140
+
141
+ If you have to, you can access the settings programmatically:
142
+
143
+ ```ruby
144
+ App.credentials[:env] # => "production"
145
+ ```
146
+
147
+ ### Defaults
148
+
149
+ Setting | Default | Description
150
+ --------|---------|------------
151
+ `env` | `-> { ENV["RACK_ENV"] }` | environment such as `development`
152
+ `dir` | `"config/credentials"` | directory where encrypted credentials are stored
153
+ `cipher` | `"aes-256-gcm"` | any of `OpenSSL::Cipher.ciphers`
154
+ `digest` | `"sha256"` | sign digest used if the cipher doesn't support AEAD
155
+ `serializer` | `Marshal` | serializer responding to `dump` and `load`
156
+
157
+ ## Development
158
+
159
+ To install the development dependencies and then run the test suite:
160
+
161
+ ```
162
+ bundle install
163
+ bundle exec rake # run tests once
164
+ bundle exec guard # run tests whenever files are modified
165
+ ```
166
+
167
+ You're welcome to [submit issues](https://github.com/svoop/dry-credentials/issues) and contribute code by [forking the project and submitting pull requests](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Inspired by +ActiveSupport::EncryptedConfiguration+, the most recent compare
4
+ # to pinpoint newly discovered safety issues was done against version 7.0.4.2.
5
+
6
+ module Dry
7
+ module Credentials
8
+ class Encryptor
9
+
10
+ DEFAULT_CIPHER = 'aes-256-gcm'
11
+ DEFAULT_DIGEST = 'sha256'
12
+ DEFAULT_SERIALIZER = Marshal
13
+ SEPARATOR = '--'
14
+
15
+ attr_reader :cipher
16
+
17
+ # @param cipher [String] any of +OpenSSL::Cipher.ciphers+
18
+ # @param digest [String] any of +openssl list+
19
+ # @param serializer [Class] must respond to +dump+ and +load+
20
+ def initialize(cipher: DEFAULT_CIPHER, digest: DEFAULT_DIGEST, serializer: DEFAULT_SERIALIZER)
21
+ @cipher = OpenSSL::Cipher.new(cipher)
22
+ @digest, @serializer = digest, serializer
23
+ end
24
+
25
+ # Generate a random key with the length requird by the current cipher,
26
+ # then Base64 encodes and unpacks all bytes to hex.
27
+ #
28
+ # @return [String] key
29
+ def generate_key
30
+ unpack(encode(SecureRandom.bytes(cipher.key_len)))
31
+ end
32
+
33
+ # Encrypts the object
34
+ #
35
+ # Relies on encrypted authenticated encryption mode if available for the
36
+ # selected cipher. Otherwise, the encrypted string is HMAC signed.
37
+ #
38
+ # @param object [Object] object to be encrypted
39
+ # @param key [String] key (Base64 encoded and unpacked to hex)
40
+ # @return [String] encrypted and authenticated/signed string
41
+ def encrypt(object, key:)
42
+ cipher.encrypt
43
+ cipher.key = decoded_key = decode(pack(key.strip))
44
+ iv = cipher.random_iv
45
+ cipher.auth_data = '' if aead?
46
+ cipher.update(@serializer.dump(object)).then do |data|
47
+ data << cipher.final
48
+ data = encode(data) + SEPARATOR + encode(iv)
49
+ data << SEPARATOR + if aead?
50
+ encode(cipher.auth_tag)
51
+ else
52
+ hmac(decoded_key, data)
53
+ end
54
+ end
55
+ end
56
+
57
+ # Decrypts the encrypted object
58
+ #
59
+ # @param encrypted_object [String] encrypted object to be decrypted
60
+ # @param key [String] key (Base64 encoded and unpacked to hex)
61
+ # @return [Object] verified and decrypted object
62
+ def decrypt(encrypted_object, key:)
63
+ cipher.decrypt
64
+ cipher.key = decoded_key = decode(pack(key.strip))
65
+ payload, iv, auth_tag = encrypted_object.strip.split(SEPARATOR)
66
+ if auth_tag.nil? ||
67
+ (aead? && decode(auth_tag).bytes.length != auth_tag_length) ||
68
+ (!aead? && hmac(decoded_key, payload + SEPARATOR + iv) != auth_tag)
69
+ then
70
+ fail Dry::Credentials::InvalidEncryptedObjectError
71
+ end
72
+ cipher.iv = decode(iv)
73
+ if aead?
74
+ cipher.auth_tag = decode(auth_tag)
75
+ cipher.auth_data = ''
76
+ end
77
+ cipher.update(decode(payload)).then do |data|
78
+ data << cipher.final
79
+ @serializer.load(data)
80
+ end
81
+ rescue OpenSSL::Cipher::CipherError, TypeError, ArgumentError
82
+ raise Dry::Credentials::InvalidEncryptedObjectError
83
+ end
84
+
85
+ private
86
+
87
+ # @example
88
+ # encode("abc") # => "YWJj"
89
+ def encode(string)
90
+ Base64.strict_encode64(string)
91
+ end
92
+
93
+ # @example
94
+ # decode("YWJj") # => "abc"
95
+ def decode(string)
96
+ Base64.strict_decode64(string)
97
+ end
98
+
99
+ # @example
100
+ # unpack("YWJj") # => "59574a6a"
101
+ def unpack(string)
102
+ string.unpack1('H*')
103
+ end
104
+
105
+ # @example
106
+ # pack("59574a6a") # => "YWJj"
107
+ def pack(string)
108
+ [string].pack('H*')
109
+ end
110
+
111
+ # Whether the cipher supports AEAD (Authenticated Encryption with
112
+ # Associated Data) or not - in which case a HMAC signature using the
113
+ # +digest+ is used instead
114
+ def aead?
115
+ @auth ||= cipher.authenticated?
116
+ end
117
+
118
+ def hmac(key, string)
119
+ OpenSSL::HMAC.hexdigest(@digest, key, string)
120
+ end
121
+
122
+ # @see https://github.com/ruby/openssl/issues/63
123
+ def auth_tag_length
124
+ 16
125
+ end
126
+
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Credentials
5
+ class UnrecognizedSettingError < StandardError
6
+ def initialize(msg='setting not recognized') = super
7
+ end
8
+
9
+ class EnvNotSetError < StandardError
10
+ def initialize(msg='env must be set') = super
11
+ end
12
+
13
+ class KeyNotSetError < StandardError
14
+ def initialize(msg='key must be set') = super
15
+ end
16
+
17
+ class InvalidEncryptedObjectError < StandardError
18
+ def initialize(msg='corrupt encrypted object or wrong key') = super
19
+ end
20
+
21
+ class YAMLFormatError < StandardError
22
+ def initialize(msg='top level must be a dictionary') = super
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Credentials
5
+ class Extension
6
+
7
+ def initialize
8
+ @settings = Dry::Credentials::Settings.new
9
+ @injected = []
10
+ end
11
+
12
+ # Load the credentials once
13
+ #
14
+ # @api private
15
+ # @return [self]
16
+ def load!
17
+ helpers = Dry::Credentials::Helpers.new(self)
18
+ if @injected.none? && !helpers.create?
19
+ @injected = Dry::Credentials::YAML.new(helpers.read_yaml).inject_into(self)
20
+ end
21
+ self
22
+ end
23
+
24
+ # Reload the credentials
25
+ #
26
+ # @return [self]
27
+ def reload!
28
+ singleton_class.undef_method(@injected.pop) until @injected.empty?
29
+ self
30
+ end
31
+
32
+ # Edit credentials file
33
+ #
34
+ # @param env [String] name of the env to edit the credentials for
35
+ # @return [self]
36
+ def edit!(env=nil)
37
+ helpers = Dry::Credentials::Helpers.new(self, env)
38
+ create = helpers.create?
39
+ yaml = helpers.read_yaml
40
+ begin
41
+ yaml = helpers.edit_yaml yaml
42
+ end until helpers.yaml_valid? yaml
43
+ helpers.write_yaml yaml
44
+ puts [helpers.key_ev, ENV[helpers.key_ev]].join('=') if create
45
+ reload!
46
+ end
47
+
48
+ # Query settings
49
+ #
50
+ # @param setting [String] name of the setting
51
+ # @return [String] setting value
52
+ def [](setting)
53
+ @settings.send(setting)
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Credentials
5
+ class Helpers
6
+
7
+ # Helpers wrapped in a separate class in order not to pollute the
8
+ # extension with methods that could collide with credentials
9
+ #
10
+ # @param extension [Dry::Credentials::Extension] extension using the helpers
11
+ # @param env [String, nil] overrides env setting
12
+ def initialize(extension, env=nil)
13
+ @extension = extension
14
+ @env = env || extension[:env]
15
+ end
16
+
17
+ # Read the encrypted file and return the decrypted YAML content
18
+ #
19
+ # @return [String] YAML content
20
+ def read_yaml
21
+ return '' if create?
22
+ encryptor.decrypt(encrypted_file.read, key: key)
23
+ end
24
+
25
+ # Write the decrypted YAML content to the encrypted file
26
+ #
27
+ # @param yaml [String] YAML content
28
+ def write_yaml(yaml)
29
+ encrypted_file.write(encryptor.encrypt(yaml, key: key))
30
+ end
31
+
32
+ # Open the given YAML in the preferred editor
33
+ #
34
+ # @param yaml [String] YAML content to edit
35
+ # @return [String] edited YAML content
36
+ def edit_yaml(yaml)
37
+ Tempfile.create('dryc') do |tempfile|
38
+ tempfile.write yaml
39
+ tempfile.close
40
+ system %Q(#{ENV['EDITOR']} "#{tempfile.path}")
41
+ File.read(tempfile.path)
42
+ end
43
+ end
44
+
45
+ # Whether the YAML content can be read
46
+ #
47
+ # @param yaml [String] YAML content
48
+ # @return [Boolean]
49
+ def yaml_valid?(yaml)
50
+ Dry::Credentials::YAML.new(yaml)
51
+ true
52
+ rescue Dry::Credentials::YAMLFormatError, Psych::SyntaxError => error
53
+ warn "WARNING: #{error.message}"
54
+ false
55
+ end
56
+
57
+ # Whether a new encrypted file will be created
58
+ #
59
+ # @return [Boolean]
60
+ def create?
61
+ !encrypted_file.exist?
62
+ end
63
+
64
+ # Name of the environment variable holding the key
65
+ #
66
+ # @return [String]
67
+ def key_ev
68
+ fail Dry::Credentials::EnvNotSetError unless @env
69
+ "#{@env.upcase}_CREDENTIALS_KEY"
70
+ end
71
+
72
+ private
73
+
74
+ def key
75
+ if create?
76
+ ENV[key_ev] = encryptor.generate_key
77
+ else
78
+ ENV[key_ev] or fail Dry::Credentials::KeyNotSetError
79
+ end
80
+ end
81
+
82
+ def encrypted_file
83
+ fail Dry::Credentials::EnvNotSetError unless @env
84
+ Pathname(@extension[:dir]).realpath.join("#{@env}.yml.enc")
85
+ end
86
+
87
+ def encryptor
88
+ Dry::Credentials::Encryptor.new(
89
+ cipher: @extension[:cipher],
90
+ digest: @extension[:digest],
91
+ serializer: @extension[:serializer]
92
+ )
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Credentials
5
+ class Settings
6
+
7
+ DEFAULT_SETTINGS = {
8
+ env: -> { ENV['RACK_ENV'] },
9
+ dir: 'config/credentials',
10
+ cipher: 'aes-256-gcm',
11
+ digest: 'sha256',
12
+ serializer: Marshal
13
+ }.freeze
14
+
15
+ def initialize
16
+ @settings = {}
17
+ end
18
+
19
+ def method_missing(key, value=nil)
20
+ fail Dry::Credentials::UnrecognizedSettingError, key unless DEFAULT_SETTINGS.has_key? key
21
+ if value
22
+ @settings[key] = value
23
+ else
24
+ resolve(@settings[key] || DEFAULT_SETTINGS[key])
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def resolve(value)
31
+ if value.respond_to? :call
32
+ value.call
33
+ else
34
+ value
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Credentials
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Credentials
5
+ class YAML
6
+
7
+ # @param string [String] YAML document content
8
+ def initialize(yaml)
9
+ @yaml = yaml
10
+ @hash = ::YAML.safe_load yaml
11
+ fail Dry::Credentials::YAMLFormatError unless @hash.instance_of? Hash
12
+ rescue Psych::DisallowedClass
13
+ raise Dry::Credentials::YAMLFormatError
14
+ end
15
+
16
+ # Define readers for the first level of the credentials on the
17
+ # given +object+.
18
+ #
19
+ # @param [Object] object to inject the methods into
20
+ # @return [Array] injected methods
21
+ def inject_into(object)
22
+ Query.new(@hash).send(:inject_into, object)
23
+ end
24
+
25
+ class Query
26
+ # @param hash [Hash] hash of hashes containing the credentials
27
+ def initialize(hash)
28
+ @hash = hash
29
+ inject_into self
30
+ end
31
+
32
+ # Get all credentials below the current node as a hash.
33
+ #
34
+ # @return [Hash] credentials
35
+ def to_h
36
+ @hash
37
+ end
38
+
39
+ private
40
+
41
+ def inject_into(object)
42
+ @hash.each do |key, value|
43
+ object.define_singleton_method key do
44
+ if value.instance_of? Hash
45
+ Query.new value
46
+ else
47
+ value
48
+ end
49
+ end
50
+ end
51
+ @hash.keys
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tempfile"
4
+ require "yaml"
5
+ require "securerandom"
6
+ require "openssl"
7
+ require "base64"
8
+
9
+ require_relative "credentials/version"
10
+ require_relative "credentials/errors"
11
+ require_relative "credentials/encryptor"
12
+ require_relative "credentials/yaml"
13
+ require_relative "credentials/settings"
14
+ require_relative "credentials/helpers"
15
+ require_relative "credentials/extension"
16
+
17
+ module Dry
18
+ module Credentials
19
+ def credentials(&block)
20
+ if block
21
+ __credentials_extension__
22
+ .instance_variable_get('@settings')
23
+ .instance_eval(&block)
24
+ self
25
+ else
26
+ __credentials_extension__.load!
27
+ end
28
+ end
29
+
30
+ def __credentials_extension__
31
+ @__credentials_extension__ ||= Extension.new
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dry/credentials"
data.tar.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ nޯ�U��:�\���� ��$A֣/
2
+ ���ok�^�T[0m����;�����fA~܀ /�-Dt\�|&Zt���€�� QrV��ԋ�AX�P�J͈b]��h0vEg�� "�v�S���e�#�Ͼ���Yr��Y�lg��՘�]�p���PD��VW�dh�Z��?���0Ӆ�+��Ȕf�>��2E���+ �=�u�h����k�
3
+ ��y
metadata ADDED
@@ -0,0 +1,210 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dry-credentials
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sven Schwyn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDODCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhydWJ5
14
+ L0RDPWJpdGNldGVyYS9EQz1jb20wHhcNMjIxMTA2MTIzNjUwWhcNMjMxMTA2MTIz
15
+ NjUwWjAjMSEwHwYDVQQDDBhydWJ5L0RDPWJpdGNldGVyYS9EQz1jb20wggEiMA0G
16
+ CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcLg+IHjXYaUlTSU7R235lQKD8ZhEe
17
+ KMhoGlSUonZ/zo1OT3KXcqTCP1iMX743xYs6upEGALCWWwq+nxvlDdnWRjF3AAv7
18
+ ikC+Z2BEowjyeCCT/0gvn4ohKcR0JOzzRaIlFUVInlGSAHx2QHZ2N8ntf54lu7nd
19
+ L8CiDK8rClsY4JBNGOgH9UC81f+m61UUQuTLxyM2CXfAYkj/sGNTvFRJcNX+nfdC
20
+ hM9r2kH1+7wsa8yG7wJ2IkrzNACD8v84oE6qVusN8OLEMUI/NaEPVPbw2LUM149H
21
+ PVa0i729A4IhroNnFNmw4wOC93ARNbM1+LW36PLMmKjKudf5Exg8VmDVAgMBAAGj
22
+ dzB1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSfK8MtR62mQ6oN
23
+ yoX/VKJzFjLSVDAdBgNVHREEFjAUgRJydWJ5QGJpdGNldGVyYS5jb20wHQYDVR0S
24
+ BBYwFIEScnVieUBiaXRjZXRlcmEuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAYG2na
25
+ ye8OE2DANQIFM/xDos/E4DaPWCJjX5xvFKNKHMCeQYPeZvLICCwyw2paE7Otwk6p
26
+ uvbg2Ks5ykXsbk5i6vxDoeeOLvmxCqI6m+tHb8v7VZtmwRJm8so0eSX0WvTaKnIf
27
+ CAn1bVUggczVdNoBXw9WAILKyw9bvh3Ft740XZrR74sd+m2pGwjCaM8hzLvrVbGP
28
+ DyYhlBeRWyQKQ0WDIsiTSRhzK8HwSTUWjvPwx7SEdIU/HZgyrk0ETObKPakVu6bH
29
+ kAyiRqgxF4dJviwtqI7mZIomWL63+kXLgjOjMe1SHxfIPo/0ji6+r1p4KYa7o41v
30
+ fwIwU1MKlFBdsjkd
31
+ -----END CERTIFICATE-----
32
+ date: 2023-02-22 00:00:00.000000000 Z
33
+ dependencies:
34
+ - !ruby/object:Gem::Dependency
35
+ name: debug
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ type: :development
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: rake
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: minitest-sound
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: minitest-focus
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: guard
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ - !ruby/object:Gem::Dependency
119
+ name: guard-minitest
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ - !ruby/object:Gem::Dependency
133
+ name: yard
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ description: |
147
+ Manage and deploy secrets (access keys, API tokens etc) in encrypted
148
+ files which can safely be committed to the code repository. To decrypt and
149
+ and use them, only one environment variable containing the corresponding key
150
+ is required.
151
+
152
+ While similar to ActiveSupport::EncryptedConfiguration, this lightweight
153
+ implementation introduces as few dependencies as necessary.
154
+ email:
155
+ - ruby@bitcetera.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files:
159
+ - README.md
160
+ - CHANGELOG.md
161
+ - LICENSE.txt
162
+ files:
163
+ - CHANGELOG.md
164
+ - LICENSE.txt
165
+ - README.md
166
+ - lib/dry-credentials.rb
167
+ - lib/dry/credentials.rb
168
+ - lib/dry/credentials/encryptor.rb
169
+ - lib/dry/credentials/errors.rb
170
+ - lib/dry/credentials/extension.rb
171
+ - lib/dry/credentials/helpers.rb
172
+ - lib/dry/credentials/settings.rb
173
+ - lib/dry/credentials/version.rb
174
+ - lib/dry/credentials/yaml.rb
175
+ homepage: https://github.com/svoop/dry-credentials
176
+ licenses:
177
+ - MIT
178
+ metadata:
179
+ homepage_uri: https://github.com/svoop/dry-credentials
180
+ changelog_uri: https://github.com/svoop/dry-credentials/blob/main/CHANGELOG.md
181
+ source_code_uri: https://github.com/svoop/dry-credentials
182
+ documentation_uri: https://www.rubydoc.info/gems/dry-credentials
183
+ bug_tracker_uri: https://github.com/svoop/dry-credentials/issues
184
+ post_install_message:
185
+ rdoc_options:
186
+ - "--title"
187
+ - Dry::Credentials
188
+ - "--main"
189
+ - README.md
190
+ - "--line-numbers"
191
+ - "--inline-source"
192
+ - "--quiet"
193
+ require_paths:
194
+ - lib
195
+ required_ruby_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: 3.0.0
200
+ required_rubygems_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ requirements: []
206
+ rubygems_version: 3.4.7
207
+ signing_key:
208
+ specification_version: 4
209
+ summary: A mixin to use encrypted credentials in your classes
210
+ test_files: []
metadata.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ SC8Ɉd��']'���� lX�B�!s��
2
+ q:���i-�1��Ѫ��E�1{θ��M]IQ�u��N*�+�|�o�P7@��E%��0�<;TU�<>���הGs����5� Dv*�
3
+ _�̃��Y_4 � �:z&W>o��.�&p��j,-uP���"d��Cj���O���+