jwt 2.2.2 → 2.4.0.beta1
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +6 -18
- data/.github/workflows/coverage.yml +27 -0
- data/.github/workflows/test.yml +66 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.rubocop.yml +20 -37
- data/.rubocop_todo.yml +22 -0
- data/{.ebert.yml → .sourcelevel.yml} +1 -1
- data/AUTHORS +79 -44
- data/Appraisals +7 -12
- data/CHANGELOG.md +143 -5
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +4 -0
- data/README.md +135 -29
- data/Rakefile +6 -1
- data/lib/jwt/algos/ecdsa.rb +23 -5
- data/lib/jwt/algos/eddsa.rb +14 -4
- data/lib/jwt/algos/hmac.rb +2 -0
- data/lib/jwt/algos/none.rb +17 -0
- data/lib/jwt/algos/ps.rb +3 -3
- data/lib/jwt/algos/rsa.rb +4 -1
- data/lib/jwt/algos/unsupported.rb +7 -4
- data/lib/jwt/algos.rb +44 -0
- data/lib/jwt/claims_validator.rb +12 -8
- data/lib/jwt/decode.rb +50 -12
- data/lib/jwt/default_options.rb +4 -1
- data/lib/jwt/encode.rb +10 -9
- data/lib/jwt/error.rb +2 -0
- data/lib/jwt/jwk/ec.rb +150 -0
- data/lib/jwt/jwk/hmac.rb +58 -0
- data/lib/jwt/jwk/key_base.rb +19 -0
- data/lib/jwt/jwk/key_finder.rb +6 -1
- data/lib/jwt/jwk/rsa.rb +85 -23
- data/lib/jwt/jwk.rb +32 -11
- data/lib/jwt/security_utils.rb +2 -0
- data/lib/jwt/signature.rb +7 -26
- data/lib/jwt/verify.rb +18 -3
- data/lib/jwt/version.rb +3 -4
- data/lib/jwt/x5c_key_finder.rb +55 -0
- data/lib/jwt.rb +1 -1
- data/ruby-jwt.gemspec +9 -9
- metadata +20 -80
- data/.travis.yml +0 -29
- data/lib/jwt/base64.rb +0 -19
data/lib/jwt/jwk/hmac.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module JWK
|
5
|
+
class HMAC < KeyBase
|
6
|
+
KTY = 'oct'
|
7
|
+
KTYS = [KTY, String].freeze
|
8
|
+
|
9
|
+
def initialize(keypair, kid = nil)
|
10
|
+
raise ArgumentError, 'keypair must be of type String' unless keypair.is_a?(String)
|
11
|
+
|
12
|
+
super
|
13
|
+
@kid = kid || generate_kid
|
14
|
+
end
|
15
|
+
|
16
|
+
def private?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def public_key
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# See https://tools.ietf.org/html/rfc7517#appendix-A.3
|
25
|
+
def export(options = {})
|
26
|
+
exported_hash = {
|
27
|
+
kty: KTY,
|
28
|
+
kid: kid
|
29
|
+
}
|
30
|
+
|
31
|
+
return exported_hash unless private? && options[:include_private] == true
|
32
|
+
|
33
|
+
exported_hash.merge(
|
34
|
+
k: keypair
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def generate_kid
|
41
|
+
sequence = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::UTF8String.new(keypair),
|
42
|
+
OpenSSL::ASN1::UTF8String.new(KTY)])
|
43
|
+
OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def import(jwk_data)
|
48
|
+
jwk_k = jwk_data[:k] || jwk_data['k']
|
49
|
+
jwk_kid = jwk_data[:kid] || jwk_data['kid']
|
50
|
+
|
51
|
+
raise JWT::JWKError, 'Key format is invalid for HMAC' unless jwk_k
|
52
|
+
|
53
|
+
self.new(jwk_k, jwk_kid)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module JWK
|
5
|
+
class KeyBase
|
6
|
+
attr_reader :keypair, :kid
|
7
|
+
|
8
|
+
def initialize(keypair, kid = nil)
|
9
|
+
@keypair = keypair
|
10
|
+
@kid = kid
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.inherited(klass)
|
14
|
+
super
|
15
|
+
::JWT::JWK.classes << klass
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/jwt/jwk/key_finder.rb
CHANGED
@@ -14,6 +14,7 @@ module JWT
|
|
14
14
|
|
15
15
|
jwk = resolve_key(kid)
|
16
16
|
|
17
|
+
raise ::JWT::DecodeError, 'No keys found in jwks' if jwks_keys.empty?
|
17
18
|
raise ::JWT::DecodeError, "Could not find public key for kid #{kid}" unless jwk
|
18
19
|
|
19
20
|
::JWT::JWK.import(jwk).keypair
|
@@ -45,8 +46,12 @@ module JWT
|
|
45
46
|
@jwks = @jwk_loader.call(opts)
|
46
47
|
end
|
47
48
|
|
49
|
+
def jwks_keys
|
50
|
+
Array(jwks[:keys] || jwks['keys'])
|
51
|
+
end
|
52
|
+
|
48
53
|
def find_key(kid)
|
49
|
-
|
54
|
+
jwks_keys.find { |key| (key[:kid] || key['kid']) == kid }
|
50
55
|
end
|
51
56
|
|
52
57
|
def reloadable?
|
data/lib/jwt/jwk/rsa.rb
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module JWK
|
5
|
-
class RSA
|
6
|
-
attr_reader :keypair
|
7
|
-
|
5
|
+
class RSA < KeyBase
|
8
6
|
BINARY = 2
|
9
|
-
KTY = 'RSA'
|
7
|
+
KTY = 'RSA'
|
8
|
+
KTYS = [KTY, OpenSSL::PKey::RSA].freeze
|
9
|
+
RSA_KEY_ELEMENTS = %i[n e d p q dp dq qi].freeze
|
10
10
|
|
11
|
-
def initialize(keypair)
|
11
|
+
def initialize(keypair, kid = nil)
|
12
12
|
raise ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA' unless keypair.is_a?(OpenSSL::PKey::RSA)
|
13
13
|
|
14
|
-
|
14
|
+
super(keypair, kid || generate_kid(keypair.public_key))
|
15
15
|
end
|
16
16
|
|
17
17
|
def private?
|
@@ -22,32 +22,94 @@ module JWT
|
|
22
22
|
keypair.public_key
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
25
|
+
def export(options = {})
|
26
|
+
exported_hash = {
|
27
|
+
kty: KTY,
|
28
|
+
n: encode_open_ssl_bn(public_key.n),
|
29
|
+
e: encode_open_ssl_bn(public_key.e),
|
30
|
+
kid: kid
|
31
|
+
}
|
32
|
+
|
33
|
+
return exported_hash unless private? && options[:include_private] == true
|
34
|
+
|
35
|
+
append_private_parts(exported_hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def generate_kid(public_key)
|
26
41
|
sequence = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::Integer.new(public_key.n),
|
27
42
|
OpenSSL::ASN1::Integer.new(public_key.e)])
|
28
43
|
OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
|
29
44
|
end
|
30
45
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
46
|
+
def append_private_parts(the_hash)
|
47
|
+
the_hash.merge(
|
48
|
+
d: encode_open_ssl_bn(keypair.d),
|
49
|
+
p: encode_open_ssl_bn(keypair.p),
|
50
|
+
q: encode_open_ssl_bn(keypair.q),
|
51
|
+
dp: encode_open_ssl_bn(keypair.dmp1),
|
52
|
+
dq: encode_open_ssl_bn(keypair.dmq1),
|
53
|
+
qi: encode_open_ssl_bn(keypair.iqmp)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def encode_open_ssl_bn(key_part)
|
58
|
+
Base64.urlsafe_encode64(key_part.to_s(BINARY), padding: false)
|
38
59
|
end
|
39
60
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
61
|
+
class << self
|
62
|
+
def import(jwk_data)
|
63
|
+
pkey_params = jwk_attributes(jwk_data, *RSA_KEY_ELEMENTS) do |value|
|
64
|
+
decode_open_ssl_bn(value)
|
65
|
+
end
|
66
|
+
kid = jwk_attributes(jwk_data, :kid)[:kid]
|
67
|
+
self.new(rsa_pkey(pkey_params), kid)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def jwk_attributes(jwk_data, *attributes)
|
73
|
+
attributes.each_with_object({}) do |attribute, hash|
|
74
|
+
value = jwk_data[attribute] || jwk_data[attribute.to_s]
|
75
|
+
value = yield(value) if block_given?
|
76
|
+
hash[attribute] = value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def rsa_pkey(rsa_parameters)
|
81
|
+
raise JWT::JWKError, 'Key format is invalid for RSA' unless rsa_parameters[:n] && rsa_parameters[:e]
|
82
|
+
|
83
|
+
populate_key(OpenSSL::PKey::RSA.new, rsa_parameters)
|
84
|
+
end
|
85
|
+
|
86
|
+
if OpenSSL::PKey::RSA.new.respond_to?(:set_key)
|
87
|
+
def populate_key(rsa_key, rsa_parameters)
|
88
|
+
rsa_key.set_key(rsa_parameters[:n], rsa_parameters[:e], rsa_parameters[:d])
|
89
|
+
rsa_key.set_factors(rsa_parameters[:p], rsa_parameters[:q]) if rsa_parameters[:p] && rsa_parameters[:q]
|
90
|
+
rsa_key.set_crt_params(rsa_parameters[:dp], rsa_parameters[:dq], rsa_parameters[:qi]) if rsa_parameters[:dp] && rsa_parameters[:dq] && rsa_parameters[:qi]
|
91
|
+
rsa_key
|
92
|
+
end
|
46
93
|
else
|
47
|
-
|
48
|
-
|
94
|
+
def populate_key(rsa_key, rsa_parameters)
|
95
|
+
rsa_key.n = rsa_parameters[:n]
|
96
|
+
rsa_key.e = rsa_parameters[:e]
|
97
|
+
rsa_key.d = rsa_parameters[:d] if rsa_parameters[:d]
|
98
|
+
rsa_key.p = rsa_parameters[:p] if rsa_parameters[:p]
|
99
|
+
rsa_key.q = rsa_parameters[:q] if rsa_parameters[:q]
|
100
|
+
rsa_key.dmp1 = rsa_parameters[:dp] if rsa_parameters[:dp]
|
101
|
+
rsa_key.dmq1 = rsa_parameters[:dq] if rsa_parameters[:dq]
|
102
|
+
rsa_key.iqmp = rsa_parameters[:qi] if rsa_parameters[:qi]
|
103
|
+
|
104
|
+
rsa_key
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def decode_open_ssl_bn(jwk_data)
|
109
|
+
return nil unless jwk_data
|
110
|
+
|
111
|
+
OpenSSL::BN.new(Base64.urlsafe_decode64(jwk_data), BINARY)
|
49
112
|
end
|
50
|
-
self.new(imported_key)
|
51
113
|
end
|
52
114
|
end
|
53
115
|
end
|
data/lib/jwt/jwk.rb
CHANGED
@@ -1,31 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'jwk/rsa'
|
4
3
|
require_relative 'jwk/key_finder'
|
5
4
|
|
6
5
|
module JWT
|
7
6
|
module JWK
|
8
|
-
MAPPINGS = {
|
9
|
-
'RSA' => ::JWT::JWK::RSA,
|
10
|
-
OpenSSL::PKey::RSA => ::JWT::JWK::RSA
|
11
|
-
}.freeze
|
12
|
-
|
13
7
|
class << self
|
14
8
|
def import(jwk_data)
|
15
|
-
|
9
|
+
jwk_kty = jwk_data[:kty] || jwk_data['kty']
|
10
|
+
raise JWT::JWKError, 'Key type (kty) not provided' unless jwk_kty
|
16
11
|
|
17
|
-
|
12
|
+
mappings.fetch(jwk_kty.to_s) do |kty|
|
18
13
|
raise JWT::JWKError, "Key type #{kty} not supported"
|
19
14
|
end.import(jwk_data)
|
20
15
|
end
|
21
16
|
|
22
|
-
def create_from(keypair)
|
23
|
-
|
17
|
+
def create_from(keypair, kid = nil)
|
18
|
+
mappings.fetch(keypair.class) do |klass|
|
24
19
|
raise JWT::JWKError, "Cannot create JWK from a #{klass.name}"
|
25
|
-
end.new(keypair)
|
20
|
+
end.new(keypair, kid)
|
21
|
+
end
|
22
|
+
|
23
|
+
def classes
|
24
|
+
@mappings = nil # reset the cached mappings
|
25
|
+
@classes ||= []
|
26
26
|
end
|
27
27
|
|
28
28
|
alias new create_from
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def mappings
|
33
|
+
@mappings ||= generate_mappings
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_mappings
|
37
|
+
classes.each_with_object({}) do |klass, hash|
|
38
|
+
next unless klass.const_defined?('KTYS')
|
39
|
+
|
40
|
+
Array(klass::KTYS).each do |kty|
|
41
|
+
hash[kty] = klass
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
29
45
|
end
|
30
46
|
end
|
31
47
|
end
|
48
|
+
|
49
|
+
require_relative 'jwk/key_base'
|
50
|
+
require_relative 'jwk/ec'
|
51
|
+
require_relative 'jwk/rsa'
|
52
|
+
require_relative 'jwk/hmac'
|
data/lib/jwt/security_utils.rb
CHANGED
data/lib/jwt/signature.rb
CHANGED
@@ -2,12 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'jwt/security_utils'
|
4
4
|
require 'openssl'
|
5
|
-
require 'jwt/algos
|
6
|
-
require 'jwt/algos/eddsa'
|
7
|
-
require 'jwt/algos/ecdsa'
|
8
|
-
require 'jwt/algos/rsa'
|
9
|
-
require 'jwt/algos/ps'
|
10
|
-
require 'jwt/algos/unsupported'
|
5
|
+
require 'jwt/algos'
|
11
6
|
begin
|
12
7
|
require 'rbnacl'
|
13
8
|
rescue LoadError
|
@@ -18,33 +13,19 @@ end
|
|
18
13
|
module JWT
|
19
14
|
# Signature logic for JWT
|
20
15
|
module Signature
|
21
|
-
|
22
|
-
|
23
|
-
Algos::Hmac,
|
24
|
-
Algos::Ecdsa,
|
25
|
-
Algos::Rsa,
|
26
|
-
Algos::Eddsa,
|
27
|
-
Algos::Ps,
|
28
|
-
Algos::Unsupported
|
29
|
-
].freeze
|
16
|
+
module_function
|
17
|
+
|
30
18
|
ToSign = Struct.new(:algorithm, :msg, :key)
|
31
19
|
ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature)
|
32
20
|
|
33
21
|
def sign(algorithm, msg, key)
|
34
|
-
algo =
|
35
|
-
|
36
|
-
end
|
37
|
-
algo.sign ToSign.new(algorithm, msg, key)
|
22
|
+
algo, code = Algos.find(algorithm)
|
23
|
+
algo.sign ToSign.new(code, msg, key)
|
38
24
|
end
|
39
25
|
|
40
26
|
def verify(algorithm, key, signing_input, signature)
|
41
|
-
|
42
|
-
|
43
|
-
algo = ALGOS.find do |alg|
|
44
|
-
alg.const_get(:SUPPORTED).include? algorithm
|
45
|
-
end
|
46
|
-
verified = algo.verify(ToVerify.new(algorithm, key, signing_input, signature))
|
47
|
-
raise(JWT::VerificationError, 'Signature verification raised') unless verified
|
27
|
+
algo, code = Algos.find(algorithm)
|
28
|
+
algo.verify(ToVerify.new(code, key, signing_input, signature))
|
48
29
|
rescue OpenSSL::PKey::PKeyError
|
49
30
|
raise JWT::VerificationError, 'Signature verification raised'
|
50
31
|
ensure
|
data/lib/jwt/verify.rb
CHANGED
@@ -10,7 +10,7 @@ module JWT
|
|
10
10
|
}.freeze
|
11
11
|
|
12
12
|
class << self
|
13
|
-
%w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub].each do |method_name|
|
13
|
+
%w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub verify_required_claims].each do |method_name|
|
14
14
|
define_method method_name do |payload, options|
|
15
15
|
new(payload, options).send(method_name)
|
16
16
|
end
|
@@ -19,6 +19,7 @@ module JWT
|
|
19
19
|
def verify_claims(payload, options)
|
20
20
|
options.each do |key, val|
|
21
21
|
next unless key.to_s =~ /verify/
|
22
|
+
|
22
23
|
Verify.send(key, payload, options) if val
|
23
24
|
end
|
24
25
|
end
|
@@ -53,9 +54,14 @@ module JWT
|
|
53
54
|
|
54
55
|
iss = @payload['iss']
|
55
56
|
|
56
|
-
|
57
|
+
options_iss = Array(options_iss).map { |item| item.is_a?(Symbol) ? item.to_s : item }
|
57
58
|
|
58
|
-
|
59
|
+
case iss
|
60
|
+
when *options_iss
|
61
|
+
nil
|
62
|
+
else
|
63
|
+
raise(JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || '<none>'}")
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
67
|
def verify_jti
|
@@ -77,10 +83,19 @@ module JWT
|
|
77
83
|
|
78
84
|
def verify_sub
|
79
85
|
return unless (options_sub = @options[:sub])
|
86
|
+
|
80
87
|
sub = @payload['sub']
|
81
88
|
raise(JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || '<none>'}") unless sub.to_s == options_sub.to_s
|
82
89
|
end
|
83
90
|
|
91
|
+
def verify_required_claims
|
92
|
+
return unless (options_required_claims = @options[:required_claims])
|
93
|
+
|
94
|
+
options_required_claims.each do |required_claim|
|
95
|
+
raise(JWT::MissingRequiredClaim, "Missing required claim #{required_claim}") unless @payload.include?(required_claim)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
84
99
|
private
|
85
100
|
|
86
101
|
def global_leeway
|
data/lib/jwt/version.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
# Moments version builder module
|
@@ -12,11 +11,11 @@ module JWT
|
|
12
11
|
# major version
|
13
12
|
MAJOR = 2
|
14
13
|
# minor version
|
15
|
-
MINOR =
|
14
|
+
MINOR = 4
|
16
15
|
# tiny version
|
17
|
-
TINY =
|
16
|
+
TINY = 0
|
18
17
|
# alpha, beta, etc. tag
|
19
|
-
PRE =
|
18
|
+
PRE = 'beta1'
|
20
19
|
|
21
20
|
# Build version string
|
22
21
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'jwt/error'
|
5
|
+
|
6
|
+
module JWT
|
7
|
+
# If the x5c header certificate chain can be validated by trusted root
|
8
|
+
# certificates, and none of the certificates are revoked, returns the public
|
9
|
+
# key from the first certificate.
|
10
|
+
# See https://tools.ietf.org/html/rfc7515#section-4.1.6
|
11
|
+
class X5cKeyFinder
|
12
|
+
def initialize(root_certificates, crls = nil)
|
13
|
+
raise(ArgumentError, 'Root certificates must be specified') unless root_certificates
|
14
|
+
|
15
|
+
@store = build_store(root_certificates, crls)
|
16
|
+
end
|
17
|
+
|
18
|
+
def from(x5c_header_or_certificates)
|
19
|
+
signing_certificate, *certificate_chain = parse_certificates(x5c_header_or_certificates)
|
20
|
+
store_context = OpenSSL::X509::StoreContext.new(@store, signing_certificate, certificate_chain)
|
21
|
+
|
22
|
+
if store_context.verify
|
23
|
+
signing_certificate.public_key
|
24
|
+
else
|
25
|
+
error = "Certificate verification failed: #{store_context.error_string}."
|
26
|
+
if (current_cert = store_context.current_cert)
|
27
|
+
error = "#{error} Certificate subject: #{current_cert.subject}."
|
28
|
+
end
|
29
|
+
|
30
|
+
raise(JWT::VerificationError, error)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_store(root_certificates, crls)
|
37
|
+
store = OpenSSL::X509::Store.new
|
38
|
+
store.purpose = OpenSSL::X509::PURPOSE_ANY
|
39
|
+
store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
|
40
|
+
root_certificates.each { |certificate| store.add_cert(certificate) }
|
41
|
+
crls&.each { |crl| store.add_crl(crl) }
|
42
|
+
store
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_certificates(x5c_header_or_certificates)
|
46
|
+
if x5c_header_or_certificates.all? { |obj| obj.is_a?(OpenSSL::X509::Certificate) }
|
47
|
+
x5c_header_or_certificates
|
48
|
+
else
|
49
|
+
x5c_header_or_certificates.map do |encoded|
|
50
|
+
OpenSSL::X509::Certificate.new(::Base64.strict_decode64(encoded))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/jwt.rb
CHANGED
data/ruby-jwt.gemspec
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require 'jwt/version'
|
4
6
|
|
@@ -13,7 +15,11 @@ Gem::Specification.new do |spec|
|
|
13
15
|
spec.description = 'A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.'
|
14
16
|
spec.homepage = 'https://github.com/jwt/ruby-jwt'
|
15
17
|
spec.license = 'MIT'
|
16
|
-
spec.required_ruby_version = '>= 2.
|
18
|
+
spec.required_ruby_version = '>= 2.5'
|
19
|
+
spec.metadata = {
|
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"
|
22
|
+
}
|
17
23
|
|
18
24
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|gemfiles|coverage|bin)/}) }
|
19
25
|
spec.executables = []
|
@@ -24,11 +30,5 @@ Gem::Specification.new do |spec|
|
|
24
30
|
spec.add_development_dependency 'bundler'
|
25
31
|
spec.add_development_dependency 'rake'
|
26
32
|
spec.add_development_dependency 'rspec'
|
27
|
-
spec.add_development_dependency 'simplecov'
|
28
|
-
spec.add_development_dependency 'simplecov-json'
|
29
|
-
spec.add_development_dependency 'codeclimate-test-reporter'
|
30
|
-
spec.add_development_dependency 'codacy-coverage'
|
31
|
-
spec.add_development_dependency 'rbnacl'
|
32
|
-
# RSASSA-PSS support provided by OpenSSL +2.1
|
33
|
-
spec.add_development_dependency 'openssl', '~> 2.1'
|
33
|
+
spec.add_development_dependency 'simplecov'
|
34
34
|
end
|