unidom-common 1.5 → 1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|