Skip to content

Commit

Permalink
Use ActiveSupport::MessageVerifier's expiry and purpose feature in Si…
Browse files Browse the repository at this point in the history
…gnedGlobalID.

Simplify the codebase by delegating expiry and purpose handling to
ActiveSupport::MessageVerifier.
  • Loading branch information
assain committed Aug 11, 2018
1 parent 5bfe23a commit 2fdd484
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 54 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ gemfile:
- gemfiles/rails_4.2.gemfile
- gemfiles/rails_5.0.gemfile
- gemfiles/rails_5.1.gemfile
- gemfiles/rails_5.2.gemfile
matrix:
include:
- rvm: 1.9.3
Expand Down
52 changes: 26 additions & 26 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,58 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actionpack (5.1.4)
actionview (= 5.1.4)
activesupport (= 5.1.4)
actionpack (5.2.1)
actionview (= 5.2.1)
activesupport (= 5.2.1)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.1.4)
activesupport (= 5.1.4)
actionview (5.2.1)
activesupport (= 5.2.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activemodel (5.1.4)
activesupport (= 5.1.4)
activesupport (5.1.4)
activemodel (5.2.1)
activesupport (= 5.2.1)
activesupport (5.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
builder (3.2.3)
concurrent-ruby (1.0.5)
crass (1.0.2)
erubi (1.7.0)
i18n (0.9.0)
crass (1.0.4)
erubi (1.7.1)
i18n (1.1.0)
concurrent-ruby (~> 1.0)
loofah (2.1.1)
loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
method_source (0.9.0)
mini_portile2 (2.3.0)
minitest (5.10.3)
nokogiri (1.8.1)
minitest (5.11.3)
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
rack (2.0.3)
rack-test (0.7.0)
rack (2.0.5)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (5.1.4)
actionpack (= 5.1.4)
activesupport (= 5.1.4)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
railties (5.2.1)
actionpack (= 5.2.1)
activesupport (= 5.2.1)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.1.0)
thor (>= 0.19.0, < 2.0)
rake (12.3.1)
thor (0.20.0)
thread_safe (0.3.6)
tzinfo (1.2.3)
tzinfo (1.2.5)
thread_safe (~> 0.1)

PLATFORMS
Expand All @@ -71,4 +71,4 @@ DEPENDENCIES
rake

BUNDLED WITH
1.15.4
1.16.1
6 changes: 6 additions & 0 deletions gemfiles/rails_5.2.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source "https://rubygems.org"

gem "activemodel", "~> 5.2.1"
gem "railties", "~> 5.2.1"

gemspec path: "../"
27 changes: 3 additions & 24 deletions lib/global_id/signed_global_id.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
require 'time'

class SignedGlobalID < GlobalID
class ExpiredMessage < StandardError; end

class << self
attr_accessor :verifier

Expand All @@ -30,20 +28,11 @@ def pick_purpose(options)

private
def verify(sgid, options)
metadata = pick_verifier(options).verify(sgid)

raise_if_expired(metadata['expires_at'])
gid = pick_verifier(options).verify(sgid, purpose: pick_purpose(options))

metadata['gid'] if pick_purpose(options) == metadata['purpose']
rescue ActiveSupport::MessageVerifier::InvalidSignature, ExpiredMessage
rescue ActiveSupport::MessageVerifier::InvalidSignature
nil
end

def raise_if_expired(expires_at)
if expires_at && Time.now.utc > Time.iso8601(expires_at)
raise ExpiredMessage, 'This signed global id has expired.'
end
end
end

attr_reader :verifier, :purpose, :expires_at
Expand All @@ -56,25 +45,15 @@ def initialize(gid, options = {})
end

def to_s
@sgid ||= @verifier.generate(to_h)
@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
10 changes: 6 additions & 4 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 Down Expand Up @@ -78,17 +78,19 @@ def with_default_verifier(verifier)
class SignedGlobalIDPurposeTest < ActiveSupport::TestCase
setup do
@login_sgid = SignedGlobalID.create(Person.new(5), for: 'login')
@like_sgid = SignedGlobalID.create(Person.new(5), for: 'like-button')
end

test 'sign with purpose when :for is provided' do
assert_equal "eyJnaWQiOiJnaWQ6Ly9iY3gvUGVyc29uLzUiLCJwdXJwb3NlIjoibG9naW4iLCJleHBpcmVzX2F0IjpudWxsfQ==--4b9630f3a1fb3d7d6584d95d4fac96433ec2deef", @login_sgid.to_s
assert_equal "eyJfcmFpbHMiOnsibWVzc2FnZSI6IkltZHBaRG92TDJKamVDOVFaWEp6YjI0dk5TST0iLCJleHAiOm51bGwsInB1ciI6ImxvZ2luIn19--c39de01a211a37d62b4773d1da7bff94ba2ec176", @login_sgid.to_s
assert_not_equal @login_sgid, @like_sgid
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 "eyJfcmFpbHMiOnsibWVzc2FnZSI6IkltZHBaRG92TDJKamVDOVFaWEp6YjI0dk5TST0iLCJleHAiOm51bGwsInB1ciI6ImRlZmF1bHQifX0=--aca9c546b5cb896c06140f59732edf87ae7e2536", sgid.to_s
assert_equal sgid, default_sgid
end

Expand Down Expand Up @@ -227,7 +229,7 @@ class SignedGlobalIDCustomParamsTest < ActiveSupport::TestCase
end

test 'parse custom params' do
sgid = SignedGlobalID.parse('eyJnaWQiOiJnaWQ6Ly9iY3gvUGVyc29uLzU/aGVsbG89d29ybGQiLCJwdXJwb3NlIjoiZGVmYXVsdCIsImV4cGlyZXNfYXQiOm51bGx9--7c042f09483dec470fa1088b76d9fd946eb30ffa')
sgid = SignedGlobalID.parse('eyJfcmFpbHMiOnsibWVzc2FnZSI6IkltZHBaRG92TDJKamVDOVFaWEp6YjI0dk5UOW9aV3hzYnoxM2IzSnNaQ0k9IiwiZXhwIjpudWxsLCJwdXIiOiJkZWZhdWx0In19--09eb7f8baa6e0e19012dc4d1fd749e0c0cd33314')
assert_equal 'world', sgid.params[:hello]
end
end

0 comments on commit 2fdd484

Please sign in to comment.