diff --git a/CHANGELOG.md b/CHANGELOG.md index eefc178e..e4cdf961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - Fix key base equality and spaceship operators [#569](https://github.com/jwt/ruby-jwt/pull/569) - [@magneland](https://github.com/magneland). - Remove explicit base64 require from x5c_key_finder [#580](https://github.com/jwt/ruby-jwt/pull/580) - [@anakinj](https://github.com/anakinj). - Performance improvements and cleanup of tests [#581](https://github.com/jwt/ruby-jwt/pull/581) - [@anakinj](https://github.com/anakinj). +- Explicit dependency to the base64 gem [#582](https://github.com/jwt/ruby-jwt/pull/582) - [@anakinj](https://github.com/anakinj). +- Deprecation warning for decoding content not compliant with RFC 4648 [#582](https://github.com/jwt/ruby-jwt/pull/582) - [@anakinj](https://github.com/anakinj). - Your contribution here ## [v2.7.1](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2023-06-09) diff --git a/lib/jwt/base64.rb b/lib/jwt/base64.rb index e69808b1..f6c47684 100644 --- a/lib/jwt/base64.rb +++ b/lib/jwt/base64.rb @@ -3,14 +3,26 @@ require 'base64' module JWT - # Base64 helpers + # Base64 encoding and decoding class Base64 class << self + # Encode a string with URL-safe Base64 complying with RFC 4648 (not padded). def url_encode(str) - ::Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '') + ::Base64.urlsafe_encode64(str, padding: false) end + # Decode a string with URL-safe Base64 complying with RFC 4648. + # Deprecated support for RFC 2045 remains for now. ("All line breaks or other characters not found in Table 1 must be ignored by decoding software") def url_decode(str) + ::Base64.urlsafe_decode64(str) + rescue ArgumentError => e + raise unless e.message == 'invalid base64' + + warn('[DEPRECATION] 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') + loose_urlsafe_decode64(str) + end + + def loose_urlsafe_decode64(str) str += '=' * (4 - str.length.modulo(4)) ::Base64.decode64(str.tr('-_', '+/')) end diff --git a/ruby-jwt.gemspec b/ruby-jwt.gemspec index 91177b3f..67ff3911 100644 --- a/ruby-jwt.gemspec +++ b/ruby-jwt.gemspec @@ -31,6 +31,8 @@ Gem::Specification.new do |spec| spec.executables = [] spec.require_paths = %w[lib] + spec.add_dependency 'base64' + spec.add_development_dependency 'appraisal' spec.add_development_dependency 'bundler' spec.add_development_dependency 'rake' diff --git a/spec/jwt/x5c_key_finder_spec.rb b/spec/jwt/x5c_key_finder_spec.rb index 7ebfc4f7..001feaa6 100644 --- a/spec/jwt/x5c_key_finder_spec.rb +++ b/spec/jwt/x5c_key_finder_spec.rb @@ -31,7 +31,7 @@ let(:crl) { issue_crl([], issuer: root_certificate, issuer_key: root_key) } - let(:x5c_header) { [Base64.strict_encode64(leaf_certificate.to_der)] } + let(:x5c_header) { [Base64.encode64(leaf_certificate.to_der)] } subject(:keyfinder) { described_class.new([root_certificate], [crl]).from(x5c_header) } it 'returns the public key from a certificate that is signed by trusted roots and not revoked' do