diff --git a/CHANGELOG.md b/CHANGELOG.md index 90cbc7a4..567621bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,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 diff --git a/lib/jwt.rb b/lib/jwt.rb index 19b987ce..235d3a9f 100644 --- a/lib/jwt.rb +++ b/lib/jwt.rb @@ -27,6 +27,8 @@ def encode(payload, key, algorithm = 'HS256', header_fields = {}) end def decode(jwt, key = nil, verify = true, options = {}, &keyfinder) # rubocop:disable Style/OptionalBooleanParameter - Decode.new(jwt, key, verify, configuration.decode.to_h.merge(options), &keyfinder).decode_segments + Deprecations.context do + Decode.new(jwt, key, verify, configuration.decode.to_h.merge(options), &keyfinder).decode_segments + end end end diff --git a/lib/jwt/base64.rb b/lib/jwt/base64.rb index e6ee0622..20f56b6c 100644 --- a/lib/jwt/base64.rb +++ b/lib/jwt/base64.rb @@ -20,7 +20,7 @@ def url_decode(str) raise Base64DecodeError, 'Invalid base64 encoding' if JWT.configuration.strict_base64_decoding loose_urlsafe_decode64(str).tap do - Deprecations.warning('Invalid base64 input detected, could be because of invalid padding, trailing whitespaces or newline chars. Graceful handling of invalid input will be dropped in the next major version of ruby-jwt') + Deprecations.warning('Invalid base64 input detected, could be because of invalid padding, trailing whitespaces or newline chars. Graceful handling of invalid input will be dropped in the next major version of ruby-jwt', only_if_valid: true) end end diff --git a/lib/jwt/deprecations.rb b/lib/jwt/deprecations.rb index 92f0e6cf..9f516a2d 100644 --- a/lib/jwt/deprecations.rb +++ b/lib/jwt/deprecations.rb @@ -4,15 +4,34 @@ module JWT # Deprecations module to handle deprecation warnings in the gem module Deprecations class << self - def warning(message) + def context + yield.tap { emit_warnings } + ensure + Thread.current[:jwt_warning_store] = nil + end + + def warning(message, only_if_valid: false) + method_name = only_if_valid ? :store : :warn case JWT.configuration.deprecation_warnings - when :warn - warn("[DEPRECATION WARNING] #{message}") when :once return if record_warned(message) - - warn("[DEPRECATION WARNING] #{message}") + when :warn + # noop + else + return end + + send(method_name, "[DEPRECATION WARNING] #{message}") + end + + def store(message) + (Thread.current[:jwt_warning_store] ||= []) << message + end + + def emit_warnings + return if Thread.current[:jwt_warning_store].nil? + + Thread.current[:jwt_warning_store].each { |warning| warn(warning) } end private diff --git a/spec/jwt/jwt_spec.rb b/spec/jwt/jwt_spec.rb index 937ceec3..f5a03361 100644 --- a/spec/jwt/jwt_spec.rb +++ b/spec/jwt/jwt_spec.rb @@ -944,4 +944,36 @@ def valid_alg?(alg) end end end + + 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 + end + end + + context 'when valid token is invalid strict base64 and decoded with the correct key' do + it 'does outputs deprecation warning' do + expect { JWT.decode("#{JWT.encode('payload', 'key')} ", 'key') }.to output(/DEPRECATION/).to_stderr + end + end + + 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 { + begin + JWT.decode("#{token} ", 'incorrect') + rescue JWT::VerificationError + nil + end + JWT.decode(token, 'key') + }.not_to output(/DEPRECATION/).to_stderr + end + end end