From 4de3018297e4c1147bd51f1d002bde006e53a1ae Mon Sep 17 00:00:00 2001 From: Tim Rudat Date: Sat, 17 Sep 2016 23:45:01 +0200 Subject: [PATCH] Fix rubocop code smells --- lib/jwt.rb | 74 +++++++++++++++++++++------------------------- lib/jwt/decode.rb | 5 ++-- lib/jwt/error.rb | 1 + lib/jwt/json.rb | 1 + lib/jwt/verify.rb | 24 +++++++-------- lib/jwt/version.rb | 3 +- 6 files changed, 51 insertions(+), 57 deletions(-) diff --git a/lib/jwt.rb b/lib/jwt.rb index 89ebe165..2e8d006d 100644 --- a/lib/jwt.rb +++ b/lib/jwt.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'base64' require 'openssl' require 'jwt/decode' @@ -17,6 +18,17 @@ module JWT 'secp521r1' => 'ES512' }.freeze + DEFAULT_OPTIONS = { + verify_expiration: true, + verify_not_before: true, + verify_iss: false, + verify_iat: false, + verify_jti: false, + verify_aud: false, + verify_sub: false, + leeway: 0 + }.freeze + module_function def sign(algorithm, msg, key) @@ -73,7 +85,7 @@ def encoded_header(algorithm = 'HS256', header_fields = {}) end def encoded_payload(payload) - raise InvalidPayload, "exp claim must be an integer" if payload['exp'] && payload['exp'].is_a?(Time) + raise InvalidPayload, 'exp claim must be an integer' if payload['exp'] && payload['exp'].is_a?(Time) base64url_encode(encode_json(payload)) end @@ -98,51 +110,19 @@ def encode(payload, key, algorithm = 'HS256', header_fields = {}) def decoded_segments(jwt, key = nil, verify = true, custom_options = {}, &keyfinder) raise(JWT::DecodeError, 'Nil JSON web token') unless jwt - options = { - verify_expiration: true, - verify_not_before: true, - verify_iss: false, - verify_iat: false, - verify_jti: false, - verify_aud: false, - verify_sub: false, - leeway: 0 - } - - merged_options = options.merge(custom_options) + merged_options = DEFAULT_OPTIONS.merge(custom_options) decoder = Decode.new jwt, key, verify, merged_options, &keyfinder decoder.decode_segments end - def decode(jwt, key = nil, verify = true, custom_options = {}, &keyfinder) raise(JWT::DecodeError, 'Nil JSON web token') unless jwt - options = { - verify_expiration: true, - verify_not_before: true, - verify_iss: false, - verify_iat: false, - verify_jti: false, - verify_aud: false, - verify_sub: false, - leeway: 0 - } - - merged_options = options.merge(custom_options) - + merged_options = DEFAULT_OPTIONS.merge(custom_options) decoder = Decode.new jwt, key, verify, merged_options, &keyfinder header, payload, signature, signing_input = decoder.decode_segments - - if verify - algo, key = signature_algorithm_and_key(header, key, &keyfinder) - if merged_options[:algorithm] && algo != merged_options[:algorithm] - raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' - end - verify_signature(algo, key, signing_input, signature) - end - + decode_verify_signature(key, header, signature, signing_input, merged_options, &keyfinder) if verify decoder.verify raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload @@ -150,12 +130,28 @@ def decode(jwt, key = nil, verify = true, custom_options = {}, &keyfinder) [payload, header] end + def decode_verify_signature(key, header, signature, signing_input, options, &keyfinder) + algo, key = signature_algorithm_and_key(header, key, &keyfinder) + if options[:algorithm] && algo != options[:algorithm] + raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' + end + verify_signature(algo, key, signing_input, signature) + end + def signature_algorithm_and_key(header, key, &keyfinder) key = yield(header) if keyfinder [header['alg'], key] end def verify_signature(algo, key, signing_input, signature) + verify_signature_algo(algo, key, signing_input, signature) + rescue OpenSSL::PKey::PKeyError + raise JWT::VerificationError, 'Signature verification raised' + ensure + OpenSSL.errors.clear + end + + def verify_signature_algo(algo, key, signing_input, signature) if %w(HS256 HS384 HS512).include?(algo) raise(JWT::VerificationError, 'Signature verification raised') unless secure_compare(signature, sign_hmac(algo, signing_input, key)) elsif %w(RS256 RS384 RS512).include?(algo) @@ -165,10 +161,6 @@ def verify_signature(algo, key, signing_input, signature) else raise JWT::VerificationError, 'Algorithm not supported' end - rescue OpenSSL::PKey::PKeyError - raise JWT::VerificationError, 'Signature verification raised' - ensure - OpenSSL.errors.clear end # From devise @@ -179,7 +171,7 @@ def secure_compare(a, b) res = 0 b.each_byte { |byte| res |= byte ^ l.shift } - res == 0 + res.zero? end def raw_to_asn1(signature, private_key) diff --git a/lib/jwt/decode.rb b/lib/jwt/decode.rb index ecd221fe..0d814244 100644 --- a/lib/jwt/decode.rb +++ b/lib/jwt/decode.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'jwt/json' require 'jwt/verify' @@ -28,7 +29,7 @@ def decode_segments def raw_segments(jwt, verify) segments = jwt.split('.') required_num_segments = verify ? [3] : [2, 3] - fail(JWT::DecodeError, 'Not enough or too many segments') unless required_num_segments.include? segments.length + raise(JWT::DecodeError, 'Not enough or too many segments') unless required_num_segments.include? segments.length segments end private :raw_segments @@ -47,7 +48,7 @@ def self.base64url_decode(str) def verify @options.each do |key, val| - next unless key.to_s.match(/verify/) + next unless key.to_s =~ /verify/ Verify.send(key, payload, @options) if val end diff --git a/lib/jwt/error.rb b/lib/jwt/error.rb index a1795ea4..2251a5f0 100644 --- a/lib/jwt/error.rb +++ b/lib/jwt/error.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module JWT class DecodeError < StandardError; end class VerificationError < DecodeError; end diff --git a/lib/jwt/json.rb b/lib/jwt/json.rb index 5c87d992..f33a3bc1 100644 --- a/lib/jwt/json.rb +++ b/lib/jwt/json.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'json' module JWT diff --git a/lib/jwt/verify.rb b/lib/jwt/verify.rb index 0f10a7c3..7379c2d2 100644 --- a/lib/jwt/verify.rb +++ b/lib/jwt/verify.rb @@ -21,19 +21,7 @@ def verify_aud return unless (options_aud = extract_option(:aud)) if @payload['aud'].is_a?(Array) - if options_aud.is_a?(Array) - options_aud.each do |aud| - raise( - JWT::InvalidAudError, - 'Invalid audience' - ) unless @payload['aud'].include?(aud.to_s) - end - else - raise( - JWT::InvalidAudError, - 'Invalid audience' - ) unless @payload['aud'].include?(options_aud.to_s) - end + verify_aud_array(@payload['aud'], options_aud) else raise( JWT::InvalidAudError, @@ -42,6 +30,16 @@ def verify_aud end end + def verify_aud_array(audience, options_aud) + if options_aud.is_a?(Array) + options_aud.each do |aud| + raise(JWT::InvalidAudError, 'Invalid audience') unless audience.include?(aud.to_s) + end + else + raise(JWT::InvalidAudError, 'Invalid audience') unless audience.include?(options_aud.to_s) + end + end + def verify_expiration return unless @payload.include?('exp') diff --git a/lib/jwt/version.rb b/lib/jwt/version.rb index 3931aa88..791a16c7 100644 --- a/lib/jwt/version.rb +++ b/lib/jwt/version.rb @@ -1,4 +1,5 @@ # encoding: utf-8 +# frozen_string_literal: true # Moments version builder module module JWT @@ -15,7 +16,7 @@ module VERSION # tiny version TINY = 6 # alpha, beta, etc. tag - PRE = nil + PRE = nil # Build version string STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')