jwt 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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