jwt 1.5.6 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8cd1a9ca017dec28c4984e18003e8ae58aee776c
4
- data.tar.gz: c5fef77f9a8e42d8fa92c060c468be6ee2e3c561
3
+ metadata.gz: f874da696e03e2c7f0ffe02942540825eb8a6314
4
+ data.tar.gz: d57f6842df5cc35d21bea1a1e511026faeb0aaa4
5
5
  SHA512:
6
- metadata.gz: c0dc92b0ea35004782c8260f8d2d47c9973a1172f5eb6bef33fe42ae3a2e8341c9264e5fafc7cb62442039409194c3aa6fbd3db78667db75af04ffd26586422f
7
- data.tar.gz: af9967d4c04b332ef8916d3b837e31c20b2e5db8c96531b277286324f29730edbc65eb66401f6db405b22dbd2701895d2579796fab368c26bd1fca58aae30840
6
+ metadata.gz: 51acfa10b330d62022d463cd4c0d25eff3ceb642b29e2c625d4aab40cd1a4138ca5597e0e19d540232f3f3b2e76fdcf4b403566f5b54aa7e687ab7d8696186e6
7
+ data.tar.gz: b8d9b8f1485f4e0c74d189c1e7ba64d71ce89f4813b134dbaf28263c695403dd102f12ab9dddde0ee7990f6cbcfde5ab5941876919bb1540b4088349129d1baf
@@ -1,2 +1,5 @@
1
+ AllCops:
2
+ Excludes:
3
+ - spec/**/*
1
4
  Metrics/LineLength:
2
5
  Enabled: false
@@ -1,13 +1,13 @@
1
- sudo: false
1
+ sudo: required
2
2
  cache: bundler
3
3
  language: ruby
4
4
  rvm:
5
- - 1.9.3
6
- - 2.0.0
7
- - 2.1.0
8
5
  - 2.2.0
9
6
  - 2.3.0
10
- script: "bundle exec rspec"
11
- addons:
12
- code_climate:
13
- repo_token: e87b175db123ab42ca2ca4420abaa13c0dc2085608402b9a25f08a83ca3ba202
7
+ - 2.4.0
8
+ script: "bundle exec rspec && bundle exec codeclimate-test-reporter"
9
+ before_install:
10
+ - sudo add-apt-repository ppa:chris-lea/libsodium -y
11
+ - sudo apt-get update -q
12
+ - sudo apt-get install libsodium-dev -y
13
+ - gem install bundler
@@ -1,5 +1,52 @@
1
1
  # Change Log
2
2
 
3
+ ## [v2.0.0](https://github.com/jwt/ruby-jwt/tree/v2.0.0) (2017-02-27)
4
+ [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.6...v2.0.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Error with method sign for String [\#171](https://github.com/jwt/ruby-jwt/issues/171)
9
+ - Refactor the encondig code [\#121](https://github.com/jwt/ruby-jwt/issues/121)
10
+ - Refactor [\#196](https://github.com/jwt/ruby-jwt/pull/196) ([EmilioCristalli](https://github.com/EmilioCristalli))
11
+ - Move signature logic to its own module [\#195](https://github.com/jwt/ruby-jwt/pull/195) ([EmilioCristalli](https://github.com/EmilioCristalli))
12
+ - Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
13
+ - Add user friendly encode error if private key is a String, \#171 [\#176](https://github.com/jwt/ruby-jwt/pull/176) ([xamenrax](https://github.com/xamenrax))
14
+ - Return empty string if signature less than byte\_size \#155 [\#175](https://github.com/jwt/ruby-jwt/pull/175) ([xamenrax](https://github.com/xamenrax))
15
+ - Remove 'typ' optional parameter [\#174](https://github.com/jwt/ruby-jwt/pull/174) ([xamenrax](https://github.com/xamenrax))
16
+ - Pass payload to keyfinder [\#172](https://github.com/jwt/ruby-jwt/pull/172) ([CodeMonkeySteve](https://github.com/CodeMonkeySteve))
17
+ - Use RbNaCl for HMAC if available with fallback to OpenSSL [\#149](https://github.com/jwt/ruby-jwt/pull/149) ([mwpastore](https://github.com/mwpastore))
18
+
19
+ **Fixed bugs:**
20
+
21
+ - ruby-jwt::raw\_to\_asn1: Fails for signatures less than byte\_size [\#155](https://github.com/jwt/ruby-jwt/issues/155)
22
+ - The leeway parameter is applies to all time based verifications [\#129](https://github.com/jwt/ruby-jwt/issues/129)
23
+ - Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
24
+ - Make algorithm option required to verify signature [\#184](https://github.com/jwt/ruby-jwt/pull/184) ([EmilioCristalli](https://github.com/EmilioCristalli))
25
+ - Validate audience when payload is a scalar and options is an array [\#183](https://github.com/jwt/ruby-jwt/pull/183) ([steti](https://github.com/steti))
26
+
27
+ **Closed issues:**
28
+
29
+ - Different encoded value between servers with same password [\#197](https://github.com/jwt/ruby-jwt/issues/197)
30
+ - Signature is different at each run [\#190](https://github.com/jwt/ruby-jwt/issues/190)
31
+ - Include custom headers with password [\#189](https://github.com/jwt/ruby-jwt/issues/189)
32
+ - can't create token - 'NotImplementedError: Unsupported signing method' [\#186](https://github.com/jwt/ruby-jwt/issues/186)
33
+ - Why jwt depends on json \< 2.0 ? [\#179](https://github.com/jwt/ruby-jwt/issues/179)
34
+ - Cannot verify JWT at all?? [\#177](https://github.com/jwt/ruby-jwt/issues/177)
35
+ - verify\_iss: true is raising JWT::DecodeError instead of JWT::InvalidIssuerError [\#170](https://github.com/jwt/ruby-jwt/issues/170)
36
+
37
+ **Merged pull requests:**
38
+
39
+ - Add Codacy coverage reporter [\#194](https://github.com/jwt/ruby-jwt/pull/194) ([excpt](https://github.com/excpt))
40
+ - Add minimum required ruby version to gemspec [\#193](https://github.com/jwt/ruby-jwt/pull/193) ([excpt](https://github.com/excpt))
41
+ - Code smell fixes [\#192](https://github.com/jwt/ruby-jwt/pull/192) ([excpt](https://github.com/excpt))
42
+ - Version bump to 2.0.0.dev [\#191](https://github.com/jwt/ruby-jwt/pull/191) ([excpt](https://github.com/excpt))
43
+ - Basic encode module refactoring \#121 [\#182](https://github.com/jwt/ruby-jwt/pull/182) ([xamenrax](https://github.com/xamenrax))
44
+ - Fix travis ci build configuration [\#181](https://github.com/jwt/ruby-jwt/pull/181) ([excpt](https://github.com/excpt))
45
+ - Fix travis ci build configuration [\#180](https://github.com/jwt/ruby-jwt/pull/180) ([excpt](https://github.com/excpt))
46
+ - Fix typo in README [\#178](https://github.com/jwt/ruby-jwt/pull/178) ([tomeduarte](https://github.com/tomeduarte))
47
+ - Fix code style [\#173](https://github.com/jwt/ruby-jwt/pull/173) ([excpt](https://github.com/excpt))
48
+ - Fixed a typo in a spec name [\#169](https://github.com/jwt/ruby-jwt/pull/169) ([Mingan](https://github.com/Mingan))
49
+
3
50
  ## [v1.5.6](https://github.com/jwt/ruby-jwt/tree/v1.5.6) (2016-09-19)
4
51
  [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.5...v1.5.6)
5
52
 
@@ -9,6 +56,7 @@
9
56
 
10
57
  **Merged pull requests:**
11
58
 
59
+ - Update changelog [\#168](https://github.com/jwt/ruby-jwt/pull/168) ([excpt](https://github.com/excpt))
12
60
  - Fix rubocop code smells [\#167](https://github.com/jwt/ruby-jwt/pull/167) ([excpt](https://github.com/excpt))
13
61
 
14
62
  ## [v1.5.5](https://github.com/jwt/ruby-jwt/tree/v1.5.5) (2016-09-16)
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  A pure ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard.
9
9
 
10
- If you have further questions releated to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
10
+ If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
11
11
 
12
12
  ## Announcements
13
13
 
@@ -55,7 +55,7 @@ decoded_token = JWT.decode token, nil, false
55
55
  # Array
56
56
  # [
57
57
  # {"data"=>"test"}, # payload
58
- # {"typ"=>"JWT", "alg"=>"none"} # header
58
+ # {"alg"=>"none"} # header
59
59
  # ]
60
60
  puts decoded_token
61
61
  ```
@@ -63,6 +63,7 @@ puts decoded_token
63
63
  **HMAC** (default: HS256)
64
64
 
65
65
  * HS256 - HMAC using SHA-256 hash algorithm (default)
66
+ * HS512256 - HMAC using SHA-512/256 hash algorithm (only available with RbNaCl; see note below)
66
67
  * HS384 - HMAC using SHA-384 hash algorithm
67
68
  * HS512 - HMAC using SHA-512 hash algorithm
68
69
 
@@ -79,11 +80,13 @@ decoded_token = JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
79
80
  # Array
80
81
  # [
81
82
  # {"data"=>"test"}, # payload
82
- # {"typ"=>"JWT", "alg"=>"HS256"} # header
83
+ # {"alg"=>"HS256"} # header
83
84
  # ]
84
85
  puts decoded_token
85
86
  ```
86
87
 
88
+ Note: If [RbNaCl](https://github.com/cryptosphere/rbnacl) is loadable, ruby-jwt will use it for HMAC-SHA256, HMAC-SHA512/256, and HMAC-SHA512. RbNaCl enforces a maximum key size of 32 bytes for these algorithms.
89
+
87
90
  **RSA**
88
91
 
89
92
  * RS256 - RSA using SHA-256 hash algorithm
@@ -104,7 +107,7 @@ decoded_token = JWT.decode token, rsa_public, true, { :algorithm => 'RS256' }
104
107
  # Array
105
108
  # [
106
109
  # {"data"=>"test"}, # payload
107
- # {"typ"=>"JWT", "alg"=>"RS256"} # header
110
+ # {"alg"=>"RS256"} # header
108
111
  # ]
109
112
  puts decoded_token
110
113
  ```
@@ -131,7 +134,7 @@ decoded_token = JWT.decode token, ecdsa_public, true, { :algorithm => 'ES256' }
131
134
  # Array
132
135
  # [
133
136
  # {"test"=>"data"}, # payload
134
- # {"typ"=>"JWT", "alg"=>"ES256"} # header
137
+ # {"alg"=>"ES256"} # header
135
138
  # ]
136
139
  puts decoded_token
137
140
  ```
@@ -152,6 +155,38 @@ used. JWT supports these reserved claim names:
152
155
  - 'iat' (Issued At) Claim
153
156
  - 'sub' (Subject) Claim
154
157
 
158
+ ## Add custom header fields
159
+ Ruby-jwt gem supports custom [header fields] (https://tools.ietf.org/html/rfc7519#section-5)
160
+ To add custom header fields you need to pass `header_fields` parameter
161
+
162
+ ```ruby
163
+ token = JWT.encode payload, key, algorithm='HS256', header_fields={}
164
+ ```
165
+
166
+ **Example:**
167
+
168
+ ```ruby
169
+ require 'jwt'
170
+
171
+ payload = {:data => 'test'}
172
+
173
+ # IMPORTANT: set nil as password parameter
174
+ token = JWT.encode payload, nil, 'none', { :typ => "JWT" }
175
+
176
+ # eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.
177
+ puts token
178
+
179
+ # Set password to nil and validation to false otherwise this won't work
180
+ decoded_token = JWT.decode token, nil, false
181
+
182
+ # Array
183
+ # [
184
+ # {"data"=>"test"}, # payload
185
+ # {"typ"=>"JWT", "alg"=>"none"} # header
186
+ # ]
187
+ puts decoded_token
188
+ ```
189
+
155
190
  ### Expiration Time Claim
156
191
 
157
192
  From [Oauth JSON Web Token 4.1.4. "exp" (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4):
@@ -186,7 +221,7 @@ token = JWT.encode exp_payload, hmac_secret, 'HS256'
186
221
 
187
222
  begin
188
223
  # add leeway to ensure the token is still accepted
189
- decoded_token = JWT.decode token, hmac_secret, true, { :leeway => leeway, :algorithm => 'HS256' }
224
+ decoded_token = JWT.decode token, hmac_secret, true, { :exp_leeway => leeway, :algorithm => 'HS256' }
190
225
  rescue JWT::ExpiredSignature
191
226
  # Handle expired token, e.g. logout user or deny access
192
227
  end
@@ -226,7 +261,7 @@ token = JWT.encode nbf_payload, hmac_secret, 'HS256'
226
261
 
227
262
  begin
228
263
  # add leeway to ensure the token is valid
229
- decoded_token = JWT.decode token, hmac_secret, true, { :leeway => leeway, :algorithm => 'HS256' }
264
+ decoded_token = JWT.decode token, hmac_secret, true, { :nbf_leeway => leeway, :algorithm => 'HS256' }
230
265
  rescue JWT::ImmatureSignature
231
266
  # Handle invalid token, e.g. logout user or deny access
232
267
  end
@@ -305,6 +340,8 @@ From [Oauth JSON Web Token 4.1.6. "iat" (Issued At) Claim](https://tools.ietf.or
305
340
 
306
341
  > The `iat` (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL.
307
342
 
343
+ **Handle Issued At Claim**
344
+
308
345
  ```ruby
309
346
  iat = Time.now.to_i
310
347
  iat_payload = { :data => 'data', :iat => iat }
@@ -319,6 +356,25 @@ rescue JWT::InvalidIatError
319
356
  end
320
357
  ```
321
358
 
359
+ **Adding Leeway**
360
+
361
+ ```ruby
362
+ iat = Time.now.to_i + 10
363
+ leeway = 30 # seconds
364
+
365
+ iat_payload = { :data => 'data', :iat => iat }
366
+
367
+ # build token issued in the future
368
+ token = JWT.encode iat_payload, hmac_secret, 'HS256'
369
+
370
+ begin
371
+ # add leeway to ensure the token is accepted
372
+ decoded_token = JWT.decode token, hmac_secret, true, { :iat_leeway => leeway, :verify_iat => true, :algorithm => 'HS256' }
373
+ rescue JWT::InvalidIatError
374
+ # Handle invalid token, e.g. logout user or deny access
375
+ end
376
+ ```
377
+
322
378
  ### Subject Claim
323
379
 
324
380
  From [Oauth JSON Web Token 4.1.2. "sub" (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2):
data/lib/jwt.rb CHANGED
@@ -1,192 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
  require 'base64'
3
- require 'openssl'
4
3
  require 'jwt/decode'
4
+ require 'jwt/default_options'
5
+ require 'jwt/encode'
5
6
  require 'jwt/error'
6
- require 'jwt/json'
7
+ require 'jwt/signature'
8
+ require 'jwt/verify'
7
9
 
8
10
  # JSON Web Token implementation
9
11
  #
10
12
  # Should be up to date with the latest spec:
11
- # https://tools.ietf.org/html/rfc7519#section-4.1.5
13
+ # https://tools.ietf.org/html/rfc7519
12
14
  module JWT
13
- extend JWT::Json
14
-
15
- NAMED_CURVES = {
16
- 'prime256v1' => 'ES256',
17
- 'secp384r1' => 'ES384',
18
- 'secp521r1' => 'ES512'
19
- }.freeze
20
-
21
- DEFAULT_OPTIONS = {
22
- verify_expiration: true,
23
- verify_not_before: true,
24
- verify_iss: false,
25
- verify_iat: false,
26
- verify_jti: false,
27
- verify_aud: false,
28
- verify_sub: false,
29
- leeway: 0
30
- }.freeze
15
+ include JWT::DefaultOptions
31
16
 
32
17
  module_function
33
18
 
34
- def sign(algorithm, msg, key)
35
- if %w(HS256 HS384 HS512).include?(algorithm)
36
- sign_hmac(algorithm, msg, key)
37
- elsif %w(RS256 RS384 RS512).include?(algorithm)
38
- sign_rsa(algorithm, msg, key)
39
- elsif %w(ES256 ES384 ES512).include?(algorithm)
40
- sign_ecdsa(algorithm, msg, key)
41
- else
42
- raise NotImplementedError, 'Unsupported signing method'
43
- end
44
- end
45
-
46
- def sign_rsa(algorithm, msg, private_key)
47
- private_key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
48
- end
49
-
50
- def sign_ecdsa(algorithm, msg, private_key)
51
- key_algorithm = NAMED_CURVES[private_key.group.curve_name]
52
- if algorithm != key_algorithm
53
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
54
- end
55
-
56
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
57
- asn1_to_raw(private_key.dsa_sign_asn1(digest.digest(msg)), private_key)
58
- end
59
-
60
- def verify_rsa(algorithm, public_key, signing_input, signature)
61
- public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
62
- end
63
-
64
- def verify_ecdsa(algorithm, public_key, signing_input, signature)
65
- key_algorithm = NAMED_CURVES[public_key.group.curve_name]
66
- if algorithm != key_algorithm
67
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
68
- end
69
-
70
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
71
- public_key.dsa_verify_asn1(digest.digest(signing_input), raw_to_asn1(signature, public_key))
72
- end
73
-
74
- def sign_hmac(algorithm, msg, key)
75
- OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
76
- end
77
-
78
- def base64url_encode(str)
79
- Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
80
- end
81
-
82
- def encoded_header(algorithm = 'HS256', header_fields = {})
83
- header = { 'typ' => 'JWT', 'alg' => algorithm }.merge(header_fields)
84
- base64url_encode(encode_json(header))
85
- end
86
-
87
- def encoded_payload(payload)
88
- raise InvalidPayload, 'exp claim must be an integer' if payload['exp'] && payload['exp'].is_a?(Time)
89
- base64url_encode(encode_json(payload))
90
- end
19
+ def decoded_segments(jwt, verify = true)
20
+ raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
91
21
 
92
- def encoded_signature(signing_input, key, algorithm)
93
- if algorithm == 'none'
94
- ''
95
- else
96
- signature = sign(algorithm, signing_input, key)
97
- base64url_encode(signature)
98
- end
22
+ decoder = Decode.new jwt, verify
23
+ decoder.decode_segments
99
24
  end
100
25
 
101
26
  def encode(payload, key, algorithm = 'HS256', header_fields = {})
102
- algorithm ||= 'none'
103
- segments = []
104
- segments << encoded_header(algorithm, header_fields)
105
- segments << encoded_payload(payload)
106
- segments << encoded_signature(segments.join('.'), key, algorithm)
107
- segments.join('.')
108
- end
109
-
110
- def decoded_segments(jwt, key = nil, verify = true, custom_options = {}, &keyfinder)
111
- raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
112
-
113
- merged_options = DEFAULT_OPTIONS.merge(custom_options)
114
-
115
- decoder = Decode.new jwt, key, verify, merged_options, &keyfinder
116
- decoder.decode_segments
27
+ encoder = Encode.new payload, key, algorithm, header_fields
28
+ encoder.segments
117
29
  end
118
30
 
119
31
  def decode(jwt, key = nil, verify = true, custom_options = {}, &keyfinder)
120
32
  raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
121
33
 
122
34
  merged_options = DEFAULT_OPTIONS.merge(custom_options)
123
- decoder = Decode.new jwt, key, verify, merged_options, &keyfinder
35
+
36
+ decoder = Decode.new jwt, verify
124
37
  header, payload, signature, signing_input = decoder.decode_segments
125
- decode_verify_signature(key, header, signature, signing_input, merged_options, &keyfinder) if verify
126
- decoder.verify
38
+ decode_verify_signature(key, header, payload, signature, signing_input, merged_options, &keyfinder) if verify
39
+
40
+ Verify.verify_claims(payload, merged_options)
127
41
 
128
42
  raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload
129
43
 
130
44
  [payload, header]
131
45
  end
132
46
 
133
- def decode_verify_signature(key, header, signature, signing_input, options, &keyfinder)
134
- algo, key = signature_algorithm_and_key(header, key, &keyfinder)
135
- if options[:algorithm] && algo != options[:algorithm]
136
- raise JWT::IncorrectAlgorithm, 'Expected a different algorithm'
137
- end
138
- verify_signature(algo, key, signing_input, signature)
139
- end
47
+ def decode_verify_signature(key, header, payload, signature, signing_input, options, &keyfinder)
48
+ algo, key = signature_algorithm_and_key(header, payload, key, &keyfinder)
140
49
 
141
- def signature_algorithm_and_key(header, key, &keyfinder)
142
- key = yield(header) if keyfinder
143
- [header['alg'], key]
144
- end
50
+ raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') unless options[:algorithm]
51
+ raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless algo == options[:algorithm]
145
52
 
146
- def verify_signature(algo, key, signing_input, signature)
147
- verify_signature_algo(algo, key, signing_input, signature)
148
- rescue OpenSSL::PKey::PKeyError
149
- raise JWT::VerificationError, 'Signature verification raised'
150
- ensure
151
- OpenSSL.errors.clear
53
+ Signature.verify(algo, key, signing_input, signature)
152
54
  end
153
55
 
154
- def verify_signature_algo(algo, key, signing_input, signature)
155
- if %w(HS256 HS384 HS512).include?(algo)
156
- raise(JWT::VerificationError, 'Signature verification raised') unless secure_compare(signature, sign_hmac(algo, signing_input, key))
157
- elsif %w(RS256 RS384 RS512).include?(algo)
158
- raise(JWT::VerificationError, 'Signature verification raised') unless verify_rsa(algo, key, signing_input, signature)
159
- elsif %w(ES256 ES384 ES512).include?(algo)
160
- raise(JWT::VerificationError, 'Signature verification raised') unless verify_ecdsa(algo, key, signing_input, signature)
161
- else
162
- raise JWT::VerificationError, 'Algorithm not supported'
56
+ def signature_algorithm_and_key(header, payload, key, &keyfinder)
57
+ if keyfinder
58
+ key = if keyfinder.arity == 2
59
+ yield(header, payload)
60
+ else
61
+ yield(header)
62
+ end
63
+ raise JWT::DecodeError, 'No verification key available' unless key
163
64
  end
164
- end
165
-
166
- # From devise
167
- # constant-time comparison algorithm to prevent timing attacks
168
- def secure_compare(a, b)
169
- return false if a.nil? || b.nil? || a.empty? || b.empty? || a.bytesize != b.bytesize
170
- l = a.unpack "C#{a.bytesize}"
171
-
172
- res = 0
173
- b.each_byte { |byte| res |= byte ^ l.shift }
174
- res.zero?
175
- end
176
-
177
- def raw_to_asn1(signature, private_key)
178
- byte_size = (private_key.group.degree + 7) / 8
179
- r = signature[0..(byte_size - 1)]
180
- s = signature[byte_size..-1]
181
- OpenSSL::ASN1::Sequence.new([r, s].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
182
- end
183
-
184
- def asn1_to_raw(signature, public_key)
185
- byte_size = (public_key.group.degree + 7) / 8
186
- OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
187
- end
188
-
189
- def base64url_decode(str)
190
- Decode.base64url_decode(str)
65
+ [header['alg'], key]
191
66
  end
192
67
  end