jwt 2.5.0 → 2.6.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.
@@ -8,28 +8,48 @@ module JWT
8
8
  ::JWT::JWK.classes << klass
9
9
  end
10
10
 
11
- def initialize(options)
11
+ def initialize(options, params = {})
12
12
  options ||= {}
13
13
 
14
- if options.is_a?(String) # For backwards compatibility when kid was a String
15
- options = { kid: options }
16
- end
14
+ @parameters = params.transform_keys(&:to_sym) # Uniform interface
17
15
 
18
- @kid = options[:kid]
19
- @kid_generator = options[:kid_generator] || ::JWT.configuration.jwk.kid_generator
16
+ # For backwards compatibility, kid_generator may be specified in the parameters
17
+ options[:kid_generator] ||= @parameters.delete(:kid_generator)
18
+
19
+ # Make sure the key has a kid
20
+ kid_generator = options[:kid_generator] || ::JWT.configuration.jwk.kid_generator
21
+ self[:kid] ||= kid_generator.new(self).generate
20
22
  end
21
23
 
22
24
  def kid
23
- @kid ||= generate_kid
25
+ self[:kid]
24
26
  end
25
27
 
26
- private
28
+ def hash
29
+ self[:kid].hash
30
+ end
31
+
32
+ def [](key)
33
+ @parameters[key.to_sym]
34
+ end
35
+
36
+ def []=(key, value)
37
+ @parameters[key.to_sym] = value
38
+ end
39
+
40
+ def ==(other)
41
+ self[:kid] == other[:kid]
42
+ end
27
43
 
28
- attr_reader :kid_generator
44
+ alias eql? ==
29
45
 
30
- def generate_kid
31
- kid_generator.new(self).generate
46
+ def <=>(other)
47
+ self[:kid] <=> other[:kid]
32
48
  end
49
+
50
+ private
51
+
52
+ attr_reader :parameters
33
53
  end
34
54
  end
35
55
  end
@@ -5,8 +5,12 @@ module JWT
5
5
  class KeyFinder
6
6
  def initialize(options)
7
7
  jwks_or_loader = options[:jwks]
8
- @jwks = jwks_or_loader if jwks_or_loader.is_a?(Hash)
9
- @jwk_loader = jwks_or_loader if jwks_or_loader.respond_to?(:call)
8
+
9
+ @jwks_loader = if jwks_or_loader.respond_to?(:call)
10
+ jwks_or_loader
11
+ else
12
+ ->(_options) { jwks_or_loader }
13
+ end
10
14
  end
11
15
 
12
16
  def key_for(kid)
@@ -14,48 +18,24 @@ module JWT
14
18
 
15
19
  jwk = resolve_key(kid)
16
20
 
17
- raise ::JWT::DecodeError, 'No keys found in jwks' if jwks_keys.empty?
21
+ raise ::JWT::DecodeError, 'No keys found in jwks' unless @jwks.any?
18
22
  raise ::JWT::DecodeError, "Could not find public key for kid #{kid}" unless jwk
19
23
 
20
- ::JWT::JWK.import(jwk).keypair
24
+ jwk.keypair
21
25
  end
22
26
 
23
27
  private
24
28
 
25
29
  def resolve_key(kid)
26
- jwk = find_key(kid)
30
+ # First try without invalidation to facilitate application caching
31
+ @jwks ||= JWT::JWK::Set.new(@jwks_loader.call(kid: kid))
32
+ jwk = @jwks.find { |key| key[:kid] == kid }
27
33
 
28
34
  return jwk if jwk
29
35
 
30
- if reloadable?
31
- load_keys(invalidate: true, kid_not_found: true, kid: kid) # invalidate for backwards compatibility
32
- return find_key(kid)
33
- end
34
-
35
- nil
36
- end
37
-
38
- def jwks
39
- return @jwks if @jwks
40
-
41
- load_keys
42
- @jwks
43
- end
44
-
45
- def load_keys(opts = {})
46
- @jwks = @jwk_loader.call(opts)
47
- end
48
-
49
- def jwks_keys
50
- Array(jwks[:keys] || jwks['keys'])
51
- end
52
-
53
- def find_key(kid)
54
- jwks_keys.find { |key| (key[:kid] || key['kid']) == kid }
55
- end
56
-
57
- def reloadable?
58
- @jwk_loader
36
+ # Second try, invalidate for backwards compatibility
37
+ @jwks = JWT::JWK::Set.new(@jwks_loader.call(invalidate: true, kid_not_found: true, kid: kid))
38
+ @jwks.find { |key| key[:kid] == kid }
59
39
  end
60
40
  end
61
41
  end
data/lib/jwt/jwk/rsa.rb CHANGED
@@ -2,20 +2,33 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
- class RSA < KeyBase
5
+ class RSA < KeyBase # rubocop:disable Metrics/ClassLength
6
6
  BINARY = 2
7
7
  KTY = 'RSA'
8
- KTYS = [KTY, OpenSSL::PKey::RSA].freeze
9
- RSA_KEY_ELEMENTS = %i[n e d p q dp dq qi].freeze
8
+ KTYS = [KTY, OpenSSL::PKey::RSA, JWT::JWK::RSA].freeze
9
+ RSA_PUBLIC_KEY_ELEMENTS = %i[kty n e].freeze
10
+ RSA_PRIVATE_KEY_ELEMENTS = %i[d p q dp dq qi].freeze
11
+ RSA_KEY_ELEMENTS = (RSA_PRIVATE_KEY_ELEMENTS + RSA_PUBLIC_KEY_ELEMENTS).freeze
10
12
 
11
- attr_reader :keypair
13
+ RSA_OPT_PARAMS = %i[p q dp dq qi].freeze
14
+ RSA_ASN1_SEQUENCE = (%i[n e d] + RSA_OPT_PARAMS).freeze # https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2
12
15
 
13
- def initialize(keypair, options = {})
14
- raise ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA' unless keypair.is_a?(OpenSSL::PKey::RSA)
16
+ def initialize(key, params = nil, options = {})
17
+ params ||= {}
15
18
 
16
- @keypair = keypair
19
+ # For backwards compatibility when kid was a String
20
+ params = { kid: params } if params.is_a?(String)
17
21
 
18
- super(options)
22
+ key_params = extract_key_params(key)
23
+
24
+ params = params.transform_keys(&:to_sym)
25
+ check_jwk(key_params, params)
26
+
27
+ super(options, key_params.merge(params))
28
+ end
29
+
30
+ def keypair
31
+ @keypair ||= self.class.create_rsa_key(jwk_attributes(*(RSA_KEY_ELEMENTS - [:kty])))
19
32
  end
20
33
 
21
34
  def private?
@@ -27,19 +40,13 @@ module JWT
27
40
  end
28
41
 
29
42
  def export(options = {})
30
- exported_hash = members.merge(kid: kid)
31
-
32
- return exported_hash unless private? && options[:include_private] == true
33
-
34
- append_private_parts(exported_hash)
43
+ exported = parameters.clone
44
+ exported.reject! { |k, _| RSA_PRIVATE_KEY_ELEMENTS.include? k } unless private? && options[:include_private] == true
45
+ exported
35
46
  end
36
47
 
37
48
  def members
38
- {
39
- kty: KTY,
40
- n: encode_open_ssl_bn(public_key.n),
41
- e: encode_open_ssl_bn(public_key.e)
42
- }
49
+ RSA_PUBLIC_KEY_ELEMENTS.each_with_object({}) { |i, h| h[i] = self[i] }
43
50
  end
44
51
 
45
52
  def key_digest
@@ -48,89 +55,135 @@ module JWT
48
55
  OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
49
56
  end
50
57
 
58
+ def []=(key, value)
59
+ if RSA_KEY_ELEMENTS.include?(key.to_sym)
60
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes'
61
+ end
62
+
63
+ super(key, value)
64
+ end
65
+
51
66
  private
52
67
 
53
- def append_private_parts(the_hash)
54
- the_hash.merge(
55
- d: encode_open_ssl_bn(keypair.d),
56
- p: encode_open_ssl_bn(keypair.p),
57
- q: encode_open_ssl_bn(keypair.q),
58
- dp: encode_open_ssl_bn(keypair.dmp1),
59
- dq: encode_open_ssl_bn(keypair.dmq1),
60
- qi: encode_open_ssl_bn(keypair.iqmp)
61
- )
68
+ def extract_key_params(key)
69
+ case key
70
+ when JWT::JWK::RSA
71
+ key.export(include_private: true)
72
+ when OpenSSL::PKey::RSA # Accept OpenSSL key as input
73
+ @keypair = key # Preserve the object to avoid recreation
74
+ parse_rsa_key(key)
75
+ when Hash
76
+ key.transform_keys(&:to_sym)
77
+ else
78
+ raise ArgumentError, 'key must be of type OpenSSL::PKey::RSA or Hash with key parameters'
79
+ end
80
+ end
81
+
82
+ def check_jwk(keypair, params)
83
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' unless (RSA_KEY_ELEMENTS & params.keys).empty?
84
+ raise JWT::JWKError, "Incorrect 'kty' value: #{keypair[:kty]}, expected #{KTY}" unless keypair[:kty] == KTY
85
+ raise JWT::JWKError, 'Key format is invalid for RSA' unless keypair[:n] && keypair[:e]
86
+ end
87
+
88
+ def parse_rsa_key(key)
89
+ {
90
+ kty: KTY,
91
+ n: encode_open_ssl_bn(key.n),
92
+ e: encode_open_ssl_bn(key.e),
93
+ d: encode_open_ssl_bn(key.d),
94
+ p: encode_open_ssl_bn(key.p),
95
+ q: encode_open_ssl_bn(key.q),
96
+ dp: encode_open_ssl_bn(key.dmp1),
97
+ dq: encode_open_ssl_bn(key.dmq1),
98
+ qi: encode_open_ssl_bn(key.iqmp)
99
+ }.compact
100
+ end
101
+
102
+ def jwk_attributes(*attributes)
103
+ attributes.each_with_object({}) do |attribute, hash|
104
+ hash[attribute] = decode_open_ssl_bn(self[attribute])
105
+ end
62
106
  end
63
107
 
64
108
  def encode_open_ssl_bn(key_part)
109
+ return unless key_part
110
+
65
111
  ::JWT::Base64.url_encode(key_part.to_s(BINARY))
66
112
  end
67
113
 
114
+ def decode_open_ssl_bn(jwk_data)
115
+ self.class.decode_open_ssl_bn(jwk_data)
116
+ end
117
+
68
118
  class << self
69
119
  def import(jwk_data)
70
- pkey_params = jwk_attributes(jwk_data, *RSA_KEY_ELEMENTS) do |value|
71
- decode_open_ssl_bn(value)
72
- end
73
- new(rsa_pkey(pkey_params), kid: jwk_attributes(jwk_data, :kid)[:kid])
120
+ new(jwk_data)
74
121
  end
75
122
 
76
- private
123
+ def decode_open_ssl_bn(jwk_data)
124
+ return nil unless jwk_data
77
125
 
78
- def jwk_attributes(jwk_data, *attributes)
79
- attributes.each_with_object({}) do |attribute, hash|
80
- value = jwk_data[attribute] || jwk_data[attribute.to_s]
81
- value = yield(value) if block_given?
82
- hash[attribute] = value
83
- end
126
+ OpenSSL::BN.new(::JWT::Base64.url_decode(jwk_data), BINARY)
84
127
  end
85
128
 
86
- def rsa_pkey(rsa_parameters)
87
- raise JWT::JWKError, 'Key format is invalid for RSA' unless rsa_parameters[:n] && rsa_parameters[:e]
129
+ def create_rsa_key_using_der(rsa_parameters)
130
+ validate_rsa_parameters!(rsa_parameters)
88
131
 
89
- create_rsa_key(rsa_parameters)
90
- end
132
+ sequence = RSA_ASN1_SEQUENCE.each_with_object([]) do |key, arr|
133
+ next if rsa_parameters[key].nil?
91
134
 
92
- if ::JWT.openssl_3?
93
- ASN1_SEQUENCE = %i[n e d p q dp dq qi].freeze
94
- def create_rsa_key(rsa_parameters)
95
- sequence = ASN1_SEQUENCE.each_with_object([]) do |key, arr|
96
- next if rsa_parameters[key].nil?
97
-
98
- arr << OpenSSL::ASN1::Integer.new(rsa_parameters[key])
99
- end
135
+ arr << OpenSSL::ASN1::Integer.new(rsa_parameters[key])
136
+ end
100
137
 
101
- if sequence.size > 2 # For a private key
102
- sequence.unshift(OpenSSL::ASN1::Integer.new(0))
103
- end
138
+ if sequence.size > 2 # Append "two-prime" version for private key
139
+ sequence.unshift(OpenSSL::ASN1::Integer.new(0))
104
140
 
105
- OpenSSL::PKey::RSA.new(OpenSSL::ASN1::Sequence(sequence).to_der)
141
+ raise JWT::JWKError, 'Creating a RSA key with a private key requires the CRT parameters to be defined' if sequence.size < RSA_ASN1_SEQUENCE.size
106
142
  end
107
- elsif OpenSSL::PKey::RSA.new.respond_to?(:set_key)
108
- def create_rsa_key(rsa_parameters)
109
- OpenSSL::PKey::RSA.new.tap do |rsa_key|
110
- rsa_key.set_key(rsa_parameters[:n], rsa_parameters[:e], rsa_parameters[:d])
111
- rsa_key.set_factors(rsa_parameters[:p], rsa_parameters[:q]) if rsa_parameters[:p] && rsa_parameters[:q]
112
- rsa_key.set_crt_params(rsa_parameters[:dp], rsa_parameters[:dq], rsa_parameters[:qi]) if rsa_parameters[:dp] && rsa_parameters[:dq] && rsa_parameters[:qi]
113
- end
143
+
144
+ OpenSSL::PKey::RSA.new(OpenSSL::ASN1::Sequence(sequence).to_der)
145
+ end
146
+
147
+ def create_rsa_key_using_sets(rsa_parameters)
148
+ validate_rsa_parameters!(rsa_parameters)
149
+
150
+ OpenSSL::PKey::RSA.new.tap do |rsa_key|
151
+ rsa_key.set_key(rsa_parameters[:n], rsa_parameters[:e], rsa_parameters[:d])
152
+ rsa_key.set_factors(rsa_parameters[:p], rsa_parameters[:q]) if rsa_parameters[:p] && rsa_parameters[:q]
153
+ rsa_key.set_crt_params(rsa_parameters[:dp], rsa_parameters[:dq], rsa_parameters[:qi]) if rsa_parameters[:dp] && rsa_parameters[:dq] && rsa_parameters[:qi]
114
154
  end
115
- else
116
- def create_rsa_key(rsa_parameters) # rubocop:disable Metrics/AbcSize
117
- OpenSSL::PKey::RSA.new.tap do |rsa_key|
118
- rsa_key.n = rsa_parameters[:n]
119
- rsa_key.e = rsa_parameters[:e]
120
- rsa_key.d = rsa_parameters[:d] if rsa_parameters[:d]
121
- rsa_key.p = rsa_parameters[:p] if rsa_parameters[:p]
122
- rsa_key.q = rsa_parameters[:q] if rsa_parameters[:q]
123
- rsa_key.dmp1 = rsa_parameters[:dp] if rsa_parameters[:dp]
124
- rsa_key.dmq1 = rsa_parameters[:dq] if rsa_parameters[:dq]
125
- rsa_key.iqmp = rsa_parameters[:qi] if rsa_parameters[:qi]
126
- end
155
+ end
156
+
157
+ def create_rsa_key_using_accessors(rsa_parameters) # rubocop:disable Metrics/AbcSize
158
+ validate_rsa_parameters!(rsa_parameters)
159
+
160
+ OpenSSL::PKey::RSA.new.tap do |rsa_key|
161
+ rsa_key.n = rsa_parameters[:n]
162
+ rsa_key.e = rsa_parameters[:e]
163
+ rsa_key.d = rsa_parameters[:d] if rsa_parameters[:d]
164
+ rsa_key.p = rsa_parameters[:p] if rsa_parameters[:p]
165
+ rsa_key.q = rsa_parameters[:q] if rsa_parameters[:q]
166
+ rsa_key.dmp1 = rsa_parameters[:dp] if rsa_parameters[:dp]
167
+ rsa_key.dmq1 = rsa_parameters[:dq] if rsa_parameters[:dq]
168
+ rsa_key.iqmp = rsa_parameters[:qi] if rsa_parameters[:qi]
127
169
  end
128
170
  end
129
171
 
130
- def decode_open_ssl_bn(jwk_data)
131
- return nil unless jwk_data
172
+ def validate_rsa_parameters!(rsa_parameters)
173
+ return unless rsa_parameters.key?(:d)
132
174
 
133
- OpenSSL::BN.new(::JWT::Base64.url_decode(jwk_data), BINARY)
175
+ parameters = RSA_OPT_PARAMS - rsa_parameters.keys
176
+ return if parameters.empty? || parameters.size == RSA_OPT_PARAMS.size
177
+
178
+ raise JWT::JWKError, 'When one of p, q, dp, dq or qi is given all the other optimization parameters also needs to be defined' # https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3.2
179
+ end
180
+
181
+ if ::JWT.openssl_3?
182
+ alias create_rsa_key create_rsa_key_using_der
183
+ elsif OpenSSL::PKey::RSA.new.respond_to?(:set_key)
184
+ alias create_rsa_key create_rsa_key_using_sets
185
+ else
186
+ alias create_rsa_key create_rsa_key_using_accessors
134
187
  end
135
188
  end
136
189
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module JWT
6
+ module JWK
7
+ class Set
8
+ include Enumerable
9
+ extend Forwardable
10
+
11
+ attr_reader :keys
12
+
13
+ def initialize(jwks = nil, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
14
+ jwks ||= {}
15
+
16
+ @keys = case jwks
17
+ when JWT::JWK::Set # Simple duplication
18
+ jwks.keys
19
+ when JWT::JWK::KeyBase # Singleton
20
+ [jwks]
21
+ when Hash
22
+ jwks = jwks.transform_keys(&:to_sym)
23
+ [*jwks[:keys]].map { |k| JWT::JWK.new(k, nil, options) }
24
+ when Array
25
+ jwks.map { |k| JWT::JWK.new(k, nil, options) }
26
+ else
27
+ raise ArgumentError, 'Can only create new JWKS from Hash, Array and JWK'
28
+ end
29
+ end
30
+
31
+ def export(options = {})
32
+ { keys: @keys.map { |k| k.export(options) } }
33
+ end
34
+
35
+ def_delegators :@keys, :each, :size, :delete, :dig
36
+
37
+ def select!(&block)
38
+ return @keys.select! unless block
39
+
40
+ self if @keys.select!(&block)
41
+ end
42
+
43
+ def reject!(&block)
44
+ return @keys.reject! unless block
45
+
46
+ self if @keys.reject!(&block)
47
+ end
48
+
49
+ def uniq!(&block)
50
+ self if @keys.uniq!(&block)
51
+ end
52
+
53
+ def merge(enum)
54
+ @keys += JWT::JWK::Set.new(enum.to_a).keys
55
+ self
56
+ end
57
+
58
+ def union(enum)
59
+ dup.merge(enum)
60
+ end
61
+
62
+ def add(key)
63
+ @keys << JWT::JWK.new(key)
64
+ self
65
+ end
66
+
67
+ def ==(other)
68
+ other.is_a?(JWT::JWK::Set) && keys.sort == other.keys.sort
69
+ end
70
+
71
+ alias eql? ==
72
+ alias filter! select!
73
+ alias length size
74
+ # For symbolic manipulation
75
+ alias | union
76
+ alias + union
77
+ alias << add
78
+ end
79
+ end
80
+ end
data/lib/jwt/jwk.rb CHANGED
@@ -1,23 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'jwk/key_finder'
4
+ require_relative 'jwk/set'
4
5
 
5
6
  module JWT
6
7
  module JWK
7
8
  class << self
8
- def import(jwk_data)
9
- jwk_kty = jwk_data[:kty] || jwk_data['kty']
10
- raise JWT::JWKError, 'Key type (kty) not provided' unless jwk_kty
11
-
12
- mappings.fetch(jwk_kty.to_s) do |kty|
13
- raise JWT::JWKError, "Key type #{kty} not supported"
14
- end.import(jwk_data)
15
- end
9
+ def create_from(key, params = nil, options = {})
10
+ if key.is_a?(Hash)
11
+ jwk_kty = key[:kty] || key['kty']
12
+ raise JWT::JWKError, 'Key type (kty) not provided' unless jwk_kty
13
+
14
+ return mappings.fetch(jwk_kty.to_s) do |kty|
15
+ raise JWT::JWKError, "Key type #{kty} not supported"
16
+ end.new(key, params, options)
17
+ end
16
18
 
17
- def create_from(keypair, kid = nil)
18
- mappings.fetch(keypair.class) do |klass|
19
+ mappings.fetch(key.class) do |klass|
19
20
  raise JWT::JWKError, "Cannot create JWK from a #{klass.name}"
20
- end.new(keypair, kid)
21
+ end.new(key, params, options)
21
22
  end
22
23
 
23
24
  def classes
@@ -26,6 +27,7 @@ module JWT
26
27
  end
27
28
 
28
29
  alias new create_from
30
+ alias import create_from
29
31
 
30
32
  private
31
33
 
@@ -7,17 +7,6 @@ module JWT
7
7
  module SecurityUtils
8
8
  module_function
9
9
 
10
- def secure_compare(left, right)
11
- left_bytesize = left.bytesize
12
-
13
- return false unless left_bytesize == right.bytesize
14
-
15
- unpacked_left = left.unpack "C#{left_bytesize}"
16
- result = 0
17
- right.each_byte { |byte| result |= byte ^ unpacked_left.shift }
18
- result.zero?
19
- end
20
-
21
10
  def verify_rsa(algorithm, public_key, signing_input, signature)
22
11
  public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
23
12
  end
@@ -39,21 +28,5 @@ module JWT
39
28
  sig_char = signature[byte_size..-1] || ''
40
29
  OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
41
30
  end
42
-
43
- def rbnacl_fixup(algorithm, key)
44
- algorithm = algorithm.sub('HS', 'SHA').to_sym
45
-
46
- return [] unless defined?(RbNaCl) && RbNaCl::HMAC.constants(false).include?(algorithm)
47
-
48
- authenticator = RbNaCl::HMAC.const_get(algorithm)
49
-
50
- # Fall back to OpenSSL for keys larger than 32 bytes.
51
- return [] if key.bytesize > authenticator.key_bytes
52
-
53
- [
54
- authenticator,
55
- key.bytes.fill(0, key.bytesize...authenticator.key_bytes).pack('C*')
56
- ]
57
- end
58
31
  end
59
32
  end
data/lib/jwt/version.rb CHANGED
@@ -11,7 +11,7 @@ module JWT
11
11
  # major version
12
12
  MAJOR = 2
13
13
  # minor version
14
- MINOR = 5
14
+ MINOR = 6
15
15
  # tiny version
16
16
  TINY = 0
17
17
  # alpha, beta, etc. tag
@@ -25,4 +25,20 @@ module JWT
25
25
  return false if OpenSSL::OPENSSL_VERSION.include?('LibreSSL')
26
26
  return true if OpenSSL::OPENSSL_VERSION_NUMBER >= 3 * 0x10000000
27
27
  end
28
+
29
+ def self.rbnacl?
30
+ defined?(::RbNaCl)
31
+ end
32
+
33
+ def self.rbnacl_6_or_greater?
34
+ rbnacl? && ::Gem::Version.new(::RbNaCl::VERSION) >= ::Gem::Version.new('6.0.0')
35
+ end
36
+
37
+ def self.openssl_3_hmac_empty_key_regression?
38
+ openssl_3? && openssl_version <= ::Gem::Version.new('3.0.0')
39
+ end
40
+
41
+ def self.openssl_version
42
+ @openssl_version ||= ::Gem::Version.new(OpenSSL::VERSION)
43
+ end
28
44
  end
data/ruby-jwt.gemspec CHANGED
@@ -18,18 +18,22 @@ Gem::Specification.new do |spec|
18
18
  spec.required_ruby_version = '>= 2.5'
19
19
  spec.metadata = {
20
20
  'bug_tracker_uri' => 'https://github.com/jwt/ruby-jwt/issues',
21
- 'changelog_uri' => "https://github.com/jwt/ruby-jwt/blob/v#{JWT.gem_version}/CHANGELOG.md"
21
+ 'changelog_uri' => "https://github.com/jwt/ruby-jwt/blob/v#{JWT.gem_version}/CHANGELOG.md",
22
+ 'rubygems_mfa_required' => 'true'
22
23
  }
23
24
 
24
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|gemfiles|coverage|bin)/}) }
25
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
+ f.match(%r{^(spec|gemfiles|coverage|bin)/}) || # Irrelevant folders
27
+ f.match(/^\.+/) || # Files and folders starting with .
28
+ f.match(/^(Appraisals|Gemfile|Rakefile)$/) # Irrelevant files
29
+ end
30
+
25
31
  spec.executables = []
26
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
27
32
  spec.require_paths = %w[lib]
28
33
 
29
34
  spec.add_development_dependency 'appraisal'
30
35
  spec.add_development_dependency 'bundler'
31
36
  spec.add_development_dependency 'rake'
32
- spec.add_development_dependency 'reek'
33
37
  spec.add_development_dependency 'rspec'
34
38
  spec.add_development_dependency 'simplecov'
35
39
  end