attr_encrypter 1.0.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 +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +212 -0
- data/lib/attr_encrypter.rb +36 -0
- data/lib/attr_encrypter/accessors.rb +38 -0
- data/lib/attr_encrypter/boxes.rb +30 -0
- data/lib/attr_encrypter/errors.rb +11 -0
- data/lib/attr_encrypter/generator.rb +12 -0
- data/lib/attr_encrypter/version.rb +5 -0
- metadata +128 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9deb2dc66f623007552ad4e619e4d96cbf1596bb2e6e327abc9319cb32c30f3f
|
|
4
|
+
data.tar.gz: baa889f1cd1de2b7abc32cd040709e0194fca2ac546c9355437b1814939294cb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1304196d54904f124f56dcbf9b28388fdd32ec17aff3501c4fabb4c3a321347fff0e9a4ee9e70f09ffb32ea61f67f43c9e4ede355295a44a0ec42f6127f364ae
|
|
7
|
+
data.tar.gz: 71245009cf9f27e050c035ab90a90edfda05b4ba0e47772c7242c57053442aefa87b1001a58e33dfc43c1a02833464c62c84cc82738fc55c1566dd90cf58a0e6
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) Michael van Rooijen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# AttrEncrypter
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/attr_encrypter)
|
|
4
|
+
[](https://github.com/mrrooijen/attr_encrypter/actions)
|
|
5
|
+
|
|
6
|
+
Encrypts/Decrypts, with key rotation, attributes on classes, using [RbNaCl] ([libsodium]).
|
|
7
|
+
|
|
8
|
+
This library was developed for- and extracted from [HireFire].
|
|
9
|
+
|
|
10
|
+
The documentation can be found on [RubyDoc].
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Compatibility
|
|
14
|
+
|
|
15
|
+
- Ruby 2.5+
|
|
16
|
+
- RbNaCl 7.0+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Installation
|
|
20
|
+
|
|
21
|
+
Ensure that you've installed [libsodium], then add the gem to your Gemfile and run `bundle`.
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
gem "attr_encrypter", "~> 1"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Example
|
|
29
|
+
|
|
30
|
+
```rb
|
|
31
|
+
class Account
|
|
32
|
+
include AttrEncrypter::Accessors
|
|
33
|
+
|
|
34
|
+
# Defines the token accessor that seamlessly encrypts and decrypts
|
|
35
|
+
# data stored in @token_digest.
|
|
36
|
+
#
|
|
37
|
+
# Note: This won't define a @token instance variable, as state is
|
|
38
|
+
# managed by the token_digest accessor using @token_digest.
|
|
39
|
+
#
|
|
40
|
+
# Note: You can add multiple attributes in a single attr_encrypter call.
|
|
41
|
+
# e.g. `attr_encrypter ENV["KEYCHAIN"], :attr_a, :attr_b, :attr_c`
|
|
42
|
+
#
|
|
43
|
+
attr_encrypter ENV["KEYCHAIN"], :token
|
|
44
|
+
|
|
45
|
+
# Defines the token_digest accessor for storing and retrieving encrypted data.
|
|
46
|
+
# You don't directly use this accessor. Both read and write operations should
|
|
47
|
+
# always go through the token/token= methods provided by the attr_encrypter method.
|
|
48
|
+
#
|
|
49
|
+
# Consider making this accessor private. We'll leave it public for this demo.
|
|
50
|
+
#
|
|
51
|
+
attr_accessor :token_digest
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The `KEYCHAIN` environment variable must contain one or more keys. To generate a key, use the following function.
|
|
56
|
+
|
|
57
|
+
```rb
|
|
58
|
+
AttrEncrypter::Generator.generate_key
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Place the generated key in the `KEYCHAIN` environment variable.
|
|
62
|
+
|
|
63
|
+
The key consists of two segments, `<version>.<secret>`. The initial key has a version of 1. Versions determine which secrets will be used to encrypt and decrypt data.
|
|
64
|
+
|
|
65
|
+
With the key in place you'll be able to store and retrieve data using the dynamically defined `token` accessor. Data assigned with `token=` will automatically be encrypted and stored with `token_digest=` in `@token_digest`.
|
|
66
|
+
|
|
67
|
+
```rb
|
|
68
|
+
account = Account.new
|
|
69
|
+
account.token = "my_secret_token"
|
|
70
|
+
account.token_digest # => "1.yCZGH0QEk8+OPT0ad29wVmCkvr/7NXZjZtxu23v2j9HKfehndH0qv9MsF4ME\n"
|
|
71
|
+
account.token # => "my_secret_token"
|
|
72
|
+
|
|
73
|
+
account.instance_variable_get("@token") # => nil
|
|
74
|
+
account.instance_variable_get("@token_digest") # => "1.yCZGH0QEk8+OPT0ad29wVmCkvr/7NXZjZtxu23v2j9HKfehndH0qv9MsF4ME\n"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The `@token_digest` value, like the keychain, also consists of two segments, `<version>.<data>`. The version matches the key version used to encrypt the data. This way, whenever data is accessed via `token`, it knows which secret to use to decrypt the data.
|
|
78
|
+
|
|
79
|
+
To clear the token, simply assign `nil` to it.
|
|
80
|
+
|
|
81
|
+
```rb
|
|
82
|
+
account.token = nil
|
|
83
|
+
account.token_digest # => nil
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
### Active Record
|
|
88
|
+
|
|
89
|
+
This is a general purpose library, and while its only hard dependency is rbnacl (libsodium), it was designed to work seamlessly with Active Record.
|
|
90
|
+
|
|
91
|
+
```rb
|
|
92
|
+
class User < ActiveRecord::Base
|
|
93
|
+
include AttrEncrypter::Accessors
|
|
94
|
+
attr_encrypter ENV["KEYCHAIN"], :token
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This assumes that you have a users table in the database, containing a column named `token_digest` of type text.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
### Key Rotation
|
|
102
|
+
|
|
103
|
+
You'll want to rotate your keys at some point.
|
|
104
|
+
|
|
105
|
+
First, add a second key to the keychain (`ENV["KEYCHAIN"]` in this case).
|
|
106
|
+
|
|
107
|
+
To generate version 2 you can again use the following function, but this time using the version argument.
|
|
108
|
+
|
|
109
|
+
```rb
|
|
110
|
+
AttrEncrypter::Generator.generate_key 2 # or 3, 4, 5...
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The keychain format allows any kind of whitespace to delimit keys.
|
|
114
|
+
|
|
115
|
+
```rb
|
|
116
|
+
ENV["KEYCHAIN"] = "<version>.<secret> <version>.<secret> <version>.<secret>"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For example.
|
|
120
|
+
|
|
121
|
+
```rb
|
|
122
|
+
ENV["KEYCHAIN"] = <<-EOS
|
|
123
|
+
1.c1dbb0dd094d4f40916c9cc0d8c974151949f105c499366b2acd9da76de7e5e9
|
|
124
|
+
2.3054563b2d80ae13c6e115405d6263e70be004f81eb3982f4a61ff9e9821e7d4
|
|
125
|
+
EOS
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Then simply reassign the token to re-encrypt the token with key version 2.
|
|
129
|
+
|
|
130
|
+
```rb
|
|
131
|
+
User.find_each do |user|
|
|
132
|
+
user.token = user.token
|
|
133
|
+
user.save
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The `user.token` (reader) decrypts the existing encrypted token from `token_digest` back to its unencrypted form using key version 1. It then uses the highest key version in the keychain, version 2, to re-encrypt the token with `user.token=` which overwrites the key version 1-encrypted token in `token_digest` with the key version 2-encrypted token. We then persist the key version 2-encrypted token to the database.
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
#### Quick Facts
|
|
141
|
+
|
|
142
|
+
* The order of the keys in the keychain is irrelevant.
|
|
143
|
+
* The key with the highest version in the keychain is always used for encryption.
|
|
144
|
+
* The key version used to encrypt data is stored along with the encrypted data (`<version>.<secret>`).
|
|
145
|
+
* The version of the encrypted data determines which key's secret to use in order to decrypt data.
|
|
146
|
+
* Keys can be safely removed from the keychain when none of the encrypted data requires it for decryption.
|
|
147
|
+
* It's recommended that you increment key versions by 1 when generating a new key.
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### Contributing
|
|
151
|
+
|
|
152
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mrrooijen/attr_encrypter.
|
|
153
|
+
|
|
154
|
+
First, install [libsodium] on your machine, and then install the remaining development dependencies:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
$ bundle
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
To open an interactive console:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
$ bundle console
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
To run the tests:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
$ bundle exec rake
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
To view the code coverage (generated after each test run):
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
$ open coverage/index.html
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
To run the local documentation server:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
$ bundle exec rake doc
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
To build a gem:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
$ bundle exec rake build
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
To build and install a gem on your local machine:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
$ bundle exec rake install
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
For a list of available tasks:
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
$ bundle exec rake --tasks
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
### Author / License
|
|
204
|
+
|
|
205
|
+
Released under the [MIT License] by [Michael van Rooijen].
|
|
206
|
+
|
|
207
|
+
[Michael van Rooijen]: https://michael.vanrooijen.io
|
|
208
|
+
[HireFire]: https://www.hirefire.io
|
|
209
|
+
[RubyDoc]: https://rubydoc.info/gems/attr_encrypter
|
|
210
|
+
[MIT License]: https://github.com/mrrooijen/attr_encrypter/blob/master/LICENSE.txt
|
|
211
|
+
[RbNaCl]: https://github.com/RubyCrypto/rbnacl
|
|
212
|
+
[libsodium]: https://doc.libsodium.org/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
require "rbnacl"
|
|
5
|
+
|
|
6
|
+
class AttrEncrypter
|
|
7
|
+
|
|
8
|
+
require "attr_encrypter/accessors"
|
|
9
|
+
require "attr_encrypter/boxes"
|
|
10
|
+
require "attr_encrypter/errors"
|
|
11
|
+
require "attr_encrypter/generator"
|
|
12
|
+
require "attr_encrypter/version"
|
|
13
|
+
|
|
14
|
+
DIGEST_FORMAT = /^(\d+)\.([a-zA-Z0-9\+\=\n\/]+)$/.freeze
|
|
15
|
+
|
|
16
|
+
def initialize(keychain)
|
|
17
|
+
@boxes = Boxes.new(keychain || "")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def encrypt(raw)
|
|
21
|
+
version = @boxes.latest_version
|
|
22
|
+
encrypted = @boxes[version].encrypt(raw)
|
|
23
|
+
encoded = Base64.encode64(encrypted)
|
|
24
|
+
|
|
25
|
+
"#{version}.#{encoded}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def decrypt(digest)
|
|
29
|
+
segments = digest.match(DIGEST_FORMAT)
|
|
30
|
+
version = segments[1].to_i
|
|
31
|
+
encoded = segments[2]
|
|
32
|
+
encrypted = Base64.decode64(encoded)
|
|
33
|
+
|
|
34
|
+
@boxes[version].decrypt(encrypted)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AttrEncrypter::Accessors
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
|
|
11
|
+
def attr_encrypter(keychain, *attributes)
|
|
12
|
+
attr_encrypter = AttrEncrypter.new(keychain)
|
|
13
|
+
|
|
14
|
+
attributes.each do |attribute|
|
|
15
|
+
reader = "#{attribute}"
|
|
16
|
+
writer = "#{attribute}="
|
|
17
|
+
digest_reader = "#{attribute}_digest"
|
|
18
|
+
digest_writer = "#{attribute}_digest="
|
|
19
|
+
|
|
20
|
+
define_method reader do
|
|
21
|
+
digest = send(digest_reader)
|
|
22
|
+
|
|
23
|
+
if digest.is_a?(String)
|
|
24
|
+
attr_encrypter.decrypt(digest)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
define_method writer do |raw|
|
|
29
|
+
if raw.is_a?(String)
|
|
30
|
+
send(digest_writer, attr_encrypter.encrypt(raw))
|
|
31
|
+
else
|
|
32
|
+
send(digest_writer, nil)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AttrEncrypter::Boxes
|
|
4
|
+
|
|
5
|
+
KEY_FORMAT = /^(\d+)\.([a-f0-9]{64})$/.freeze
|
|
6
|
+
|
|
7
|
+
def initialize(keychain)
|
|
8
|
+
@boxes = keychain.split.reduce({}) do |keys, item|
|
|
9
|
+
segments = item.match(KEY_FORMAT)
|
|
10
|
+
version = segments[1].to_i
|
|
11
|
+
key = [segments[2]].pack("H*")
|
|
12
|
+
|
|
13
|
+
keys.merge(version => RbNaCl::SimpleBox.from_secret_key(key))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if @boxes.empty?
|
|
17
|
+
raise AttrEncrypter::Errors::NoKeychainError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
@boxes.freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def [](version)
|
|
24
|
+
@boxes[version]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def latest_version
|
|
28
|
+
@boxes.keys.max
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AttrEncrypter::Errors
|
|
4
|
+
class NoKeychainError < StandardError
|
|
5
|
+
def message
|
|
6
|
+
"AttrEncrypter.new(keychain) requires a valid keychain containing at least one key." \
|
|
7
|
+
"\nYou can generate a key using AttrEncrypter::Generator.generate_key(version = 1)." \
|
|
8
|
+
"\nHere's a (version 1) key if you need one: #{AttrEncrypter::Generator.generate_key}" \
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AttrEncrypter::Generator
|
|
4
|
+
|
|
5
|
+
def self.generate_key(version = 1)
|
|
6
|
+
byte_size = RbNaCl::SecretBox.key_bytes
|
|
7
|
+
secret_bytes = RbNaCl::Random.random_bytes(byte_size)
|
|
8
|
+
secret_hex = secret_bytes.unpack("H*")[0]
|
|
9
|
+
|
|
10
|
+
"#{version}.#{secret_hex}"
|
|
11
|
+
end
|
|
12
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: attr_encrypter
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Michael van Rooijen
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-06-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rbnacl
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '7'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 13.0.1
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 13.0.1
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: yard
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.9.25
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - '='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.9.25
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: minitest
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - '='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 5.14.1
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - '='
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 5.14.1
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: simplecov
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - '='
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 0.18.5
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - '='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 0.18.5
|
|
83
|
+
description:
|
|
84
|
+
email:
|
|
85
|
+
- michael@vanrooijen.io
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- CHANGELOG.md
|
|
91
|
+
- LICENSE.txt
|
|
92
|
+
- README.md
|
|
93
|
+
- lib/attr_encrypter.rb
|
|
94
|
+
- lib/attr_encrypter/accessors.rb
|
|
95
|
+
- lib/attr_encrypter/boxes.rb
|
|
96
|
+
- lib/attr_encrypter/errors.rb
|
|
97
|
+
- lib/attr_encrypter/generator.rb
|
|
98
|
+
- lib/attr_encrypter/version.rb
|
|
99
|
+
homepage: https://github.com/mrrooijen/attr_encrypter
|
|
100
|
+
licenses:
|
|
101
|
+
- MIT
|
|
102
|
+
metadata:
|
|
103
|
+
homepage_uri: https://github.com/mrrooijen/attr_encrypter
|
|
104
|
+
source_code_uri: https://github.com/mrrooijen/attr_encrypter
|
|
105
|
+
changelog_uri: https://github.com/mrrooijen/attr_encrypter/blob/master/CHANGELOG.md
|
|
106
|
+
bug_tracker_uri: https://github.com/mrrooijen/attr_encrypter/issues
|
|
107
|
+
documentation_uri: https://rubydoc.info/gems/attr_encrypter
|
|
108
|
+
post_install_message:
|
|
109
|
+
rdoc_options: []
|
|
110
|
+
require_paths:
|
|
111
|
+
- lib
|
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: 2.5.0
|
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
|
+
requirements:
|
|
119
|
+
- - ">="
|
|
120
|
+
- !ruby/object:Gem::Version
|
|
121
|
+
version: '0'
|
|
122
|
+
requirements: []
|
|
123
|
+
rubygems_version: 3.1.2
|
|
124
|
+
signing_key:
|
|
125
|
+
specification_version: 4
|
|
126
|
+
summary: Encrypts/Decrypts, with key rotation, attributes on classes, using RbNaCl
|
|
127
|
+
(libsodium).
|
|
128
|
+
test_files: []
|