jwt 2.1.0 → 2.2.0.pre.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.travis.yml +9 -3
  4. data/AUTHORS +84 -0
  5. data/Appraisals +14 -0
  6. data/CHANGELOG.md +77 -8
  7. data/README.md +96 -85
  8. data/lib/jwt.rb +9 -42
  9. data/lib/jwt/algos/ecdsa.rb +1 -1
  10. data/lib/jwt/algos/ps.rb +43 -0
  11. data/lib/jwt/base64.rb +19 -0
  12. data/lib/jwt/claims_validator.rb +33 -0
  13. data/lib/jwt/decode.rb +76 -25
  14. data/lib/jwt/encode.rb +42 -25
  15. data/lib/jwt/error.rb +16 -12
  16. data/lib/jwt/json.rb +18 -0
  17. data/lib/jwt/jwk.rb +31 -0
  18. data/lib/jwt/jwk/key_finder.rb +57 -0
  19. data/lib/jwt/jwk/rsa.rb +45 -0
  20. data/lib/jwt/security_utils.rb +6 -0
  21. data/lib/jwt/signature.rb +2 -0
  22. data/lib/jwt/verify.rb +1 -5
  23. data/lib/jwt/version.rb +3 -3
  24. data/ruby-jwt.gemspec +6 -3
  25. metadata +44 -58
  26. data/.reek.yml +0 -40
  27. data/Manifest +0 -8
  28. data/spec/fixtures/certs/ec256-private.pem +0 -8
  29. data/spec/fixtures/certs/ec256-public.pem +0 -4
  30. data/spec/fixtures/certs/ec256-wrong-private.pem +0 -8
  31. data/spec/fixtures/certs/ec256-wrong-public.pem +0 -4
  32. data/spec/fixtures/certs/ec384-private.pem +0 -9
  33. data/spec/fixtures/certs/ec384-public.pem +0 -5
  34. data/spec/fixtures/certs/ec384-wrong-private.pem +0 -9
  35. data/spec/fixtures/certs/ec384-wrong-public.pem +0 -5
  36. data/spec/fixtures/certs/ec512-private.pem +0 -10
  37. data/spec/fixtures/certs/ec512-public.pem +0 -6
  38. data/spec/fixtures/certs/ec512-wrong-private.pem +0 -10
  39. data/spec/fixtures/certs/ec512-wrong-public.pem +0 -6
  40. data/spec/fixtures/certs/rsa-1024-private.pem +0 -15
  41. data/spec/fixtures/certs/rsa-1024-public.pem +0 -6
  42. data/spec/fixtures/certs/rsa-2048-private.pem +0 -27
  43. data/spec/fixtures/certs/rsa-2048-public.pem +0 -9
  44. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +0 -27
  45. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +0 -9
  46. data/spec/fixtures/certs/rsa-4096-private.pem +0 -51
  47. data/spec/fixtures/certs/rsa-4096-public.pem +0 -14
  48. data/spec/integration/readme_examples_spec.rb +0 -202
  49. data/spec/jwt/verify_spec.rb +0 -232
  50. data/spec/jwt_spec.rb +0 -315
  51. data/spec/spec_helper.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0fca109273d0c036454af123d30bb3eb75f0de39
4
- data.tar.gz: 8848296d35465d3411f71d882da73ef05663f6a6
2
+ SHA256:
3
+ metadata.gz: faa454cb34b8e65b8d83996ec036f63eba2c3b9a9239d1abbe1c975be9bec69f
4
+ data.tar.gz: 590d89a3825fd03d82f6fe076f4bef60c564322befac28de85abe6559568b942
5
5
  SHA512:
6
- metadata.gz: 213d4ea31197a90be8b8cd08ea92dee4659f47b884bc3571440697db979cf98b04e3d1cf487bc94a7a8a8f3f29ee34ebf48d7cc5bd9cfa9f2ca65a092bb2c3d3
7
- data.tar.gz: 530335d90320cdc5501cc1f67984502f79a390641b904567971ad4858a285128cc4702dbf54d505324bcb1ea3ecdf5675057c942e9709ecf0f17b4099229c04d
6
+ metadata.gz: bb9aba3a38c1c88d1359a243dee4fdbed12e36a802620c42d9a53489f9be86f90125fadd5159365440d0f1f94982c2b9270609c8167b20db6c2b0adb1ced6017
7
+ data.tar.gz: 63069e007053ccb569b2846adc4cc1587aac2a7a62d5716ec6eafc2a893988aa71e3fa5cd672ad9fb53cd9c2100f3ea8a21b8200afe27c76f555ecb490e4ce86
data/.gitignore CHANGED
@@ -8,4 +8,4 @@ coverage/
8
8
  .ruby-version
9
9
  .vscode/
10
10
  .bundle
11
- bin/
11
+ *gemfile.lock
@@ -3,9 +3,15 @@ cache: bundler
3
3
  dist: trusty
4
4
  language: ruby
5
5
  rvm:
6
- - 2.2.0
7
- - 2.3.0
8
- - 2.4.0
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
9
+ - 2.6
10
+ gemfiles:
11
+ - gemfiles/standalone.gemfile
12
+ - gemfiles/rails_5.0.gemfile
13
+ - gemfiles/rails_5.1.gemfile
14
+ - gemfiles/rails_5.2.gemfile
9
15
  script: "bundle exec rspec && bundle exec codeclimate-test-reporter"
10
16
  before_install:
11
17
  - sudo add-apt-repository ppa:chris-lea/libsodium -y
data/AUTHORS ADDED
@@ -0,0 +1,84 @@
1
+ Tim Rudat
2
+ Jeff Lindsay
3
+ A.B
4
+ Emilio Cristalli
5
+ Bob Aman
6
+ Zane Shannon
7
+ Oliver
8
+ Paul Battley
9
+ Nikita Shatov
10
+ blackanger
11
+ Tyler Pickett
12
+ James Stonehill
13
+ Adam Michael
14
+ Ville Lautanala
15
+ Peter M. Goldstein
16
+ Joakim Antman
17
+ Korstiaan de Ridder
18
+ Klaas Jan Wierenga
19
+ Steve Sloan
20
+ Bill Mill
21
+ Erik Michaels-Ober
22
+ Brian Flethcer
23
+ Jurriaan Pruis
24
+ Kevin Olbrich
25
+ Larry Lv
26
+ Rodrigo López Dato
27
+ Steven Davidovitz
28
+ Tom Wey
29
+ lukas
30
+ ojab
31
+ sawyerzhang
32
+ wohlgejm
33
+ yann ARMAND
34
+ Jordan Brough
35
+ Juanito Fatas
36
+ Julio Lopez
37
+ Zuzanna Stolińska
38
+ Katelyn Kasperowicz
39
+ aarongray
40
+ B
41
+ Adam Greene
42
+ Lowell Kirsh
43
+ Lucas Mazza
44
+ Makoto Chiba
45
+ Manuel Bustillo
46
+ Marco Adkins
47
+ Micah Gates
48
+ Mike Eirih
49
+ Mike Pastore
50
+ Mingan
51
+ Mitch Birti
52
+ Nicolas Leger
53
+ Austin Kabiru
54
+ Artsiom Kuts
55
+ Arnaud Mesureur
56
+ Ariel Salomon
57
+ Rob Wygand
58
+ danielgrippi
59
+ Ryan Brushett
60
+ Ryan McIlmoyl
61
+ Aman Gupta
62
+ Steve Teti
63
+ revodoge
64
+ Taiki Sugawara
65
+ nycvotes-dev
66
+ Alexandr Kostrikov
67
+ Tobias Haar
68
+ Toby Pinder
69
+ rono23
70
+ Tomé Duarte
71
+ Travis Hunter
72
+ Alexander Boyd
73
+ Yuji Yaginuma
74
+ Ernie Miller
75
+ Evgeni Golov
76
+ Ewoud Kohl van Wijngaarden
77
+ Ilyaaaaaaaaaaaaa Zhitomirskiy
78
+ Dorian Marié
79
+ Dave Grijalva
80
+ Jens Hausherr
81
+ Jeremiah Wuenschel
82
+ Brandon Keepers
83
+ John Downey
84
+ Josh Bodah
@@ -0,0 +1,14 @@
1
+ appraise 'standalone' do
2
+ end
3
+
4
+ appraise 'rails-5.0' do
5
+ gem 'rails', '~> 5.0.0'
6
+ end
7
+
8
+ appraise 'rails-5.1' do
9
+ gem 'rails', '~> 5.1.0'
10
+ end
11
+
12
+ appraise 'rails-5.2' do
13
+ gem 'rails', '~> 5.2.0'
14
+ end
@@ -1,7 +1,75 @@
1
1
  # Change Log
2
2
 
3
- ## [2.1.0](https://github.com/jwt/ruby-jwt/tree/2.1.0) (2017-10-06)
4
- [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0...2.1.0)
3
+ ## [2.2.0-beta.0](https://github.com/jwt/ruby-jwt/tree/2.2.0-beta.0) (2019-03-20)
4
+ [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.1.0...2.2.0-beta.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Use iat\_leeway option [\#273](https://github.com/jwt/ruby-jwt/issues/273)
9
+ - Use of global state in latest version breaks thread safety of JWT.decode [\#268](https://github.com/jwt/ruby-jwt/issues/268)
10
+ - JSON support [\#246](https://github.com/jwt/ruby-jwt/issues/246)
11
+ - Change the Github homepage URL to https [\#301](https://github.com/jwt/ruby-jwt/pull/301) ([ekohl](https://github.com/ekohl))
12
+ - Fix Salt length for conformance with PS family specification. [\#300](https://github.com/jwt/ruby-jwt/pull/300) ([tobypinder](https://github.com/tobypinder))
13
+ - Add support for Ruby 2.6 [\#299](https://github.com/jwt/ruby-jwt/pull/299) ([bustikiller](https://github.com/bustikiller))
14
+ - update homepage in gemspec to use HTTPS [\#298](https://github.com/jwt/ruby-jwt/pull/298) ([evgeni](https://github.com/evgeni))
15
+ - Make sure alg parameter value isn't added twice [\#297](https://github.com/jwt/ruby-jwt/pull/297) ([korstiaan](https://github.com/korstiaan))
16
+ - Claims Validation [\#295](https://github.com/jwt/ruby-jwt/pull/295) ([jamesstonehill](https://github.com/jamesstonehill))
17
+ - JWT::Encode refactorings, alg and exp related bugfixes [\#293](https://github.com/jwt/ruby-jwt/pull/293) ([anakinj](https://github.com/anakinj))
18
+ - Proposal of simple JWK support [\#289](https://github.com/jwt/ruby-jwt/pull/289) ([anakinj](https://github.com/anakinj))
19
+ - Add RSASSA-PSS signature signing support [\#285](https://github.com/jwt/ruby-jwt/pull/285) ([oliver-hohn](https://github.com/oliver-hohn))
20
+ - Add note about using a hard coded algorithm in README [\#280](https://github.com/jwt/ruby-jwt/pull/280) ([revodoge](https://github.com/revodoge))
21
+ - Add Appraisal support [\#278](https://github.com/jwt/ruby-jwt/pull/278) ([olbrich](https://github.com/olbrich))
22
+ - Fix decode threading issue [\#269](https://github.com/jwt/ruby-jwt/pull/269) ([ab320012](https://github.com/ab320012))
23
+ - Removed leeway from verify\_iat [\#257](https://github.com/jwt/ruby-jwt/pull/257) ([ab320012](https://github.com/ab320012))
24
+
25
+ **Fixed bugs:**
26
+
27
+ - Inconsistent handling of payload claim data types [\#282](https://github.com/jwt/ruby-jwt/issues/282)
28
+ - Use iat\\_leeway option [\#273](https://github.com/jwt/ruby-jwt/issues/273)
29
+ - Issued at validation [\#247](https://github.com/jwt/ruby-jwt/issues/247)
30
+ - Fix bug and simplify segment validation [\#292](https://github.com/jwt/ruby-jwt/pull/292) ([anakinj](https://github.com/anakinj))
31
+ - Removed leeway from verify\\_iat [\#257](https://github.com/jwt/ruby-jwt/pull/257) ([ab320012](https://github.com/ab320012))
32
+
33
+ **Closed issues:**
34
+
35
+ - RS256, public and private keys [\#291](https://github.com/jwt/ruby-jwt/issues/291)
36
+ - Allow passing current time to `decode` [\#288](https://github.com/jwt/ruby-jwt/issues/288)
37
+ - Verify exp claim without verifying jwt [\#281](https://github.com/jwt/ruby-jwt/issues/281)
38
+ - Decoding JWT with ES256 and secp256k1 curve [\#277](https://github.com/jwt/ruby-jwt/issues/277)
39
+ - Audience as an array - how to specify? [\#276](https://github.com/jwt/ruby-jwt/issues/276)
40
+ - signature validation using decode method for JWT [\#271](https://github.com/jwt/ruby-jwt/issues/271)
41
+ - JWT is easily breakable [\#267](https://github.com/jwt/ruby-jwt/issues/267)
42
+ - Ruby JWT Token [\#265](https://github.com/jwt/ruby-jwt/issues/265)
43
+ - ECDSA supported algorithms constant is defined as a string, not an array [\#264](https://github.com/jwt/ruby-jwt/issues/264)
44
+ - NoMethodError: undefined method `group' for \<xxxxx\> [\#261](https://github.com/jwt/ruby-jwt/issues/261)
45
+ - 'DecodeError'will replace 'ExpiredSignature' [\#260](https://github.com/jwt/ruby-jwt/issues/260)
46
+ - TypeError: no implicit conversion of OpenSSL::PKey::RSA into String [\#259](https://github.com/jwt/ruby-jwt/issues/259)
47
+ - NameError: uninitialized constant JWT::Algos::Eddsa::RbNaCl [\#258](https://github.com/jwt/ruby-jwt/issues/258)
48
+ - Get new token if curren token expired [\#256](https://github.com/jwt/ruby-jwt/issues/256)
49
+ - Infer algorithm from header [\#254](https://github.com/jwt/ruby-jwt/issues/254)
50
+ - Why is the result of decode is an array? [\#252](https://github.com/jwt/ruby-jwt/issues/252)
51
+ - Add support for headless token [\#251](https://github.com/jwt/ruby-jwt/issues/251)
52
+ - Leeway or exp\_leeway [\#215](https://github.com/jwt/ruby-jwt/issues/215)
53
+ - Could you describe purpose of cert fixtures and their cryptokey lengths. [\#185](https://github.com/jwt/ruby-jwt/issues/185)
54
+
55
+ **Merged pull requests:**
56
+
57
+ - Misc config improvements [\#296](https://github.com/jwt/ruby-jwt/pull/296) ([jamesstonehill](https://github.com/jamesstonehill))
58
+ - Fix JSON conflict between \#293 and \#292 [\#294](https://github.com/jwt/ruby-jwt/pull/294) ([anakinj](https://github.com/anakinj))
59
+ - Drop Ruby 2.2 from test matrix [\#290](https://github.com/jwt/ruby-jwt/pull/290) ([anakinj](https://github.com/anakinj))
60
+ - Remove broken reek config [\#283](https://github.com/jwt/ruby-jwt/pull/283) ([excpt](https://github.com/excpt))
61
+ - Add missing test, Update common files [\#275](https://github.com/jwt/ruby-jwt/pull/275) ([excpt](https://github.com/excpt))
62
+ - Remove iat\_leeway option [\#274](https://github.com/jwt/ruby-jwt/pull/274) ([wohlgejm](https://github.com/wohlgejm))
63
+ - improving code quality of jwt module [\#266](https://github.com/jwt/ruby-jwt/pull/266) ([ab320012](https://github.com/ab320012))
64
+ - fixed ECDSA supported versions const [\#263](https://github.com/jwt/ruby-jwt/pull/263) ([starbeast](https://github.com/starbeast))
65
+ - Added my name to contributor list [\#262](https://github.com/jwt/ruby-jwt/pull/262) ([ab320012](https://github.com/ab320012))
66
+ - Use `Class\#new` Shorthand For Error Subclasses [\#255](https://github.com/jwt/ruby-jwt/pull/255) ([akabiru](https://github.com/akabiru))
67
+ - \[CI\] Test against Ruby 2.5 [\#253](https://github.com/jwt/ruby-jwt/pull/253) ([nicolasleger](https://github.com/nicolasleger))
68
+ - Fix README [\#250](https://github.com/jwt/ruby-jwt/pull/250) ([rono23](https://github.com/rono23))
69
+ - Fix link format [\#248](https://github.com/jwt/ruby-jwt/pull/248) ([y-yagi](https://github.com/y-yagi))
70
+
71
+ ## [v2.1.0](https://github.com/jwt/ruby-jwt/tree/v2.1.0) (2017-10-06)
72
+ [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0...v2.1.0)
5
73
 
6
74
  **Implemented enhancements:**
7
75
 
@@ -26,6 +94,7 @@
26
94
 
27
95
  **Merged pull requests:**
28
96
 
97
+ - Release 2.1.0 preparations [\#243](https://github.com/jwt/ruby-jwt/pull/243) ([excpt](https://github.com/excpt))
29
98
  - Update README.md [\#242](https://github.com/jwt/ruby-jwt/pull/242) ([excpt](https://github.com/excpt))
30
99
  - Update ebert configuration [\#232](https://github.com/jwt/ruby-jwt/pull/232) ([excpt](https://github.com/excpt))
31
100
  - added algos/strategy classes + structs for inputs [\#230](https://github.com/jwt/ruby-jwt/pull/230) ([ab320012](https://github.com/ab320012))
@@ -74,9 +143,9 @@
74
143
  - Refactor [\#196](https://github.com/jwt/ruby-jwt/pull/196) ([EmilioCristalli](https://github.com/EmilioCristalli))
75
144
  - Move signature logic to its own module [\#195](https://github.com/jwt/ruby-jwt/pull/195) ([EmilioCristalli](https://github.com/EmilioCristalli))
76
145
  - Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
77
- - 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))
78
- - Return empty string if signature less than byte\_size \#155 [\#175](https://github.com/jwt/ruby-jwt/pull/175) ([xamenrax](https://github.com/xamenrax))
79
- - Remove 'typ' optional parameter [\#174](https://github.com/jwt/ruby-jwt/pull/174) ([xamenrax](https://github.com/xamenrax))
146
+ - Add user friendly encode error if private key is a String, \#171 [\#176](https://github.com/jwt/ruby-jwt/pull/176) ([ogonki-vetochki](https://github.com/ogonki-vetochki))
147
+ - Return empty string if signature less than byte\_size \#155 [\#175](https://github.com/jwt/ruby-jwt/pull/175) ([ogonki-vetochki](https://github.com/ogonki-vetochki))
148
+ - Remove 'typ' optional parameter [\#174](https://github.com/jwt/ruby-jwt/pull/174) ([ogonki-vetochki](https://github.com/ogonki-vetochki))
80
149
  - Pass payload to keyfinder [\#172](https://github.com/jwt/ruby-jwt/pull/172) ([CodeMonkeySteve](https://github.com/CodeMonkeySteve))
81
150
  - Use RbNaCl for HMAC if available with fallback to OpenSSL [\#149](https://github.com/jwt/ruby-jwt/pull/149) ([mwpastore](https://github.com/mwpastore))
82
151
 
@@ -94,7 +163,6 @@
94
163
  - Signature is different at each run [\#190](https://github.com/jwt/ruby-jwt/issues/190)
95
164
  - Include custom headers with password [\#189](https://github.com/jwt/ruby-jwt/issues/189)
96
165
  - can't create token - 'NotImplementedError: Unsupported signing method' [\#186](https://github.com/jwt/ruby-jwt/issues/186)
97
- - Why jwt depends on json \< 2.0 ? [\#179](https://github.com/jwt/ruby-jwt/issues/179)
98
166
  - Cannot verify JWT at all?? [\#177](https://github.com/jwt/ruby-jwt/issues/177)
99
167
  - verify\_iss: true is raising JWT::DecodeError instead of JWT::InvalidIssuerError [\#170](https://github.com/jwt/ruby-jwt/issues/170)
100
168
 
@@ -106,12 +174,12 @@
106
174
  - Add minimum required ruby version to gemspec [\#193](https://github.com/jwt/ruby-jwt/pull/193) ([excpt](https://github.com/excpt))
107
175
  - Code smell fixes [\#192](https://github.com/jwt/ruby-jwt/pull/192) ([excpt](https://github.com/excpt))
108
176
  - Version bump to 2.0.0.dev [\#191](https://github.com/jwt/ruby-jwt/pull/191) ([excpt](https://github.com/excpt))
109
- - Basic encode module refactoring \#121 [\#182](https://github.com/jwt/ruby-jwt/pull/182) ([xamenrax](https://github.com/xamenrax))
177
+ - Basic encode module refactoring \#121 [\#182](https://github.com/jwt/ruby-jwt/pull/182) ([ogonki-vetochki](https://github.com/ogonki-vetochki))
110
178
  - Fix travis ci build configuration [\#181](https://github.com/jwt/ruby-jwt/pull/181) ([excpt](https://github.com/excpt))
111
179
  - Fix travis ci build configuration [\#180](https://github.com/jwt/ruby-jwt/pull/180) ([excpt](https://github.com/excpt))
112
180
  - Fix typo in README [\#178](https://github.com/jwt/ruby-jwt/pull/178) ([tomeduarte](https://github.com/tomeduarte))
113
181
  - Fix code style [\#173](https://github.com/jwt/ruby-jwt/pull/173) ([excpt](https://github.com/excpt))
114
- - Fixed a typo in a spec name [\#169](https://github.com/jwt/ruby-jwt/pull/169) ([Mingan](https://github.com/Mingan))
182
+ - Fixed a typo in a spec name [\#169](https://github.com/jwt/ruby-jwt/pull/169) ([mingan](https://github.com/mingan))
115
183
 
116
184
  ## [v1.5.6](https://github.com/jwt/ruby-jwt/tree/v1.5.6) (2016-09-19)
117
185
  [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.5...v1.5.6)
@@ -367,6 +435,7 @@
367
435
 
368
436
  **Closed issues:**
369
437
 
438
+ - yanking of version 0.1.12 causes issues [\#39](https://github.com/jwt/ruby-jwt/issues/39)
370
439
  - Semantic versioning [\#37](https://github.com/jwt/ruby-jwt/issues/37)
371
440
  - Update gem to get latest changes [\#36](https://github.com/jwt/ruby-jwt/issues/36)
372
441
 
data/README.md CHANGED
@@ -5,8 +5,9 @@
5
5
  [![Code Climate](https://codeclimate.com/github/jwt/ruby-jwt/badges/gpa.svg)](https://codeclimate.com/github/jwt/ruby-jwt)
6
6
  [![Test Coverage](https://codeclimate.com/github/jwt/ruby-jwt/badges/coverage.svg)](https://codeclimate.com/github/jwt/ruby-jwt/coverage)
7
7
  [![Issue Count](https://codeclimate.com/github/jwt/ruby-jwt/badges/issue_count.svg)](https://codeclimate.com/github/jwt/ruby-jwt)
8
+ [![Ebert](https://ebertapp.io/github/jwt/ruby-jwt.svg)](https://ebertapp.io/github/jwt/ruby-jwt)
8
9
 
9
- A pure ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard.
10
+ A ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard.
10
11
 
11
12
  If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
12
13
 
@@ -31,7 +32,7 @@ And run `bundle install`
31
32
 
32
33
  ## Algorithms and Usage
33
34
 
34
- The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cryptographic signing. Currently the jwt gem supports NONE, HMAC, RSASSA and ECDSA. If you are using cryptographic signing, you need to specify the algorithm in the options hash whenever you call JWT.decode to ensure that an attacker [cannot bypass the algorithm verification step](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/).
35
+ The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cryptographic signing. Currently the jwt gem supports NONE, HMAC, RSASSA and ECDSA. If you are using cryptographic signing, you need to specify the algorithm in the options hash whenever you call JWT.decode to ensure that an attacker [cannot bypass the algorithm verification step](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). **It is strongly recommended that you hard code the algorithm, as you may leave yourself vulnerable by dynamically picking the algorithm**
35
36
 
36
37
  See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)
37
38
 
@@ -42,12 +43,12 @@ See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values
42
43
  ```ruby
43
44
  require 'jwt'
44
45
 
45
- payload = {:data => 'test'}
46
+ payload = { data: 'test' }
46
47
 
47
48
  # IMPORTANT: set nil as password parameter
48
49
  token = JWT.encode payload, nil, 'none'
49
50
 
50
- # eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.
51
+ # eyJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.
51
52
  puts token
52
53
 
53
54
  # Set password to nil and validation to false otherwise this won't work
@@ -73,10 +74,10 @@ hmac_secret = 'my$ecretK3y'
73
74
 
74
75
  token = JWT.encode payload, hmac_secret, 'HS256'
75
76
 
76
- # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.ZxW8go9hz3ETCSfxFxpwSkYg_602gOPKearsf6DsxgY
77
+ # eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.pNIWIL34Jo13LViZAJACzK6Yf0qnvT_BuwOxiMCPE-Y
77
78
  puts token
78
79
 
79
- decoded_token = JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
80
+ decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
80
81
 
81
82
  # Array
82
83
  # [
@@ -104,10 +105,10 @@ rsa_public = rsa_private.public_key
104
105
 
105
106
  token = JWT.encode payload, rsa_private, 'RS256'
106
107
 
107
- # eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ0ZXN0IjoiZGF0YSJ9.c2FynXNyi6_PeKxrDGxfS3OLwQ8lTDbWBWdq7oMviCy2ZfFpzvW2E_odCWJrbLof-eplHCsKzW7MGAntHMALXgclm_Cs9i2Exi6BZHzpr9suYkrhIjwqV1tCgMBCQpdeMwIq6SyKVjgH3L51ivIt0-GDDPDH1Rcut3jRQzp3Q35bg3tcI2iVg7t3Msvl9QrxXAdYNFiS5KXH22aJZ8X_O2HgqVYBXfSB1ygTYUmKTIIyLbntPQ7R22rFko1knGWOgQCoYXwbtpuKRZVFrxX958L2gUWgb4jEQNf3fhOtkBm1mJpj-7BGst00o8g_3P2zHy-3aKgpPo1XlKQGjRrrxA
108
+ # eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.GplO4w1spRgvEJQ3-FOtZr-uC8L45Jt7SN0J4woBnEXG_OZBSNcZjAJWpjadVYEe2ev3oUBFDYM1N_-0BTVeFGGYvMewu8E6aMjSZvOpf1cZBew-Vt4poSq7goG2YRI_zNPt3af2lkPqXD796IKC5URrEvcgF5xFQ-6h07XRDpSRx1ECrNsUOt7UM3l1IB4doY11GzwQA5sHDTmUZ0-kBT76ZMf12Srg_N3hZwphxBtudYtN5VGZn420sVrQMdPE_7Ni3EiWT88j7WCr1xrF60l8sZT3yKCVleG7D2BEXacTntB7GktBv4Xo8OKnpwpqTpIlC05dMowMkz3rEAAYbQ
108
109
  puts token
109
110
 
110
- decoded_token = JWT.decode token, rsa_public, true, { :algorithm => 'RS256' }
111
+ decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'RS256' }
111
112
 
112
113
  # Array
113
114
  # [
@@ -131,10 +132,10 @@ ecdsa_public.private_key = nil
131
132
 
132
133
  token = JWT.encode payload, ecdsa_key, 'ES256'
133
134
 
134
- # eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJ0ZXN0IjoiZGF0YSJ9.MEQCIAtShrxRwP1L9SapqaT4f7hajDJH4t_rfm-YlZcNDsBNAiB64M4-JRfyS8nRMlywtQ9lHbvvec9U54KznzOe1YxTyA
135
+ # eyJhbGciOiJFUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.AlLW--kaF7EX1NMX9WJRuIW8NeRJbn2BLXHns7Q5TZr7Hy3lF6MOpMlp7GoxBFRLISQ6KrD0CJOrR8aogEsPeg
135
136
  puts token
136
137
 
137
- decoded_token = JWT.decode token, ecdsa_public, true, { :algorithm => 'ES256' }
138
+ decoded_token = JWT.decode token, ecdsa_public, true, { algorithm: 'ES256' }
138
139
 
139
140
  # Array
140
141
  # [
@@ -154,17 +155,17 @@ gem 'rbnacl'
154
155
 
155
156
  For more detailed installation instruction check the official [repository](https://github.com/cryptosphere/rbnacl) on GitHub.
156
157
 
157
- * ED25519
158
+ * ED25519
158
159
 
159
- ```ruby
160
- private_key = RbNaCl::Signatures::Ed25519::SigningKey.new("abcdefghijklmnopqrstuvwxyzABCDEF")
160
+ ```ruby
161
+ private_key = RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF')
161
162
  public_key = private_key.verify_key
162
- token = JWT.encode payload, private_key, 'ED25519'
163
+ token = JWT.encode payload, private_key, 'ED25519'
163
164
 
164
- # eyJhbGciOiJFRDI1NTE5In0.eyJ0ZXN0IjoiZGF0YSJ9.-Ki0vxVOlsPXovPsYRT_9OXrLSgQd4RDAgCLY_PLmcP4q32RYy-yUUmX82ycegdekR9wo26me1wOzjmSU5nTCQ
165
+ # eyJhbGciOiJFRDI1NTE5In0.eyJkYXRhIjoidGVzdCJ9.6xIztXyOupskddGA_RvKU76V9b2dCQUYhoZEVFnRimJoPYIzZ2Fm47CWw8k2NTCNpgfAuxg9OXjaiVK7MvrbCQ
165
166
  puts token
166
167
 
167
- decoded_token = JWT.decode token, public_key, true, {:algorithm => 'ED25519' }
168
+ decoded_token = JWT.decode token, public_key, true, { algorithm: 'ED25519' }
168
169
  # Array
169
170
  # [
170
171
  # {"test"=>"data"}, # payload
@@ -175,7 +176,34 @@ decoded_token = JWT.decode token, public_key, true, {:algorithm => 'ED25519' }
175
176
 
176
177
  **RSASSA-PSS**
177
178
 
178
- Not implemented.
179
+ In order to use this algorithm you need to add the `openssl` gem to you `Gemfile` with a version greater or equal to `2.1`.
180
+
181
+ ```ruby
182
+ gem 'openssl', '~> 2.1'
183
+ ```
184
+
185
+ * PS256 - RSASSA-PSS using SHA-256 hash algorithm
186
+ * PS384 - RSASSA-PSS using SHA-384 hash algorithm
187
+ * PS512 - RSASSA-PSS using SHA-512 hash algorithm
188
+
189
+ ```ruby
190
+ rsa_private = OpenSSL::PKey::RSA.generate 2048
191
+ rsa_public = rsa_private.public_key
192
+
193
+ token = JWT.encode payload, rsa_private, 'PS256'
194
+
195
+ # eyJhbGciOiJQUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.KEmqagMUHM-NcmXo6818ZazVTIAkn9qU9KQFT1c5Iq91n0KRpAI84jj4ZCdkysDlWokFs3Dmn4MhcXP03oJKLFgnoPL40_Wgg9iFr0jnIVvnMUp1kp2RFUbL0jqExGTRA3LdAhuvw6ZByGD1bkcWjDXygjQw-hxILrT1bENjdr0JhFd-cB0-ps5SB0mwhFNcUw-OM3Uu30B1-mlFaelUY8jHJYKwLTZPNxHzndt8RGXF8iZLp7dGb06HSCKMcVzhASGMH4ZdFystRe2hh31cwcvnl-Eo_D4cdwmpN3Abhk_8rkxawQJR3duh8HNKc4AyFPo7SabEaSu2gLnLfN3yfg
196
+ puts token
197
+
198
+ decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'PS256' }
199
+
200
+ # Array
201
+ # [
202
+ # {"data"=>"test"}, # payload
203
+ # {"alg"=>"PS256"} # header
204
+ # ]
205
+ puts decoded_token
206
+ ```
179
207
 
180
208
  ## Support for reserved claim names
181
209
  JSON Web Token defines some reserved claim names and defines how they should be
@@ -190,7 +218,7 @@ used. JWT supports these reserved claim names:
190
218
  - 'sub' (Subject) Claim
191
219
 
192
220
  ## Add custom header fields
193
- Ruby-jwt gem supports custom [header fields] (https://tools.ietf.org/html/rfc7519#section-5)
221
+ Ruby-jwt gem supports custom [header fields](https://tools.ietf.org/html/rfc7519#section-5)
194
222
  To add custom header fields you need to pass `header_fields` parameter
195
223
 
196
224
  ```ruby
@@ -202,12 +230,12 @@ token = JWT.encode payload, key, algorithm='HS256', header_fields={}
202
230
  ```ruby
203
231
  require 'jwt'
204
232
 
205
- payload = {:data => 'test'}
233
+ payload = { data: 'test' }
206
234
 
207
235
  # IMPORTANT: set nil as password parameter
208
- token = JWT.encode payload, nil, 'none', { :typ => "JWT" }
236
+ token = JWT.encode payload, nil, 'none', { typ: 'JWT' }
209
237
 
210
- # eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.
238
+ # eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJkYXRhIjoidGVzdCJ9.
211
239
  puts token
212
240
 
213
241
  # Set password to nil and validation to false otherwise this won't work
@@ -231,12 +259,12 @@ From [Oauth JSON Web Token 4.1.4. "exp" (Expiration Time) Claim](https://tools.i
231
259
 
232
260
  ```ruby
233
261
  exp = Time.now.to_i + 4 * 3600
234
- exp_payload = { :data => 'data', :exp => exp }
262
+ exp_payload = { data: 'data', exp: exp }
235
263
 
236
264
  token = JWT.encode exp_payload, hmac_secret, 'HS256'
237
265
 
238
266
  begin
239
- decoded_token = JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
267
+ decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
240
268
  rescue JWT::ExpiredSignature
241
269
  # Handle expired token, e.g. logout user or deny access
242
270
  end
@@ -248,14 +276,14 @@ end
248
276
  exp = Time.now.to_i - 10
249
277
  leeway = 30 # seconds
250
278
 
251
- exp_payload = { :data => 'data', :exp => exp }
279
+ exp_payload = { data: 'data', exp: exp }
252
280
 
253
281
  # build expired token
254
282
  token = JWT.encode exp_payload, hmac_secret, 'HS256'
255
283
 
256
284
  begin
257
285
  # add leeway to ensure the token is still accepted
258
- decoded_token = JWT.decode token, hmac_secret, true, { :exp_leeway => leeway, :algorithm => 'HS256' }
286
+ decoded_token = JWT.decode token, hmac_secret, true, { exp_leeway: leeway, algorithm: 'HS256' }
259
287
  rescue JWT::ExpiredSignature
260
288
  # Handle expired token, e.g. logout user or deny access
261
289
  end
@@ -271,12 +299,12 @@ From [Oauth JSON Web Token 4.1.5. "nbf" (Not Before) Claim](https://tools.ietf.o
271
299
 
272
300
  ```ruby
273
301
  nbf = Time.now.to_i - 3600
274
- nbf_payload = { :data => 'data', :nbf => nbf }
302
+ nbf_payload = { data: 'data', nbf: nbf }
275
303
 
276
304
  token = JWT.encode nbf_payload, hmac_secret, 'HS256'
277
305
 
278
306
  begin
279
- decoded_token = JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
307
+ decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
280
308
  rescue JWT::ImmatureSignature
281
309
  # Handle invalid token, e.g. logout user or deny access
282
310
  end
@@ -288,14 +316,14 @@ end
288
316
  nbf = Time.now.to_i + 10
289
317
  leeway = 30
290
318
 
291
- nbf_payload = { :data => 'data', :nbf => nbf }
319
+ nbf_payload = { data: 'data', nbf: nbf }
292
320
 
293
321
  # build expired token
294
322
  token = JWT.encode nbf_payload, hmac_secret, 'HS256'
295
323
 
296
324
  begin
297
325
  # add leeway to ensure the token is valid
298
- decoded_token = JWT.decode token, hmac_secret, true, { :nbf_leeway => leeway, :algorithm => 'HS256' }
326
+ decoded_token = JWT.decode token, hmac_secret, true, { nbf_leeway: leeway, algorithm: 'HS256' }
299
327
  rescue JWT::ImmatureSignature
300
328
  # Handle invalid token, e.g. logout user or deny access
301
329
  end
@@ -311,13 +339,13 @@ You can pass multiple allowed issuers as an Array, verification will pass if one
311
339
 
312
340
  ```ruby
313
341
  iss = 'My Awesome Company Inc. or https://my.awesome.website/'
314
- iss_payload = { :data => 'data', :iss => iss }
342
+ iss_payload = { data: 'data', iss: iss }
315
343
 
316
344
  token = JWT.encode iss_payload, hmac_secret, 'HS256'
317
345
 
318
346
  begin
319
347
  # Add iss to the validation to check if the token has been manipulated
320
- decoded_token = JWT.decode token, hmac_secret, true, { :iss => iss, :verify_iss => true, :algorithm => 'HS256' }
348
+ decoded_token = JWT.decode token, hmac_secret, true, { iss: iss, verify_iss: true, algorithm: 'HS256' }
321
349
  rescue JWT::InvalidIssuerError
322
350
  # Handle invalid token, e.g. logout user or deny access
323
351
  end
@@ -331,13 +359,13 @@ From [Oauth JSON Web Token 4.1.3. "aud" (Audience) Claim](https://tools.ietf.org
331
359
 
332
360
  ```ruby
333
361
  aud = ['Young', 'Old']
334
- aud_payload = { :data => 'data', :aud => aud }
362
+ aud_payload = { data: 'data', aud: aud }
335
363
 
336
364
  token = JWT.encode aud_payload, hmac_secret, 'HS256'
337
365
 
338
366
  begin
339
367
  # Add aud to the validation to check if the token has been manipulated
340
- decoded_token = JWT.decode token, hmac_secret, true, { :aud => aud, :verify_aud => true, :algorithm => 'HS256' }
368
+ decoded_token = JWT.decode token, hmac_secret, true, { aud: aud, verify_aud: true, algorithm: 'HS256' }
341
369
  rescue JWT::InvalidAudError
342
370
  # Handle invalid token, e.g. logout user or deny access
343
371
  puts 'Audience Error'
@@ -354,58 +382,38 @@ From [Oauth JSON Web Token 4.1.7. "jti" (JWT ID) Claim](https://tools.ietf.org/h
354
382
  # Use the secret and iat to create a unique key per request to prevent replay attacks
355
383
  jti_raw = [hmac_secret, iat].join(':').to_s
356
384
  jti = Digest::MD5.hexdigest(jti_raw)
357
- jti_payload = { :data => 'data', :iat => iat, :jti => jti }
385
+ jti_payload = { data: 'data', iat: iat, jti: jti }
358
386
 
359
387
  token = JWT.encode jti_payload, hmac_secret, 'HS256'
360
388
 
361
389
  begin
362
390
  # If :verify_jti is true, validation will pass if a JTI is present
363
- #decoded_token = JWT.decode token, hmac_secret, true, { :verify_jti => true, :algorithm => 'HS256' }
391
+ #decoded_token = JWT.decode token, hmac_secret, true, { verify_jti: true, algorithm: 'HS256' }
364
392
  # Alternatively, pass a proc with your own code to check if the JTI has already been used
365
- decoded_token = JWT.decode token, hmac_secret, true, { :verify_jti => proc { |jti| my_validation_method(jti) }, :algorithm => 'HS256' }
393
+ decoded_token = JWT.decode token, hmac_secret, true, { verify_jti: proc { |jti| my_validation_method(jti) }, algorithm: 'HS256' }
366
394
  rescue JWT::InvalidJtiError
367
395
  # Handle invalid token, e.g. logout user or deny access
368
396
  puts 'Error'
369
397
  end
370
-
371
398
  ```
372
399
 
373
400
  ### Issued At Claim
374
401
 
375
402
  From [Oauth JSON Web Token 4.1.6. "iat" (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6):
376
403
 
377
- > 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.
404
+ > 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. The `leeway` option is not taken into account when verifying this claim. The `iat_leeway` option was removed in version 2.2.0. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL.
378
405
 
379
406
  **Handle Issued At Claim**
380
407
 
381
408
  ```ruby
382
409
  iat = Time.now.to_i
383
- iat_payload = { :data => 'data', :iat => iat }
410
+ iat_payload = { data: 'data', iat: iat }
384
411
 
385
412
  token = JWT.encode iat_payload, hmac_secret, 'HS256'
386
413
 
387
414
  begin
388
415
  # Add iat to the validation to check if the token has been manipulated
389
- decoded_token = JWT.decode token, hmac_secret, true, { :verify_iat => true, :algorithm => 'HS256' }
390
- rescue JWT::InvalidIatError
391
- # Handle invalid token, e.g. logout user or deny access
392
- end
393
- ```
394
-
395
- **Adding Leeway**
396
-
397
- ```ruby
398
- iat = Time.now.to_i + 10
399
- leeway = 30 # seconds
400
-
401
- iat_payload = { :data => 'data', :iat => iat }
402
-
403
- # build token issued in the future
404
- token = JWT.encode iat_payload, hmac_secret, 'HS256'
405
-
406
- begin
407
- # add leeway to ensure the token is accepted
408
- decoded_token = JWT.decode token, hmac_secret, true, { :iat_leeway => leeway, :verify_iat => true, :algorithm => 'HS256' }
416
+ decoded_token = JWT.decode token, hmac_secret, true, { verify_iat: true, algorithm: 'HS256' }
409
417
  rescue JWT::InvalidIatError
410
418
  # Handle invalid token, e.g. logout user or deny access
411
419
  end
@@ -419,18 +427,43 @@ From [Oauth JSON Web Token 4.1.2. "sub" (Subject) Claim](https://tools.ietf.org/
419
427
 
420
428
  ```ruby
421
429
  sub = 'Subject'
422
- sub_payload = { :data => 'data', :sub => sub }
430
+ sub_payload = { data: 'data', sub: sub }
423
431
 
424
432
  token = JWT.encode sub_payload, hmac_secret, 'HS256'
425
433
 
426
434
  begin
427
435
  # Add sub to the validation to check if the token has been manipulated
428
- decoded_token = JWT.decode token, hmac_secret, true, { 'sub' => sub, :verify_sub => true, :algorithm => 'HS256' }
436
+ decoded_token = JWT.decode token, hmac_secret, true, { sub: sub, verify_sub: true, algorithm: 'HS256' }
429
437
  rescue JWT::InvalidSubError
430
438
  # Handle invalid token, e.g. logout user or deny access
431
439
  end
432
440
  ```
433
441
 
442
+ ### JSON Web Key (JWK)
443
+
444
+ JWK is a JSON structure representing a cryptographic key. Currently only supports RSA public keys.
445
+
446
+ ```ruby
447
+ jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048))
448
+ payload, headers = { data: 'data' }, { kid: jwk.kid }
449
+
450
+ token = JWT.encode(payload, jwk.keypair, 'RS512', headers)
451
+
452
+ # The jwk loader would fetch the set of JWKs from a trusted source
453
+ jwk_loader = ->(options) do
454
+ @cached_keys = nil if options[:invalidate] # need to reload the keys
455
+ @cached_keys ||= { keys: [jwk.export] }
456
+ end
457
+
458
+ begin
459
+ JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwk_loader})
460
+ rescue JWT::JWKError
461
+ # Handle problems with the provided JWKs
462
+ rescue JWT::DecodeError
463
+ # Handle other decode related issues e.g. no kid in header, no matching public key found etc.
464
+ end
465
+ ```
466
+
434
467
  # Development and Tests
435
468
 
436
469
  We depend on [Bundler](http://rubygems.org/gems/bundler) for defining gemspec and performing releases to rubygems.org, which can be done with
@@ -449,30 +482,8 @@ bundle exec rspec
449
482
 
450
483
  ## Contributors
451
484
 
452
- * Jordan Brough <github.jordanb@xoxy.net>
453
- * Ilya Zhitomirskiy <ilya@joindiaspora.com>
454
- * Daniel Grippi <daniel@joindiaspora.com>
455
- * Jeff Lindsay <progrium@gmail.com>
456
- * Bob Aman <bob@sporkmonger.com>
457
- * Micah Gates <github@mgates.com>
458
- * Rob Wygand <rob@wygand.com>
459
- * Ariel Salomon (Oscil8)
460
- * Paul Battley <pbattley@gmail.com>
461
- * Zane Shannon [@zshannon](https://github.com/zshannon)
462
- * Brian Fletcher [@punkle](https://github.com/punkle)
463
- * Alex [@ZhangHanDong](https://github.com/ZhangHanDong)
464
- * John Downey [@jtdowney](https://github.com/jtdowney)
465
- * Adam Greene [@skippy](https://github.com/skippy)
466
- * Tim Rudat [@excpt](https://github.com/excpt) <timrudat@gmail.com> - Maintainer
485
+ See `AUTHORS` file.
467
486
 
468
487
  ## License
469
488
 
470
- MIT
471
-
472
- Copyright (c) 2011 Jeff Lindsay
473
-
474
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
475
-
476
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
477
-
478
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
489
+ See `LICENSE` file.