umbrellio-sequel-plugins 0.4.0.114 → 0.4.0.164
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 +4 -4
- data/.travis.yml +1 -4
- data/Gemfile.lock +49 -46
- data/README.md +51 -17
- data/Rakefile +3 -1
- data/lib/sequel/plugins/attr_encrypted.rb +98 -0
- data/lib/sequel/plugins/attr_encrypted/simple_crypt.rb +46 -0
- data/lib/sequel/timestamp_migrator_undo_extension.rb +7 -3
- data/lib/umbrellio-sequel-plugins.rb +1 -1
- data/utils/database.rb +1 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bd4394bf53fcf0c95a1c67b2268c5def71d15f2a64fec6e30cb70fcb281caed
|
4
|
+
data.tar.gz: 57178f6c6365073e28bb3787f6253a774c6b134d6cd4a84656725e2d6400d373
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f34fda6b627aed0be50ae0a3fa6bc3978d7186f8477748870ff1871868ddbca2c0175b6bd4a7471b617406b28c0efee4ace1096d94795e40e402d7e0b2d0a1e9
|
7
|
+
data.tar.gz: b440a1b8b808c71b8c52fee03d0ead284dbbdf963cf3391fba385392703db6744b0aad41268e298430641709270f1f595edcabc63e3184ad0ec0d157beb8cecd
|
data/.travis.yml
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
language: ruby
|
2
2
|
|
3
3
|
os: linux
|
4
|
+
|
4
5
|
dist: xenial
|
5
6
|
|
6
7
|
jobs:
|
@@ -43,10 +44,6 @@ install: bundle install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
|
|
43
44
|
before_script:
|
44
45
|
- psql -c 'create database sequel_plugins;' -U postgres
|
45
46
|
|
46
|
-
script:
|
47
|
-
- bundle exec rspec
|
48
|
-
- bundle exec rubocop
|
49
|
-
|
50
47
|
deploy:
|
51
48
|
provider: rubygems
|
52
49
|
api_key:
|
data/Gemfile.lock
CHANGED
@@ -8,78 +8,81 @@ PATH
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activesupport (6.0.
|
11
|
+
activesupport (6.0.3.4)
|
12
12
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
13
|
i18n (>= 0.7, < 2)
|
14
14
|
minitest (~> 5.1)
|
15
15
|
tzinfo (~> 1.1)
|
16
|
-
zeitwerk (~> 2.2)
|
17
|
-
ast (2.4.
|
18
|
-
coderay (1.1.
|
19
|
-
concurrent-ruby (1.1.
|
16
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
17
|
+
ast (2.4.1)
|
18
|
+
coderay (1.1.3)
|
19
|
+
concurrent-ruby (1.1.7)
|
20
20
|
coveralls (0.8.23)
|
21
21
|
json (>= 1.8, < 3)
|
22
22
|
simplecov (~> 0.16.1)
|
23
23
|
term-ansicolor (~> 1.3)
|
24
24
|
thor (>= 0.19.4, < 2.0)
|
25
25
|
tins (~> 1.6)
|
26
|
-
diff-lcs (1.
|
26
|
+
diff-lcs (1.4.4)
|
27
27
|
docile (1.3.2)
|
28
|
-
i18n (1.8.
|
28
|
+
i18n (1.8.5)
|
29
29
|
concurrent-ruby (~> 1.0)
|
30
|
-
|
31
|
-
json (2.3.0)
|
30
|
+
json (2.3.1)
|
32
31
|
method_source (1.0.0)
|
33
|
-
minitest (5.14.
|
34
|
-
money (6.13.
|
32
|
+
minitest (5.14.2)
|
33
|
+
money (6.13.8)
|
35
34
|
i18n (>= 0.6.4, <= 2)
|
36
|
-
parallel (1.
|
37
|
-
parser (2.7.
|
38
|
-
ast (~> 2.4.
|
35
|
+
parallel (1.20.1)
|
36
|
+
parser (2.7.2.0)
|
37
|
+
ast (~> 2.4.1)
|
39
38
|
pg (1.2.3)
|
40
|
-
pry (0.13.
|
39
|
+
pry (0.13.1)
|
41
40
|
coderay (~> 1.1)
|
42
41
|
method_source (~> 1.0)
|
43
|
-
rack (2.2.
|
42
|
+
rack (2.2.3)
|
44
43
|
rainbow (3.0.0)
|
45
44
|
rake (13.0.1)
|
45
|
+
regexp_parser (2.0.0)
|
46
46
|
rexml (3.2.4)
|
47
|
-
rspec (3.
|
48
|
-
rspec-core (~> 3.
|
49
|
-
rspec-expectations (~> 3.
|
50
|
-
rspec-mocks (~> 3.
|
51
|
-
rspec-core (3.
|
52
|
-
rspec-support (~> 3.
|
53
|
-
rspec-expectations (3.
|
47
|
+
rspec (3.10.0)
|
48
|
+
rspec-core (~> 3.10.0)
|
49
|
+
rspec-expectations (~> 3.10.0)
|
50
|
+
rspec-mocks (~> 3.10.0)
|
51
|
+
rspec-core (3.10.0)
|
52
|
+
rspec-support (~> 3.10.0)
|
53
|
+
rspec-expectations (3.10.0)
|
54
54
|
diff-lcs (>= 1.2.0, < 2.0)
|
55
|
-
rspec-support (~> 3.
|
56
|
-
rspec-mocks (3.
|
55
|
+
rspec-support (~> 3.10.0)
|
56
|
+
rspec-mocks (3.10.0)
|
57
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
58
|
-
rspec-support (~> 3.
|
59
|
-
rspec-support (3.
|
60
|
-
rubocop (0.
|
61
|
-
jaro_winkler (~> 1.5.1)
|
58
|
+
rspec-support (~> 3.10.0)
|
59
|
+
rspec-support (3.10.0)
|
60
|
+
rubocop (0.90.0)
|
62
61
|
parallel (~> 1.10)
|
63
|
-
parser (>= 2.7.
|
62
|
+
parser (>= 2.7.1.1)
|
64
63
|
rainbow (>= 2.2.2, < 4.0)
|
64
|
+
regexp_parser (>= 1.7)
|
65
65
|
rexml
|
66
|
+
rubocop-ast (>= 0.3.0, < 1.0)
|
66
67
|
ruby-progressbar (~> 1.7)
|
67
68
|
unicode-display_width (>= 1.4.0, < 2.0)
|
68
|
-
rubocop-
|
69
|
-
|
70
|
-
|
71
|
-
rubocop
|
72
|
-
rubocop-
|
73
|
-
|
74
|
-
rubocop (
|
75
|
-
rubocop-
|
76
|
-
|
69
|
+
rubocop-ast (0.8.0)
|
70
|
+
parser (>= 2.7.1.5)
|
71
|
+
rubocop-config-umbrellio (0.90.0.93)
|
72
|
+
rubocop (= 0.90.0)
|
73
|
+
rubocop-performance (= 1.7.1)
|
74
|
+
rubocop-rails (= 2.7.0)
|
75
|
+
rubocop-rspec (= 1.42.0)
|
76
|
+
rubocop-performance (1.7.1)
|
77
|
+
rubocop (>= 0.82.0)
|
78
|
+
rubocop-rails (2.7.0)
|
79
|
+
activesupport (>= 4.2.0)
|
77
80
|
rack (>= 1.1)
|
78
|
-
rubocop (>= 0.
|
79
|
-
rubocop-rspec (1.
|
80
|
-
rubocop (>= 0.
|
81
|
+
rubocop (>= 0.87.0)
|
82
|
+
rubocop-rspec (1.42.0)
|
83
|
+
rubocop (>= 0.87.0)
|
81
84
|
ruby-progressbar (1.10.1)
|
82
|
-
sequel (5.
|
85
|
+
sequel (5.39.0)
|
83
86
|
simplecov (0.16.1)
|
84
87
|
docile (~> 1.1)
|
85
88
|
json (>= 1.8, < 3)
|
@@ -91,12 +94,12 @@ GEM
|
|
91
94
|
tins (~> 1.0)
|
92
95
|
thor (1.0.1)
|
93
96
|
thread_safe (0.3.6)
|
94
|
-
tins (1.
|
97
|
+
tins (1.26.0)
|
95
98
|
sync
|
96
|
-
tzinfo (1.2.
|
99
|
+
tzinfo (1.2.8)
|
97
100
|
thread_safe (~> 0.1)
|
98
101
|
unicode-display_width (1.7.0)
|
99
|
-
zeitwerk (2.
|
102
|
+
zeitwerk (2.4.2)
|
100
103
|
|
101
104
|
PLATFORMS
|
102
105
|
ruby
|
data/README.md
CHANGED
@@ -13,29 +13,30 @@ gem 'umbrellio-sequel-plugins'
|
|
13
13
|
|
14
14
|
And then execute:
|
15
15
|
|
16
|
-
|
16
|
+
$ bundle
|
17
17
|
|
18
18
|
# Extensions
|
19
19
|
|
20
|
-
- `CurrencyRates`
|
21
|
-
- `PGTools`
|
22
|
-
- `Slave`
|
23
|
-
- `Synchronize`
|
24
|
-
- `
|
25
|
-
- `
|
20
|
+
- [`CurrencyRates`](#CurrencyRates)
|
21
|
+
- [`PGTools`](#PGTools)
|
22
|
+
- [`Slave`](#Slave)
|
23
|
+
- [`Synchronize`](#Synchronize)
|
24
|
+
- [`Methods in Migrations`](#Methods-in-Migrations)
|
25
|
+
- [`Deferrable Foreign Keys`](#Deferrable-Foreign-Keys)
|
26
26
|
|
27
27
|
# Plugins
|
28
28
|
|
29
|
-
- `
|
30
|
-
- `
|
31
|
-
- `
|
32
|
-
- `
|
33
|
-
- `
|
34
|
-
- `
|
35
|
-
- `
|
29
|
+
- [`AttrEncrypted`](#AttrEncrypted)
|
30
|
+
- [`Duplicate`](#Duplicate)
|
31
|
+
- [`GetColumnValue`](#GetColumnValue)
|
32
|
+
- [`MoneyAccessors`](#MoneyAccessors)
|
33
|
+
- [`StoreAccessors`](#StoreAccessors)
|
34
|
+
- [`Synchronize`](#Synchronize)
|
35
|
+
- [`Upsert`](#Upsert)
|
36
|
+
- [`WithLock`](#WithLock)
|
36
37
|
|
37
38
|
# Tools
|
38
|
-
- `TimestampMigratorUndoExtension`
|
39
|
+
- [`TimestampMigratorUndoExtension`](#TimestampMigratorUndoExtension)
|
39
40
|
|
40
41
|
## CurrencyRates
|
41
42
|
|
@@ -203,6 +204,39 @@ end
|
|
203
204
|
# => <Husband @attributes={id:1, wife_id: 1}>
|
204
205
|
```
|
205
206
|
|
207
|
+
## AttrEncrypted
|
208
|
+
|
209
|
+
Enable: `Sequel::Model.plugin :attr_encrypted`
|
210
|
+
|
211
|
+
Plugin for storing encrypted model attributes.
|
212
|
+
|
213
|
+
Example:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
Sequel.migration do
|
217
|
+
change do
|
218
|
+
alter_table :orders do
|
219
|
+
add_column :encrypted_first_name, :text
|
220
|
+
add_column :encrypted_last_name, :text
|
221
|
+
add_column :encrypted_secret_data, :text
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
class Order < Sequel::Model
|
227
|
+
attr_encrypted :first_name, :last_name, key: Settings.private_key
|
228
|
+
attr_encrypted :secret_data, key: Settings.another_private_key
|
229
|
+
end
|
230
|
+
|
231
|
+
Order.create(first_name: "Ivan")
|
232
|
+
# => INSERT INTO "orders" ("encrypted_first_name") VALUES ('/sTi9Q==$OTpuMRq5k8R3JayQ$WjSManQGP9UaZ3C40yDjKg==')
|
233
|
+
|
234
|
+
order = Order.create(first_name: "Ivan", last_name: "Smith",
|
235
|
+
secret_data: { "some_key" => "Some Value" })
|
236
|
+
order.first_name # => "Ivan"
|
237
|
+
order.secret_data # => { "some_key" => "Some Value" }
|
238
|
+
```
|
239
|
+
|
206
240
|
## Duplicate
|
207
241
|
|
208
242
|
Enable: `Sequel::Model.plugin :duplicate`
|
@@ -302,7 +336,7 @@ Example:
|
|
302
336
|
|
303
337
|
```ruby
|
304
338
|
class User < Sequel::Model
|
305
|
-
|
339
|
+
store :data, :first_name
|
306
340
|
end
|
307
341
|
|
308
342
|
user = User.create(first_name: "John")
|
@@ -354,7 +388,7 @@ Example:
|
|
354
388
|
```ruby
|
355
389
|
user = User.first
|
356
390
|
user.with_lock do
|
357
|
-
|
391
|
+
user.update(name: "James")
|
358
392
|
end
|
359
393
|
```
|
360
394
|
|
data/Rakefile
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Creates encrypted attribute storing
|
4
|
+
module Sequel::Plugins::AttrEncrypted
|
5
|
+
SEPARATOR = "$"
|
6
|
+
require "sequel/plugins/attr_encrypted/simple_crypt"
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Setup attr encrypted
|
10
|
+
#
|
11
|
+
# @param attrs [Array<Symbol>] column names
|
12
|
+
# @param key [String] 32 bytes key
|
13
|
+
# @example
|
14
|
+
# Sequel.migration do
|
15
|
+
# change do
|
16
|
+
# alter_table :orders do
|
17
|
+
# add_column :encrypted_first_name, :text
|
18
|
+
# add_column :encrypted_last_name, :text
|
19
|
+
# add_column :encrypted_secret_data, :text
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# class Order < Sequel::Model
|
25
|
+
# attr_encrypted :first_name, :last_name, key: Settings.private_key
|
26
|
+
# attr_encrypted :secret_data, key: Settings.another_private_key
|
27
|
+
# end
|
28
|
+
|
29
|
+
# Order.create(first_name: "Ivan")
|
30
|
+
# # => INSERT INTO "orders" ("encrypted_first_name")
|
31
|
+
# VALUES ('/sTi9Q==$OTpuMRq5k8R3JayQ$WjSManQGP9UaZ3C40yDjKg==')
|
32
|
+
#
|
33
|
+
# order = Order.create(first_name: "Ivan", last_name: "Smith",
|
34
|
+
# secret_data: { "some_key" => "Some Value" })
|
35
|
+
# order.first_name # => "Ivan"
|
36
|
+
# order.last_name # => "Smith"
|
37
|
+
# order.secret_data # => { "some_key" => "Some Value" }
|
38
|
+
def attr_encrypted(*attrs, key:)
|
39
|
+
include_encrypted_module!
|
40
|
+
attrs.each do |attr|
|
41
|
+
define_encrypted_setter(attr, key)
|
42
|
+
define_encrypted_getter(attr, key)
|
43
|
+
@_encrypted_attributes << attr
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def define_encrypted_setter(attr, key)
|
50
|
+
@_attr_encrypted_module.module_eval do
|
51
|
+
define_method("#{attr}=") do |value|
|
52
|
+
instance_variable_set("@#{attr}", value)
|
53
|
+
|
54
|
+
send("encrypted_#{attr}=", SimpleCrypt.encrypt(value.to_json, key))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_encrypted_getter(attr, key)
|
60
|
+
@_attr_encrypted_module.module_eval do
|
61
|
+
define_method(attr.to_s) do
|
62
|
+
instance_variable_get("@#{attr}") || begin
|
63
|
+
decrypted = SimpleCrypt.decrypt(send("encrypted_#{attr}"), key)
|
64
|
+
|
65
|
+
result = !decrypted.nil? ? JSON.parse(decrypted) : decrypted
|
66
|
+
instance_variable_set("@#{attr}", result)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def include_encrypted_module!
|
73
|
+
return if defined?(@_attr_encrypted_module)
|
74
|
+
|
75
|
+
@_encrypted_attributes ||= []
|
76
|
+
@_attr_encrypted_module = Module.new
|
77
|
+
prepend @_attr_encrypted_module
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module InstanceMethods
|
82
|
+
def save(*)
|
83
|
+
super.tap { _reset_encrypted_attrs_ivars }
|
84
|
+
end
|
85
|
+
|
86
|
+
def refresh(*)
|
87
|
+
super.tap { _reset_encrypted_attrs_ivars }
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def _reset_encrypted_attrs_ivars
|
93
|
+
self.class.instance_variable_get(:@_encrypted_attributes)&.each do |attr|
|
94
|
+
instance_variable_set("@#{attr}", nil)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequel::Plugins::AttrEncrypted::SimpleCrypt
|
4
|
+
extend self
|
5
|
+
require "base64"
|
6
|
+
|
7
|
+
SEPARATOR = "$"
|
8
|
+
|
9
|
+
def encrypt(string, key)
|
10
|
+
return unless string.is_a?(String) && !string.empty?
|
11
|
+
|
12
|
+
encryptor = new_cipher(key, &:encrypt)
|
13
|
+
iv = encryptor.random_iv
|
14
|
+
|
15
|
+
encrypted = encryptor.update(string) + encryptor.final
|
16
|
+
dump(encrypted, iv, encryptor.auth_tag)
|
17
|
+
end
|
18
|
+
|
19
|
+
def decrypt(string, key)
|
20
|
+
encrypted, iv, auth_tag = parse(string) if string.is_a?(String)
|
21
|
+
return if [encrypted, iv, auth_tag].any?(&:nil?)
|
22
|
+
|
23
|
+
decryptor = new_cipher(key, &:decrypt)
|
24
|
+
decryptor.iv = iv
|
25
|
+
decryptor.auth_tag = auth_tag
|
26
|
+
|
27
|
+
decryptor.update(encrypted) + decryptor.final
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def new_cipher(key)
|
33
|
+
result = OpenSSL::Cipher.new("aes-256-gcm")
|
34
|
+
yield(result)
|
35
|
+
result.key = key
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse(string)
|
40
|
+
string.split(SEPARATOR).map { |x| Base64.strict_decode64(x) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def dump(*values)
|
44
|
+
Array(values).map { |x| Base64.strict_encode64(x) }.join(SEPARATOR)
|
45
|
+
end
|
46
|
+
end
|
@@ -8,10 +8,10 @@ module Sequel
|
|
8
8
|
# Rollback a migration
|
9
9
|
def undo(version)
|
10
10
|
path = files.find { |file| migration_version_from_file(get_filename(file)) == version }
|
11
|
-
|
11
|
+
error!("Migration #{version} does not exist in the filesystem") unless path
|
12
12
|
|
13
13
|
filename = get_filename(path)
|
14
|
-
|
14
|
+
error!("Migration #{version} is not applied") unless applied_migrations.include?(filename)
|
15
15
|
|
16
16
|
migration = get_migration(path)
|
17
17
|
|
@@ -41,7 +41,7 @@ module Sequel
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
Sequel::TimestampMigrator.prepend
|
44
|
+
Sequel::TimestampMigrator.prepend(TimestampMigratorLogger)
|
45
45
|
|
46
46
|
private
|
47
47
|
|
@@ -57,6 +57,10 @@ module Sequel
|
|
57
57
|
def get_filename(path)
|
58
58
|
File.basename(path).downcase
|
59
59
|
end
|
60
|
+
|
61
|
+
def error!(message)
|
62
|
+
raise Sequel::Migrator::Error, message
|
63
|
+
end
|
60
64
|
end
|
61
65
|
end
|
62
66
|
# rubocop:enable Layout/ClassStructure
|
data/utils/database.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: umbrellio-sequel-plugins
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.0.
|
4
|
+
version: 0.4.0.164
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nulldef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -190,6 +190,8 @@ files:
|
|
190
190
|
- lib/sequel/extensions/pg_tools.rb
|
191
191
|
- lib/sequel/extensions/slave.rb
|
192
192
|
- lib/sequel/extensions/synchronize.rb
|
193
|
+
- lib/sequel/plugins/attr_encrypted.rb
|
194
|
+
- lib/sequel/plugins/attr_encrypted/simple_crypt.rb
|
193
195
|
- lib/sequel/plugins/duplicate.rb
|
194
196
|
- lib/sequel/plugins/get_column_value.rb
|
195
197
|
- lib/sequel/plugins/money_accessors.rb
|
@@ -224,8 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
226
|
- !ruby/object:Gem::Version
|
225
227
|
version: '0'
|
226
228
|
requirements: []
|
227
|
-
|
228
|
-
rubygems_version: 2.7.7
|
229
|
+
rubygems_version: 3.0.8
|
229
230
|
signing_key:
|
230
231
|
specification_version: 4
|
231
232
|
summary: Sequel plugins
|