attr_keyring 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d02280da9cb28259980ea283b6030672957657ead8b895594176eef09d78382b
4
- data.tar.gz: 88ddda0bb1d9a85869246e46ab49a8f4889bc0c398d616be9dd162eec239a177
3
+ metadata.gz: 4a1335e867e0b79f0f8082b6cceaa30e40feeb7a9cb140dbb133989ad47af66f
4
+ data.tar.gz: fa5803034ce08ff55f515fc87e774eeb16b96597e229f55266bfdafd51225dd0
5
5
  SHA512:
6
- metadata.gz: 6a3108027fac7dbfee097e7afa3227f58f33560e540f19bc0f0b63cb4e482e8315ffafdbd4360bc31724426c9150109c6b9e46e9ecdf70526ca13cb34a8bee93
7
- data.tar.gz: 16a5ca41d03b434dbf2eb4a5751af6595e7d00c93867159c3990a3e1d0a104d170dfd434580eff0420b1b966afe0877ec70362c6d66cad34e89e0f5fed8867d4
6
+ metadata.gz: 1d2bc02c88a3871191cc41e32707452f1df9c50040991a8b09394d06a7a06d83a84b3574ac2e1e291e41cb8525d190213e31066eb9922440bbbe3426271829eb
7
+ data.tar.gz: '00086d53fd3bd74cc0ab4a1e5b511b02ddb081dc01531df75999461200c15b5e87069e0b38eb62f5c353ed121cb8f4657ec1e130aebfc0d254528a9365896389'
@@ -4,6 +4,8 @@ name: Tests
4
4
  on:
5
5
  pull_request:
6
6
  push:
7
+ workflow_dispatch:
8
+ inputs: {}
7
9
 
8
10
  jobs:
9
11
  build:
@@ -12,9 +14,10 @@ jobs:
12
14
  strategy:
13
15
  fail-fast: false
14
16
  matrix:
15
- ruby: ["2.7", "3.0"]
17
+ ruby: ["2.7", "3.0", "3.1"]
16
18
  gemfile:
17
19
  - gemfiles/7_0.gemfile
20
+ - gemfiles/6_1.gemfile
18
21
  - gemfiles/6_0.gemfile
19
22
 
20
23
  services:
@@ -26,9 +29,9 @@ jobs:
26
29
  --health-retries 5
27
30
 
28
31
  steps:
29
- - uses: actions/checkout@v1
32
+ - uses: actions/checkout@v3.0.2
30
33
 
31
- - uses: actions/cache@v2
34
+ - uses: actions/cache@v3.0.1
32
35
  with:
33
36
  path: vendor/bundle
34
37
  key: >
data/README.md CHANGED
@@ -144,6 +144,21 @@ user.encrypted_email
144
144
  #=> WG8Epo0ABz0Z1X5gX7kttc98w9Ei59B5uXGK36Zin9G0VqbxX3naOWOm4RI6w6Uu
145
145
  ```
146
146
 
147
+ If you want to store a hash, you can use the `encoder:` option.
148
+
149
+ ```ruby
150
+ class User < ApplicationRecord
151
+ attr_keyring ENV["USER_KEYRING"],
152
+ digest_salt: "<custom salt>"
153
+
154
+ attr_encrypt :data, encoder: JSON
155
+ end
156
+ ```
157
+
158
+ An encoder is just an object that responds to the methods `dump(data)` and
159
+ `parse(data)`, just like the `JSON` interface. Alternatively, you can use
160
+ `AttrKeyring::Encoders::JSON`, which returns hashes with symbolized keys.
161
+
147
162
  ### Encryption
148
163
 
149
164
  By default, AES-128-CBC is the algorithm used for encryption. This algorithm
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ gemspec path: ".."
5
+ gem "activerecord", "~> 6.1.0"
@@ -21,7 +21,7 @@ module AttrKeyring
21
21
  def reload(options = nil)
22
22
  instance = super
23
23
 
24
- self.class.encrypted_attributes.each do |attribute|
24
+ self.class.encrypted_attributes.each do |attribute, _options|
25
25
  clear_decrypted_column_cache(attribute)
26
26
  end
27
27
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AttrKeyring
4
+ module Encoders
5
+ module JSONEncoder
6
+ def self.dump(data)
7
+ ::JSON.dump(data)
8
+ end
9
+
10
+ def self.parse(data)
11
+ ::JSON.parse(data, symbolize_names: true)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AttrKeyring
4
- VERSION = "0.6.1"
4
+ VERSION = "0.7.0"
5
5
  end
data/lib/attr_keyring.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  module AttrKeyring
4
4
  require "attr_keyring/version"
5
5
  require "keyring"
6
+ require "attr_keyring/encoders/json_encoder"
6
7
 
7
8
  def self.active_record
8
9
  require "attr_keyring/active_record"
@@ -23,7 +24,7 @@ module AttrKeyring
23
24
  attr_accessor :encrypted_attributes, :keyring, :keyring_column_name
24
25
  end
25
26
 
26
- self.encrypted_attributes = []
27
+ self.encrypted_attributes = {}
27
28
  self.keyring = Keyring.new({}, digest_salt: "")
28
29
  self.keyring_column_name = :keyring_id
29
30
  end
@@ -42,11 +43,12 @@ module AttrKeyring
42
43
  self.keyring = Keyring.new(keyring, options)
43
44
  end
44
45
 
45
- def attr_encrypt(*attributes)
46
- self.encrypted_attributes ||= []
47
- encrypted_attributes.push(*attributes)
46
+ def attr_encrypt(*attributes, encoder: nil)
47
+ self.encrypted_attributes ||= {}
48
48
 
49
49
  attributes.each do |attribute|
50
+ encrypted_attributes[attribute.to_sym] = {encoder: encoder}
51
+
50
52
  define_attr_encrypt_writer(attribute)
51
53
  define_attr_encrypt_reader(attribute)
52
54
  end
@@ -70,6 +72,8 @@ module AttrKeyring
70
72
  clear_decrypted_column_cache(attribute)
71
73
  return reset_encrypted_column(attribute) unless encryptable_value?(value)
72
74
 
75
+ encoder = self.class.encrypted_attributes[attribute][:encoder]
76
+ value = encoder.dump(value) if encoder
73
77
  value = value.to_s
74
78
 
75
79
  previous_keyring_id = public_send(self.class.keyring_column_name)
@@ -86,6 +90,7 @@ module AttrKeyring
86
90
 
87
91
  private def attr_decrypt_column(attribute)
88
92
  cache_name = :"@#{attribute}"
93
+
89
94
  if instance_variable_defined?(cache_name)
90
95
  return instance_variable_get(cache_name)
91
96
  end
@@ -99,6 +104,9 @@ module AttrKeyring
99
104
  public_send(self.class.keyring_column_name)
100
105
  )
101
106
 
107
+ encoder = self.class.encrypted_attributes[attribute][:encoder]
108
+ decrypted_value = encoder.parse(decrypted_value) if encoder
109
+
102
110
  instance_variable_set(cache_name, decrypted_value)
103
111
  end
104
112
 
@@ -123,10 +131,13 @@ module AttrKeyring
123
131
 
124
132
  keyring_id = self.class.keyring.current_key.id
125
133
 
126
- self.class.encrypted_attributes.each do |attribute|
134
+ self.class.encrypted_attributes.each do |attribute, options|
127
135
  value = public_send(attribute)
128
136
  next unless encryptable_value?(value)
129
137
 
138
+ encoder = options[:encoder]
139
+ value = encoder.dump(value) if encoder
140
+
130
141
  encrypted_value, _, digest = self.class.keyring.encrypt(value)
131
142
 
132
143
  public_send("encrypted_#{attribute}=", encrypted_value)
@@ -38,7 +38,10 @@ module Keyring
38
38
  expected_hmac = hmac_digest(key.signing_key, encrypted_payload)
39
39
 
40
40
  unless verify_signature(expected_hmac, hmac)
41
- raise InvalidAuthentication, "Expected HMAC to be #{Base64.strict_encode64(expected_hmac)}; got #{Base64.strict_encode64(hmac)} instead" # rubocop:disable Layout/LineLength
41
+ raise InvalidAuthentication,
42
+ "Expected HMAC to be " \
43
+ "#{Base64.strict_encode64(expected_hmac)}; " \
44
+ "got #{Base64.strict_encode64(hmac)} instead"
42
45
  end
43
46
 
44
47
  cipher.iv = iv
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attr_keyring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-11 00:00:00.000000000 Z
11
+ date: 2022-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -204,9 +204,11 @@ files:
204
204
  - examples/keyring_sample.rb
205
205
  - examples/sequel_sample.rb
206
206
  - gemfiles/6_0.gemfile
207
+ - gemfiles/6_1.gemfile
207
208
  - gemfiles/7_0.gemfile
208
209
  - lib/attr_keyring.rb
209
210
  - lib/attr_keyring/active_record.rb
211
+ - lib/attr_keyring/encoders/json_encoder.rb
210
212
  - lib/attr_keyring/sequel.rb
211
213
  - lib/attr_keyring/version.rb
212
214
  - lib/keyring.rb
@@ -231,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
233
  - !ruby/object:Gem::Version
232
234
  version: '0'
233
235
  requirements: []
234
- rubygems_version: 3.2.32
236
+ rubygems_version: 3.3.7
235
237
  signing_key:
236
238
  specification_version: 4
237
239
  summary: Simple encryption-at-rest plugin for ActiveRecord.