@@ -136,6 +136,10 @@ def index
136
136
render inline : "<%= form_tag (params[:form_path] || '/per_form_tokens/post_one'), method: (params[:form_method] || :post) %>"
137
137
end
138
138
139
+ def button_to
140
+ render inline : "<%= button_to 'Button', (params[:form_path] || '/per_form_tokens/post_one'), method: (params[:form_method] || :post) %>"
141
+ end
142
+
139
143
def post_one
140
144
render plain : ''
141
145
end
@@ -652,15 +656,9 @@ def test_per_form_token_is_same_size_as_global_token
652
656
def test_accepts_token_for_correct_path_and_method
653
657
get :index
654
658
655
- form_token = nil
656
- assert_select 'input[name=custom_authenticity_token]' do |elts |
657
- form_token = elts . first [ 'value' ]
658
- assert_not_nil form_token
659
- end
659
+ form_token = assert_presence_and_fetch_form_csrf_token
660
660
661
- actual = @controller . send ( :unmask_token , Base64 . strict_decode64 ( form_token ) )
662
- expected = @controller . send ( :per_form_csrf_token , session , '/per_form_tokens/post_one' , 'post' )
663
- assert_equal expected , actual
661
+ assert_matches_session_token_on_server form_token
664
662
665
663
# This is required because PATH_INFO isn't reset between requests.
666
664
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one'
@@ -673,15 +671,9 @@ def test_accepts_token_for_correct_path_and_method
673
671
def test_rejects_token_for_incorrect_path
674
672
get :index
675
673
676
- form_token = nil
677
- assert_select 'input[name=custom_authenticity_token]' do |elts |
678
- form_token = elts . first [ 'value' ]
679
- assert_not_nil form_token
680
- end
674
+ form_token = assert_presence_and_fetch_form_csrf_token
681
675
682
- actual = @controller . send ( :unmask_token , Base64 . strict_decode64 ( form_token ) )
683
- expected = @controller . send ( :per_form_csrf_token , session , '/per_form_tokens/post_one' , 'post' )
684
- assert_equal expected , actual
676
+ assert_matches_session_token_on_server form_token
685
677
686
678
# This is required because PATH_INFO isn't reset between requests.
687
679
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_two'
@@ -693,15 +685,9 @@ def test_rejects_token_for_incorrect_path
693
685
def test_rejects_token_for_incorrect_method
694
686
get :index
695
687
696
- form_token = nil
697
- assert_select 'input[name=custom_authenticity_token]' do |elts |
698
- form_token = elts . first [ 'value' ]
699
- assert_not_nil form_token
700
- end
688
+ form_token = assert_presence_and_fetch_form_csrf_token
701
689
702
- actual = @controller . send ( :unmask_token , Base64 . strict_decode64 ( form_token ) )
703
- expected = @controller . send ( :per_form_csrf_token , session , '/per_form_tokens/post_one' , 'post' )
704
- assert_equal expected , actual
690
+ assert_matches_session_token_on_server form_token
705
691
706
692
# This is required because PATH_INFO isn't reset between requests.
707
693
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one'
@@ -710,6 +696,36 @@ def test_rejects_token_for_incorrect_method
710
696
end
711
697
end
712
698
699
+ def test_rejects_token_for_incorrect_method_button_to
700
+ get :button_to , params : { form_method : 'delete' }
701
+
702
+ form_token = assert_presence_and_fetch_form_csrf_token
703
+
704
+ assert_matches_session_token_on_server form_token , 'delete'
705
+
706
+ # This is required because PATH_INFO isn't reset between requests.
707
+ @request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one'
708
+ assert_raises ( ActionController ::InvalidAuthenticityToken ) do
709
+ patch :post_one , params : { custom_authenticity_token : form_token }
710
+ end
711
+ end
712
+
713
+ %w{ delete post patch } . each do |verb |
714
+ test "Accepts proper token for #{ verb } method on button_to tag" do
715
+ get :button_to , params : { form_method : verb }
716
+
717
+ form_token = assert_presence_and_fetch_form_csrf_token
718
+
719
+ assert_matches_session_token_on_server form_token , verb
720
+
721
+ # This is required because PATH_INFO isn't reset between requests.
722
+ @request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one'
723
+ assert_nothing_raised do
724
+ send verb , :post_one , params : { custom_authenticity_token : form_token }
725
+ end
726
+ end
727
+ end
728
+
713
729
def test_accepts_global_csrf_token
714
730
get :index
715
731
@@ -726,15 +742,9 @@ def test_accepts_global_csrf_token
726
742
def test_ignores_params
727
743
get :index , params : { form_path : '/per_form_tokens/post_one?foo=bar' }
728
744
729
- form_token = nil
730
- assert_select 'input[name=custom_authenticity_token]' do |elts |
731
- form_token = elts . first [ 'value' ]
732
- assert_not_nil form_token
733
- end
745
+ form_token = assert_presence_and_fetch_form_csrf_token
734
746
735
- actual = @controller . send ( :unmask_token , Base64 . strict_decode64 ( form_token ) )
736
- expected = @controller . send ( :per_form_csrf_token , session , '/per_form_tokens/post_one' , 'post' )
737
- assert_equal expected , actual
747
+ assert_matches_session_token_on_server form_token
738
748
739
749
# This is required because PATH_INFO isn't reset between requests.
740
750
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one?foo=baz'
@@ -747,11 +757,7 @@ def test_ignores_params
747
757
def test_ignores_trailing_slash_during_generation
748
758
get :index , params : { form_path : '/per_form_tokens/post_one/' }
749
759
750
- form_token = nil
751
- assert_select 'input[name=custom_authenticity_token]' do |elts |
752
- form_token = elts . first [ 'value' ]
753
- assert_not_nil form_token
754
- end
760
+ form_token = assert_presence_and_fetch_form_csrf_token
755
761
756
762
# This is required because PATH_INFO isn't reset between requests.
757
763
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one'
@@ -764,11 +770,7 @@ def test_ignores_trailing_slash_during_generation
764
770
def test_ignores_trailing_slash_during_validation
765
771
get :index
766
772
767
- form_token = nil
768
- assert_select 'input[name=custom_authenticity_token]' do |elts |
769
- form_token = elts . first [ 'value' ]
770
- assert_not_nil form_token
771
- end
773
+ form_token = assert_presence_and_fetch_form_csrf_token
772
774
773
775
# This is required because PATH_INFO isn't reset between requests.
774
776
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one/'
@@ -781,17 +783,27 @@ def test_ignores_trailing_slash_during_validation
781
783
def test_method_is_case_insensitive
782
784
get :index , params : { form_method : "POST" }
783
785
784
- form_token = nil
785
- assert_select 'input[name=custom_authenticity_token]' do |elts |
786
- form_token = elts . first [ 'value' ]
787
- assert_not_nil form_token
788
- end
789
-
786
+ form_token = assert_presence_and_fetch_form_csrf_token
790
787
# This is required because PATH_INFO isn't reset between requests.
791
788
@request . env [ 'PATH_INFO' ] = '/per_form_tokens/post_one/'
792
789
assert_nothing_raised do
793
790
post :post_one , params : { custom_authenticity_token : form_token }
794
791
end
795
792
assert_response :success
796
793
end
794
+
795
+ private
796
+ def assert_presence_and_fetch_form_csrf_token
797
+ assert_select 'input[name="custom_authenticity_token"]' do |input |
798
+ form_csrf_token = input . first [ 'value' ]
799
+ assert_not_nil form_csrf_token
800
+ return form_csrf_token
801
+ end
802
+ end
803
+
804
+ def assert_matches_session_token_on_server ( form_token , method = 'post' )
805
+ actual = @controller . send ( :unmask_token , Base64 . strict_decode64 ( form_token ) )
806
+ expected = @controller . send ( :per_form_csrf_token , session , '/per_form_tokens/post_one' , method )
807
+ assert_equal expected , actual
808
+ end
797
809
end
0 commit comments