unidom-common 1.5 → 1.6
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/README.md +120 -0
- data/app/models/unidom/common/concerns/argument_validation.rb +21 -0
- data/app/models/unidom/common/concerns/exact_column.rb +35 -0
- data/app/models/unidom/common/concerns/model_extension.rb +17 -1
- data/app/models/unidom/common/concerns/notation_column.rb +52 -0
- data/app/models/unidom/common/concerns/secure_column.rb +58 -0
- data/app/views/layouts/unidom/common/application.html.erb +1 -1
- data/lib/unidom/common/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ca73aa2b3b39d5cd33bf7e5a3b6a31605cedfd6
|
4
|
+
data.tar.gz: 6b0d9ab155ff7a442e19d754cc1a78417ffbd3d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ba36cf153a52b1f321b4a97279fce29b33b7b891652d45c3afe96304491337cb3065ebb81df668e6d3c8cac649fd6020a77dd3e7c874f6fb38d990f901eff4e
|
7
|
+
data.tar.gz: c39c2db1e0bad0c883cea0dfafdd5cf84c20050c88414bc8b8966f46ca43fff4d5f96f4491fdf49b41a5d3cc1c2bf9938ae09bdd71833f8cf09678514a940fc6
|
data/README.md
CHANGED
@@ -164,6 +164,126 @@ Person.passport_number_is('E00000000').first==person # true
|
|
164
164
|
|
165
165
|
|
166
166
|
|
167
|
+
## Secure Column
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
# db/migrate/YYYYMMDDHHMMSS_create_orderings.rb
|
171
|
+
class CreateOrderings < ActiveRecord::Migration[5.0]
|
172
|
+
|
173
|
+
def change
|
174
|
+
|
175
|
+
create_table :orderings, id: :uuid do |t|
|
176
|
+
|
177
|
+
t.string :placer_name, null: false, default: nil, limit: 200
|
178
|
+
t.string :taker_name, null: false, default: nil, limit: 200
|
179
|
+
t.string :receiver_name, null: false, default: nil, limit: 200
|
180
|
+
|
181
|
+
t.jsonb :placer
|
182
|
+
t.jsonb :taker
|
183
|
+
t.jsonb :receiver
|
184
|
+
|
185
|
+
t.binary :placer_identification_number_exact_signature, null: false, default: nil, limit: 80
|
186
|
+
t.binary :placer_mobile_phone_number_exact_signature, null: false, default: nil, limit: 80
|
187
|
+
t.binary :taker_identification_number_exact_signature, null: false, default: nil, limit: 80
|
188
|
+
t.binary :taker_mobile_phone_number_exact_signature, null: false, default: nil, limit: 80
|
189
|
+
t.binary :receiver_identification_number_exact_signature, null: false, default: nil, limit: 80
|
190
|
+
t.binary :receiver_mobile_phone_number_exact_signature, null: false, default: nil, limit: 80
|
191
|
+
|
192
|
+
t.column :state, 'char(1)', null: false, default: 'C'
|
193
|
+
t.datetime :opened_at, null: false, default: Time.utc(1970)
|
194
|
+
t.datetime :closed_at, null: false, default: Time.utc(3000)
|
195
|
+
t.boolean :defunct, null: false, default: false
|
196
|
+
t.jsonb :notation, null: false, default: {}
|
197
|
+
|
198
|
+
t.timestamps
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
add_index :orderings, :placer_identification_number_exact_signature, name: :index_orderings_on_placer_identification_number
|
203
|
+
add_index :orderings, :placer_mobile_phone_number_exact_signature, name: :index_orderings_on_placer_mobile_phone_number
|
204
|
+
add_index :orderings, :taker_identification_number_exact_signature, name: :index_orderings_on_taker_identification_number
|
205
|
+
add_index :orderings, :taker_mobile_phone_number_exact_signature, name: :index_orderings_on_taker_mobile_phone_number
|
206
|
+
add_index :orderings, :receiver_identification_number_exact_signature, name: :index_orderings_on_receiver_identification_number
|
207
|
+
add_index :orderings, :receiver_mobile_phone_number_exact_signature, name: :index_orderings_on_receiver_mobile_phone_number
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
# app/models/orderings.rb
|
214
|
+
class Ordering < ApplicationRecord
|
215
|
+
|
216
|
+
include Unidom::Common::Concerns::ModelExtension
|
217
|
+
|
218
|
+
validates :placer_name, presence: true, length: { in: 2..columns_hash['placer_name'].limit }
|
219
|
+
validates :taker_name, presence: true, length: { in: 2..columns_hash['taker_name'].limit }
|
220
|
+
validates :receiver_name, presence: true, length: { in: 2..columns_hash['receiver_name'].limit }
|
221
|
+
|
222
|
+
validates :placer_address, presence: true, length: { in: 2..200 }
|
223
|
+
validates :taker_address, presence: true, length: { in: 2..200 }
|
224
|
+
validates :receiver_address, presence: true, length: { in: 2..200 }
|
225
|
+
|
226
|
+
validates :placer_identification_number, presence: true, length: { is: 18 }, format: Unidom::Certificate::China::IdentityCard::FORMAT_VALIDATION_REGEX
|
227
|
+
validates :taker_identification_number, presence: true, length: { is: 18 }, format: Unidom::Certificate::China::IdentityCard::FORMAT_VALIDATION_REGEX
|
228
|
+
validates :receiver_identification_number, presence: true, length: { is: 18 }, format: Unidom::Certificate::China::IdentityCard::FORMAT_VALIDATION_REGEX
|
229
|
+
|
230
|
+
validates :placer_mobile_phone_number, presence: true, length: { is: 11 }, numericality: { integer_only: true }, format: Unidom::Contact::China::MobilePhoneNumber::FORMAT_VALIDATION_REGEX
|
231
|
+
validates :taker_mobile_phone_number, presence: true, length: { is: 11 }, numericality: { integer_only: true }, format: Unidom::Contact::China::MobilePhoneNumber::FORMAT_VALIDATION_REGEX
|
232
|
+
validates :receiver_mobile_phone_number, presence: true, length: { is: 11 }, numericality: { integer_only: true }, format: Unidom::Contact::China::MobilePhoneNumber::FORMAT_VALIDATION_REGEX
|
233
|
+
|
234
|
+
exact_column :placer_identification_number, :placer_mobile_phone_number
|
235
|
+
exact_column :taker_identification_number, :taker_mobile_phone_number
|
236
|
+
exact_column :receiver_identification_number, :receiver_mobile_phone_number
|
237
|
+
|
238
|
+
secure_column :placer, fields: [ :placer_name, :placer_address, :placer_identification_number, :placer_mobile_phone_number ]
|
239
|
+
secure_column :taker, fields: [ :taker_name, :taker_address, :taker_identification_number, :taker_mobile_phone_number ]
|
240
|
+
secure_column :receiver, fields: [ :receiver_name, :receiver_address, :receiver_identification_number, :receiver_mobile_phone_number ]
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
# in any controller or rails console:
|
245
|
+
@placer_name = 'Tim'
|
246
|
+
@taker_name = 'Bob'
|
247
|
+
@receiver_name = 'Roy'
|
248
|
+
|
249
|
+
@placer_identification_number = '11022119801231999X'
|
250
|
+
@taker_identification_number = '350105199006184567'
|
251
|
+
@receiver_identification_number = '532307200001010003'
|
252
|
+
|
253
|
+
@placer_mobile_phone_number = '13987654321'
|
254
|
+
@taker_mobile_phone_number = '18812345678'
|
255
|
+
@receiver_mobile_phone_number = '17101020304'
|
256
|
+
|
257
|
+
@placer_address = 'Beijing'
|
258
|
+
@taker_address = 'Jiangsu'
|
259
|
+
@receiver_address = 'Guizhou'
|
260
|
+
|
261
|
+
@ordering = Ordering.new opened_at: Time.now,
|
262
|
+
placer_name: @placer_name,
|
263
|
+
taker_name: @taker_name,
|
264
|
+
receiver_name: @receiver_name,
|
265
|
+
placer_address: @placer_address,
|
266
|
+
taker_address: @taker_address,
|
267
|
+
receiver_address: @receiver_address,
|
268
|
+
placer_identification_number: @placer_identification_number,
|
269
|
+
taker_identification_number: @taker_identification_number,
|
270
|
+
receiver_identification_number: @receiver_identification_number,
|
271
|
+
placer_mobile_phone_number: @placer_mobile_phone_number,
|
272
|
+
taker_mobile_phone_number: @taker_mobile_phone_number,
|
273
|
+
receiver_mobile_phone_number: @receiver_mobile_phone_number
|
274
|
+
@ordering.save!
|
275
|
+
|
276
|
+
ordering_1 = Ordering.placer_identification_number_is(@placer_identification_number).valid_at.alive.first
|
277
|
+
ordering_2 = Ordering.taker_identification_number_is(@taker_identification_number).valid_at.alive.first
|
278
|
+
ordering_3 = Ordering.receiver_identification_number_is(@receiver_identification_number).valid_at.alive.first
|
279
|
+
ordering_4 = Ordering.placer_mobile_phone_number_is(@placer_mobile_phone_number).valid_at.alive.first
|
280
|
+
ordering_5 = Ordering.taker_mobile_phone_number_is(@taker_mobile_phone_number).valid_at.alive.first
|
281
|
+
ordering_6 = Ordering.receiver_mobile_phone_number_is(@receiver_mobile_phone_number).valid_at.alive.first
|
282
|
+
# @ordering should be identical to any of ordering_1, ordering_2, ordering_3, ordering_4, ordering_5, or ordering_6
|
283
|
+
```
|
284
|
+
|
285
|
+
|
286
|
+
|
167
287
|
## Numeration
|
168
288
|
|
169
289
|
```ruby
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Unidom::Common::Concerns::ArgumentValidation
|
2
|
+
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do |includer|
|
6
|
+
|
7
|
+
def assert_present!(name, value)
|
8
|
+
raise ArgumentError.new("The #{name} argument is required.") if value.blank?
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
def assert_present!(name, value)
|
16
|
+
raise ArgumentError.new("The #{name} argument is required.") if value.blank?
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Unidom::Common::Concerns::ExactColumn
|
2
|
+
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do |includer|
|
6
|
+
|
7
|
+
cattr_accessor :exact_column_names
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def exact_column(*names)
|
14
|
+
|
15
|
+
exact_column_names = exact_column_names||[]
|
16
|
+
exact_column_names += names
|
17
|
+
|
18
|
+
names.each do |name|
|
19
|
+
name = name.to_s
|
20
|
+
instance_eval do
|
21
|
+
scope :"#{name}_is", ->(value) { where "#{name}_exact_signature" => exact_signature(self, name, value) }
|
22
|
+
before_save do send "#{name}_exact_signature=", self.class.exact_signature(self.class, name, send(name)) end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def exact_signature(klass, name, value)
|
29
|
+
text = "#{Rails.application.secrets[:secret_key_base]}@#{Rails.root}/#{klass.table_name}##{name}=#{value}"
|
30
|
+
"#{Digest::MD5.digest(text)}#{Digest::SHA512.digest(text)}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -2,6 +2,11 @@ module Unidom::Common::Concerns::ModelExtension
|
|
2
2
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
+
include Unidom::Common::Concerns::ArgumentValidation
|
6
|
+
include Unidom::Common::Concerns::NotationColumn
|
7
|
+
include Unidom::Common::Concerns::ExactColumn
|
8
|
+
include Unidom::Common::Concerns::SecureColumn
|
9
|
+
|
5
10
|
included do |includer|
|
6
11
|
|
7
12
|
validates :state, presence: true, length: { is: columns_hash['state'].limit }
|
@@ -17,6 +22,7 @@ module Unidom::Common::Concerns::ModelExtension
|
|
17
22
|
scope :alive, ->(living: true) { where defunct: !living }
|
18
23
|
scope :dead, ->(defunct: true) { where defunct: defunct }
|
19
24
|
|
25
|
+
=begin
|
20
26
|
scope :notation_column_where, ->(name, operator, value) do
|
21
27
|
operation = :like==operator ? { operator: 'ILIKE', value: "%#{value}%" } : { operator: operator.to_s, value: value }
|
22
28
|
where "#{table_name}.notation -> 'columns' ->> '#{name}' #{operation[:operator]} :value", value: operation[:value]
|
@@ -25,6 +31,7 @@ module Unidom::Common::Concerns::ModelExtension
|
|
25
31
|
scope :notation_boolean_column_where, ->(name, value) do
|
26
32
|
where "(#{table_name}.notation -> 'columns' ->> '#{name}')::boolean = :value", value: (value ? true : false)
|
27
33
|
end
|
34
|
+
=end
|
28
35
|
|
29
36
|
if columns_hash['ordinal'].present?&&:integer==columns_hash['ordinal'].type
|
30
37
|
validates :ordinal, presence: true, numericality: { integer_only: true, greater_than: 0 }
|
@@ -136,9 +143,11 @@ module Unidom::Common::Concerns::ModelExtension
|
|
136
143
|
end
|
137
144
|
end
|
138
145
|
|
146
|
+
=begin
|
139
147
|
def assert_present!(name, value)
|
140
148
|
raise ArgumentError.new("The #{name} argument is required.") if value.blank?
|
141
149
|
end
|
150
|
+
=end
|
142
151
|
|
143
152
|
end
|
144
153
|
|
@@ -147,7 +156,7 @@ module Unidom::Common::Concerns::ModelExtension
|
|
147
156
|
def to_id(model)
|
148
157
|
model.respond_to?(:id) ? model.id : model
|
149
158
|
end
|
150
|
-
|
159
|
+
=begin
|
151
160
|
def notation_column(*names)
|
152
161
|
names.each do |name|
|
153
162
|
name = name.to_s
|
@@ -177,7 +186,9 @@ module Unidom::Common::Concerns::ModelExtension
|
|
177
186
|
end
|
178
187
|
end
|
179
188
|
end
|
189
|
+
=end
|
180
190
|
|
191
|
+
=begin
|
181
192
|
def exact_column(*names)
|
182
193
|
names.each do |name|
|
183
194
|
name = name.to_s
|
@@ -189,15 +200,20 @@ module Unidom::Common::Concerns::ModelExtension
|
|
189
200
|
end
|
190
201
|
end
|
191
202
|
end
|
203
|
+
=end
|
192
204
|
|
205
|
+
=begin
|
193
206
|
def assert_present!(name, value)
|
194
207
|
raise ArgumentError.new("The #{name} argument is required.") if value.blank?
|
195
208
|
end
|
209
|
+
=end
|
196
210
|
|
211
|
+
=begin
|
197
212
|
def exact_signature(klass, name, value)
|
198
213
|
text = "#{Rails.application.secrets[:secret_key_base]}@#{Rails.root}/#{klass.table_name}##{name}=#{value}"
|
199
214
|
"#{Digest::MD5.digest(text)}#{Digest::SHA512.digest(text)}"
|
200
215
|
end
|
216
|
+
=end
|
201
217
|
|
202
218
|
end
|
203
219
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Unidom::Common::Concerns::NotationColumn
|
2
|
+
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do |includer|
|
6
|
+
|
7
|
+
scope :notation_column_where, ->(name, operator, value) do
|
8
|
+
operation = :like==operator ? { operator: 'ILIKE', value: "%#{value}%" } : { operator: operator.to_s, value: value }
|
9
|
+
where "#{table_name}.notation -> 'columns' ->> '#{name}' #{operation[:operator]} :value", value: operation[:value]
|
10
|
+
end
|
11
|
+
|
12
|
+
scope :notation_boolean_column_where, ->(name, value) do
|
13
|
+
where "(#{table_name}.notation -> 'columns' ->> '#{name}')::boolean = :value", value: (value ? true : false)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
def notation_column(*names)
|
21
|
+
names.each do |name|
|
22
|
+
name = name.to_s
|
23
|
+
instance_eval do
|
24
|
+
define_method(name) do
|
25
|
+
notation.try(:[], 'columns').try(:[], name)
|
26
|
+
end
|
27
|
+
define_method("#{name}=") do |value|
|
28
|
+
notation['columns'] ||= {}
|
29
|
+
notation['columns'][name] = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def notation_boolean_column(*names)
|
36
|
+
names.each do |name|
|
37
|
+
name = name.to_s
|
38
|
+
instance_eval do
|
39
|
+
define_method("#{name}?") do
|
40
|
+
notation.try(:[], 'columns').try(:[], name)
|
41
|
+
end
|
42
|
+
define_method("#{name}=") do |value|
|
43
|
+
notation['columns'] ||= {}
|
44
|
+
notation['columns'][name] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Unidom::Common::Concerns::SecureColumn
|
2
|
+
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include Unidom::Common::Concerns::ExactColumn
|
5
|
+
include Unidom::Common::Concerns::Aes256Cryptor
|
6
|
+
|
7
|
+
included do |includer|
|
8
|
+
|
9
|
+
cattr_accessor :secure_columns
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
def secure_column(name, fields: [])
|
16
|
+
|
17
|
+
name = name.to_s
|
18
|
+
secure_columns = secure_columns||{}
|
19
|
+
if secure_columns[name].present?
|
20
|
+
raise ArgumentError.new("The #{name} column was defined as a secure column already.")
|
21
|
+
else
|
22
|
+
secure_columns[name] = fields
|
23
|
+
end
|
24
|
+
fields.each do |field| attr_accessor field.to_sym if columns_hash[field.to_s].blank? end
|
25
|
+
|
26
|
+
instance_eval do
|
27
|
+
|
28
|
+
before_save do
|
29
|
+
content = { 'nonce' => SecureRandom.hex(8), 'timestamp' => Time.now.to_i }
|
30
|
+
secure_columns[name].each do |field| content[field.to_s] = send(field) end
|
31
|
+
content = content.sort.to_h.to_json
|
32
|
+
aes_key = Digest::SHA512::digest self.class.exact_signature(self.class, name, '')
|
33
|
+
encoded = hex_encrypt content, key: aes_key
|
34
|
+
json = {
|
35
|
+
encoded: encoded,
|
36
|
+
signature: Unidom::Common::Numeration.hex(self.class.exact_signature self.class, name, content)
|
37
|
+
}
|
38
|
+
send "#{name}=", json
|
39
|
+
end
|
40
|
+
|
41
|
+
after_find do
|
42
|
+
json = send(name)
|
43
|
+
return if json['encoded'].blank?||json['signature'].blank?
|
44
|
+
aes_key = Digest::SHA512::digest self.class.exact_signature(self.class, name, '')
|
45
|
+
content = decrypt Unidom::Common::Numeration.rev_hex(json['encoded']), key: aes_key
|
46
|
+
actual_signature = self.class.exact_signature(self.class, name, content)
|
47
|
+
return if Unidom::Common::Numeration.rev_hex(json['signature'])!=actual_signature
|
48
|
+
parsed = JSON.parse content
|
49
|
+
parsed.each do |key, value| send "#{key}=", value unless [ 'nonce', 'timestamp' ].include? key end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unidom-common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Topbit Du
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -82,8 +82,12 @@ files:
|
|
82
82
|
- app/controllers/unidom/common/application_controller.rb
|
83
83
|
- app/helpers/unidom/common/application_helper.rb
|
84
84
|
- app/models/unidom/common/concerns/aes256_cryptor.rb
|
85
|
+
- app/models/unidom/common/concerns/argument_validation.rb
|
86
|
+
- app/models/unidom/common/concerns/exact_column.rb
|
85
87
|
- app/models/unidom/common/concerns/md5_digester.rb
|
86
88
|
- app/models/unidom/common/concerns/model_extension.rb
|
89
|
+
- app/models/unidom/common/concerns/notation_column.rb
|
90
|
+
- app/models/unidom/common/concerns/secure_column.rb
|
87
91
|
- app/models/unidom/common/concerns/sha1_digester.rb
|
88
92
|
- app/models/unidom/common/concerns/sha256_digester.rb
|
89
93
|
- app/models/unidom/common/concerns/sha2_digester.rb
|