From bc2c2514b0fce49218c23e63cd57334d90f9bd11 Mon Sep 17 00:00:00 2001 From: Matthew Simpson Date: Mon, 25 Apr 2022 11:49:36 +0100 Subject: [PATCH 1/2] Autocorrect Rubocop errors --- .rubocop_todo.yml | 104 ------------------------------ Appraisals | 2 + Gemfile | 2 + Rakefile | 2 + bin/console.rb | 1 + lib/jwt/algos/ecdsa.rb | 9 ++- lib/jwt/algos/eddsa.rb | 3 + lib/jwt/algos/hmac.rb | 2 + lib/jwt/algos/none.rb | 2 + lib/jwt/algos/ps.rb | 2 + lib/jwt/algos/rsa.rb | 5 +- lib/jwt/algos/unsupported.rb | 2 + lib/jwt/claims_validator.rb | 4 +- lib/jwt/decode.rb | 2 + lib/jwt/default_options.rb | 2 + lib/jwt/encode.rb | 8 +-- lib/jwt/jwk.rb | 1 + lib/jwt/jwk/ec.rb | 2 +- lib/jwt/jwk/hmac.rb | 2 +- lib/jwt/jwk/rsa.rb | 3 +- lib/jwt/security_utils.rb | 2 + lib/jwt/signature.rb | 3 +- lib/jwt/verify.rb | 3 + ruby-jwt.gemspec | 4 +- spec/jwt/claims_validator_spec.rb | 2 +- 25 files changed, 55 insertions(+), 119 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index c1442e11..175b8e6a 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -14,123 +14,19 @@ Gemspec/RequireMFA: Exclude: - 'ruby-jwt.gemspec' -# Offense count: 10 -# Cop supports --auto-correct. -Layout/EmptyLineAfterGuardClause: - Exclude: - - 'lib/jwt/algos/ecdsa.rb' - - 'lib/jwt/algos/eddsa.rb' - - 'lib/jwt/algos/rsa.rb' - - 'lib/jwt/decode.rb' - - 'lib/jwt/jwk.rb' - - 'lib/jwt/jwk/rsa.rb' - - 'lib/jwt/verify.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. -# SupportedHashRocketStyles: key, separator, table -# SupportedColonStyles: key, separator, table -# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit -Layout/HashAlignment: - Exclude: - - 'lib/jwt/algos/ecdsa.rb' - # Offense count: 1 Lint/MissingSuper: Exclude: - 'lib/jwt/jwk/key_base.rb' - # Offense count: 1 # Configuration parameters: IgnoredMethods, CountRepeatedAttributes. Metrics/AbcSize: Max: 25 -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: IgnoredMethods. -# IgnoredMethods: ==, equal?, eql? -Style/ClassEqualityComparison: - Exclude: - - 'lib/jwt/algos/rsa.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/ExpandPathArguments: - Exclude: - - 'ruby-jwt.gemspec' - -# Offense count: 19 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: always, always_true, never -Style/FrozenStringLiteralComment: - Exclude: - - 'Appraisals' - - 'Gemfile' - - 'Rakefile' - - 'bin/console.rb' - - 'lib/jwt/algos/ecdsa.rb' - - 'lib/jwt/algos/eddsa.rb' - - 'lib/jwt/algos/hmac.rb' - - 'lib/jwt/algos/none.rb' - - 'lib/jwt/algos/ps.rb' - - 'lib/jwt/algos/rsa.rb' - - 'lib/jwt/algos/unsupported.rb' - - 'lib/jwt/claims_validator.rb' - - 'lib/jwt/default_options.rb' - - 'lib/jwt/security_utils.rb' - - 'ruby-jwt.gemspec' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/HashTransformKeys: - Exclude: - - 'lib/jwt/claims_validator.rb' - - 'lib/jwt/encode.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, Autocorrect. -# SupportedStyles: module_function, extend_self, forbidden -Style/ModuleFunction: - Exclude: - - 'lib/jwt/signature.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: Strict. -Style/NumericLiterals: - MinDigits: 6 - # Offense count: 1 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - 'lib/jwt.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -Style/RedundantFreeze: - Exclude: - - 'lib/jwt/encode.rb' - - 'lib/jwt/jwk/ec.rb' - - 'lib/jwt/jwk/hmac.rb' - - 'lib/jwt/jwk/rsa.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods. -# AllowedMethods: present?, blank?, presence, try, try! -Style/SafeNavigation: - Exclude: - - 'lib/jwt/encode.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/SlicingWithRange: - Exclude: - - 'lib/jwt/security_utils.rb' - diff --git a/Appraisals b/Appraisals index 4a434504..42cdb5bf 100644 --- a/Appraisals +++ b/Appraisals @@ -1,3 +1,5 @@ +# frozen_string_literal: true + appraise 'standalone' do # No additions end diff --git a/Gemfile b/Gemfile index 976d7a5f..b2efbee8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gemspec diff --git a/Rakefile b/Rakefile index d641df1c..49dc3f72 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'bundler/setup' require 'bundler/gem_tasks' diff --git a/bin/console.rb b/bin/console.rb index e588d4a6..72129a5b 100755 --- a/bin/console.rb +++ b/bin/console.rb @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true require 'bundler/setup' require 'jwt' diff --git a/lib/jwt/algos/ecdsa.rb b/lib/jwt/algos/ecdsa.rb index 4bb4222f..d3b93f70 100644 --- a/lib/jwt/algos/ecdsa.rb +++ b/lib/jwt/algos/ecdsa.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module Ecdsa @@ -5,9 +7,9 @@ module Ecdsa NAMED_CURVES = { 'prime256v1' => 'ES256', - 'secp256r1' => 'ES256', # alias for prime256v1 - 'secp384r1' => 'ES384', - 'secp521r1' => 'ES512' + 'secp256r1' => 'ES256', # alias for prime256v1 + 'secp384r1' => 'ES384', + 'secp521r1' => 'ES512' }.freeze SUPPORTED = NAMED_CURVES.values.uniq.freeze @@ -31,6 +33,7 @@ def verify(to_verify) if algorithm != key_algorithm raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided" end + digest = OpenSSL::Digest.new(curve_definition[:digest]) public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key)) end diff --git a/lib/jwt/algos/eddsa.rb b/lib/jwt/algos/eddsa.rb index ab349bc2..ed4f2e90 100644 --- a/lib/jwt/algos/eddsa.rb +++ b/lib/jwt/algos/eddsa.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module Eddsa @@ -23,6 +25,7 @@ def verify(to_verify) raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided" end raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey" if public_key.class != RbNaCl::Signatures::Ed25519::VerifyKey + public_key.verify(signature, signing_input) end end diff --git a/lib/jwt/algos/hmac.rb b/lib/jwt/algos/hmac.rb index 6ed273b8..b298f518 100644 --- a/lib/jwt/algos/hmac.rb +++ b/lib/jwt/algos/hmac.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module Hmac diff --git a/lib/jwt/algos/none.rb b/lib/jwt/algos/none.rb index 17d15f14..7de3733a 100644 --- a/lib/jwt/algos/none.rb +++ b/lib/jwt/algos/none.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module None diff --git a/lib/jwt/algos/ps.rb b/lib/jwt/algos/ps.rb index 554aff7b..20d182c0 100644 --- a/lib/jwt/algos/ps.rb +++ b/lib/jwt/algos/ps.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module Ps diff --git a/lib/jwt/algos/rsa.rb b/lib/jwt/algos/rsa.rb index c6621bc7..252c8f88 100644 --- a/lib/jwt/algos/rsa.rb +++ b/lib/jwt/algos/rsa.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module Rsa @@ -7,7 +9,8 @@ module Rsa def sign(to_sign) algorithm, msg, key = to_sign.values - raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.class == String + raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.instance_of?(String) + key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg) end diff --git a/lib/jwt/algos/unsupported.rb b/lib/jwt/algos/unsupported.rb index 179a262e..f5e38341 100644 --- a/lib/jwt/algos/unsupported.rb +++ b/lib/jwt/algos/unsupported.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module Algos module Unsupported diff --git a/lib/jwt/claims_validator.rb b/lib/jwt/claims_validator.rb index 27030c99..f84fcb3c 100644 --- a/lib/jwt/claims_validator.rb +++ b/lib/jwt/claims_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative './error' module JWT @@ -9,7 +11,7 @@ class ClaimsValidator ].freeze def initialize(payload) - @payload = payload.each_with_object({}) { |(k, v), h| h[k.to_sym] = v } + @payload = payload.transform_keys(&:to_sym) end def validate! diff --git a/lib/jwt/decode.rb b/lib/jwt/decode.rb index 5a288bfc..fa4c03f7 100644 --- a/lib/jwt/decode.rb +++ b/lib/jwt/decode.rb @@ -11,6 +11,7 @@ module JWT class Decode def initialize(jwt, key, verify, options, &keyfinder) raise(JWT::DecodeError, 'Nil JSON web token') unless jwt + @jwt = jwt @key = key @options = options @@ -30,6 +31,7 @@ def decode_segments verify_claims end raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload + [payload, header] end diff --git a/lib/jwt/default_options.rb b/lib/jwt/default_options.rb index fc02c70f..b24b8514 100644 --- a/lib/jwt/default_options.rb +++ b/lib/jwt/default_options.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT module DefaultOptions DEFAULT_OPTIONS = { diff --git a/lib/jwt/encode.rb b/lib/jwt/encode.rb index f5bca389..e761ec3e 100644 --- a/lib/jwt/encode.rb +++ b/lib/jwt/encode.rb @@ -7,14 +7,14 @@ module JWT # Encoding logic for JWT class Encode - ALG_NONE = 'none'.freeze - ALG_KEY = 'alg'.freeze + ALG_NONE = 'none' + ALG_KEY = 'alg' def initialize(options) @payload = options[:payload] @key = options[:key] _, @algorithm = Algos.find(options[:algorithm]) - @headers = options[:headers].each_with_object({}) { |(key, value), headers| headers[key.to_s] = value } + @headers = options[:headers].transform_keys(&:to_s) end def segments @@ -45,7 +45,7 @@ def encode_header end def encode_payload - if @payload && @payload.is_a?(Hash) + if @payload.is_a?(Hash) ClaimsValidator.new(@payload).validate! end diff --git a/lib/jwt/jwk.rb b/lib/jwt/jwk.rb index 0c1a9cab..1db2060e 100644 --- a/lib/jwt/jwk.rb +++ b/lib/jwt/jwk.rb @@ -36,6 +36,7 @@ def mappings def generate_mappings classes.each_with_object({}) do |klass, hash| next unless klass.const_defined?('KTYS') + Array(klass::KTYS).each do |kty| hash[kty] = klass end diff --git a/lib/jwt/jwk/ec.rb b/lib/jwt/jwk/ec.rb index e3634810..ef5dfe60 100644 --- a/lib/jwt/jwk/ec.rb +++ b/lib/jwt/jwk/ec.rb @@ -8,7 +8,7 @@ class EC < KeyBase extend Forwardable def_delegators :@keypair, :public_key - KTY = 'EC'.freeze + KTY = 'EC' KTYS = [KTY, OpenSSL::PKey::EC].freeze BINARY = 2 diff --git a/lib/jwt/jwk/hmac.rb b/lib/jwt/jwk/hmac.rb index 61839e97..c30db73f 100644 --- a/lib/jwt/jwk/hmac.rb +++ b/lib/jwt/jwk/hmac.rb @@ -3,7 +3,7 @@ module JWT module JWK class HMAC < KeyBase - KTY = 'oct'.freeze + KTY = 'oct' KTYS = [KTY, String].freeze def initialize(keypair, kid = nil) diff --git a/lib/jwt/jwk/rsa.rb b/lib/jwt/jwk/rsa.rb index 78215503..a6fa79a0 100644 --- a/lib/jwt/jwk/rsa.rb +++ b/lib/jwt/jwk/rsa.rb @@ -4,12 +4,13 @@ module JWT module JWK class RSA < KeyBase BINARY = 2 - KTY = 'RSA'.freeze + KTY = 'RSA' KTYS = [KTY, OpenSSL::PKey::RSA].freeze RSA_KEY_ELEMENTS = %i[n e d p q dp dq qi].freeze def initialize(keypair, kid = nil) raise ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA' unless keypair.is_a?(OpenSSL::PKey::RSA) + super(keypair, kid || generate_kid(keypair.public_key)) end diff --git a/lib/jwt/security_utils.rb b/lib/jwt/security_utils.rb index b95dbe81..274239c4 100644 --- a/lib/jwt/security_utils.rb +++ b/lib/jwt/security_utils.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JWT # Collection of security methods # diff --git a/lib/jwt/signature.rb b/lib/jwt/signature.rb index 5dcb3489..e46a5f8f 100644 --- a/lib/jwt/signature.rb +++ b/lib/jwt/signature.rb @@ -13,7 +13,8 @@ module JWT # Signature logic for JWT module Signature - extend self + module_function + ToSign = Struct.new(:algorithm, :msg, :key) ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature) diff --git a/lib/jwt/verify.rb b/lib/jwt/verify.rb index c5ba0a10..4ca36b78 100644 --- a/lib/jwt/verify.rb +++ b/lib/jwt/verify.rb @@ -19,6 +19,7 @@ class << self def verify_claims(payload, options) options.each do |key, val| next unless key.to_s =~ /verify/ + Verify.send(key, payload, options) if val end end @@ -82,12 +83,14 @@ def verify_not_before 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 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 @payload.include?(required_claim) end diff --git a/ruby-jwt.gemspec b/ruby-jwt.gemspec index 0cdc99a2..9595f275 100644 --- a/ruby-jwt.gemspec +++ b/ruby-jwt.gemspec @@ -1,4 +1,6 @@ -lib = File.expand_path('../lib/', __FILE__) +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'jwt/version' diff --git a/spec/jwt/claims_validator_spec.rb b/spec/jwt/claims_validator_spec.rb index e2908879..be24bc89 100644 --- a/spec/jwt/claims_validator_spec.rb +++ b/spec/jwt/claims_validator_spec.rb @@ -8,7 +8,7 @@ shared_examples_for 'a NumericDate claim' do |claim| context "when #{claim} payload is an integer" do - let(:claims) { { claim => 12345 } } + let(:claims) { { claim => 12_345 } } it 'does not raise error' do expect { subject }.not_to raise_error From aa6890b839c5ef0b0a6be21c4625acebe1f37a51 Mon Sep 17 00:00:00 2001 From: Matthew Simpson Date: Mon, 25 Apr 2022 12:09:37 +0100 Subject: [PATCH 2/2] Add missing super --- .rubocop_todo.yml | 10 ---------- lib/jwt/jwk/key_base.rb | 1 + 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 175b8e6a..9f1e7f37 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -14,16 +14,6 @@ Gemspec/RequireMFA: Exclude: - 'ruby-jwt.gemspec' -# Offense count: 1 -Lint/MissingSuper: - Exclude: - - 'lib/jwt/jwk/key_base.rb' - -# Offense count: 1 -# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. -Metrics/AbcSize: - Max: 25 - # Offense count: 1 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? diff --git a/lib/jwt/jwk/key_base.rb b/lib/jwt/jwk/key_base.rb index 46619a79..00e29d7f 100644 --- a/lib/jwt/jwk/key_base.rb +++ b/lib/jwt/jwk/key_base.rb @@ -11,6 +11,7 @@ def initialize(keypair, kid = nil) end def self.inherited(klass) + super ::JWT::JWK.classes << klass end end