Skip to content

Commit

Permalink
Default to new behavior but fallback parsing to old behavior
Browse files Browse the repository at this point in the history
We don't have a reason to make this configurable.
  • Loading branch information
rafaelfranca committed Jan 25, 2023
1 parent bc6345f commit 12f7629
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 227 deletions.
3 changes: 0 additions & 3 deletions lib/global_id/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ class Railtie < Rails::Railtie # :nodoc:
GlobalID.app = app.config.global_id.app ||= default_app_name
SignedGlobalID.expires_in = app.config.global_id.fetch(:expires_in, default_expires_in)

app.config.global_id.use_verifier_to_handle_metadata ||= false
SignedGlobalID.use_verifier_to_handle_metadata = app.config.global_id.use_verifier_to_handle_metadata

config.after_initialize do
GlobalID.app = app.config.global_id.app ||= default_app_name
SignedGlobalID.expires_in = app.config.global_id.fetch(:expires_in, default_expires_in)
Expand Down
27 changes: 5 additions & 22 deletions lib/global_id/signed_global_id.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
require 'time'

class SignedGlobalID < GlobalID
cattr_accessor :use_verifier_to_handle_metadata, instance_accessor: false, default: false

class ExpiredMessage < StandardError; end

class << self
Expand All @@ -29,18 +27,17 @@ def pick_purpose(options)

private
def verify(sgid, options)
verify_with_verifier_validated_metadata(sgid, options) || verify_with_self_validated_metadata(sgid, options)
verify_with_verifier_validated_metadata(sgid, options) ||
verify_with_legacy_self_validated_metadata(sgid, options)
end

def verify_with_verifier_validated_metadata(sgid, options)
if use_verifier_to_handle_metadata
pick_verifier(options).verify(sgid, purpose: pick_purpose(options))
end
pick_verifier(options).verify(sgid, purpose: pick_purpose(options))
rescue ActiveSupport::MessageVerifier::InvalidSignature
nil
end

def verify_with_self_validated_metadata(sgid, options)
def verify_with_legacy_self_validated_metadata(sgid, options)
metadata = pick_verifier(options).verify(sgid)

raise_if_expired(metadata['expires_at'])
Expand All @@ -67,29 +64,15 @@ def initialize(gid, options = {})
end

def to_s
if self.class.use_verifier_to_handle_metadata
@sgid ||= @verifier.generate(@uri.to_s, purpose: purpose, expires_at: expires_at)
else
@sgid ||= @verifier.generate(to_h)
end
@sgid ||= @verifier.generate(@uri.to_s, purpose: purpose, expires_at: expires_at)
end
alias to_param to_s

def to_h
# Some serializers decodes symbol keys to symbols, others to strings.
# Using string keys remedies that.
{ 'gid' => @uri.to_s, 'purpose' => purpose, 'expires_at' => encoded_expiration }
end

def ==(other)
super && @purpose == other.purpose
end

private
def encoded_expiration
expires_at.utc.iso8601(3) if expires_at
end

def pick_expiration(options)
return options[:expires_at] if options.key?(:expires_at)

Expand Down
203 changes: 1 addition & 202 deletions test/cases/signed_global_id_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class SignedGlobalIDTest < ActiveSupport::TestCase
end

test 'as string' do
assert_equal 'eyJnaWQiOiJnaWQ6Ly9iY3gvUGVyc29uLzUiLCJwdXJwb3NlIjoiZGVmYXVsdCIsImV4cGlyZXNfYXQiOm51bGx9--04a6f59140259756b22008c8c0f76ea5ed485579', @person_sgid.to_s
assert_equal 'eyJfcmFpbHMiOnsibWVzc2FnZSI6IkltZHBaRG92TDJKamVDOVFaWEp6YjI0dk5TST0iLCJleHAiOm51bGwsInB1ciI6ImRlZmF1bHQifX0=--aca9c546b5cb896c06140f59732edf87ae7e2536', @person_sgid.to_s
end

test 'model id' do
Expand All @@ -31,105 +31,11 @@ class SignedGlobalIDTest < ActiveSupport::TestCase
end
end

class SignedGlobalIDVerifierTest < ActiveSupport::TestCase
setup do
@person_sgid = SignedGlobalID.create(Person.new(5))
end

test 'parse raises when default verifier is nil' do
gid = @person_sgid.to_s
with_default_verifier nil do
assert_raise ArgumentError do
SignedGlobalID.parse(gid)
end
end
end

test 'create raises when default verifier is nil' do
with_default_verifier nil do
assert_raise ArgumentError do
SignedGlobalID.create(Person.new(5))
end
end
end

test 'create accepts a :verifier' do
with_default_verifier nil do
expected = SignedGlobalID.create(Person.new(5), verifier: VERIFIER)
assert_equal @person_sgid, expected
end
end

test 'new accepts a :verifier' do
with_default_verifier nil do
expected = SignedGlobalID.new(Person.new(5).to_gid.uri, verifier: VERIFIER)
assert_equal @person_sgid, expected
end
end

def with_default_verifier(verifier)
original, SignedGlobalID.verifier = SignedGlobalID.verifier, verifier
yield
ensure
SignedGlobalID.verifier = original
end
end

class SignedGlobalIDPurposeTest < ActiveSupport::TestCase
setup do
@login_sgid = SignedGlobalID.create(Person.new(5), for: 'login')
end

test 'sign with purpose when :for is provided' do
assert_equal "eyJnaWQiOiJnaWQ6Ly9iY3gvUGVyc29uLzUiLCJwdXJwb3NlIjoibG9naW4iLCJleHBpcmVzX2F0IjpudWxsfQ==--4b9630f3a1fb3d7d6584d95d4fac96433ec2deef", @login_sgid.to_s
end

test 'sign with default purpose when no :for is provided' do
sgid = SignedGlobalID.create(Person.new(5))
default_sgid = SignedGlobalID.create(Person.new(5), for: "default")

assert_equal "eyJnaWQiOiJnaWQ6Ly9iY3gvUGVyc29uLzUiLCJwdXJwb3NlIjoiZGVmYXVsdCIsImV4cGlyZXNfYXQiOm51bGx9--04a6f59140259756b22008c8c0f76ea5ed485579", sgid.to_s
assert_equal sgid, default_sgid
end

test 'create accepts a :for' do
expected = SignedGlobalID.create(Person.new(5), for: "login")
assert_equal @login_sgid, expected
end

test 'new accepts a :for' do
expected = SignedGlobalID.new(Person.new(5).to_gid.uri, for: 'login')
assert_equal @login_sgid, expected
end

test 'parse returns nil when purpose mismatch' do
sgid = @login_sgid.to_s
assert_nil SignedGlobalID.parse sgid
assert_nil SignedGlobalID.parse sgid, for: 'like_button'
end

test 'equal only with same purpose' do
expected = SignedGlobalID.create(Person.new(5), for: 'login')
like_sgid = SignedGlobalID.create(Person.new(5), for: 'like_button')
no_purpose_sgid = SignedGlobalID.create(Person.new(5))

assert_equal @login_sgid, expected
assert_not_equal @login_sgid, like_sgid
assert_not_equal @login_sgid, no_purpose_sgid
end
end

class SignedGlobalIDPurposeCheckedByVerifierTest < ActiveSupport::TestCase
setup do
@old_use_verifier_to_handle_metadata = SignedGlobalID.use_verifier_to_handle_metadata
SignedGlobalID.use_verifier_to_handle_metadata = true
@login_sgid = SignedGlobalID.create(Person.new(5), for: 'login')
end

teardown do
SignedGlobalID.use_verifier_to_handle_metadata = @old_use_verifier_to_handle_metadata
end

test 'sign with purpose when :for is provided' do
assert_equal "eyJfcmFpbHMiOnsibWVzc2FnZSI6IkltZHBaRG92TDJKamVDOVFaWEp6YjI0dk5TST0iLCJleHAiOm51bGwsInB1ciI6ImxvZ2luIn19--c39de01a211a37d62b4773d1da7bff94ba2ec176", @login_sgid.to_s
assert_not_equal @login_sgid, SignedGlobalID.create(Person.new(5), for: 'like-button')
Expand Down Expand Up @@ -276,113 +182,6 @@ def with_expiration_in(expires_in)
end
end

class SignedGlobalIDExpirationCheckedByVerifierTest < ActiveSupport::TestCase
setup do
@old_use_verifier_to_handle_metadata = SignedGlobalID.use_verifier_to_handle_metadata
SignedGlobalID.use_verifier_to_handle_metadata = true
@uri = Person.new(5).to_gid.uri
end

teardown do
SignedGlobalID.use_verifier_to_handle_metadata = @old_use_verifier_to_handle_metadata
end

test 'expires_in defaults to class level expiration' do
with_expiration_in 1.hour do
encoded_sgid = SignedGlobalID.new(@uri).to_s

travel 59.minutes
assert_not_nil SignedGlobalID.parse(encoded_sgid)

travel 2.minutes
assert_nil SignedGlobalID.parse(encoded_sgid)
end
end

test 'passing in expires_in overrides class level expiration' do
with_expiration_in 1.hour do
encoded_sgid = SignedGlobalID.new(@uri, expires_in: 2.hours).to_s

travel 1.hour
assert_not_nil SignedGlobalID.parse(encoded_sgid)

travel 1.hour + 3.seconds
assert_nil SignedGlobalID.parse(encoded_sgid)
end
end

test 'passing expires_in less than a second is not expired' do
encoded_sgid = SignedGlobalID.new(@uri, expires_in: 1.second).to_s
present = Time.now

Time.stub :now, present + 0.5.second do
assert_not_nil SignedGlobalID.parse(encoded_sgid)
end

Time.stub :now, present + 2.seconds do
assert_nil SignedGlobalID.parse(encoded_sgid)
end
end

test 'passing expires_in nil turns off expiration checking' do
with_expiration_in 1.hour do
encoded_sgid = SignedGlobalID.new(@uri, expires_in: nil).to_s

travel 1.hour
assert_not_nil SignedGlobalID.parse(encoded_sgid)

travel 1.hour
assert_not_nil SignedGlobalID.parse(encoded_sgid)
end
end

test 'passing expires_at sets expiration date' do
date = Date.today.end_of_day
sgid = SignedGlobalID.new(@uri, expires_at: date)

assert_equal date, sgid.expires_at

travel 1.day
assert_nil SignedGlobalID.parse(sgid.to_s)
end

test 'passing nil expires_at turns off expiration checking' do
with_expiration_in 1.hour do
encoded_sgid = SignedGlobalID.new(@uri, expires_at: nil).to_s

travel 4.hours
assert_not_nil SignedGlobalID.parse(encoded_sgid)
end
end

test 'passing expires_at overrides class level expires_in' do
with_expiration_in 1.hour do
date = Date.tomorrow.end_of_day
sgid = SignedGlobalID.new(@uri, expires_at: date)

assert_equal date, sgid.expires_at

travel 2.hours
assert_not_nil SignedGlobalID.parse(sgid.to_s)
end
end

test 'favor expires_at over expires_in' do
sgid = SignedGlobalID.new(@uri, expires_at: Date.tomorrow.end_of_day, expires_in: 1.hour)

travel 1.hour
assert_not_nil SignedGlobalID.parse(sgid.to_s)
end

private
def with_expiration_in(expires_in)
old_expires, SignedGlobalID.expires_in = SignedGlobalID.expires_in, expires_in
yield
ensure
SignedGlobalID.expires_in = old_expires
end
end

class SignedGlobalIDCustomParamsTest < ActiveSupport::TestCase
test 'create custom params' do
sgid = SignedGlobalID.create(Person.new(5), hello: 'world')
Expand Down

0 comments on commit 12f7629

Please sign in to comment.