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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e44a8b8ccece3288519276076c2131e12741b95
4
- data.tar.gz: 9b3ae6a040a4049c4fbfdaf933e6f20fa38a5ff6
3
+ metadata.gz: 1ca73aa2b3b39d5cd33bf7e5a3b6a31605cedfd6
4
+ data.tar.gz: 6b0d9ab155ff7a442e19d754cc1a78417ffbd3d4
5
5
  SHA512:
6
- metadata.gz: 078a2f58cc191dd3bafe0b54ba141314b092f3868d9f9e3a870a4f4f48f9c7ad409ed24110498775e633dbef8387649b3c5d770ee3ce29dac597f31c0b66844b
7
- data.tar.gz: f24e6d3d7a65872cd0910b3aa7c098a1cbb2e1b7d41e84b50f86f0bd15e5dc351920de85eeed7b3b33fdc4895204332503cf33f37d6935d94b5bd0fc4efe782f
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
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <title>Common</title>
4
+ <title>Unidom Common</title>
5
5
  <%= stylesheet_link_tag 'unidom/common/application', media: 'all' %>
6
6
  <%= csrf_meta_tags %>
7
7
  </head>
@@ -1,5 +1,5 @@
1
1
  module Unidom
2
2
  module Common
3
- VERSION = '1.5'.freeze
3
+ VERSION = '1.6'.freeze
4
4
  end
5
5
  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.5'
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-02 00:00:00.000000000 Z
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