Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
66d4259af2 | |||
ccd68b8af4 | |||
6f96109f45 | |||
b586c534ce | |||
7b618f56cb | |||
c5098263b3 | |||
69cd01361b | |||
2d6152d762 | |||
6b6278e940 | |||
de62444eca | |||
e19ded1362 | |||
fd0eba29d7 | |||
b29a95d0cb | |||
e590fe26e5 | |||
decbc120e3 | |||
18634bbf60 | |||
0aef68495c | |||
32393fd8f3 | |||
66bbd9da67 |
|
@ -1,4 +1,4 @@
|
||||||
FROM docker.io/perl:5.36
|
FROM docker.io/perl:5.40
|
||||||
|
|
||||||
# Move it
|
# Move it
|
||||||
WORKDIR /opt
|
WORKDIR /opt
|
||||||
|
|
|
@ -61,7 +61,7 @@ tests locally:
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
- Tripcodes/PGP signing somehow perhaps...
|
- Stop working on this and start the imageboard
|
||||||
|
|
||||||
## AGPL-3.0+ANTIFA compliance
|
## AGPL-3.0+ANTIFA compliance
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,11 @@ sub startup($self) {
|
||||||
->to('thread#flag')
|
->to('thread#flag')
|
||||||
->name('flag_thread');
|
->name('flag_thread');
|
||||||
|
|
||||||
|
# Redirect for this old path to the new one
|
||||||
|
$thread->any([qw{GET POST}], '/post', sub ($c) {
|
||||||
|
$c->redirect_to('post_thread')
|
||||||
|
});
|
||||||
|
|
||||||
$human_thread->any([qw{GET POST}], '/post')
|
$human_thread->any([qw{GET POST}], '/post')
|
||||||
->to('thread#create')
|
->to('thread#create')
|
||||||
->name('post_thread');
|
->name('post_thread');
|
||||||
|
|
|
@ -39,8 +39,15 @@ sub login($self) {
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('email' )->size(6, 320);
|
$v->required('email' )->size(6, 320);
|
||||||
$v->required('password')->size(12, undef);
|
$v->required('password')->size(12, undef);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -153,8 +160,15 @@ sub create($self) {
|
||||||
$v->required('name' )->size(1, 64);
|
$v->required('name' )->size(1, 64);
|
||||||
$v->required('email' )->size(6, 320);
|
$v->required('email' )->size(6, 320);
|
||||||
$v->required('password')->size(12, undef);
|
$v->required('password')->size(12, undef);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -178,8 +192,15 @@ sub admin_reset($self) {
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('email' )->size(6, 320);
|
$v->required('email' )->size(6, 320);
|
||||||
$v->required('password')->size(12, undef);
|
$v->required('password')->size(12, undef);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -201,8 +222,15 @@ sub mod_reset($self) {
|
||||||
|
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('password')->size(12, undef);
|
$v->required('password')->size(12, undef);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -226,8 +254,15 @@ sub lock_acct($self) {
|
||||||
|
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('email')->size(6, 320);
|
$v->required('email')->size(6, 320);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -248,8 +283,15 @@ sub unlock_acct($self) {
|
||||||
|
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('email')->size(6, 320);
|
$v->required('email')->size(6, 320);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -270,8 +312,15 @@ sub promote($self) {
|
||||||
|
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('email')->size(6, 320);
|
$v->required('email')->size(6, 320);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -292,8 +341,15 @@ sub demote($self) {
|
||||||
|
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('email')->size(6, 320);
|
$v->required('email')->size(6, 320);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -20,8 +20,15 @@ sub captcha($self) {
|
||||||
if ($v && $v->has_data) {
|
if ($v && $v->has_data) {
|
||||||
$v->required('answer')->num(1, 9);
|
$v->required('answer')->num(1, 9);
|
||||||
$v->required('number')->size(1, 4);
|
$v->required('number')->size(1, 4);
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -36,8 +36,15 @@ sub create($self) {
|
||||||
$v->required('body' )->size(2, $body_limit);
|
$v->required('body' )->size(2, $body_limit);
|
||||||
$v->optional('bump' );
|
$v->optional('bump' );
|
||||||
$v->optional('preview');
|
$v->optional('preview');
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -15,8 +15,15 @@ sub create($self) {
|
||||||
$v->required('title' )->size(1, 127);
|
$v->required('title' )->size(1, 127);
|
||||||
$v->required('body' )->size(2, $body_limit);
|
$v->required('body' )->size(2, $body_limit);
|
||||||
$v->optional('preview');
|
$v->optional('preview');
|
||||||
|
$v->csrf_protect;
|
||||||
|
|
||||||
if ($v->has_error) {
|
if ($v->has_error('csrf_token')) {
|
||||||
|
$self->stash(
|
||||||
|
status => 403,
|
||||||
|
error => 'Something went wrong, please try again. 🥺'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elsif ($v->has_error) {
|
||||||
$self->stash(status => 400)
|
$self->stash(status => 400)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -156,7 +156,8 @@ sub flagged($self) {
|
||||||
SELECT 'remark',
|
SELECT 'remark',
|
||||||
remark_id
|
remark_id
|
||||||
FROM remarks
|
FROM remarks
|
||||||
WHERE flagged_status;
|
WHERE flagged_status
|
||||||
|
ORDER BY id DESC;
|
||||||
END_SQL
|
END_SQL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +171,8 @@ sub hidden($self) {
|
||||||
SELECT 'remark',
|
SELECT 'remark',
|
||||||
remark_id
|
remark_id
|
||||||
FROM remarks
|
FROM remarks
|
||||||
WHERE hidden_status;
|
WHERE hidden_status
|
||||||
|
ORDER BY id DESC;
|
||||||
END_SQL
|
END_SQL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +272,8 @@ sub list($self) {
|
||||||
TO_CHAR(last_login_date, $1) AS last_login_date,
|
TO_CHAR(last_login_date, $1) AS last_login_date,
|
||||||
lock_status,
|
lock_status,
|
||||||
admin_status
|
admin_status
|
||||||
FROM moderators;
|
FROM moderators
|
||||||
|
ORDER BY last_login_date DESC;
|
||||||
END_SQL
|
END_SQL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,6 @@ table { width: 100%; }
|
||||||
|
|
||||||
table, th, td {
|
table, th, td {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
border: 0.15em dotted black;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
(function () {
|
(function () {
|
||||||
const bodyStyle = document.body.style;
|
|
||||||
|
|
||||||
function setImage(url) {
|
function setImage(url) {
|
||||||
bodyStyle.backgroundImage = "url('" + url + "')";
|
document.body.style.backgroundImage = "url('" + url + "')";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (new Date().getMonth()) {
|
switch (new Date().getMonth()) {
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
# PostText v0.1
|
# PostText v0.1
|
||||||
# Jul 22 2022
|
# Jul 22 2022
|
||||||
|
|
||||||
use v5.36;
|
use v5.40;
|
||||||
#no warnings 'experimental';
|
|
||||||
use Mojo::File qw{curfile};
|
use Mojo::File qw{curfile};
|
||||||
use lib curfile->dirname->sibling('lib')->to_string;
|
use lib curfile->dirname->sibling('lib')->to_string;
|
||||||
use Mojolicious::Commands;
|
use Mojolicious::Commands;
|
||||||
|
|
17
t/admin.t
17
t/admin.t
|
@ -10,6 +10,11 @@ my %valid_login = (
|
||||||
);
|
);
|
||||||
|
|
||||||
subtest Login => sub {
|
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)
|
$t->post_ok('/login', form => \%valid_login)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{moderator/flagged});
|
->header_like(Location => qr{moderator/flagged});
|
||||||
|
@ -31,9 +36,10 @@ subtest Login => sub {
|
||||||
$t->get_ok('/moderator/admin/create')
|
$t->get_ok('/moderator/admin/create')
|
||||||
->status_is(200)
|
->status_is(200)
|
||||||
->text_like(h2 => qr/Create Moderator/)
|
->text_like(h2 => qr/Create Moderator/)
|
||||||
->element_exists('form input[name="name"]' )
|
->element_exists('form input[name="name"]' )
|
||||||
->element_exists('form input[name="email"]' )
|
->element_exists('form input[name="email"]' )
|
||||||
->element_exists('form input[name="password"]')
|
->element_exists('form input[name="password"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]')
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest Reset => sub {
|
subtest Reset => sub {
|
||||||
|
@ -43,6 +49,7 @@ subtest Login => sub {
|
||||||
->element_exists('a[href*="/moderator/admin/reset"]')
|
->element_exists('a[href*="/moderator/admin/reset"]')
|
||||||
->element_exists('form input[name="email"]' )
|
->element_exists('form input[name="email"]' )
|
||||||
->element_exists('form input[name="password"]' )
|
->element_exists('form input[name="password"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]' )
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest Lock => sub {
|
subtest Lock => sub {
|
||||||
|
@ -51,6 +58,7 @@ subtest Login => sub {
|
||||||
->text_like(h2 => qr/Lock Account/)
|
->text_like(h2 => qr/Lock Account/)
|
||||||
->element_exists('a[href*="/moderator/admin/lock"]')
|
->element_exists('a[href*="/moderator/admin/lock"]')
|
||||||
->element_exists('form input[name="email"]' )
|
->element_exists('form input[name="email"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]' )
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest Unlock => sub {
|
subtest Unlock => sub {
|
||||||
|
@ -59,6 +67,7 @@ subtest Login => sub {
|
||||||
->text_like(h2 => qr/Unlock Account/)
|
->text_like(h2 => qr/Unlock Account/)
|
||||||
->element_exists('a[href*="/moderator/admin/unlock"]')
|
->element_exists('a[href*="/moderator/admin/unlock"]')
|
||||||
->element_exists('form input[name="email"]' )
|
->element_exists('form input[name="email"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]' )
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest Promote => sub {
|
subtest Promote => sub {
|
||||||
|
@ -67,6 +76,7 @@ subtest Login => sub {
|
||||||
->text_like(h2 => qr/Promote Moderator/)
|
->text_like(h2 => qr/Promote Moderator/)
|
||||||
->element_exists('a[href*="/moderator/admin/promote"]')
|
->element_exists('a[href*="/moderator/admin/promote"]')
|
||||||
->element_exists('form input[name="email"]' )
|
->element_exists('form input[name="email"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]' )
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest Demote => sub {
|
subtest Demote => sub {
|
||||||
|
@ -75,6 +85,7 @@ subtest Login => sub {
|
||||||
->text_like(h2 => qr/Demote Admin/)
|
->text_like(h2 => qr/Demote Admin/)
|
||||||
->element_exists('a[href*="/moderator/admin/demote"]')
|
->element_exists('a[href*="/moderator/admin/demote"]')
|
||||||
->element_exists('form input[name="email"]' )
|
->element_exists('form input[name="email"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]' )
|
||||||
};
|
};
|
||||||
|
|
||||||
# Admin session ends
|
# Admin session ends
|
||||||
|
|
55
t/human.t
55
t/human.t
|
@ -25,18 +25,39 @@ subtest 'Bumping thread', sub {
|
||||||
$t->get_ok('/human/thread/bump/1')->status_is(302)
|
$t->get_ok('/human/thread/bump/1')->status_is(302)
|
||||||
->header_like(Location => qr/captcha/);
|
->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 CAPTCHA
|
||||||
|
$bad_bot{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok($bump_thread_url, form => \%bad_bot)
|
$t->post_ok($bump_thread_url, form => \%bad_bot)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->element_exists('p[class="stash-with-error"]')
|
->element_exists('p[class="stash-with-error"]')
|
||||||
->text_like(p => qr/Sounds like something a robot would say/);
|
->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)
|
$t->post_ok($bump_thread_url, form => \%invalid_captcha)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->element_exists('p[class="field-with-error"]')
|
->element_exists('p[class="field-with-error"]')
|
||||||
->text_like(p => qr/Should be a single number/);
|
->text_like(p => qr/Should be a single number/);
|
||||||
|
|
||||||
# Solved CAPTCHA
|
# 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)
|
$t->post_ok($bump_thread_url, form => \%good_human)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{human/thread/bump/1});
|
->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)
|
$t->get_ok('/human/thread/flag/1')->status_is(302)
|
||||||
->header_like(Location => qr/captcha/);
|
->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 CAPTCHA
|
||||||
|
$bad_bot{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok($flag_thread_url, form => \%bad_bot)
|
$t->post_ok($flag_thread_url, form => \%bad_bot)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->element_exists('p[class="stash-with-error"]')
|
->element_exists('p[class="stash-with-error"]')
|
||||||
->text_like(p => qr/Sounds like something a robot would say/);
|
->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)
|
$t->post_ok($flag_thread_url, form => \%invalid_captcha)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->element_exists('p[class="field-with-error"]')
|
->element_exists('p[class="field-with-error"]')
|
||||||
->text_like(p => qr/Should be a single number/);
|
->text_like(p => qr/Should be a single number/);
|
||||||
|
|
||||||
# Solved CAPTCHA
|
# 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)
|
$t->post_ok($flag_thread_url, form => \%good_human)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{human/thread/flag/1});
|
->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)
|
$t->get_ok('/human/remark/flag/1')->status_is(302)
|
||||||
->header_like(Location => qr/captcha/);
|
->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 CAPTCHA
|
||||||
|
$bad_bot{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok($flag_remark_url, form => \%bad_bot)
|
$t->post_ok($flag_remark_url, form => \%bad_bot)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->element_exists('p[class="stash-with-error"]')
|
->element_exists('p[class="stash-with-error"]')
|
||||||
->text_like(p => qr/Sounds like something a robot would say/);
|
->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)
|
$t->post_ok($flag_remark_url, form => \%invalid_captcha)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->element_exists('p[class="field-with-error"]')
|
->element_exists('p[class="field-with-error"]')
|
||||||
->text_like(p => qr/Should be a single number/);
|
->text_like(p => qr/Should be a single number/);
|
||||||
|
|
||||||
# Solved CAPTCHA
|
# 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)
|
$t->post_ok($flag_remark_url, form => \%good_human)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{human/remark/flag/1});
|
->header_like(Location => qr{human/remark/flag/1});
|
||||||
|
|
|
@ -17,16 +17,28 @@ my %invalid_login = (
|
||||||
subtest Login => sub {
|
subtest Login => sub {
|
||||||
$t->get_ok('/login')
|
$t->get_ok('/login')
|
||||||
->status_is(200)
|
->status_is(200)
|
||||||
->element_exists('form input[name="email"]')
|
->element_exists('form input[name="email"]' )
|
||||||
->element_exists('form input[name="password"]')
|
->element_exists('form input[name="password"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]')
|
||||||
->text_like(h2 => qr/Moderator Login/);
|
->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)
|
$t->post_ok('/login', form => \%invalid_login)
|
||||||
->status_is(403)
|
->status_is(403)
|
||||||
->element_exists('form input[name="email"]')
|
->element_exists('form input[name="email"]')
|
||||||
->element_exists('form input[name="password"]')
|
->element_exists('form input[name="password"]')
|
||||||
->text_like(p => qr/Invalid login/);
|
->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)
|
$t->post_ok('/login', form => \%valid_login)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{moderator/flagged});
|
->header_like(Location => qr{moderator/flagged});
|
||||||
|
|
55
t/post.t
55
t/post.t
|
@ -44,6 +44,11 @@ $t->get_ok('/human/remark/post/1')->status_is(302)
|
||||||
->header_like(Location => qr/captcha/);
|
->header_like(Location => qr/captcha/);
|
||||||
|
|
||||||
# Do CAPTCHA
|
# Do CAPTCHA
|
||||||
|
$t->get_ok($bump_thread_url);
|
||||||
|
|
||||||
|
$good_captcha{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok($bump_thread_url, form => \%good_captcha)
|
$t->post_ok($bump_thread_url, form => \%good_captcha)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{human/thread/bump/1});
|
->header_like(Location => qr{human/thread/bump/1});
|
||||||
|
@ -53,10 +58,11 @@ $t->ua->max_redirects(1);
|
||||||
subtest 'Post new thread', sub {
|
subtest 'Post new thread', sub {
|
||||||
# GET
|
# GET
|
||||||
$t->get_ok('/human/thread/post')->status_is(200)
|
$t->get_ok('/human/thread/post')->status_is(200)
|
||||||
->element_exists('form input[name="author"]' )
|
->element_exists('form input[name="author"]' )
|
||||||
->element_exists('form input[name="title"]' )
|
->element_exists('form input[name="title"]' )
|
||||||
->element_exists('form textarea[name="body"]')
|
->element_exists('form textarea[name="body"]' )
|
||||||
->element_exists('form button[type="submit"]' )
|
->element_exists('form button[type="submit"]' )
|
||||||
|
->element_exists('form input[name="csrf_token"]')
|
||||||
->text_like(h2 => qr/New Thread/);
|
->text_like(h2 => qr/New Thread/);
|
||||||
|
|
||||||
# POST
|
# POST
|
||||||
|
@ -64,17 +70,31 @@ subtest 'Post new thread', sub {
|
||||||
->element_exists('form input[name="author"]' )
|
->element_exists('form input[name="author"]' )
|
||||||
->element_exists('form input[name="title"]' )
|
->element_exists('form input[name="title"]' )
|
||||||
->element_exists('form textarea[name="body"]')
|
->element_exists('form textarea[name="body"]')
|
||||||
->element_exists('form button[type="submit"]' )
|
->element_exists('form button[type="submit"]')
|
||||||
->text_like(h2 => qr/New Thread/);
|
->text_like(h2 => qr/New Thread/);
|
||||||
|
|
||||||
|
# No CSRF token
|
||||||
|
$t->post_ok('/human/thread/post', form => \%valid_thread)
|
||||||
|
->status_is(403)
|
||||||
|
->text_like(p => qr/Something went wrong/);
|
||||||
|
|
||||||
|
$invalid_title{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/thread/post', form => \%invalid_title)
|
$t->post_ok('/human/thread/post', form => \%invalid_title)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->text_like(p => qr/Must be between/);
|
->text_like(p => qr/Must be between/);
|
||||||
|
|
||||||
|
$invalid_thread{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/thread/post', form => \%invalid_thread)
|
$t->post_ok('/human/thread/post', form => \%invalid_thread)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->text_like(p => qr/Must be between/);
|
->text_like(p => qr/Must be between/);
|
||||||
|
|
||||||
|
$valid_thread{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/thread/post', form => \%valid_thread)
|
$t->post_ok('/human/thread/post', form => \%valid_thread)
|
||||||
->status_is(200)
|
->status_is(200)
|
||||||
->text_like(h2 => qr/Thread #\d+/);
|
->text_like(h2 => qr/Thread #\d+/);
|
||||||
|
@ -85,29 +105,44 @@ subtest 'Post new remark', sub {
|
||||||
$t->get_ok('/human/remark/post/1')->status_is(200)
|
$t->get_ok('/human/remark/post/1')->status_is(200)
|
||||||
->element_exists('form input[name="author"]' )
|
->element_exists('form input[name="author"]' )
|
||||||
->element_exists('form textarea[name="body"]')
|
->element_exists('form textarea[name="body"]')
|
||||||
->element_exists('form button[type="submit"]' )
|
->element_exists('form button[type="submit"]')
|
||||||
->text_like(h2 => qr/Remark on Thread #/);
|
->text_like(h2 => qr/Remark on Thread #/);
|
||||||
$t->get_ok('/human/remark/post/65536')->status_is(404)
|
$t->get_ok('/human/remark/post/65536')->status_is(404)
|
||||||
->text_like(p => qr/Thread not found/);
|
->text_like(p => qr/Thread not found/);
|
||||||
# Test the remark-to-remark thing
|
# Test the remark-to-remark thing
|
||||||
$t->get_ok('/human/remark/post/1/1')->status_is(200)
|
$t->get_ok('/human/remark/post/1/1')->status_is(200)
|
||||||
->element_exists('form input[name="author"]' )
|
->element_exists('form input[name="author"]' )
|
||||||
->element_exists('form textarea[name="body"]')
|
->element_exists('form textarea[name="body"]' )
|
||||||
->element_exists('form button[type="submit"]' )
|
->element_exists('form button[type="submit"]' )
|
||||||
->element_exists('a[href$="/remark/single/1"]')
|
->element_exists('a[href$="/remark/single/1"]')
|
||||||
->text_like(h3 => qr/Last Remark/);
|
->text_like(h3 => qr/Last Remark/);
|
||||||
|
|
||||||
# POST
|
# POST
|
||||||
$t->post_ok('/human/remark/post/1')->status_is(200)
|
$t->post_ok('/human/remark/post/1')->status_is(200)
|
||||||
->element_exists('form input[name="author"]' )
|
->element_exists('form input[name="author"]' )
|
||||||
->element_exists('form textarea[name="body"]')
|
->element_exists('form textarea[name="body"]' )
|
||||||
->element_exists('form button[type="submit"]' )
|
->element_exists('form button[type="submit"]' )
|
||||||
->text_like(h2 => qr/Remark on Thread #/);
|
->text_like(h2 => qr/Remark on Thread #/);
|
||||||
|
|
||||||
|
# No CSRF token
|
||||||
|
$t->post_ok('/human/remark/post/1', form => \%valid_remark)
|
||||||
|
->status_is(403)
|
||||||
|
->text_like(p => qr/Something went wrong/);
|
||||||
|
|
||||||
|
$t->get_ok('/human/remark/post/1');
|
||||||
|
|
||||||
|
$valid_remark{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/remark/post/1', form => \%valid_remark)
|
$t->post_ok('/human/remark/post/1', form => \%valid_remark)
|
||||||
->status_is(200)
|
->status_is(200)
|
||||||
->text_like(h2 => qr/Thread #1/);
|
->text_like(h2 => qr/Thread #1/);
|
||||||
|
|
||||||
|
$t->get_ok('/human/remark/post/1');
|
||||||
|
|
||||||
|
$invalid_remark{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/remark/post/1', form => \%invalid_remark)
|
$t->post_ok('/human/remark/post/1', form => \%invalid_remark)
|
||||||
->status_is(400)
|
->status_is(400)
|
||||||
->text_like(p => qr/Must be between/);
|
->text_like(p => qr/Must be between/);
|
||||||
|
|
15
t/preview.t
15
t/preview.t
|
@ -23,6 +23,11 @@ my %preview_remark = (
|
||||||
);
|
);
|
||||||
|
|
||||||
# Do CAPTCHA
|
# Do CAPTCHA
|
||||||
|
$t->get_ok($bump_thread_url);
|
||||||
|
|
||||||
|
$good_captcha{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok($bump_thread_url, form => \%good_captcha)
|
$t->post_ok($bump_thread_url, form => \%good_captcha)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{human/thread/bump/1});
|
->header_like(Location => qr{human/thread/bump/1});
|
||||||
|
@ -36,10 +41,20 @@ subtest 'Check the form + button', sub {
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest 'Submit input', sub {
|
subtest 'Submit input', sub {
|
||||||
|
$t->get_ok('/human/remark/post/1');
|
||||||
|
|
||||||
|
$preview_remark{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/remark/post/1', form => \%preview_remark)
|
$t->post_ok('/human/remark/post/1', form => \%preview_remark)
|
||||||
->status_is(200)
|
->status_is(200)
|
||||||
->text_like(p => qr/ayy\.\.\. lmao/);
|
->text_like(p => qr/ayy\.\.\. lmao/);
|
||||||
|
|
||||||
|
$t->get_ok('/human/thread/post');
|
||||||
|
|
||||||
|
$preview_thread{'csrf_token'} =
|
||||||
|
$t->tx->res->dom->at('input[name="csrf_token"]')->val;
|
||||||
|
|
||||||
$t->post_ok('/human/thread/post', form => \%preview_thread)
|
$t->post_ok('/human/thread/post', form => \%preview_thread)
|
||||||
->status_is(200)
|
->status_is(200)
|
||||||
->text_like(p => qr/ayy\.\.\. lmao/);
|
->text_like(p => qr/ayy\.\.\. lmao/);
|
||||||
|
|
10
t/redirect_old_path.t
Normal file
10
t/redirect_old_path.t
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use Mojo::Base -strict;
|
||||||
|
use Test::More;
|
||||||
|
use Test::Mojo;
|
||||||
|
|
||||||
|
my $t = Test::Mojo->new('PostText');
|
||||||
|
|
||||||
|
$t->get_ok('/thread/post')->status_is(302)
|
||||||
|
->header_like(Location => qr{human/thread/post});
|
||||||
|
|
||||||
|
done_testing;
|
11
t/search.t
11
t/search.t
|
@ -8,12 +8,23 @@ my %good_human = (answer => 1, number => 'Ⅰ');
|
||||||
my $search_url =
|
my $search_url =
|
||||||
'/captcha/H4sIABJ8PGUAA8soKSmw0tfPyU9OzMnILy6xMjYwMNDPKM1NzNMvTk0sSs4AAPrUR3kiAAAA%0A';
|
'/captcha/H4sIABJ8PGUAA8soKSmw0tfPyU9OzMnILy6xMjYwMNDPKM1NzNMvTk0sSs4AAPrUR3kiAAAA%0A';
|
||||||
|
|
||||||
|
subtest 'Search form', sub {
|
||||||
|
$t->get_ok('/thread/list')
|
||||||
|
->element_exists('form input[name="q"]' )
|
||||||
|
->element_exists('form button[type="submit"]');
|
||||||
|
};
|
||||||
|
|
||||||
subtest 'Search before CAPTCHA', sub {
|
subtest 'Search before CAPTCHA', sub {
|
||||||
$t->get_ok('/human/search')->status_is(302)
|
$t->get_ok('/human/search')->status_is(302)
|
||||||
->header_like(Location => qr/captcha/);
|
->header_like(Location => qr/captcha/);
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest 'Search after 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)
|
$t->post_ok($search_url, form => \%good_human)
|
||||||
->status_is(302)
|
->status_is(302)
|
||||||
->header_like(Location => qr{human/search});
|
->header_like(Location => qr{human/search});
|
||||||
|
|
|
@ -18,5 +18,6 @@
|
||||||
<%= label_for password => 'Password' %>
|
<%= label_for password => 'Password' %>
|
||||||
<%= password_field password => (id => 'password') %>
|
<%= password_field password => (id => 'password') %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Reset</button>
|
<button type="submit" class="form-button">Reset</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -26,5 +26,6 @@
|
||||||
<%= label_for password => 'Password' %>
|
<%= label_for password => 'Password' %>
|
||||||
<%= password_field password => (id => 'password') %>
|
<%= password_field password => (id => 'password') %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Create</button>
|
<button type="submit" class="form-button">Create</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -10,5 +10,6 @@
|
||||||
<%= label_for email => 'Email' %>
|
<%= label_for email => 'Email' %>
|
||||||
<%= email_field email => (id => 'email', autofocus => undef) %>
|
<%= email_field email => (id => 'email', autofocus => undef) %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Demote</button>
|
<button type="submit" class="form-button">Demote</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -10,5 +10,6 @@
|
||||||
<%= label_for email => 'Email' %>
|
<%= label_for email => 'Email' %>
|
||||||
<%= email_field email => (id => 'email', autofocus => undef) %>
|
<%= email_field email => (id => 'email', autofocus => undef) %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Lock</button>
|
<button type="submit" class="form-button">Lock</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -12,11 +12,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<% if (my $error = validation->error('password')) { =%>
|
<% if (my $error = validation->error('password')) { =%>
|
||||||
<p class="field-with-error">Must be between <%= $error->[2] %>
|
<p class="field-with-error">Must be atleast <%= $error->[2] %>
|
||||||
and <%= $error->[3] %> characters.</p>
|
characters.</p>
|
||||||
<% } =%>
|
<% } =%>
|
||||||
<%= label_for password => 'Password' %>
|
<%= label_for password => 'Password' %>
|
||||||
<%= password_field password => (id => 'password') %>
|
<%= password_field password => (id => 'password') %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Login</button>
|
<button type="submit" class="form-button">Login</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<%= label_for password => 'Password' %>
|
<%= label_for password => 'Password' %>
|
||||||
<%= password_field password => (id => 'password', autofocus => undef) %>
|
<%= password_field password => (id => 'password', autofocus => undef) %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Reset</button>
|
<button type="submit" class="form-button">Reset</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
@ -10,5 +10,6 @@
|
||||||
<%= label_for email => 'Email' %>
|
<%= label_for email => 'Email' %>
|
||||||
<%= email_field email => (id => 'email', autofocus => undef) %>
|
<%= email_field email => (id => 'email', autofocus => undef) %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Promote</button>
|
<button type="submit" class="form-button">Promote</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -10,5 +10,6 @@
|
||||||
<%= label_for email => 'Email' %>
|
<%= label_for email => 'Email' %>
|
||||||
<%= email_field email => (id => 'email', autofocus => undef) %>
|
<%= email_field email => (id => 'email', autofocus => undef) %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Unlock</button>
|
<button type="submit" class="form-button">Unlock</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -26,5 +26,6 @@
|
||||||
) %>
|
) %>
|
||||||
</div>
|
</div>
|
||||||
<%= hidden_field number => $roman_numeral, id => 'number' %>
|
<%= hidden_field number => $roman_numeral, id => 'number' %>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Answer</button>
|
<button type="submit" class="form-button">Answer</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
<%= check_box preview => 1, id => 'preview' %>
|
<%= check_box preview => 1, id => 'preview' %>
|
||||||
<%= label_for preview => 'Preview' %>
|
<%= label_for preview => 'Preview' %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Post</button>
|
<button type="submit" class="form-button">Post</button>
|
||||||
</form>
|
</form>
|
||||||
<%# Putting this first above the thread body (nested if, yucky sry) %>
|
<%# Putting this first above the thread body (nested if, yucky sry) %>
|
||||||
|
|
|
@ -61,5 +61,6 @@
|
||||||
<%= check_box preview => 1, id => 'preview' %>
|
<%= check_box preview => 1, id => 'preview' %>
|
||||||
<%= label_for preview => 'Preview' %>
|
<%= label_for preview => 'Preview' %>
|
||||||
</div>
|
</div>
|
||||||
|
<%= csrf_field %>
|
||||||
<button type="submit" class="form-button">Post</button>
|
<button type="submit" class="form-button">Post</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user