diff --git a/.rubocop.yml b/.rubocop.yml index 112054ac..204fa8bf 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -9,33 +9,17 @@ AllCops: Style/Documentation: Enabled: false -Style/BlockDelimiters: - Exclude: - - spec/**/*_spec.rb - -Style/GuardClause: - Enabled: false - Style/IfUnlessModifier: Enabled: false -Style/Lambda: - Enabled: false - -Style/RaiseArgs: - Enabled: false - Metrics/AbcSize: Max: 25 Metrics/ClassLength: - Max: 121 - -Metrics/ModuleLength: - Max: 100 + Max: 112 Metrics/MethodLength: - Max: 20 + Max: 18 Metrics/BlockLength: Exclude: @@ -45,24 +29,5 @@ Metrics/BlockLength: Layout/LineLength: Enabled: false -Layout/EndAlignment: - EnforcedStyleAlignWith: variable - -Layout/EmptyLineBetweenDefs: - Enabled: true - AllowAdjacentOneLineDefs: true - -Style/FormatString: - Enabled: false - -Layout/MultilineMethodCallIndentation: - EnforcedStyle: indented - -Layout/MultilineOperationIndentation: - EnforcedStyle: indented - -Style/WordArray: - Enabled: false - Gemspec/DevelopmentDependencies: EnforcedStyle: gemspec diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b86376..567621bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ **Fixes and enhancements:** - Print deprecation warnings only on when token decoding succeeds [#600](https://github.com/jwt/ruby-jwt/pull/600) ([@anakinj](https://github.com/anakinj)) +- Unify code style [#602](https://github.com/jwt/ruby-jwt/pull/602) ([@anakinj](https://github.com/anakinj)) - Your contribution here ## [v2.8.1](https://github.com/jwt/ruby-jwt/tree/v2.8.1) (2024-02-29) diff --git a/lib/jwt/configuration/jwk_configuration.rb b/lib/jwt/configuration/jwk_configuration.rb index e39ca498..90503961 100644 --- a/lib/jwt/configuration/jwk_configuration.rb +++ b/lib/jwt/configuration/jwk_configuration.rb @@ -18,7 +18,7 @@ def kid_generator_type=(value) JWT::JWK::Thumbprint else raise ArgumentError, "#{value} is not a valid kid generator type." - end + end end attr_accessor :kid_generator diff --git a/lib/jwt/decode.rb b/lib/jwt/decode.rb index 0d56a0ef..aa73e8ab 100644 --- a/lib/jwt/decode.rb +++ b/lib/jwt/decode.rb @@ -10,7 +10,7 @@ module JWT # Decoding logic for JWT class Decode def initialize(jwt, key, verify, options, &keyfinder) - raise(JWT::DecodeError, 'Nil JSON web token') unless jwt + raise JWT::DecodeError, 'Nil JSON web token' unless jwt @jwt = jwt @key = key @@ -30,7 +30,7 @@ def decode_segments verify_signature verify_claims end - raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload + raise JWT::DecodeError, 'Not enough or too many segments' unless header && payload [payload, header] end @@ -46,21 +46,21 @@ def verify_signature return if Array(@key).any? { |key| verify_signature_for?(key) } - raise(JWT::VerificationError, 'Signature verification failed') + raise JWT::VerificationError, 'Signature verification failed' end def verify_algo - raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms.empty? - raise(JWT::IncorrectAlgorithm, 'Token is missing alg header') unless alg_in_header - raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') if allowed_and_valid_algorithms.empty? + raise JWT::IncorrectAlgorithm, 'An algorithm must be specified' if allowed_algorithms.empty? + raise JWT::IncorrectAlgorithm, 'Token is missing alg header' unless alg_in_header + raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' if allowed_and_valid_algorithms.empty? end def set_key @key = find_key(&@keyfinder) if @keyfinder @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(header['kid']) if @options[:jwks] - if (x5c_options = @options[:x5c]) - @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(header['x5c']) - end + return unless (x5c_options = @options[:x5c]) + + @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(header['x5c']) end def verify_signature_for?(key) @@ -122,7 +122,7 @@ def validate_segment_count! return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed return if segment_length == 2 && none_algorithm? - raise(JWT::DecodeError, 'Not enough or too many segments') + raise JWT::DecodeError, 'Not enough or too many segments' end def segment_length diff --git a/lib/jwt/jwk/ec.rb b/lib/jwt/jwk/ec.rb index 32dee96f..41e74831 100644 --- a/lib/jwt/jwk/ec.rb +++ b/lib/jwt/jwk/ec.rb @@ -153,26 +153,26 @@ def create_ec_key(jwk_crv, jwk_x, jwk_y, jwk_d) # rubocop:disable Metrics/Method ) sequence = if jwk_d - # https://datatracker.ietf.org/doc/html/rfc5915.html - # ECPrivateKey ::= SEQUENCE { - # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - # privateKey OCTET STRING, - # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - # publicKey [1] BIT STRING OPTIONAL - # } - - OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(1), - OpenSSL::ASN1::OctetString(OpenSSL::BN.new(decode_octets(jwk_d), 2).to_s(2)), - OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT), - OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT) - ]) - else - OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve)]), - OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed)) - ]) - end + # https://datatracker.ietf.org/doc/html/rfc5915.html + # ECPrivateKey ::= SEQUENCE { + # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + # privateKey OCTET STRING, + # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + # publicKey [1] BIT STRING OPTIONAL + # } + + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(1), + OpenSSL::ASN1::OctetString(OpenSSL::BN.new(decode_octets(jwk_d), 2).to_s(2)), + OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT), + OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT) + ]) + else + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve)]), + OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed)) + ]) + end OpenSSL::PKey::EC.new(sequence.to_der) end diff --git a/lib/jwt/jwk/key_finder.rb b/lib/jwt/jwk/key_finder.rb index b3ccdc0c..fd053416 100644 --- a/lib/jwt/jwk/key_finder.rb +++ b/lib/jwt/jwk/key_finder.rb @@ -8,10 +8,10 @@ def initialize(options) jwks_or_loader = options[:jwks] @jwks_loader = if jwks_or_loader.respond_to?(:call) - jwks_or_loader - else - ->(_options) { jwks_or_loader } - end + jwks_or_loader + else + ->(_options) { jwks_or_loader } + end end def key_for(kid) diff --git a/lib/jwt/jwk/set.rb b/lib/jwt/jwk/set.rb index 0023a626..72e5f663 100644 --- a/lib/jwt/jwk/set.rb +++ b/lib/jwt/jwk/set.rb @@ -25,7 +25,7 @@ def initialize(jwks = nil, options = {}) # rubocop:disable Metrics/CyclomaticCom jwks.map { |k| JWT::JWK.new(k, nil, options) } else raise ArgumentError, 'Can only create new JWKS from Hash, Array and JWK' - end + end end def export(options = {}) diff --git a/lib/jwt/verify.rb b/lib/jwt/verify.rb index 23427386..4bc7635f 100644 --- a/lib/jwt/verify.rb +++ b/lib/jwt/verify.rb @@ -34,19 +34,19 @@ def verify_aud return unless (options_aud = @options[:aud]) aud = @payload['aud'] - raise(JWT::InvalidAudError, "Invalid audience. Expected #{options_aud}, received #{aud || ''}") if ([*aud] & [*options_aud]).empty? + raise JWT::InvalidAudError, "Invalid audience. Expected #{options_aud}, received #{aud || ''}" if ([*aud] & [*options_aud]).empty? end def verify_expiration return unless contains_key?(@payload, 'exp') - raise(JWT::ExpiredSignature, 'Signature has expired') if @payload['exp'].to_i <= (Time.now.to_i - exp_leeway) + raise JWT::ExpiredSignature, 'Signature has expired' if @payload['exp'].to_i <= (Time.now.to_i - exp_leeway) end def verify_iat return unless contains_key?(@payload, 'iat') iat = @payload['iat'] - raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f + raise JWT::InvalidIatError, 'Invalid iat' if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f end def verify_iss @@ -60,7 +60,7 @@ def verify_iss when *options_iss nil else - raise(JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || ''}") + raise JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || ''}" end end @@ -70,29 +70,29 @@ def verify_jti if options_verify_jti.respond_to?(:call) verified = options_verify_jti.arity == 2 ? options_verify_jti.call(jti, @payload) : options_verify_jti.call(jti) - raise(JWT::InvalidJtiError, 'Invalid jti') unless verified + raise JWT::InvalidJtiError, 'Invalid jti' unless verified elsif jti.to_s.strip.empty? - raise(JWT::InvalidJtiError, 'Missing jti') + raise JWT::InvalidJtiError, 'Missing jti' end end def verify_not_before return unless contains_key?(@payload, 'nbf') - raise(JWT::ImmatureSignature, 'Signature nbf has not been reached') if @payload['nbf'].to_i > (Time.now.to_i + nbf_leeway) + raise JWT::ImmatureSignature, 'Signature nbf has not been reached' if @payload['nbf'].to_i > (Time.now.to_i + nbf_leeway) end def verify_sub return unless (options_sub = @options[:sub]) sub = @payload['sub'] - raise(JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || ''}") unless sub.to_s == options_sub.to_s + raise JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || ''}" unless sub.to_s == options_sub.to_s end def verify_required_claims return unless (options_required_claims = @options[:required_claims]) options_required_claims.each do |required_claim| - raise(JWT::MissingRequiredClaim, "Missing required claim #{required_claim}") unless contains_key?(@payload, required_claim) + raise JWT::MissingRequiredClaim, "Missing required claim #{required_claim}" unless contains_key?(@payload, required_claim) end end diff --git a/lib/jwt/x5c_key_finder.rb b/lib/jwt/x5c_key_finder.rb index 29ae2b79..26540855 100644 --- a/lib/jwt/x5c_key_finder.rb +++ b/lib/jwt/x5c_key_finder.rb @@ -7,7 +7,7 @@ module JWT # See https://tools.ietf.org/html/rfc7515#section-4.1.6 class X5cKeyFinder def initialize(root_certificates, crls = nil) - raise(ArgumentError, 'Root certificates must be specified') unless root_certificates + raise ArgumentError, 'Root certificates must be specified' unless root_certificates @store = build_store(root_certificates, crls) end @@ -24,7 +24,7 @@ def from(x5c_header_or_certificates) error = "#{error} Certificate subject: #{current_cert.subject}." end - raise(JWT::VerificationError, error) + raise JWT::VerificationError, error end end diff --git a/spec/integration/readme_examples_spec.rb b/spec/integration/readme_examples_spec.rb index fcf1f369..725f9d73 100644 --- a/spec/integration/readme_examples_spec.rb +++ b/spec/integration/readme_examples_spec.rb @@ -308,7 +308,7 @@ # The jwk loader would fetch the set of JWKs from a trusted source, # to avoid malicious invalidations some kind of protection needs to be implemented. # This example only allows cache invalidations every 5 minutes. - jwk_loader = ->(options) do + jwk_loader = lambda do |options| if options[:kid_not_found] && @cache_last_update < Time.now.to_i - 300 logger.info("Invalidating JWK cache. #{options[:kid]} not found from previous cache") @cached_keys = nil @@ -352,7 +352,7 @@ token = JWT.encode(payload, jwk.signing_key, 'RS512', headers) - jwks_loader = ->(options) do + jwks_loader = lambda do |options| # The jwk loader would fetch the set of JWKs from a trusted source. # To avoid malicious requests triggering cache invalidations there needs to be # some kind of grace time or other logic for determining the validity of the invalidation. diff --git a/spec/jwt/jwk/decode_with_jwk_spec.rb b/spec/jwt/jwk/decode_with_jwk_spec.rb index bb4d68ae..d55ff64b 100644 --- a/spec/jwt/jwk/decode_with_jwk_spec.rb +++ b/spec/jwt/jwk/decode_with_jwk_spec.rb @@ -59,7 +59,7 @@ context 'when jwk keys are loaded using a proc/lambda' do it 'decodes the token' do - payload, _header = described_class.decode(signed_token, nil, true, { algorithms: [algorithm], jwks: lambda { |_opts| public_jwks } }) + payload, _header = described_class.decode(signed_token, nil, true, { algorithms: [algorithm], jwks: ->(_opts) { public_jwks } }) expect(payload).to eq(token_payload) end end diff --git a/spec/jwt/jwk/ec_spec.rb b/spec/jwt/jwk/ec_spec.rb index cc95f627..27acda24 100644 --- a/spec/jwt/jwk/ec_spec.rb +++ b/spec/jwt/jwk/ec_spec.rb @@ -93,7 +93,7 @@ let(:include_private) { false } let(:exported_key) { described_class.new(keypair).export(include_private: include_private) } - ['P-256', 'P-384', 'P-521', 'P-256K'].each do |crv| + %w[P-256 P-384 P-521 P-256K].each do |crv| context "when crv=#{crv}" do let(:openssl_curve) { JWT::JWK::EC.to_openssl_curve(crv) } let(:ec_key) { OpenSSL::PKey::EC.generate(openssl_curve) } @@ -116,9 +116,9 @@ end context 'with a custom "kid" value' do - let(:exported_key) { + let(:exported_key) do super().merge(kid: 'custom_key_identifier') - } + end it 'imports that "kid" value' do expect(subject.kid).to eq('custom_key_identifier') end diff --git a/spec/jwt/jwk/hmac_spec.rb b/spec/jwt/jwk/hmac_spec.rb index a31b5498..b64e5c3a 100644 --- a/spec/jwt/jwk/hmac_spec.rb +++ b/spec/jwt/jwk/hmac_spec.rb @@ -56,18 +56,18 @@ end context 'with a custom "kid" value' do - let(:exported_key) { + let(:exported_key) do super().merge(kid: 'custom_key_identifier') - } + end it 'imports that "kid" value' do expect(subject.kid).to eq('custom_key_identifier') end end context 'with a common parameter' do - let(:exported_key) { + let(:exported_key) do super().merge(use: 'sig') - } + end it 'imports that common parameter' do expect(subject[:use]).to eq('sig') end diff --git a/spec/jwt/jwk/thumbprint_spec.rb b/spec/jwt/jwk/thumbprint_spec.rb index 665877c4..174c9fce 100644 --- a/spec/jwt/jwk/thumbprint_spec.rb +++ b/spec/jwt/jwk/thumbprint_spec.rb @@ -8,7 +8,7 @@ subject(:thumbprint) { described_class.new(jwk).to_s } context 'when example from RFC is given' do - let(:jwk_json) { + let(:jwk_json) do ' { "kty": "RSA", @@ -22,13 +22,13 @@ "alg": "RS256" } ' - } + end it { is_expected.to eq('NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs') } end context 'when HMAC key is given' do - let(:jwk_json) { + let(:jwk_json) do ' { "kty":"oct", @@ -36,7 +36,7 @@ "k":"B4uZ7IbZTnjdCQjUBXTpzMUznCYj3wdYDZcceeU0mLg" } ' - } + end it { is_expected.to eq('wPf4ZF5qlzoFxsGkft4eu1iWcehgAcahZL4XPV4dT-s') } end diff --git a/spec/jwt/jwt_spec.rb b/spec/jwt/jwt_spec.rb index 5dcd05b5..cf7da054 100644 --- a/spec/jwt/jwt_spec.rb +++ b/spec/jwt/jwt_spec.rb @@ -379,7 +379,7 @@ it 'should fail if only invalid keys are given' do expect do - JWT.decode(token, ['not_the_secret', 'not_the_secret_2'], true, { algorithm: 'HS256' }) + JWT.decode(token, %w[not_the_secret not_the_secret_2], true, { algorithm: 'HS256' }) end.to raise_error(JWT::VerificationError, 'Signature verification failed') end end @@ -513,11 +513,11 @@ end.to raise_error JWT::IncorrectAlgorithm expect do - JWT.decode token, data[:secret], true, algorithms: ['HS512', 'HS384'] + JWT.decode token, data[:secret], true, algorithms: %w[HS512 HS384] end.not_to raise_error expect do - JWT.decode token, data[:secret], true, 'algorithms' => ['HS512', 'HS384'] + JWT.decode token, data[:secret], true, 'algorithms' => %w[HS512 HS384] end.not_to raise_error end @@ -608,7 +608,7 @@ it 'should not raise InvalidPayload exception if payload is an array' do expect do - JWT.encode(['my', 'payload'], 'secret') + JWT.encode(%w[my payload], 'secret') end.not_to raise_error end @@ -790,7 +790,7 @@ it 'starts trying with the algorithm referred in the header' do expect(JWT::JWA::Rsa).not_to receive(:verify) - JWT.decode(token, 'secret', true, algorithm: ['RS512', 'HS256']) + JWT.decode(token, 'secret', true, algorithm: %w[RS512 HS256]) end end @@ -805,7 +805,7 @@ context 'with issue with ES256 keys' do it 'tries until the first match' do token = JWT.encode(payload, data['ES256_private'], 'ES256', 'iss' => 'ES256') - result = JWT.decode(token, nil, true, algorithm: ['ES256', 'HS256']) do |header, _| + result = JWT.decode(token, nil, true, algorithm: %w[ES256 HS256]) do |header, _| iss_key_mappings[header['iss']] end @@ -814,7 +814,7 @@ it 'tries until the first match' do token = JWT.encode(payload, data['ES256_private_v2'], 'ES256', 'iss' => 'ES256') - result = JWT.decode(token, nil, true, algorithm: ['ES256', 'HS256']) do |header, _| + result = JWT.decode(token, nil, true, algorithm: %w[ES256 HS256]) do |header, _| iss_key_mappings[header['iss']] end @@ -825,7 +825,7 @@ context 'with issue with HS256 keys' do it 'tries until the first match' do token = JWT.encode(payload, data['HS256'], 'HS256', 'iss' => 'HS256') - result = JWT.decode(token, nil, true, algorithm: ['ES256', 'HS256']) do |header, _| + result = JWT.decode(token, nil, true, algorithm: %w[ES256 HS256]) do |header, _| iss_key_mappings[header['iss']] end @@ -947,13 +947,11 @@ def valid_alg?(alg) context 'when invalid token is valid loose base64' do it 'does not output deprecations warnings' do - expect { - begin - JWT.decode("#{JWT.encode('a', 'b')} 9", 'b') - rescue JWT::VerificationError - nil - end - }.not_to output(/DEPRECATION/).to_stderr + expect do + JWT.decode("#{JWT.encode('a', 'b')} 9", 'b') + rescue JWT::VerificationError + nil + end.not_to output(/DEPRECATION/).to_stderr end end @@ -966,14 +964,14 @@ def valid_alg?(alg) context 'when valid token is invalid strict base64 and decoded with the incorrect key' do it 'does not output deprecation warning, even when decoded with the correct key' do token = JWT.encode('payload', 'key') - expect { + expect do begin JWT.decode("#{token} ", 'incorrect') rescue JWT::VerificationError nil end JWT.decode(token, 'key') - }.not_to output(/DEPRECATION/).to_stderr + end.not_to output(/DEPRECATION/).to_stderr end end end diff --git a/spec/jwt/verify_spec.rb b/spec/jwt/verify_spec.rb index f2907000..cb259c05 100644 --- a/spec/jwt/verify_spec.rb +++ b/spec/jwt/verify_spec.rb @@ -246,13 +246,13 @@ def issuer_start_with_ruby?(issuer) it 'it should not throw arguement error with 2 args' do expect do - described_class.verify_jti(payload, options.merge(verify_jti: ->(_jti, _pl) { + described_class.verify_jti(payload, options.merge(verify_jti: lambda { |_jti, _pl| true })) end.to_not raise_error end it 'should have payload as second param in proc' do - described_class.verify_jti(payload, options.merge(verify_jti: ->(_jti, pl) { + described_class.verify_jti(payload, options.merge(verify_jti: lambda { |_jti, pl| expect(pl).to eq(payload) })) end @@ -296,7 +296,7 @@ def issuer_start_with_ruby?(issuer) context '.verify_claims' do let(:fail_verifications_options) { { iss: 'mismatched-issuer', aud: 'no-match', sub: 'some subject' } } - let(:fail_verifications_payload) { + let(:fail_verifications_payload) do { 'exp' => (Time.now.to_i - 50), 'jti' => ' ', @@ -305,7 +305,7 @@ def issuer_start_with_ruby?(issuer) 'iat' => 'not a number', 'sub' => 'not-a-match' } - } + end %w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub].each do |method| let(:payload) { base_payload.merge(fail_verifications_payload) } @@ -330,7 +330,7 @@ def issuer_start_with_ruby?(issuer) it 'must verify the claims if all required claims are present' do payload = base_payload.merge('exp' => (Time.now.to_i + 5), 'custom_claim' => true) - described_class.verify_required_claims(payload, options.merge(required_claims: ['exp', 'custom_claim'])) + described_class.verify_required_claims(payload, options.merge(required_claims: %w[exp custom_claim])) end end end