enkrip 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ed86ace6f37ae25ece693100929e8c4a85721901fdce14878ba320293937c776
4
+ data.tar.gz: 0b744465c19433f28b0317e933f11d711446aad4accdf2cbfee7863264256abc
5
+ SHA512:
6
+ metadata.gz: 22acbd270fa85f882801487b5e507b59085af06592dd57bbdd23e66e85a761683243640cf00ca9eb193c31cb99df200cff0356e3651275630cdb016c5f1aa7d5
7
+ data.tar.gz: fd963e2d091f3a29a3a5542bf0d7b4f80b5b71998c9747ed4309be683f0f2a97abbfb5dbada4fe7ae6c63b523cdc028380190feb74902bdc1c76e6c6c3da75b0
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ enkrip (0.1.0)
5
+ activerecord (>= 5.2, < 6)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (5.2.1)
11
+ activesupport (= 5.2.1)
12
+ activerecord (5.2.1)
13
+ activemodel (= 5.2.1)
14
+ activesupport (= 5.2.1)
15
+ arel (>= 9.0)
16
+ activesupport (5.2.1)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ arel (9.0.0)
22
+ concurrent-ruby (1.0.5)
23
+ i18n (1.1.1)
24
+ concurrent-ruby (~> 1.0)
25
+ minitest (5.11.3)
26
+ rake (12.3.1)
27
+ sqlite3 (1.3.13)
28
+ thread_safe (0.3.6)
29
+ tzinfo (1.2.5)
30
+ thread_safe (~> 0.1)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ bundler (~> 1.16)
37
+ enkrip!
38
+ minitest (~> 5.11)
39
+ rake (~> 12.3)
40
+ sqlite3
41
+
42
+ BUNDLED WITH
43
+ 1.16.6
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2018 Kunto Aji Kristianto
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,100 @@
1
+ # Enkrip
2
+
3
+ Encrypt & decrypt Active Record's model attributes with Message Encryptor.
4
+
5
+ ## Goals
6
+
7
+ * Seamlessly encrypt and decrypt value for both string and numeric attribute
8
+ * Compatible with Active Model validation
9
+ * Automatically convert numeric attributes to desired data types
10
+
11
+ ## Limitations
12
+
13
+ * All attributes that are defined in `numeric_attributes` will be forced to use UTF-8 encoding
14
+ * Enkrip requires Active Record 5.2 or newer
15
+ * Does not compatible with [activerecord-import](https://rubygems.org/gems/activerecord-import)
16
+
17
+ ## Installation
18
+
19
+ Add `enkrip` to your Rails app’s Gemfile and run bundle install:
20
+
21
+ ```
22
+ gem 'enkrip'
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ After installation, you need to define `ENKRIP_LENGTH`, `ENKRIP_SALT`, and `ENKRIP_SECRET` environment variables:
28
+
29
+ ```
30
+ # example
31
+ export ENKRIP_LENGTH=32 # 32 is default value from ActiveSupport::MessageEncryptor.key_len
32
+ export ENKRIP_SALT=random_salt_with_length_32 # you can generate from SecureRandom.random_bytes(YOUR_ENKRIP_LENGTH)
33
+ export ENKRIP_SECRET=random_secret_with_length_32
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ Use text data type for encrypted attributes
39
+
40
+ ```
41
+ # migration
42
+
43
+ class CreatePosts < ActiveRecord::Migration[5.2]
44
+ def change
45
+ create_table :posts do |t|
46
+ t.text :my_string
47
+ t.text :my_numeric
48
+
49
+ t.timestamps
50
+ end
51
+ end
52
+ end
53
+ ```
54
+
55
+ After run the migration, define you encrypted attributes
56
+
57
+ ```
58
+ # Active Record model
59
+
60
+ class Post < ActiveRecord::Base
61
+ include Enkrip::Model
62
+
63
+ enkrip_configure do |config|
64
+ config.string_attributes << :my_string
65
+ config.numeric_attributes << :my_numeric
66
+ config.purpose = :example # optional, default is nil
67
+ config.convert_method_for_numeric_attribute = :to_f # optional, default is to_i
68
+ config.default_value_if_numeric_attribute_blank = 0.0 # optional, default is 0
69
+ end
70
+ end
71
+ ```
72
+
73
+ You can check encrypted value from rails console with raw query
74
+
75
+ ```
76
+ # Rails 5.2 console
77
+ post = Post.new => #<Post id: nil, my_string: nil, my_numeric: nil, created_at: nil, updated_at: nil>
78
+ post.valid? # => false
79
+ post.errors.full_messages # => ["My numeric must be greater than 0", "My string can't be blank"]
80
+
81
+ post.my_string = "aloha" # => "aloha"
82
+ post.my_numeric = 5 # => 5
83
+ post.save # => true
84
+
85
+ raw = ActiveRecord::Base.connection.exec_query 'SELECT my_string, my_numeric FROM posts limit 1'
86
+
87
+ raw.rows.first[raw.columns.find_index('my_string')]
88
+ # => "TUVQcnRBck5oYzMvRlRZUWR3Mzlzdz09LS1tZ09xNGNYbnkzdFc2d1duMEIrdUdBPT0=--ffae1f04753ca5c636915746a4c6fccf81897138"
89
+
90
+ raw.rows.first[raw.columns.find_index('my_numeric')]
91
+ # => "TkdSbURRNzVMbUF6MjF0bjI2ZEtmQT09LS1rRHhqQ2xpWGhYaHBoRlhCRnVZSmh3PT0=--74e45e6c96df78258a1731994a71a74c5047d655"
92
+
93
+ post.reload
94
+ post.my_string # => "aloha"
95
+ post.my_numeric # => 5
96
+ ```
97
+
98
+ ## License
99
+
100
+ Enkrip is released under the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc 'Run tests'
8
+ task default: :test
@@ -0,0 +1,21 @@
1
+ require 'date'
2
+ require_relative 'lib/enkrip/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'enkrip'
6
+ spec.version = Enkrip::VERSION
7
+ spec.date = Date.today.to_s
8
+ spec.summary = 'encrypt & decrypt Active Record attributes with Message Encryptor'
9
+ spec.description = 'Enkrip will encrypt & decrypt Active Record attributes seamlessly with Message Encryptor. By default compatible with Active model validation'
10
+ spec.author = 'Kunto Aji Kristianto'
11
+ spec.email = 'kuntoaji@kaklabs.com'
12
+ spec.files = `git ls-files -z`.split("\x0")
13
+ spec.homepage = 'http://github.com/kuntoaji/enkrip'
14
+ spec.license = 'MIT'
15
+
16
+ spec.add_dependency 'activerecord', '>= 5.2', '< 6'
17
+ spec.add_development_dependency 'bundler', '~> 1.16'
18
+ spec.add_development_dependency 'rake', '~> 12.3'
19
+ spec.add_development_dependency 'minitest', '~> 5.11'
20
+ spec.add_development_dependency 'sqlite3', '~> 0'
21
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+ require 'enkrip/version'
5
+ require 'enkrip/engine'
6
+ require 'enkrip/model'
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enkrip
4
+ LENGTH = ENV['ENKRIP_LENGTH'].to_i # ActiveSupport::MessageEncryptor.key_len
5
+ SALT = ENV['ENKRIP_SALT'] # SecureRandom.random_bytes(LENGTH)
6
+ SECRET = ENV['ENKRIP_SECRET']
7
+ KEY = ActiveSupport::KeyGenerator.new(SECRET).generate_key(SALT, LENGTH).freeze
8
+
9
+ class Engine
10
+ class << self
11
+ @@verifier = ActiveSupport::MessageEncryptor.new(Enkrip::KEY)
12
+
13
+ def encrypt(value, purpose: nil)
14
+ @@verifier.encrypt_and_sign value, purpose: purpose
15
+ end
16
+
17
+ def decrypt(value, purpose: nil)
18
+ @@verifier.decrypt_and_verify value, purpose: purpose
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enkrip
4
+ module Model
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ after_find :decrypt
9
+ before_save :encrypt
10
+ after_save :decrypt
11
+
12
+ def encrypt
13
+ self.class::ENCRYPTED_CONFIG.all_attributes.each do |attr|
14
+ self[attr] = Enkrip::Engine.encrypt(self[attr], purpose: self.class::ENCRYPTED_CONFIG.purpose) if respond_to?(attr) && self[attr].present?
15
+ end
16
+ end
17
+
18
+ def decrypt
19
+ self.class::ENCRYPTED_CONFIG.all_attributes.each do |attr|
20
+ self[attr] = Enkrip::Engine.decrypt(self[attr], purpose: self.class::ENCRYPTED_CONFIG.purpose) if respond_to?(attr) && self[attr].present?
21
+ end
22
+ end
23
+ end
24
+
25
+ class_methods do
26
+ def enkrip_configure
27
+ config = OpenStruct.new(
28
+ string_attributes: [],
29
+ numeric_attributes: [],
30
+ purpose: nil,
31
+ convert_method_for_numeric_attribute: :to_i,
32
+ default_value_if_numeric_attribute_blank: 0
33
+ )
34
+
35
+ yield config
36
+
37
+ config.all_attributes = config.string_attributes + config.numeric_attributes
38
+ const_set :ENCRYPTED_CONFIG, config
39
+
40
+ config.numeric_attributes.each do |attr|
41
+ define_method(attr) do
42
+ value = super()
43
+ value.present? ? value.force_encoding('UTF-8').send(config.convert_method_for_numeric_attribute) : config.default_value_if_numeric_attribute_blank
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enkrip
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ describe Enkrip do
4
+ def test_version
5
+ assert Enkrip::VERSION
6
+ end
7
+
8
+ def test_encryption_decryption
9
+ model = ExampleModel.new my_string: '', my_numeric: 0
10
+ assert_equal model.valid?, false
11
+
12
+ model.my_string = 'my example string'
13
+ model.my_numeric = 1
14
+ model.save!
15
+ model.reload
16
+
17
+ raw = ActiveRecord::Base.connection.exec_query 'SELECT my_string, my_numeric FROM example_models limit 1'
18
+ encrypted_my_string = raw.rows.first.first
19
+ encrypted_my_numeric = raw.rows.first.last
20
+
21
+ assert_equal encrypted_my_string.nil?, false
22
+ assert_equal encrypted_my_string.empty?, false
23
+ refute_equal encrypted_my_string, model.my_string
24
+ assert_equal model.my_string, 'my example string'
25
+ assert_equal Enkrip::Engine.decrypt(encrypted_my_string, purpose: :example), 'my example string'
26
+
27
+ assert_equal encrypted_my_numeric.nil?, false
28
+ assert_equal encrypted_my_numeric.empty?, false
29
+ refute_equal encrypted_my_numeric, model.my_numeric
30
+ assert_equal model.my_numeric, 1
31
+ assert_equal Enkrip::Engine.decrypt(encrypted_my_numeric, purpose: :example).to_i, 1
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+
3
+ ENV['ENKRIP_LENGTH'] = '32'
4
+ ENV['ENKRIP_SALT'] = 'y\xBC\xAD\xA7\xAE6\xAD\x9F](\x89\xB2\xF6!\xED\xC8\xA2(1\x8E\xA9&/ef`\xD3\xB3\x11\xB6C\xB4' # SecureRandom.random_bytes(LENGTH)
5
+ ENV['ENKRIP_SECRET'] = 'f031fbebc6bb5a69094139c24090fd42'
6
+
7
+ require_relative '../lib/enkrip'
8
+
9
+ ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:', encoding: 'unicode'
10
+ ActiveRecord::Base.connection.create_table(:example_models, force: true) do |t|
11
+ t.text :my_string
12
+ t.text :my_numeric
13
+ end
14
+
15
+ class ExampleModel < ActiveRecord::Base
16
+ include Enkrip::Model
17
+ validates :my_numeric, numericality: { greater_than: 0 }
18
+ validates :my_string, presence: true
19
+
20
+ enkrip_configure do |config|
21
+ config.string_attributes << :my_string
22
+ config.numeric_attributes << :my_numeric
23
+ config.purpose = :example # optional
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enkrip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kunto Aji Kristianto
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-10-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6'
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.16'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.16'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '12.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '12.3'
61
+ - !ruby/object:Gem::Dependency
62
+ name: minitest
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.11'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '5.11'
75
+ - !ruby/object:Gem::Dependency
76
+ name: sqlite3
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ description: Enkrip will encrypt & decrypt Active Record attributes seamlessly with
90
+ Message Encryptor. By default compatible with Active model validation
91
+ email: kuntoaji@kaklabs.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - ".gitignore"
97
+ - Gemfile
98
+ - Gemfile.lock
99
+ - LICENSE.txt
100
+ - README.md
101
+ - Rakefile
102
+ - enkrip.gemspec
103
+ - lib/enkrip.rb
104
+ - lib/enkrip/engine.rb
105
+ - lib/enkrip/model.rb
106
+ - lib/enkrip/version.rb
107
+ - test/test_enkrip.rb
108
+ - test/test_helper.rb
109
+ homepage: http://github.com/kuntoaji/enkrip
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.7.6
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: encrypt & decrypt Active Record attributes with Message Encryptor
133
+ test_files: []