From 9d87ff6857987b68f1f2bcf73edde2391981e16d Mon Sep 17 00:00:00 2001 From: Matteo Pierro Date: Sat, 31 Aug 2024 16:45:13 +0300 Subject: [PATCH] add a Wrapper for older algorithm --- lib/jwt/jwa.rb | 40 +++++++++++++++++++++++++++++++- lib/jwt/jwa/signing_algorithm.rb | 8 +++++++ spec/jwt/jwt_spec.rb | 17 ++++++++++---- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/lib/jwt/jwa.rb b/lib/jwt/jwa.rb index 26e0276d..9bc3a33f 100644 --- a/lib/jwt/jwa.rb +++ b/lib/jwt/jwa.rb @@ -30,11 +30,49 @@ def resolve(algorithm) unless algorithm.is_a?(SigningAlgorithm) Deprecations.warning('Custom algorithms are required to include JWT::JWA::SigningAlgorithm') - algorithm.extend(SigningAlgorithm) + return Wrapper.new(algorithm) end algorithm end end + + class Wrapper + include SigningAlgorithm + + def initialize(algorithm) + @algorithm = algorithm + end + + def alg + return @algorithm.alg if @algorithm.respond_to?(:alg) + + super + end + + def valid_alg?(*args, **kwargs) + return @algorithm.valid_alg?(*args, **kwargs) if @algorithm.respond_to?(:valid_alg?) + + super + end + + def header(*args, **kwargs) + return @algorithm.header(*args, **kwargs) if @algorithm.respond_to?(:header) + + super + end + + def sign(*args, **kwargs) + return @algorithm.sign(*args, **kwargs) if @algorithm.respond_to?(:sign) + + super + end + + def verify(*args, **kwargs) + return @algorithm.verify(*args, **kwargs) if @algorithm.respond_to?(:verify) + + super + end + end end end diff --git a/lib/jwt/jwa/signing_algorithm.rb b/lib/jwt/jwa/signing_algorithm.rb index b7295468..62c7d90b 100644 --- a/lib/jwt/jwa/signing_algorithm.rb +++ b/lib/jwt/jwa/signing_algorithm.rb @@ -23,6 +23,14 @@ def header(*) { 'alg' => alg } end + def sign(*) + raise EncodeError, 'Algorithm implementation is missing the sign method' + end + + def verify(*) + raise DecodeError, 'Algorithm implementation is missing the verify method' + end + def raise_verify_error!(message) raise(DecodeError.new(message).tap { |e| e.set_backtrace(caller(1)) }) end diff --git a/spec/jwt/jwt_spec.rb b/spec/jwt/jwt_spec.rb index 69c1965d..1bcdb15b 100644 --- a/spec/jwt/jwt_spec.rb +++ b/spec/jwt/jwt_spec.rb @@ -902,19 +902,30 @@ def header(*) context 'when class is not utilizing the ::JWT::JWA::SigningAlgorithm module' do let(:custom_algorithm) do Class.new do + attr_reader :alg + def initialize(signature: 'custom_signature', alg: 'custom') @signature = signature @alg = alg end + def header(*) + { 'alg' => @alg, 'foo' => 'bar' } + end + def sign(*) @signature end + + def verify(*) + true + end end end it 'emits a deprecation warning' do expect { token }.to output("[DEPRECATION WARNING] Custom algorithms are required to include JWT::JWA::SigningAlgorithm\n").to_stderr + expect(JWT.decode(token, 'secret', true, algorithm: custom_algorithm.new)).to eq([payload, { 'alg' => 'custom', 'foo' => 'bar' }]) end end @@ -937,9 +948,8 @@ def sign(*) end end - # This behaviour should be somehow nicer it 'raises an error on encoding' do - expect { token }.to raise_error(NoMethodError) + expect { token }.to raise_error(JWT::EncodeError, /missing the sign method/) end it 'allows decoding' do @@ -958,9 +968,8 @@ def sign(*) expect(token).to eq(expected_token) end - # This behaviour should be somehow nicer it 'raises error on decoding' do - expect { JWT.decode(expected_token, 'secret', true, algorithm: custom_algorithm.new) }.to raise_error(NoMethodError) + expect { JWT.decode(expected_token, 'secret', true, algorithm: custom_algorithm.new) }.to raise_error(JWT::DecodeError, /missing the verify method/) end end end