jwt 2.5.0 → 2.7.1

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.
@@ -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
 
@@ -50,3 +52,4 @@ require_relative 'jwk/key_base'
50
52
  require_relative 'jwk/ec'
51
53
  require_relative 'jwk/rsa'
52
54
  require_relative 'jwk/hmac'
55
+ require_relative 'jwk/okp_rbnacl' if ::JWT.rbnacl?
data/lib/jwt/version.rb CHANGED
@@ -11,9 +11,9 @@ module JWT
11
11
  # major version
12
12
  MAJOR = 2
13
13
  # minor version
14
- MINOR = 5
14
+ MINOR = 7
15
15
  # tiny version
16
- TINY = 0
16
+ TINY = 1
17
17
  # alpha, beta, etc. tag
18
18
  PRE = nil
19
19
 
@@ -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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Rudat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-25 00:00:00.000000000 Z
11
+ date: 2023-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: reek
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: rspec
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -101,28 +87,20 @@ executables: []
101
87
  extensions: []
102
88
  extra_rdoc_files: []
103
89
  files:
104
- - ".codeclimate.yml"
105
- - ".github/workflows/coverage.yml"
106
- - ".github/workflows/test.yml"
107
- - ".gitignore"
108
- - ".reek.yml"
109
- - ".rspec"
110
- - ".rubocop.yml"
111
- - ".sourcelevel.yml"
112
90
  - AUTHORS
113
- - Appraisals
114
91
  - CHANGELOG.md
115
92
  - CODE_OF_CONDUCT.md
116
93
  - CONTRIBUTING.md
117
- - Gemfile
118
94
  - LICENSE
119
95
  - README.md
120
- - Rakefile
121
96
  - lib/jwt.rb
122
97
  - lib/jwt/algos.rb
98
+ - lib/jwt/algos/algo_wrapper.rb
123
99
  - lib/jwt/algos/ecdsa.rb
124
100
  - lib/jwt/algos/eddsa.rb
125
101
  - lib/jwt/algos/hmac.rb
102
+ - lib/jwt/algos/hmac_rbnacl.rb
103
+ - lib/jwt/algos/hmac_rbnacl_fixed.rb
126
104
  - lib/jwt/algos/none.rb
127
105
  - lib/jwt/algos/ps.rb
128
106
  - lib/jwt/algos/rsa.rb
@@ -143,10 +121,10 @@ files:
143
121
  - lib/jwt/jwk/key_base.rb
144
122
  - lib/jwt/jwk/key_finder.rb
145
123
  - lib/jwt/jwk/kid_as_key_digest.rb
124
+ - lib/jwt/jwk/okp_rbnacl.rb
146
125
  - lib/jwt/jwk/rsa.rb
126
+ - lib/jwt/jwk/set.rb
147
127
  - lib/jwt/jwk/thumbprint.rb
148
- - lib/jwt/security_utils.rb
149
- - lib/jwt/signature.rb
150
128
  - lib/jwt/verify.rb
151
129
  - lib/jwt/version.rb
152
130
  - lib/jwt/x5c_key_finder.rb
@@ -156,7 +134,8 @@ licenses:
156
134
  - MIT
157
135
  metadata:
158
136
  bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
159
- changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.5.0/CHANGELOG.md
137
+ changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.7.1/CHANGELOG.md
138
+ rubygems_mfa_required: 'true'
160
139
  post_install_message:
161
140
  rdoc_options: []
162
141
  require_paths:
@@ -172,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
151
  - !ruby/object:Gem::Version
173
152
  version: '0'
174
153
  requirements: []
175
- rubygems_version: 3.3.21
154
+ rubygems_version: 3.3.7
176
155
  signing_key:
177
156
  specification_version: 4
178
157
  summary: JSON Web Token implementation in Ruby
data/.codeclimate.yml DELETED
@@ -1,8 +0,0 @@
1
- plugins:
2
- fixme:
3
- enabled: true
4
- shellcheck:
5
- enabled: true
6
- rubocop:
7
- enabled: true
8
- channel: rubocop-1-23-0
@@ -1,27 +0,0 @@
1
- ---
2
- name: coverage
3
- on:
4
- push:
5
- branches:
6
- - "master"
7
- jobs:
8
- coverage:
9
- name: coverage
10
- runs-on: ubuntu-20.04
11
- env:
12
- BUNDLE_GEMFILE: 'gemfiles/rbnacl.gemfile'
13
- CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
14
- steps:
15
- - uses: actions/checkout@v2
16
- - name: Install libsodium
17
- run: |
18
- sudo apt-get update -q
19
- sudo apt-get install libsodium-dev -y
20
- - name: Set up Ruby
21
- uses: ruby/setup-ruby@v1
22
- with:
23
- ruby-version: "2.7"
24
- bundler-cache: true
25
- - uses: paambaati/codeclimate-action@v3.0.0
26
- with:
27
- coverageCommand: bundle exec rspec
@@ -1,67 +0,0 @@
1
- ---
2
- name: test
3
- on:
4
- push:
5
- branches:
6
- - "*"
7
- pull_request:
8
- branches:
9
- - "*"
10
- jobs:
11
- lint:
12
- name: RuboCop
13
- timeout-minutes: 30
14
- runs-on: ubuntu-latest
15
- steps:
16
- - uses: actions/checkout@v3
17
- - name: Set up Ruby
18
- uses: ruby/setup-ruby@v1
19
- with:
20
- ruby-version: "3.0"
21
- bundler-cache: true
22
- - name: Run RuboCop
23
- run: bundle exec rubocop
24
- test:
25
- name: ${{ matrix.os }} - Ruby ${{ matrix.ruby }}
26
- runs-on: ${{ matrix.os }}
27
- strategy:
28
- fail-fast: false
29
- matrix:
30
- os:
31
- - ubuntu-20.04
32
- ruby:
33
- - "2.5"
34
- - "2.6"
35
- - "2.7"
36
- - "3.0"
37
- - "3.1"
38
- gemfile:
39
- - gemfiles/standalone.gemfile
40
- - gemfiles/openssl.gemfile
41
- - gemfiles/rbnacl.gemfile
42
- experimental: [false]
43
- include:
44
- - { os: ubuntu-20.04, ruby: "2.7", gemfile: 'gemfiles/rbnacl.gemfile', experimental: false }
45
- - { os: ubuntu-22.04, ruby: "3.1", experimental: false }
46
- - { os: ubuntu-20.04, ruby: "truffleruby-head", experimental: true }
47
- - { os: ubuntu-22.04, ruby: "head", experimental: true }
48
- continue-on-error: ${{ matrix.experimental }}
49
- env:
50
- BUNDLE_GEMFILE: ${{ matrix.gemfile }}
51
-
52
- steps:
53
- - uses: actions/checkout@v3
54
-
55
- - name: Install libsodium
56
- run: |
57
- sudo apt-get update -q
58
- sudo apt-get install libsodium-dev -y
59
-
60
- - name: Set up Ruby
61
- uses: ruby/setup-ruby@v1
62
- with:
63
- ruby-version: ${{ matrix.ruby }}
64
- bundler-cache: true
65
-
66
- - name: Run tests
67
- run: bundle exec rspec
data/.gitignore DELETED
@@ -1,13 +0,0 @@
1
- .idea/
2
- jwt.gemspec
3
- pkg
4
- Gemfile.lock
5
- coverage/
6
- .DS_Store
7
- .rbenv-gemsets
8
- .ruby-version
9
- .vscode/
10
- .bundle
11
- *gemfile.lock
12
- .byebug_history
13
- *.gem
data/.reek.yml DELETED
@@ -1,22 +0,0 @@
1
- ---
2
- detectors:
3
- TooManyStatements:
4
- max_statements: 10
5
- UtilityFunction:
6
- enabled: false
7
- LongParameterList:
8
- enabled: false
9
- DuplicateMethodCall:
10
- max_calls: 2
11
- IrresponsibleModule:
12
- enabled: false
13
- NestedIterators:
14
- max_allowed_nesting: 2
15
- UnusedParameters:
16
- enabled: false
17
- FeatureEnvy:
18
- enabled: false
19
- ControlParameter:
20
- enabled: false
21
- UnusedPrivateMethod:
22
- enabled: false
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --require spec_helper
2
- --color
data/.rubocop.yml DELETED
@@ -1,67 +0,0 @@
1
- AllCops:
2
- TargetRubyVersion: 2.5
3
- NewCops: enable
4
- SuggestExtensions: false
5
- Exclude:
6
- - 'gemfiles/*.gemfile'
7
- - 'vendor/**/*'
8
-
9
- Style/Documentation:
10
- Enabled: false
11
-
12
- Style/BlockDelimiters:
13
- Exclude:
14
- - spec/**/*_spec.rb
15
-
16
- Style/GuardClause:
17
- Enabled: false
18
-
19
- Style/IfUnlessModifier:
20
- Enabled: false
21
-
22
- Style/Lambda:
23
- Enabled: false
24
-
25
- Style/RaiseArgs:
26
- Enabled: false
27
-
28
- Metrics/AbcSize:
29
- Max: 25
30
-
31
- Metrics/ClassLength:
32
- Max: 112
33
-
34
- Metrics/ModuleLength:
35
- Max: 100
36
-
37
- Metrics/MethodLength:
38
- Max: 20
39
-
40
- Metrics/BlockLength:
41
- Exclude:
42
- - spec/**/*_spec.rb
43
-
44
- Layout/LineLength:
45
- Enabled: false
46
-
47
- Layout/EndAlignment:
48
- EnforcedStyleAlignWith: variable
49
-
50
- Layout/EmptyLineBetweenDefs:
51
- Enabled: true
52
- AllowAdjacentOneLineDefs: true
53
-
54
- Style/FormatString:
55
- Enabled: false
56
-
57
- Layout/MultilineMethodCallIndentation:
58
- EnforcedStyle: indented
59
-
60
- Layout/MultilineOperationIndentation:
61
- EnforcedStyle: indented
62
-
63
- Style/WordArray:
64
- Enabled: false
65
-
66
- Gemspec/RequireMFA:
67
- Enabled: false
data/.sourcelevel.yml DELETED
@@ -1,17 +0,0 @@
1
- engines:
2
- reek:
3
- enabled: true
4
- fixme:
5
- enabled: true
6
- rubocop:
7
- enabled: true
8
- channel: latest
9
- duplication:
10
- config:
11
- languages:
12
- - ruby
13
- enabled: true
14
- remark-lint:
15
- enabled: false
16
- exclude_paths:
17
- - spec
data/Appraisals DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- appraise 'standalone' do
4
- # No additions
5
- end
6
-
7
- appraise 'openssl' do
8
- gem 'openssl', '~> 2.1'
9
- end
10
-
11
- appraise 'rbnacl' do
12
- gem 'rbnacl'
13
- end
data/Gemfile DELETED
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- gemspec
6
-
7
- gem 'rubocop', '~> 1.23.0' # Keep .codeclimate.yml channel in sync with this one
data/Rakefile DELETED
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/setup'
4
- require 'bundler/gem_tasks'
5
-
6
- begin
7
- require 'rspec/core/rake_task'
8
- require 'rubocop/rake_task'
9
-
10
- RSpec::Core::RakeTask.new(:test)
11
- RuboCop::RakeTask.new(:rubocop)
12
-
13
- task default: %i[rubocop test]
14
- rescue LoadError
15
- puts 'RSpec rake tasks not available. Please run "bundle install" to install missing dependencies.'
16
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- # Collection of security methods
5
- #
6
- # @see: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/security_utils.rb
7
- module SecurityUtils
8
- module_function
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
- def verify_rsa(algorithm, public_key, signing_input, signature)
22
- public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
23
- end
24
-
25
- def verify_ps(algorithm, public_key, signing_input, signature)
26
- formatted_algorithm = algorithm.sub('PS', 'sha')
27
-
28
- public_key.verify_pss(formatted_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: formatted_algorithm)
29
- end
30
-
31
- def asn1_to_raw(signature, public_key)
32
- byte_size = (public_key.group.degree + 7) / 8
33
- OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
34
- end
35
-
36
- def raw_to_asn1(signature, private_key)
37
- byte_size = (private_key.group.degree + 7) / 8
38
- sig_bytes = signature[0..(byte_size - 1)]
39
- sig_char = signature[byte_size..-1] || ''
40
- OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
41
- 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
- end
59
- end
data/lib/jwt/signature.rb DELETED
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'jwt/security_utils'
4
- require 'openssl'
5
- require 'jwt/algos'
6
- begin
7
- require 'rbnacl'
8
- rescue LoadError
9
- raise if defined?(RbNaCl)
10
- end
11
-
12
- # JWT::Signature module
13
- module JWT
14
- # Signature logic for JWT
15
- module Signature
16
- module_function
17
-
18
- ToSign = Struct.new(:algorithm, :msg, :key)
19
- ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature)
20
-
21
- def sign(algorithm, msg, key)
22
- algo, code = Algos.find(algorithm)
23
- algo.sign ToSign.new(code, msg, key)
24
- end
25
-
26
- def verify(algorithm, key, signing_input, signature)
27
- algo, code = Algos.find(algorithm)
28
- algo.verify(ToVerify.new(code, key, signing_input, signature))
29
- rescue OpenSSL::PKey::PKeyError
30
- raise JWT::VerificationError, 'Signature verification raised'
31
- ensure
32
- OpenSSL.errors.clear
33
- end
34
- end
35
- end