diff --git a/.codeclimate.yml b/.codeclimate.yml index f7ecb6cf..2544930f 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -5,4 +5,4 @@ plugins: enabled: true rubocop: enabled: true - channel: rubocop-1-31-0 + channel: rubocop-1-56-3 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..b25c7fee --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,10 @@ + +### Description + +This Pull Request changes/fixes this thing + +### Checklist + +Before the PR can be merged be sure the following are checked: +* [ ] There are tests for the fix or feature added/changed +* [ ] A description of the changes and a reference to the PR has been added to CHANGELOG.md. More details in the [CONTRIBUTING.md](https://github.com/jwt/ruby-jwt/blob/main/CONTRIBUTING.md) diff --git a/.rubocop.yml b/.rubocop.yml index 45648764..7d3e95ee 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -63,3 +63,6 @@ Layout/MultilineOperationIndentation: Style/WordArray: Enabled: false + +Gemspec/DevelopmentDependencies: + EnforcedStyle: gemspec diff --git a/.simplecov b/.simplecov index e3e3dee1..4af4eb6a 100644 --- a/.simplecov +++ b/.simplecov @@ -6,7 +6,7 @@ require 'simplecov_json_formatter' SimpleCov.start do command_name "Job #{File.basename(ENV['BUNDLE_GEMFILE'])}" if ENV['BUNDLE_GEMFILE'] project_name 'Ruby JWT - Ruby JSON Web Token implementation' - coverage_dir "coverage-#{::OpenSSL::Digest::SHA256.hexdigest(ENV['GITHUB_STEP_SUMMARY'])}" if ENV['GITHUB_STEP_SUMMARY'] + coverage_dir "coverage-#{OpenSSL::Digest::SHA256.hexdigest(ENV['GITHUB_STEP_SUMMARY'])}" if ENV['GITHUB_STEP_SUMMARY'] add_filter 'spec' end diff --git a/Appraisals b/Appraisals index bbd89a10..528d261e 100644 --- a/Appraisals +++ b/Appraisals @@ -1,13 +1,15 @@ # frozen_string_literal: true appraise 'standalone' do - # No additions + remove_gem 'rubocop' end appraise 'openssl' do gem 'openssl', '~> 2.1' + remove_gem 'rubocop' end appraise 'rbnacl' do gem 'rbnacl', '>= 6' + remove_gem 'rubocop' end diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bf5fa89..c9b8e082 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,20 @@ - Algorithms moved under the `::JWT::JWA` module ([@anakinj](https://github.com/anakinj)) - Your contribution here +## [v2.7.2](https://github.com/jwt/ruby-jwt/tree/v2.7.2) (NEXT) + +[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.1...v2.7.2) + +**Features:** + +- Updated rubocop to 1.56 [#573](https://github.com/jwt/ruby-jwt/pull/573) - [@anakinj](https://github.com/anakinj). +- Your contribution here + +**Fixes and enhancements:** + +- Fix signature has expired error if payload is a string [#555](https://github.com/jwt/ruby-jwt/pull/555) - [@GobinathAL](https://github.com/GobinathAL). +- Your contribution here + ## [v2.7.1](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2023-06-09) [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.0...v2.8.0) diff --git a/Gemfile b/Gemfile index 9acd6388..ca1ebb64 100644 --- a/Gemfile +++ b/Gemfile @@ -4,4 +4,4 @@ source 'https://rubygems.org' gemspec -gem 'rubocop', '< 1.32' # Keep .codeclimate.yml channel in sync with this one +gem 'rubocop', '~> 1.56.3' # Keep .codeclimate.yml channel in sync with this one diff --git a/bin/smoke.rb b/bin/smoke.rb index 84e61c8f..588c6b6a 100755 --- a/bin/smoke.rb +++ b/bin/smoke.rb @@ -3,7 +3,7 @@ require 'jwt' -puts "Running simple encode/decode test for #{::JWT.gem_version}" +puts "Running simple encode/decode test for #{JWT.gem_version}" secret = 'secretkeyforsigning' -token = ::JWT.encode({ con: 'tent' }, secret, 'HS256') -::JWT.decode(token, secret, true, algorithm: 'HS256') +token = JWT.encode({ con: 'tent' }, secret, 'HS256') +JWT.decode(token, secret, true, algorithm: 'HS256') diff --git a/gemfiles/openssl.gemfile b/gemfiles/openssl.gemfile index 7c42dd1a..94ce8660 100644 --- a/gemfiles/openssl.gemfile +++ b/gemfiles/openssl.gemfile @@ -2,7 +2,6 @@ source "https://rubygems.org" -gem "rubocop", "< 1.32" gem "openssl", "~> 2.1" gemspec path: "../" diff --git a/gemfiles/rbnacl.gemfile b/gemfiles/rbnacl.gemfile index 0e142ffd..ce73f33d 100644 --- a/gemfiles/rbnacl.gemfile +++ b/gemfiles/rbnacl.gemfile @@ -2,7 +2,6 @@ source "https://rubygems.org" -gem "rubocop", "< 1.32" gem "rbnacl", ">= 6" gemspec path: "../" diff --git a/gemfiles/standalone.gemfile b/gemfiles/standalone.gemfile index 835aeb21..095e6608 100644 --- a/gemfiles/standalone.gemfile +++ b/gemfiles/standalone.gemfile @@ -2,6 +2,4 @@ source "https://rubygems.org" -gem "rubocop", "< 1.32" - gemspec path: "../" diff --git a/lib/jwt/jwk.rb b/lib/jwt/jwk.rb index d8d14ae6..f6852bda 100644 --- a/lib/jwt/jwk.rb +++ b/lib/jwt/jwk.rb @@ -52,4 +52,4 @@ def generate_mappings require_relative 'jwk/ec' require_relative 'jwk/rsa' require_relative 'jwk/hmac' -require_relative 'jwk/okp_rbnacl' if ::JWT.rbnacl? +require_relative 'jwk/okp_rbnacl' if JWT.rbnacl? diff --git a/lib/jwt/version.rb b/lib/jwt/version.rb index eefd44d6..3c6ae616 100644 --- a/lib/jwt/version.rb +++ b/lib/jwt/version.rb @@ -21,7 +21,8 @@ module VERSION def self.openssl_3? return false if OpenSSL::OPENSSL_VERSION.include?('LibreSSL') - return true if OpenSSL::OPENSSL_VERSION_NUMBER >= 3 * 0x10000000 + + true if 3 * 0x10000000 <= OpenSSL::OPENSSL_VERSION_NUMBER end def self.rbnacl? diff --git a/ruby-jwt.gemspec b/ruby-jwt.gemspec index d375c0fb..91177b3f 100644 --- a/ruby-jwt.gemspec +++ b/ruby-jwt.gemspec @@ -35,5 +35,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler' spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec' + spec.add_development_dependency 'rubocop' spec.add_development_dependency 'simplecov' end diff --git a/spec/configuration/jwk_configuration_spec.rb b/spec/configuration/jwk_configuration_spec.rb index d89b602a..a0ed7220 100644 --- a/spec/configuration/jwk_configuration_spec.rb +++ b/spec/configuration/jwk_configuration_spec.rb @@ -11,7 +11,7 @@ context 'when valid value is passed' do it 'sets the generator matching the value' do subject.kid_generator_type = :rfc7638_thumbprint - expect(subject.kid_generator).to eq(::JWT::JWK::Thumbprint) + expect(subject.kid_generator).to eq(JWT::JWK::Thumbprint) end end end diff --git a/spec/integration/readme_examples_spec.rb b/spec/integration/readme_examples_spec.rb index 8e917f33..fcf1f369 100644 --- a/spec/integration/readme_examples_spec.rb +++ b/spec/integration/readme_examples_spec.rb @@ -29,7 +29,7 @@ end it 'decodes with HMAC algorithm without secret key' do - pending 'Different behaviour on OpenSSL 3.0 (https://github.com/openssl/openssl/issues/13089)' if ::JWT.openssl_3_hmac_empty_key_regression? + pending 'Different behaviour on OpenSSL 3.0 (https://github.com/openssl/openssl/issues/13089)' if JWT.openssl_3_hmac_empty_key_regression? token = JWT.encode payload, nil, 'HS256' decoded_token = JWT.decode token, nil, false @@ -80,7 +80,7 @@ end end - if ::Gem::Version.new(OpenSSL::VERSION) >= ::Gem::Version.new('2.1') + if Gem::Version.new(OpenSSL::VERSION) >= Gem::Version.new('2.1') it 'RSASSA-PSS' do rsa_private = OpenSSL::PKey::RSA.generate 2048 rsa_public = rsa_private.public_key @@ -414,7 +414,7 @@ end it 'JWK with thumbprint as kid via type' do - JWT.configuration.jwk.kid_generator = ::JWT::JWK::Thumbprint + JWT.configuration.jwk.kid_generator = JWT::JWK::Thumbprint jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048)) @@ -424,7 +424,7 @@ end it 'JWK with thumbprint given in the initializer (legacy)' do - jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), kid_generator: ::JWT::JWK::Thumbprint) + jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), kid_generator: JWT::JWK::Thumbprint) jwk_hash = jwk.export @@ -432,7 +432,7 @@ end it 'JWK with thumbprint given in the initializer' do - jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), nil, kid_generator: ::JWT::JWK::Thumbprint) + jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), nil, kid_generator: JWT::JWK::Thumbprint) jwk_hash = jwk.export @@ -460,8 +460,8 @@ def self.verify(data:, signature:, verification_key:) end end - token = ::JWT.encode({ 'pay' => 'load' }, 'secret', custom_hs512_alg) - _payload, _header = ::JWT.decode(token, 'secret', true, algorithm: custom_hs512_alg) + token = JWT.encode({ 'pay' => 'load' }, 'secret', custom_hs512_alg) + _payload, _header = JWT.decode(token, 'secret', true, algorithm: custom_hs512_alg) end end end diff --git a/spec/jwk/decode_with_jwk_spec.rb b/spec/jwk/decode_with_jwk_spec.rb index 686d224b..fc65d615 100644 --- a/spec/jwk/decode_with_jwk_spec.rb +++ b/spec/jwk/decode_with_jwk_spec.rb @@ -166,7 +166,7 @@ if defined?(RbNaCl) context 'when OKP keys are used' do before do - skip('Requires the rbnacl gem') unless ::JWT.rbnacl? + skip('Requires the rbnacl gem') unless JWT.rbnacl? end let(:keypair) { RbNaCl::Signatures::Ed25519::SigningKey.new(SecureRandom.hex) } diff --git a/spec/jwk/okp_rbnacl_spec.rb b/spec/jwk/okp_rbnacl_spec.rb index 08bd9ef7..48f50342 100644 --- a/spec/jwk/okp_rbnacl_spec.rb +++ b/spec/jwk/okp_rbnacl_spec.rb @@ -11,7 +11,7 @@ subject(:instance) { described_class.new(key) } before do - skip('Requires the rbnacl gem') unless ::JWT.rbnacl? + skip('Requires the rbnacl gem') unless JWT.rbnacl? end describe '.new' do diff --git a/spec/jwk/rsa_spec.rb b/spec/jwk/rsa_spec.rb index 234e3458..9f5d8323 100644 --- a/spec/jwk/rsa_spec.rb +++ b/spec/jwk/rsa_spec.rb @@ -152,7 +152,7 @@ let(:jwk_parameters) { all_jwk_parameters.slice(:e, :n) } it 'creates a valid RSA object representing a public key' do - expect(subject).to be_a(::OpenSSL::PKey::RSA) + expect(subject).to be_a(OpenSSL::PKey::RSA) expect(subject.private?).to eq(false) end end @@ -169,7 +169,7 @@ let(:jwk_parameters) { all_jwk_parameters.slice(:n, :e, :d, :p, :q, :dp, :dq, :qi) } it 'creates a valid RSA object representing a public key' do - expect(subject).to be_a(::OpenSSL::PKey::RSA) + expect(subject).to be_a(OpenSSL::PKey::RSA) expect(subject.private?).to eq(true) end end @@ -180,11 +180,11 @@ let(:jwk_parameters) { all_jwk_parameters.slice(:e, :n, :d) } before do - skip 'OpenSSL prior to 2.2 does not seem to support partial parameters' if ::JWT.openssl_version < ::Gem::Version.new('2.2') + skip 'OpenSSL prior to 2.2 does not seem to support partial parameters' if JWT.openssl_version < Gem::Version.new('2.2') end it 'creates a valid RSA object representing a private key' do - expect(subject).to be_a(::OpenSSL::PKey::RSA) + expect(subject).to be_a(OpenSSL::PKey::RSA) expect(subject.private?).to eq(true) end @@ -217,7 +217,7 @@ describe '.create_rsa_key_using_sets' do before do skip 'OpenSSL without the RSA#set_key method not supported' unless OpenSSL::PKey::RSA.new.respond_to?(:set_key) - skip 'OpenSSL 3.0 does not allow mutating objects anymore' if ::JWT.openssl_3? + skip 'OpenSSL 3.0 does not allow mutating objects anymore' if JWT.openssl_3? end subject(:rsa) { described_class.create_rsa_key_using_sets(rsa_parameters) } diff --git a/spec/jwk_spec.rb b/spec/jwk_spec.rb index 79ba8a2d..8945e685 100644 --- a/spec/jwk_spec.rb +++ b/spec/jwk_spec.rb @@ -12,14 +12,14 @@ subject { described_class.import(params) } it 'creates a ::JWT::JWK::RSA instance' do - expect(subject).to be_a ::JWT::JWK::RSA + expect(subject).to be_a JWT::JWK::RSA expect(subject.export).to eq(exported_key) end context 'parsed from JSON' do let(:params) { exported_key } it 'creates a ::JWT::JWK::RSA instance from JSON parsed JWK' do - expect(subject).to be_a ::JWT::JWK::RSA + expect(subject).to be_a JWT::JWK::RSA expect(subject.export).to eq(exported_key) end end @@ -53,17 +53,17 @@ context 'when RSA key is given' do let(:keypair) { rsa_key } - it { is_expected.to be_a ::JWT::JWK::RSA } + it { is_expected.to be_a JWT::JWK::RSA } end context 'when secret key is given' do let(:keypair) { 'secret-key' } - it { is_expected.to be_a ::JWT::JWK::HMAC } + it { is_expected.to be_a JWT::JWK::HMAC } end context 'when EC key is given' do let(:keypair) { ec_key } - it { is_expected.to be_a ::JWT::JWK::EC } + it { is_expected.to be_a JWT::JWK::EC } end context 'when kid is given' do diff --git a/spec/jwt/configuration_spec.rb b/spec/jwt/configuration_spec.rb index 22a3359a..39d09e21 100644 --- a/spec/jwt/configuration_spec.rb +++ b/spec/jwt/configuration_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe ::JWT do +RSpec.describe JWT do describe 'JWT.configure' do it 'yields the configuration' do expect { |b| described_class.configure(&b) }.to yield_with_args(described_class.configuration) diff --git a/spec/jwt/jwa/ecdsa_spec.rb b/spec/jwt/jwa/ecdsa_spec.rb index f1799e6b..32d1bfd4 100644 --- a/spec/jwt/jwa/ecdsa_spec.rb +++ b/spec/jwt/jwa/ecdsa_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe ::JWT::JWA::Ecdsa do +RSpec.describe JWT::Algos::Ecdsa do describe '.curve_by_name' do subject { described_class.curve_by_name(curve_name) } diff --git a/spec/jwt/jwa/hmac_spec.rb b/spec/jwt/jwa/hmac_spec.rb index 9fbd2b72..84bc6734 100644 --- a/spec/jwt/jwa/hmac_spec.rb +++ b/spec/jwt/jwa/hmac_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe ::JWT::JWA::Hmac do +RSpec.describe JWT::JWA::Hmac do describe '.sign' do subject { described_class.sign('HS256', 'test', hmac_secret) } diff --git a/spec/jwt_spec.rb b/spec/jwt_spec.rb index 2185d3ea..cfd1b65b 100644 --- a/spec/jwt_spec.rb +++ b/spec/jwt_spec.rb @@ -38,7 +38,7 @@ 'PS512' => '' } - if ::JWT.rbnacl? + if JWT.rbnacl? ed25519_private = RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF') ed25519_public = ed25519_private.verify_key data.merge!( @@ -267,7 +267,7 @@ end end - if ::Gem::Version.new(OpenSSL::VERSION) >= ::Gem::Version.new('2.1') + if Gem::Version.new(OpenSSL::VERSION) >= Gem::Version.new('2.1') %w[PS256 PS384 PS512].each do |alg| context "alg: #{alg}" do before(:each) do @@ -621,7 +621,7 @@ context 'when the alg value is given as a header parameter' do it 'does not override the actual algorithm used' do pending 'Breaking change in 3.0' - headers = ::JSON.parse(Base64.urlsafe_decode64(JWT.encode('Hello World', 'secret', 'HS256', { alg: 'HS123' }).split('.').first)) + headers = JSON.parse(JWT::Base64.url_decode(JWT.encode('Hello World', 'secret', 'HS256', { alg: 'HS123' }).split('.').first)) expect(headers['alg']).to eq('HS256') end @@ -632,7 +632,7 @@ context 'when hmac algorithm is used without secret key' do it 'encodes payload' do - pending 'Different behaviour on OpenSSL 3.0 (https://github.com/openssl/openssl/issues/13089)' if ::JWT.openssl_3_hmac_empty_key_regression? + pending 'Different behaviour on OpenSSL 3.0 (https://github.com/openssl/openssl/issues/13089)' if JWT.openssl_3_hmac_empty_key_regression? payload = { a: 1, b: 'b' } token = JWT.encode(payload, '', 'HS256') @@ -667,9 +667,9 @@ describe '::JWT.decode with verify_iat parameter' do let!(:time_now) { Time.now } - let(:token) { ::JWT.encode({ pay: 'load', iat: iat }, 'secret', 'HS256') } + let(:token) { JWT.encode({ pay: 'load', iat: iat }, 'secret', 'HS256') } - subject(:decoded_token) { ::JWT.decode(token, 'secret', true, verify_iat: true) } + subject(:decoded_token) { JWT.decode(token, 'secret', true, verify_iat: true) } before { allow(Time).to receive(:now) { time_now } } @@ -690,7 +690,7 @@ context 'when iat is 1 second before Time.now' do let(:iat) { time_now.to_i + 1 } it 'raises an error' do - expect { decoded_token }.to raise_error(::JWT::InvalidIatError, 'Invalid iat') + expect { decoded_token }.to raise_error(JWT::InvalidIatError, 'Invalid iat') end end end @@ -792,7 +792,7 @@ let(:key_finder) { instance_double('::JWT::X5cKeyFinder') } before do - expect(::JWT::X5cKeyFinder).to receive(:new).with(root_certificates, nil).and_return(key_finder) + expect(JWT::X5cKeyFinder).to receive(:new).with(root_certificates, nil).and_return(key_finder) expect(key_finder).to receive(:from).and_return(data[:rsa_public]) end @@ -832,23 +832,38 @@ end describe 'when none token is and decoding without key and with verification' do - let(:none_token) { ::JWT.encode(payload, nil, 'none') } + let(:none_token) { JWT.encode(payload, nil, 'none') } it 'decodes the token' do - expect(::JWT.decode(none_token, nil, true, algorithms: 'none')).to eq([payload, { 'alg' => 'none' }]) + expect(JWT.decode(none_token, nil, true, algorithms: 'none')).to eq([payload, { 'alg' => 'none' }]) end end describe 'when none token is decoded with a key given' do - let(:none_token) { ::JWT.encode(payload, nil, 'none') } + let(:none_token) { JWT.encode(payload, nil, 'none') } it 'decodes the token' do - expect(::JWT.decode(none_token, 'key', true, algorithms: 'none')).to eq([payload, { 'alg' => 'none' }]) + expect(JWT.decode(none_token, 'key', true, algorithms: 'none')).to eq([payload, { 'alg' => 'none' }]) end end describe 'when none token is decoded without verify' do - let(:none_token) { ::JWT.encode(payload, nil, 'none') } + let(:none_token) { JWT.encode(payload, nil, 'none') } it 'decodes the token' do - expect(::JWT.decode(none_token, 'key', false)).to eq([payload, { 'alg' => 'none' }]) + expect(JWT.decode(none_token, 'key', false)).to eq([payload, { 'alg' => 'none' }]) + end + end + + describe 'when token signed with nil and decoded with nil' do + let(:no_key_token) { JWT.encode(payload, nil, 'HS512') } + it 'raises JWT::DecodeError' do + pending 'Different behaviour on OpenSSL 3.0 (https://github.com/openssl/openssl/issues/13089)' if JWT.openssl_3_hmac_empty_key_regression? + expect { JWT.decode(no_key_token, nil, true, algorithms: 'HS512') }.to raise_error(JWT::DecodeError, 'No verification key available') + end + end + + context 'when token ends with a newline char' do + let(:token) { "#{JWT.encode(payload, 'secret', 'HS256')}\n" } + it 'ignores the newline and decodes the token' do + expect(JWT.decode(token, 'secret', true, algorithm: 'HS256')).to include(payload) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f29c496b..d4ec8deb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,7 +14,7 @@ config.expect_with :rspec do |c| c.syntax = :expect end - config.before(:example) { ::JWT.configuration.reset! } + config.before(:example) { JWT.configuration.reset! } config.run_all_when_everything_filtered = true config.filter_run :focus config.order = 'random'