m2m_keygen 0.2.0 → 0.4.0

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.
@@ -44,6 +44,94 @@
44
44
  <ul id="full_list" class="method">
45
45
 
46
46
 
47
+ <li class="odd ">
48
+ <div class="item">
49
+ <span class='object_link'><a href="M2mKeygen/Signature.html#algorithm-instance_method" title="M2mKeygen::Signature#algorithm (method)">#algorithm</a></span>
50
+ <small>M2mKeygen::Signature</small>
51
+ </div>
52
+ </li>
53
+
54
+
55
+ <li class="even ">
56
+ <div class="item">
57
+ <span class='object_link'><a href="M2mKeygen/ParamsEncoder.html#encode-instance_method" title="M2mKeygen::ParamsEncoder#encode (method)">#encode</a></span>
58
+ <small>M2mKeygen::ParamsEncoder</small>
59
+ </div>
60
+ </li>
61
+
62
+
63
+ <li class="odd ">
64
+ <div class="item">
65
+ <span class='object_link'><a href="M2mKeygen/RackValidator.html#header_name-instance_method" title="M2mKeygen::RackValidator#header_name (method)">#header_name</a></span>
66
+ <small>M2mKeygen::RackValidator</small>
67
+ </div>
68
+ </li>
69
+
70
+
71
+ <li class="even ">
72
+ <div class="item">
73
+ <span class='object_link'><a href="M2mKeygen/Signature.html#initialize-instance_method" title="M2mKeygen::Signature#initialize (method)">#initialize</a></span>
74
+ <small>M2mKeygen::Signature</small>
75
+ </div>
76
+ </li>
77
+
78
+
79
+ <li class="odd ">
80
+ <div class="item">
81
+ <span class='object_link'><a href="M2mKeygen/RackValidator.html#initialize-instance_method" title="M2mKeygen::RackValidator#initialize (method)">#initialize</a></span>
82
+ <small>M2mKeygen::RackValidator</small>
83
+ </div>
84
+ </li>
85
+
86
+
87
+ <li class="even ">
88
+ <div class="item">
89
+ <span class='object_link'><a href="M2mKeygen/ParamsEncoder.html#initialize-instance_method" title="M2mKeygen::ParamsEncoder#initialize (method)">#initialize</a></span>
90
+ <small>M2mKeygen::ParamsEncoder</small>
91
+ </div>
92
+ </li>
93
+
94
+
95
+ <li class="odd ">
96
+ <div class="item">
97
+ <span class='object_link'><a href="M2mKeygen/Signature.html#secret-instance_method" title="M2mKeygen::Signature#secret (method)">#secret</a></span>
98
+ <small>M2mKeygen::Signature</small>
99
+ </div>
100
+ </li>
101
+
102
+
103
+ <li class="even ">
104
+ <div class="item">
105
+ <span class='object_link'><a href="M2mKeygen/Signature.html#sign-instance_method" title="M2mKeygen::Signature#sign (method)">#sign</a></span>
106
+ <small>M2mKeygen::Signature</small>
107
+ </div>
108
+ </li>
109
+
110
+
111
+ <li class="odd ">
112
+ <div class="item">
113
+ <span class='object_link'><a href="M2mKeygen/RackValidator.html#signature-instance_method" title="M2mKeygen::RackValidator#signature (method)">#signature</a></span>
114
+ <small>M2mKeygen::RackValidator</small>
115
+ </div>
116
+ </li>
117
+
118
+
119
+ <li class="even ">
120
+ <div class="item">
121
+ <span class='object_link'><a href="M2mKeygen/Signature.html#validate-instance_method" title="M2mKeygen::Signature#validate (method)">#validate</a></span>
122
+ <small>M2mKeygen::Signature</small>
123
+ </div>
124
+ </li>
125
+
126
+
127
+ <li class="odd ">
128
+ <div class="item">
129
+ <span class='object_link'><a href="M2mKeygen/RackValidator.html#validate-instance_method" title="M2mKeygen::RackValidator#validate (method)">#validate</a></span>
130
+ <small>M2mKeygen::RackValidator</small>
131
+ </div>
132
+ </li>
133
+
134
+
47
135
 
48
136
  </ul>
49
137
  </div>
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Mon Aug 29 16:32:02 2022 by
103
+ Generated on Tue Aug 30 15:18:09 2022 by
104
104
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
105
  0.9.28 (ruby-3.1.2).
106
106
  </div>
@@ -0,0 +1,56 @@
1
+ # typed: strict
2
+
3
+ module M2mKeygen
4
+ # Encoder for params hash
5
+ class ParamsEncoder
6
+ extend T::Sig
7
+
8
+ sig { params(params: Types::ParamsType).void }
9
+ def initialize(params)
10
+ @params = T.let(params, Types::ParamsType)
11
+ end
12
+
13
+ sig { returns(String) }
14
+ def encode
15
+ return "" if @params.nil? || @params.empty?
16
+ @params
17
+ .sort_by { |k, _| k.to_s }
18
+ .reject { |_, v| (v.is_a?(String) && v == "") || v.nil? }
19
+ .map { |k, v| "#{k}=#{jsonify_value(encode_value(T.must(v)))}" }
20
+ .join("&")
21
+ end
22
+
23
+ private
24
+
25
+ sig do
26
+ params(value: Types::ParamsValueType).returns(
27
+ T.any(String, Symbol, Integer)
28
+ )
29
+ end
30
+ def jsonify_value(value)
31
+ return value unless value.is_a?(Hash) || value.is_a?(Array)
32
+ value.to_json
33
+ end
34
+
35
+ sig do
36
+ params(value: Types::ParamsValueType).returns(Types::ParamsValueType)
37
+ end
38
+ def encode_value(value)
39
+ return encode_hash_value(value) if value.is_a?(Hash)
40
+ value
41
+ end
42
+
43
+ sig do
44
+ params(value: Types::ParamsHashNotNilType).returns(
45
+ T::Hash[String, Types::ParamsValueType]
46
+ )
47
+ end
48
+ def encode_hash_value(value)
49
+ value
50
+ .sort_by { |k, _| k.to_s }
51
+ .reject { |_, v| (v.is_a?(String) && v == "") || v.nil? }
52
+ .map { |k, v| [k.to_s, encode_value(v)] }
53
+ .to_h
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+
3
+ require "rack"
4
+
5
+ module M2mKeygen
6
+ class RackValidator
7
+ extend T::Sig
8
+
9
+ sig { returns(Signature) }
10
+ attr_reader :signature
11
+
12
+ sig { returns(String) }
13
+ attr_reader :header_name
14
+
15
+ sig { params(secret: String, algorithm: String, header_name: String).void }
16
+ def initialize(secret, algorithm: "sha512", header_name: "X-Signature")
17
+ @header_name = T.let("HTTP_#{header_name.tr("-", "_").upcase}", String)
18
+ @signature = T.let(Signature.new(secret, algorithm: algorithm), Signature)
19
+ end
20
+
21
+ sig { params(req: Rack::Request).returns(T::Boolean) }
22
+ def validate(req)
23
+ # This will cover the case when Rails is used.
24
+ req = Rack::Request.new(req.env)
25
+ @signature.validate(
26
+ params: req.params,
27
+ verb: req.request_method,
28
+ path: req.path,
29
+ signature: req.env["HTTP_X_SIGNATURE"]
30
+ ) && req.params["expiry"] && req.params["expiry"].to_i > Time.now.to_i &&
31
+ req.params["expiry"].to_i < Time.now.to_i + 120
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,78 @@
1
+ # typed: strict
2
+
3
+ require "openssl"
4
+ require "json"
5
+
6
+ module M2mKeygen
7
+ class Signature
8
+ extend T::Sig
9
+
10
+ sig { returns(String) }
11
+ attr_reader :secret
12
+
13
+ sig { returns(String) }
14
+ attr_reader :algorithm
15
+
16
+ sig { params(secret: String, algorithm: String).void }
17
+ def initialize(secret, algorithm: "sha512")
18
+ @secret = T.let(secret, String)
19
+ @algorithm = T.let(algorithm, String)
20
+ OpenSSL::HMAC.hexdigest(@algorithm, @secret, "")
21
+ end
22
+
23
+ sig do
24
+ params(
25
+ params: Types::ParamsType,
26
+ verb: T.any(String, Symbol),
27
+ path: String
28
+ ).returns(String)
29
+ end
30
+ def sign(params:, verb:, path:)
31
+ OpenSSL::HMAC.hexdigest(
32
+ @algorithm,
33
+ @secret,
34
+ "#{verb.to_s.upcase}#{path}#{ParamsEncoder.new(params).encode}"
35
+ )
36
+ end
37
+
38
+ sig do
39
+ params(
40
+ params: Types::ParamsType,
41
+ verb: T.any(String, Symbol),
42
+ path: String,
43
+ signature: String
44
+ ).returns(T::Boolean)
45
+ end
46
+ def validate(params:, verb:, path:, signature:)
47
+ if OpenSSL.methods.include?(:fixed_length_secure_compare)
48
+ OpenSSL.fixed_length_secure_compare(
49
+ sign(params: params, verb: verb, path: path),
50
+ signature
51
+ )
52
+ else
53
+ fallback_fixed_length_secure_compare(
54
+ sign(params: params, verb: verb, path: path),
55
+ signature
56
+ )
57
+ end
58
+ rescue StandardError
59
+ false
60
+ end
61
+
62
+ private
63
+
64
+ # Ruby 2.7 openssl lib doesn't have fixed_length_secure_compare method
65
+ # File activesupport/lib/active_support/security_utils.rb, line 11
66
+ # With sorbet fix
67
+ sig { params(str_a: String, str_b: String).returns(T::Boolean) }
68
+ def fallback_fixed_length_secure_compare(str_a, str_b)
69
+ return false unless str_a.bytesize == str_b.bytesize
70
+
71
+ l = str_a.unpack "C#{str_a.bytesize}"
72
+
73
+ res = 0
74
+ str_b.each_byte { |byte| res |= byte ^ l.shift.to_i }
75
+ res == 0
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+ module M2mKeygen
3
+ module Types
4
+ extend T::Sig
5
+
6
+ ParamsType =
7
+ T.type_alias do
8
+ T.nilable(T::Hash[T.any(String, Symbol), T.nilable(ParamsValueType)])
9
+ end
10
+
11
+ ParamsHashNotNilType =
12
+ T.type_alias { T::Hash[T.any(String, Symbol), ParamsValueType] }
13
+
14
+ ParamsValueType =
15
+ T.type_alias do
16
+ T.any(
17
+ Integer,
18
+ String,
19
+ Symbol,
20
+ T::Array[T.untyped],
21
+ T::Hash[T.untyped, T.untyped]
22
+ )
23
+ end
24
+ end
25
+ end
@@ -3,5 +3,5 @@
3
3
 
4
4
  module M2mKeygen
5
5
  # Gem version
6
- VERSION = "0.2.0"
6
+ VERSION = "0.4.0"
7
7
  end
data/lib/m2m_keygen.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # typed: strict
2
- # frozen_string_literal: true
3
2
 
4
- require_relative "m2m_keygen/version"
3
+ require "sorbet-runtime"
4
+ require "zeitwerk"
5
+
6
+ loader = Zeitwerk::Loader.for_gem
7
+ loader.setup
5
8
 
6
9
  # Main module
7
10
  module M2mKeygen
data/m2m_keygen.gemspec CHANGED
@@ -20,6 +20,9 @@ Gem::Specification.new do |spec|
20
20
  spec.metadata[
21
21
  "changelog_uri"
22
22
  ] = "https://github.com/Billcorporate/m2m_keygen_ruby/blob/main/CHANGELOG.md"
23
+ spec.metadata[
24
+ "documentation_uri"
25
+ ] = "https://billcorporate.github.io/m2m_keygen_ruby"
23
26
  spec.metadata = { "rubygems_mfa_required" => "true" }
24
27
 
25
28
  # Specify which files should be added to the gem when it is released.
@@ -38,6 +41,7 @@ Gem::Specification.new do |spec|
38
41
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
39
42
  spec.require_paths = ["lib"]
40
43
 
44
+ spec.add_dependency "rack"
41
45
  spec.add_dependency "sorbet-runtime"
42
46
  spec.add_dependency "zeitwerk", "~> 2.6"
43
47
  end
@@ -1534,6 +1534,30 @@ class ActiveSupport::Cache::Strategy::LocalCache::LocalStore
1534
1534
  def write_entry(key, entry); end
1535
1535
  end
1536
1536
 
1537
+ # --
1538
+ # This class wraps up local storage for middlewares. Only the middleware method should
1539
+ # construct them.
1540
+ #
1541
+ # source://activesupport-7.0.3.1/lib/active_support/cache/strategy/local_cache_middleware.rb:13
1542
+ class ActiveSupport::Cache::Strategy::LocalCache::Middleware
1543
+ # @return [Middleware] a new instance of Middleware
1544
+ #
1545
+ # source://activesupport-7.0.3.1/lib/active_support/cache/strategy/local_cache_middleware.rb:16
1546
+ def initialize(name, local_cache_key); end
1547
+
1548
+ # source://activesupport-7.0.3.1/lib/active_support/cache/strategy/local_cache_middleware.rb:27
1549
+ def call(env); end
1550
+
1551
+ # source://activesupport-7.0.3.1/lib/active_support/cache/strategy/local_cache_middleware.rb:14
1552
+ def local_cache_key; end
1553
+
1554
+ # source://activesupport-7.0.3.1/lib/active_support/cache/strategy/local_cache_middleware.rb:14
1555
+ def name; end
1556
+
1557
+ # source://activesupport-7.0.3.1/lib/active_support/cache/strategy/local_cache_middleware.rb:22
1558
+ def new(app); end
1559
+ end
1560
+
1537
1561
  # These options mean something to all cache implementations. Individual cache
1538
1562
  # implementations may support additional options.
1539
1563
  #