has_checksum 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0f066270f67757a8b3f61e7ca0a8d8f0d8ded705a73d31ecb8c6e09fdb723690
4
+ data.tar.gz: 021c8c7a2e3896c860875d815d58c089bbdf6cfae70de210628ff7dd0f7f87db
5
+ SHA512:
6
+ metadata.gz: 13ddd916e34295c9b62f75e896d742da8c726c23e93f880ffcefa1373aa8ab278bfd4c793283e8fa7ec29fec437f1327fe3b2377aea65f449d7082af3fc20777
7
+ data.tar.gz: 56d229b20e5412cbc6bd20dd9ae1a98bc8f4bce638ae9782ec51416357314e0e8d7ea6a8aecc046931cdd8612f848f4b3d96186c120377a6a4d09c78b83247f3
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,34 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
9
+ - 2.6
10
+ - 2.7
11
+
12
+ before_install:
13
+ - gem update --system
14
+ - gem update bundler
15
+ - gem cleanup bundler
16
+
17
+ gemfile:
18
+ - gemfiles/4.2.gemfile
19
+ - gemfiles/5.0.gemfile
20
+ - gemfiles/5.1.gemfile
21
+ - gemfiles/5.2.gemfile
22
+ - gemfiles/6.0.gemfile
23
+
24
+ matrix:
25
+ exclude:
26
+ - rvm: 2.3
27
+ gemfile: gemfiles/6.0.gemfile
28
+ - rvm: 2.4
29
+ gemfile: gemfiles/6.0.gemfile
30
+ - rvm: 2.7
31
+ gemfile: gemfiles/4.2.gemfile
32
+
33
+ notifications:
34
+ email: false
@@ -0,0 +1,24 @@
1
+ appraise "4.2" do
2
+ gem "activerecord", "~> 4.2.11"
3
+ gem "sqlite3", "~> 1.3.6"
4
+ end
5
+
6
+ appraise "5.0" do
7
+ gem "activerecord", "~> 5.0.7"
8
+ gem "sqlite3", "~> 1.3.6"
9
+ end
10
+
11
+ appraise "5.1" do
12
+ gem "activerecord", "~> 5.1.7"
13
+ gem "sqlite3"
14
+ end
15
+
16
+ appraise "5.2" do
17
+ gem "activerecord", "~> 5.2.4"
18
+ gem "sqlite3"
19
+ end
20
+
21
+ appraise "6.0" do
22
+ gem "activerecord", "~> 6.0.2"
23
+ gem "sqlite3"
24
+ end
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 sshaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,131 @@
1
+ # HasChecksum
2
+
3
+ [![Build Status](https://travis-ci.org/sshaw/has_checksum.svg?branch=master)](https://travis-ci.org/sshaw/has_checksum)
4
+
5
+ Automatically calculate checksums and signatures from the values of your class' attributes/methods
6
+
7
+ Works with POROs and ActiveRecord.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem "has_checksum"
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ gem install has_checksum
24
+
25
+ ## Usage
26
+
27
+ Use the [`has_checksum`](#has_checksum) and/or [`has_signature`](#has_signature) class methods to calculate checksums or signatures of your class' columns and/or methods' return values.
28
+
29
+ ### `has_checksum`
30
+
31
+ ```rb
32
+ class User
33
+ include HasChecksum
34
+
35
+ attr_accessor :username
36
+
37
+ has_checksum :username
38
+ end
39
+
40
+ user = User.new
41
+ user.username = "sshaw"
42
+ user.username_checksum # 5b891e901f3c8859115dcdfe323944ec7b4abbde9f7b680430fca7d2c7af89e5
43
+ ```
44
+
45
+ By default SHA256 is used.
46
+
47
+ Multiple attributes can be specified:
48
+
49
+ ```rb
50
+ class User
51
+ include HasChecksum
52
+
53
+ attr_accessor :username
54
+ attr_accessor :updated_at
55
+
56
+ has_checksum :username, :updated_at
57
+ end
58
+
59
+ user = User.new
60
+ user.username = "sshaw"
61
+ user.updated_at = Time.now
62
+ user.username_updated_at_checksum # bf6bfb33a4927184eae61195afcff0b033b13da15d79629d513639717c06e15f
63
+ ```
64
+
65
+ Use the`:method` and `:algorithm` arguments to change the method name and algorithm. Here we use an ActiveRecord subclass:
66
+
67
+ ```rb
68
+ class User < ActiveRecord::Base
69
+ include HasChecksum
70
+
71
+ has_checksum :settings, :updated_at, :method => "settings_signature", :algorithm => "md5"
72
+ end
73
+
74
+ user.settings[:timezone] = "America/Los_Angeles"
75
+ user.save!
76
+ user.settings_signature # 4a390b8df412ab4168b9856291437bba
77
+ ```
78
+
79
+ With ActiveRecord, if the generated method is a database column, the checksum will be persisted:
80
+
81
+ ```
82
+ rails g migration add_settings_signature_to_users settings_signature:string # should use char(N), really
83
+ ```
84
+
85
+ `:algorithm` can also be a block:
86
+
87
+ ```rb
88
+ class User < ActiveRecord::Base
89
+ include HasChecksum
90
+
91
+ has_checksum :settings, :updated_at, :algorithm => ->(value) { whirlpool(value) }
92
+ end
93
+ ```
94
+
95
+ By default the checksum will be hex encoded but you can change this via `:encode`:
96
+
97
+ ```rb
98
+ class User < ActiveRecord::Base
99
+ include HasChecksum
100
+
101
+ has_checksum :settings, :updated_at, :encode => "base64" # or "binary" or "bubblebabble"
102
+ end
103
+ ```
104
+
105
+ ### `has_signature`
106
+
107
+ Calculates a hash-based message authentication code (HMAC).
108
+ This (mostly) works the same as [`has_checksum`](#has_checksum) but requires a `:key` argument that will be used as the HMAC's key:
109
+
110
+ ```rb
111
+ class User < ActiveRecord::Base
112
+ include HasChecksum
113
+
114
+ has_signature :id, :created_at, :last_login_at, :key => :some_salt_column, :method => "session_id"
115
+ end
116
+ ```
117
+
118
+ If `:key` is a `Symbol` it will treated as a method name. If it's a `String` is will be used literally, as the key.
119
+ It can also be a `Proc` that returns the key.
120
+
121
+ ## See Also
122
+
123
+ [rspec-checksum-matchers](https://gist.github.com/sshaw/df14f6f89860b2dbcfd2)
124
+
125
+ ## Author
126
+
127
+ Skye Shaw (skye.shaw -AT- gmail)
128
+
129
+ ## License
130
+
131
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.2.11"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,65 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ has_checksum (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (4.2.11.1)
10
+ activesupport (= 4.2.11.1)
11
+ builder (~> 3.1)
12
+ activerecord (4.2.11.1)
13
+ activemodel (= 4.2.11.1)
14
+ activesupport (= 4.2.11.1)
15
+ arel (~> 6.0)
16
+ activesupport (4.2.11.1)
17
+ i18n (~> 0.7)
18
+ minitest (~> 5.1)
19
+ thread_safe (~> 0.3, >= 0.3.4)
20
+ tzinfo (~> 1.1)
21
+ appraisal (2.2.0)
22
+ bundler
23
+ rake
24
+ thor (>= 0.14.0)
25
+ arel (6.0.4)
26
+ builder (3.2.4)
27
+ concurrent-ruby (1.1.5)
28
+ diff-lcs (1.3)
29
+ i18n (0.9.5)
30
+ concurrent-ruby (~> 1.0)
31
+ minitest (5.14.0)
32
+ rake (10.5.0)
33
+ rspec (3.9.0)
34
+ rspec-core (~> 3.9.0)
35
+ rspec-expectations (~> 3.9.0)
36
+ rspec-mocks (~> 3.9.0)
37
+ rspec-core (3.9.1)
38
+ rspec-support (~> 3.9.1)
39
+ rspec-expectations (3.9.0)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-mocks (3.9.1)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.9.0)
45
+ rspec-support (3.9.2)
46
+ sqlite3 (1.3.13)
47
+ thor (1.0.1)
48
+ thread_safe (0.3.6)
49
+ tzinfo (1.2.6)
50
+ thread_safe (~> 0.1)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ activerecord (~> 4.2.11)
57
+ appraisal
58
+ bundler (~> 2.0)
59
+ has_checksum!
60
+ rake (~> 10.0)
61
+ rspec (~> 3.0)
62
+ sqlite3 (~> 1.3.6)
63
+
64
+ BUNDLED WITH
65
+ 2.0.2
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.0.7"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ has_checksum (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.0.7.2)
10
+ activesupport (= 5.0.7.2)
11
+ activerecord (5.0.7.2)
12
+ activemodel (= 5.0.7.2)
13
+ activesupport (= 5.0.7.2)
14
+ arel (~> 7.0)
15
+ activesupport (5.0.7.2)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (7.1.4)
25
+ concurrent-ruby (1.1.5)
26
+ diff-lcs (1.3)
27
+ i18n (1.8.2)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.14.0)
30
+ rake (10.5.0)
31
+ rspec (3.9.0)
32
+ rspec-core (~> 3.9.0)
33
+ rspec-expectations (~> 3.9.0)
34
+ rspec-mocks (~> 3.9.0)
35
+ rspec-core (3.9.1)
36
+ rspec-support (~> 3.9.1)
37
+ rspec-expectations (3.9.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.9.0)
40
+ rspec-mocks (3.9.1)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.9.0)
43
+ rspec-support (3.9.2)
44
+ sqlite3 (1.3.13)
45
+ thor (1.0.1)
46
+ thread_safe (0.3.6)
47
+ tzinfo (1.2.6)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (~> 5.0.7)
55
+ appraisal
56
+ bundler (~> 2.0)
57
+ has_checksum!
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3 (~> 1.3.6)
61
+
62
+ BUNDLED WITH
63
+ 2.0.2
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.1.7"
6
+ gem "sqlite3"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ has_checksum (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.1.7)
10
+ activesupport (= 5.1.7)
11
+ activerecord (5.1.7)
12
+ activemodel (= 5.1.7)
13
+ activesupport (= 5.1.7)
14
+ arel (~> 8.0)
15
+ activesupport (5.1.7)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (8.0.0)
25
+ concurrent-ruby (1.1.5)
26
+ diff-lcs (1.3)
27
+ i18n (1.8.2)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.14.0)
30
+ rake (10.5.0)
31
+ rspec (3.9.0)
32
+ rspec-core (~> 3.9.0)
33
+ rspec-expectations (~> 3.9.0)
34
+ rspec-mocks (~> 3.9.0)
35
+ rspec-core (3.9.1)
36
+ rspec-support (~> 3.9.1)
37
+ rspec-expectations (3.9.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.9.0)
40
+ rspec-mocks (3.9.1)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.9.0)
43
+ rspec-support (3.9.2)
44
+ sqlite3 (1.4.2)
45
+ thor (1.0.1)
46
+ thread_safe (0.3.6)
47
+ tzinfo (1.2.6)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (~> 5.1.7)
55
+ appraisal
56
+ bundler (~> 2.0)
57
+ has_checksum!
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3
61
+
62
+ BUNDLED WITH
63
+ 2.0.2
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.2.4"
6
+ gem "sqlite3"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ has_checksum (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.2.4.1)
10
+ activesupport (= 5.2.4.1)
11
+ activerecord (5.2.4.1)
12
+ activemodel (= 5.2.4.1)
13
+ activesupport (= 5.2.4.1)
14
+ arel (>= 9.0)
15
+ activesupport (5.2.4.1)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (9.0.0)
25
+ concurrent-ruby (1.1.5)
26
+ diff-lcs (1.3)
27
+ i18n (1.8.2)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.14.0)
30
+ rake (10.5.0)
31
+ rspec (3.9.0)
32
+ rspec-core (~> 3.9.0)
33
+ rspec-expectations (~> 3.9.0)
34
+ rspec-mocks (~> 3.9.0)
35
+ rspec-core (3.9.1)
36
+ rspec-support (~> 3.9.1)
37
+ rspec-expectations (3.9.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.9.0)
40
+ rspec-mocks (3.9.1)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.9.0)
43
+ rspec-support (3.9.2)
44
+ sqlite3 (1.4.2)
45
+ thor (1.0.1)
46
+ thread_safe (0.3.6)
47
+ tzinfo (1.2.6)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (~> 5.2.4)
55
+ appraisal
56
+ bundler (~> 2.0)
57
+ has_checksum!
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3
61
+
62
+ BUNDLED WITH
63
+ 2.0.2
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.0.2"
6
+ gem "sqlite3"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ has_checksum (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (6.0.2.1)
10
+ activesupport (= 6.0.2.1)
11
+ activerecord (6.0.2.1)
12
+ activemodel (= 6.0.2.1)
13
+ activesupport (= 6.0.2.1)
14
+ activesupport (6.0.2.1)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 0.7, < 2)
17
+ minitest (~> 5.1)
18
+ tzinfo (~> 1.1)
19
+ zeitwerk (~> 2.2)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ concurrent-ruby (1.1.5)
25
+ diff-lcs (1.3)
26
+ i18n (1.8.2)
27
+ concurrent-ruby (~> 1.0)
28
+ minitest (5.14.0)
29
+ rake (10.5.0)
30
+ rspec (3.9.0)
31
+ rspec-core (~> 3.9.0)
32
+ rspec-expectations (~> 3.9.0)
33
+ rspec-mocks (~> 3.9.0)
34
+ rspec-core (3.9.1)
35
+ rspec-support (~> 3.9.1)
36
+ rspec-expectations (3.9.0)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.9.0)
39
+ rspec-mocks (3.9.1)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-support (3.9.2)
43
+ sqlite3 (1.4.2)
44
+ thor (1.0.1)
45
+ thread_safe (0.3.6)
46
+ tzinfo (1.2.6)
47
+ thread_safe (~> 0.1)
48
+ zeitwerk (2.2.2)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (~> 6.0.2)
55
+ appraisal
56
+ bundler (~> 2.0)
57
+ has_checksum!
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3
61
+
62
+ BUNDLED WITH
63
+ 2.0.2
@@ -0,0 +1,34 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "has_checksum/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "has_checksum"
7
+ spec.version = HasChecksum::VERSION
8
+ spec.authors = ["Skye Shaw"]
9
+ spec.email = ["skye.shaw@gmail.com"]
10
+
11
+ spec.summary = %q{Automatically calculate checksums and signatures from the values of your class' attributes/methods}
12
+ spec.description = %q{Automatically calculate checksums and signatures from the values of your ActiveRecord or POROs classes' attributes/methods}
13
+ spec.homepage = "https://github.com/sshaw/has_checksum"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/sshaw/has_checksum"
18
+ spec.metadata["changelog_uri"] = "https://github.com/sshaw/has_checksum/Changes"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "appraisal"
30
+ spec.add_development_dependency "activerecord"
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end
@@ -0,0 +1,160 @@
1
+ require "has_checksum/version"
2
+
3
+ require "openssl"
4
+ require "digest"
5
+
6
+ module HasChecksum
7
+ def self.included(klass)
8
+ klass.extend ClassMethods
9
+ klass.class_eval do
10
+
11
+ private
12
+
13
+ def digest_string(methods)
14
+ methods.map { |name| public_send(name) }.join("")
15
+ end
16
+
17
+ def calculate_signature(digest, value, options = {})
18
+ key = case options[:key]
19
+ when Symbol
20
+ raise "key option refers to an unknown method '#{options[:key]}'" unless respond_to?(options[:key])
21
+ send(options[:key])
22
+ when Proc
23
+ options[:key][]
24
+ else
25
+ options[:key]
26
+ end
27
+
28
+ hmac = OpenSSL::HMAC.new(key.to_s, digest)
29
+ hmac << value
30
+
31
+ case options[:format]
32
+ when :binary, "binary"
33
+ hmac.digest
34
+ else
35
+ hmac.hexdigest
36
+ end
37
+ end
38
+
39
+ def calculate_checksum(klass, value, options = {})
40
+ case options[:format]
41
+ when :binary, "binary"
42
+ klass.digest(value)
43
+ when :base64, "base64"
44
+ klass.base64digest(value)
45
+ when :bubblebabble, "bubblebabble"
46
+ klass.bubblebabble(value)
47
+ else
48
+ klass.hexdigest(value)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ module ClassMethods
55
+ def has_signature(*config)
56
+ source, options = has_checksum_configure(config)
57
+ raise ArgumentError, "key option required to calculate a signature" unless options[:key]
58
+
59
+ if !options[:algorithm].respond_to?(:call)
60
+ begin
61
+ options[:algorithm] = OpenSSL::Digest.new(options[:algorithm])
62
+ rescue RuntimeError
63
+ raise ArgumentError, "unknown algorithm '#{options[:algorithm]}'"
64
+ end
65
+ end
66
+
67
+ options[:method] ||= "%s_signature" % source.join("_")
68
+ define_methods(:calculate_signature, source, options)
69
+ end
70
+
71
+ def has_checksum(*config)
72
+ source, options = has_checksum_configure(config)
73
+
74
+ if !options[:algorithm].respond_to?(:call)
75
+ # TODO: use OpenSSL here too?
76
+ begin
77
+ options[:algorithm] = Digest.const_get(options[:algorithm].upcase)
78
+ # Digest seems to only raise LoadError here but we add NameError for good measure
79
+ rescue LoadError, NameError
80
+ raise ArgumentError, "unknown algorithm '#{options[:algorithm]}'"
81
+ end
82
+ end
83
+
84
+ options[:method] ||= "%s_checksum" % source.join("_")
85
+ define_methods(:calculate_checksum, source, options)
86
+ end
87
+
88
+ private
89
+
90
+ def has_checksum_configure(config)
91
+ config.flatten!
92
+ raise ArgumentError, "config required" if config.empty?
93
+
94
+ options = config[-1].is_a?(Hash) ? config.pop : {}
95
+ raise ArgumentError, "no column(s) specified" if config.empty?
96
+
97
+ options[:algorithm] ||= "sha256"
98
+
99
+ if self < ::ActiveRecord::Base
100
+ extend ActiveRecord
101
+ else
102
+ extend PORO
103
+ end
104
+
105
+ [ Array(config), options ]
106
+ end
107
+ end
108
+
109
+ module PORO
110
+ private
111
+
112
+ def define_methods(calculator, source, options)
113
+ klass = options[:algorithm]
114
+ if klass.respond_to?(:call)
115
+ define_method(options[:method]) { klass[digest_string(source)] }
116
+ else
117
+ define_method(options[:method]) { send(calculator, klass, digest_string(source), options) }
118
+ end
119
+ end
120
+ end
121
+
122
+ module ActiveRecord
123
+ private
124
+
125
+ def define_methods(calculator, source, options)
126
+ klass = options[:algorithm]
127
+ if klass.respond_to?(:call)
128
+ define_method(options[:method]) { klass[digest_string(source)] }
129
+ else
130
+ define_method(options[:method]) { send(calculator, klass, digest_string(source), options) }
131
+ end
132
+
133
+ # Check if we a column to write to or if we only recalculate
134
+ return unless columns_hash.include?(options[:method].to_s)
135
+
136
+ watching = source.map(&:to_s)
137
+ if options[:key].is_a?(Symbol)
138
+ key = options[:key].to_s
139
+ # if the key is a column it could change too and we must recalculate, e.g., updated_at
140
+ watching += [key] if columns_hash.include?(key)
141
+ end
142
+
143
+ if klass.respond_to?(:call)
144
+ after_create { update_column(options[:method], klass[digest_string(source)]) }
145
+ around_update do |_, block|
146
+ changed = (watching & changed_attributes.keys).any?
147
+ block[]
148
+ update_column(options[:method], klass[digest_string(source)]) if changed
149
+ end
150
+ else
151
+ after_create { update_column(options[:method], public_send(options[:method])) }
152
+ around_update do |_, block|
153
+ changed = (watching & changed_attributes.keys).any?
154
+ block[]
155
+ update_column(options[:method], public_send(options[:method])) if changed
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasChecksum
4
+ VERSION = "0.0.1"
5
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_checksum
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Skye Shaw
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: appraisal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description: Automatically calculate checksums and signatures from the values of your
84
+ ActiveRecord or POROs classes' attributes/methods
85
+ email:
86
+ - skye.shaw@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".travis.yml"
94
+ - Appraisals
95
+ - Gemfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - gemfiles/4.2.gemfile
100
+ - gemfiles/4.2.gemfile.lock
101
+ - gemfiles/5.0.gemfile
102
+ - gemfiles/5.0.gemfile.lock
103
+ - gemfiles/5.1.gemfile
104
+ - gemfiles/5.1.gemfile.lock
105
+ - gemfiles/5.2.gemfile
106
+ - gemfiles/5.2.gemfile.lock
107
+ - gemfiles/6.0.gemfile
108
+ - gemfiles/6.0.gemfile.lock
109
+ - has_checksum.gemspec
110
+ - lib/has_checksum.rb
111
+ - lib/has_checksum/version.rb
112
+ homepage: https://github.com/sshaw/has_checksum
113
+ licenses:
114
+ - MIT
115
+ metadata:
116
+ homepage_uri: https://github.com/sshaw/has_checksum
117
+ source_code_uri: https://github.com/sshaw/has_checksum
118
+ changelog_uri: https://github.com/sshaw/has_checksum/Changes
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.7.6
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Automatically calculate checksums and signatures from the values of your
139
+ class' attributes/methods
140
+ test_files: []