From b29a95d0cb4f255b9f7e86998c9ebec81f8817c1 Mon Sep 17 00:00:00 2001 From: swaggboi Date: Thu, 15 Aug 2024 19:56:02 -0400 Subject: [PATCH] Tests for CSRF --- t/admin.t | 17 +++++++++++++--- t/human.t | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ t/moderator.t | 16 +++++++++++++-- t/search.t | 5 +++++ 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/t/admin.t b/t/admin.t index 43a663c..0901e75 100644 --- a/t/admin.t +++ b/t/admin.t @@ -10,6 +10,11 @@ my %valid_login = ( ); subtest Login => sub { + $t->get_ok('/login'); + + $valid_login{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok('/login', form => \%valid_login) ->status_is(302) ->header_like(Location => qr{moderator/flagged}); @@ -31,9 +36,10 @@ subtest Login => sub { $t->get_ok('/moderator/admin/create') ->status_is(200) ->text_like(h2 => qr/Create Moderator/) - ->element_exists('form input[name="name"]' ) - ->element_exists('form input[name="email"]' ) - ->element_exists('form input[name="password"]') + ->element_exists('form input[name="name"]' ) + ->element_exists('form input[name="email"]' ) + ->element_exists('form input[name="password"]' ) + ->element_exists('form input[name="csrf_token"]') }; subtest Reset => sub { @@ -43,6 +49,7 @@ subtest Login => sub { ->element_exists('a[href*="/moderator/admin/reset"]') ->element_exists('form input[name="email"]' ) ->element_exists('form input[name="password"]' ) + ->element_exists('form input[name="csrf_token"]' ) }; subtest Lock => sub { @@ -51,6 +58,7 @@ subtest Login => sub { ->text_like(h2 => qr/Lock Account/) ->element_exists('a[href*="/moderator/admin/lock"]') ->element_exists('form input[name="email"]' ) + ->element_exists('form input[name="csrf_token"]' ) }; subtest Unlock => sub { @@ -59,6 +67,7 @@ subtest Login => sub { ->text_like(h2 => qr/Unlock Account/) ->element_exists('a[href*="/moderator/admin/unlock"]') ->element_exists('form input[name="email"]' ) + ->element_exists('form input[name="csrf_token"]' ) }; subtest Promote => sub { @@ -67,6 +76,7 @@ subtest Login => sub { ->text_like(h2 => qr/Promote Moderator/) ->element_exists('a[href*="/moderator/admin/promote"]') ->element_exists('form input[name="email"]' ) + ->element_exists('form input[name="csrf_token"]' ) }; subtest Demote => sub { @@ -75,6 +85,7 @@ subtest Login => sub { ->text_like(h2 => qr/Demote Admin/) ->element_exists('a[href*="/moderator/admin/demote"]') ->element_exists('form input[name="email"]' ) + ->element_exists('form input[name="csrf_token"]' ) }; # Admin session ends diff --git a/t/human.t b/t/human.t index 7b22ca5..235dc81 100644 --- a/t/human.t +++ b/t/human.t @@ -25,18 +25,39 @@ subtest 'Bumping thread', sub { $t->get_ok('/human/thread/bump/1')->status_is(302) ->header_like(Location => qr/captcha/); + $t->get_ok($bump_thread_url) + ->status_is(200) + ->element_exists('input[name="answer"]' ) + ->element_exists('input[name="number"]' ) + ->element_exists('input[name="csrf_token"]'); + + # Bad CSRF + $t->post_ok($bump_thread_url, form => \%bad_bot) + ->status_is(403) + ->element_exists('p[class="stash-with-error"]') + ->text_like(p => qr/Something went wrong/); + # Bad CAPTCHA + $bad_bot{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($bump_thread_url, form => \%bad_bot) ->status_is(400) ->element_exists('p[class="stash-with-error"]') ->text_like(p => qr/Sounds like something a robot would say/); + $invalid_captcha{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($bump_thread_url, form => \%invalid_captcha) ->status_is(400) ->element_exists('p[class="field-with-error"]') ->text_like(p => qr/Should be a single number/); # Solved CAPTCHA + $good_human{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($bump_thread_url, form => \%good_human) ->status_is(302) ->header_like(Location => qr{human/thread/bump/1}); @@ -56,18 +77,35 @@ subtest 'Flagging thread', sub { $t->get_ok('/human/thread/flag/1')->status_is(302) ->header_like(Location => qr/captcha/); + # Bad CSRF + $t->get_ok($flag_thread_url); + + $t->post_ok($flag_thread_url, form => \%bad_bot) + ->status_is(403) + ->element_exists('p[class="stash-with-error"]') + ->text_like(p => qr/Something went wrong/); + # Bad CAPTCHA + $bad_bot{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($flag_thread_url, form => \%bad_bot) ->status_is(400) ->element_exists('p[class="stash-with-error"]') ->text_like(p => qr/Sounds like something a robot would say/); + $invalid_captcha{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($flag_thread_url, form => \%invalid_captcha) ->status_is(400) ->element_exists('p[class="field-with-error"]') ->text_like(p => qr/Should be a single number/); # Solved CAPTCHA + $good_human{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($flag_thread_url, form => \%good_human) ->status_is(302) ->header_like(Location => qr{human/thread/flag/1}); @@ -83,18 +121,35 @@ subtest 'Flagging remark', sub { $t->get_ok('/human/remark/flag/1')->status_is(302) ->header_like(Location => qr/captcha/); + # Bad CSRF + $t->get_ok($flag_remark_url); + + $t->post_ok($flag_remark_url, form => \%bad_bot) + ->status_is(403) + ->element_exists('p[class="stash-with-error"]') + ->text_like(p => qr/Something went wrong/); + # Bad CAPTCHA + $bad_bot{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($flag_remark_url, form => \%bad_bot) ->status_is(400) ->element_exists('p[class="stash-with-error"]') ->text_like(p => qr/Sounds like something a robot would say/); + $invalid_captcha{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($flag_remark_url, form => \%invalid_captcha) ->status_is(400) ->element_exists('p[class="field-with-error"]') ->text_like(p => qr/Should be a single number/); # Solved CAPTCHA + $good_human{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($flag_remark_url, form => \%good_human) ->status_is(302) ->header_like(Location => qr{human/remark/flag/1}); diff --git a/t/moderator.t b/t/moderator.t index 9b79b2c..3ecfdc1 100644 --- a/t/moderator.t +++ b/t/moderator.t @@ -17,16 +17,28 @@ my %invalid_login = ( subtest Login => sub { $t->get_ok('/login') ->status_is(200) - ->element_exists('form input[name="email"]') - ->element_exists('form input[name="password"]') + ->element_exists('form input[name="email"]' ) + ->element_exists('form input[name="password"]' ) + ->element_exists('form input[name="csrf_token"]') ->text_like(h2 => qr/Moderator Login/); + # Bad CSRF token + $t->post_ok('/login', form => \%valid_login) + ->status_is(403) + ->text_like(p => qr/Something went wrong/); + + $invalid_login{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok('/login', form => \%invalid_login) ->status_is(403) ->element_exists('form input[name="email"]') ->element_exists('form input[name="password"]') ->text_like(p => qr/Invalid login/); + $valid_login{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok('/login', form => \%valid_login) ->status_is(302) ->header_like(Location => qr{moderator/flagged}); diff --git a/t/search.t b/t/search.t index 6e6b47a..cc82660 100644 --- a/t/search.t +++ b/t/search.t @@ -14,6 +14,11 @@ subtest 'Search before CAPTCHA', sub { }; subtest 'Search after CAPTCHA', sub { + $t->get_ok($search_url); + + $good_human{'csrf_token'} = + $t->tx->res->dom->at('input[name="csrf_token"]')->val; + $t->post_ok($search_url, form => \%good_human) ->status_is(302) ->header_like(Location => qr{human/search});