lufi/t/test.t

316 lines
9.1 KiB
Perl

# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
use Mojo::Base -strict;
use Mojo::File;
use Mojo::JSON qw(to_json from_json true false);
use Mojolicious;
use Test::More;
use Test::Mojo;
use Lufi::DB::File;
use Lufi::DB::Slice;
use FindBin qw($Bin);
my ($m, $cfile, $config_orig, $config_file, $config_content);
my $msg = Encode::encode_utf8(to_json {
"total" => 1,
"part" => 0,
"size" => 7,
"name" => "foobaré.txt",
"type" => "text/plain",
"delay" => "0",
"del_at_first_view" => 1,
"id" => undef,
"zipped" => 0,
"i" => 0
});
my $filename_test = Encode::encode_utf8('foobaré');
my $encrypted = '"{\\"iv\\":\\"2RGAviAeYybBqcLCmnqlgA==\\",\\"v\\":1,\\"iter\\":10000,\\"ks\\":128,\\"ts\\":64,\\"mode\\":\\"ccm\\",\\"adata\\":\\"\\",\\"cipher\\":\\"aes\\",\\"salt\\":\\"1dvKtbZ8hxA=\\",\\"ct\\":\\"w9wDZCwNSyH/yL7q1GW5fPSdi+w=\\"}"';
my $encrypted_rgx = $encrypted;
$encrypted_rgx =~ s@\\@\\\\@g;
$encrypted_rgx =~ s@\+@\\+@g;
$encrypted_rgx =~ s@(\{|\})@\\$1@g;
BEGIN {
use lib 'lib';
$m = Mojolicious->new;
$cfile = Mojo::File->new($Bin, '..', 'lufi.conf');
if (defined $ENV{MOJO_CONFIG}) {
$cfile = Mojo::File->new($ENV{MOJO_CONFIG});
unless (-e $cfile->to_abs) {
$cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG});
}
}
my $config = $m->plugin(
'Config' => {
file => $cfile->to_abs->to_string,
default => {
prefix => '/',
provisioning => 100,
provis_step => 5,
length => 10,
token_length => 32,
secrets => ['hfudsifdsih'],
default_delay => 0,
max_delay => 0,
mail => {
how => 'sendmail'
},
mail_sender => 'no-reply@lufi.io',
theme => 'default',
upload_dir => 'files',
session_duration => 3600,
allow_pwd_on_files => 0,
dbtype => 'sqlite',
db_path => 'lufi.db',
force_burn_after_reading => 0,
x_frame_options => 'DENY',
x_content_type_options => 'nosniff',
x_xss_protection => '1; mode=block',
}
}
);
$m->plugin('Lufi::Plugin::Helpers');
$m->plugin('DebugDumperHelper');
} ## end BEGIN
Lufi::DB::Slice->new(app => $m)->delete_all;
Lufi::DB::File->new(app => $m)->delete_all;
$config_file = Mojo::File->new($cfile->to_abs->to_string);
$config_orig = $config_file->slurp;
my $t = Test::Mojo->new('Lufi');
## Wait for short generation
sleep 5;
## Let's go
$t->get_ok('/')
->status_is(200)
->content_like(qr@Lufi@i);
test_infos_api(false);
test_upload_file();
test_download_file();
## Test htpasswd
switch_to_htpasswd();
test_infos_api(true);
auth_test_suite('luc', 'toto');
restore_config();
## Test LDAP
switch_to_ldap();
test_infos_api(true);
auth_test_suite('zoidberg', 'zoidberg');
restore_config();
## Test Swift object storage
switch_to_swift();
test_upload_file();
test_download_file();
restore_config();
done_testing();
######
### Functions
##
sub test_infos_api {
my $auth = shift;
$t->get_ok('/about/config')
->status_is(200)
->json_has(
'/allow_pwd_on_files', '/need_authentication', '/max_delay',
'/instance_name', '/broadcast_message', '/max_file_size',
'/keep_ip_during', '/report', '/stop_upload',
'/delay_for_size', '/default_delay', '/force_burn_after_reading'
)
->json_is(
'/allow_pwd_on_files' => 1,
'/need_authentication' => $auth,
'/max_delay' => 0,
'/instance_name' => 'Lufi',
'/broadcast_message' => undef,
'/max_file_size' => undef,
'/keep_ip_during' => 365,
'/report' => 'mailto:report@example.com',
'/stop_upload' => false,
'/delay_for_size' => undef,
'/default_delay' => 0,
'/force_burn_after_reading' => 0
);
}
sub test_upload_file {
$t->websocket_ok('/upload/')
->send_ok($msg.'XXMOJOXX'.$encrypted)
->message_ok
->message_like(qr@"created_at":\d+@)
->message_like(qr@"del_at_first_view":true@)
->message_like(qr@"delay":0@)
->message_like(qr@"duration":\d+@)
->message_like(qr@"i":0@)
->message_like(qr@"j":0@)
->message_like(qr@"name":"$filename_test\.txt"@)
->message_like(qr@"parts":1@)
->message_like(qr@"sent_delay":0@)
->message_like(qr@"short":"[^"]+"@)
->message_like(qr@"size":7@)
->message_like(qr@"success":true@)
->message_like(qr@"token":"[^"]+"}@)
->finish_ok;
}
sub test_download_file {
my $ws_msg;
$t->ua->websocket_p('/upload/')->then(sub {
my $tx = shift;
my $promise = Mojo::Promise->new;
$tx->on(finish => sub { $promise->resolve });
$tx->on(message => sub {
my $tx = shift;
$ws_msg = shift;
$tx->finish;
});
$tx->send($msg.'XXMOJOXX'.$encrypted);
return $promise;
})->catch(sub {
my $err = shift;
is($err, undef);
})->wait;
$ws_msg = from_json($ws_msg);
$t->websocket_ok('/download/'.$ws_msg->{short})
->send_ok(to_json({part => 0}))
->message_ok
->message_like(qr@"total":1@)
->message_like(qr@"part":0@)
->message_like(qr@"i":0@)
->message_like(qr@"id":null@)
->message_like(qr@"del_at_first_view":1@)
->message_like(qr@"delay":"0"@)
->message_like(qr@"name":"$filename_test\.txt"@)
->message_like(qr@"size":7@)
->message_like(qr@"type":"text\\/plain"@)
->message_like(qr@XXMOJOXX@)
->message_like(qr@$encrypted_rgx@)
->send_ok(to_json({ended => true}))
->finish_ok;
# The file is not supposed to be available anymore
$t->websocket_ok('/download/'.$ws_msg->{short})
->send_ok(to_json({part => 0}))
->message_ok
->message_like(qr@"msg":"Error: the file existed but was deleted\."@)
->message_like(qr@"success":false@)
->send_ok(to_json({ended => true}))
->finish_ok;
}
sub auth_test_suite {
my ($login, $pass) = @_;
$t->get_ok('/')
->status_is(302)
->header_is(Location => '/login');
test_fail_upload();
test_login($login, $pass);
test_upload_file();
test_download_file();
my $token = '';
$t->post_ok('/logout' => form => { csrf_token => $token })
->status_is(200)
->content_like(qr@Bad CSRF token\.@);
$token = $t->ua->get('/')->res->dom->find('input[name="csrf_token"]')->first->attr('value');
$t->post_ok('/logout' => form => { csrf_token => $token })
->status_is(200)
->content_like(qr@You have been successfully logged out\.@);
test_fail_upload();
}
sub test_fail_upload {
# An empty message would make it fail if we were allowed to go in the authenticated part
$t->websocket_ok('/upload/')
->send_ok('')
->finish_ok;
}
sub test_login {
my ($login, $pass) = @_;
$t->get_ok('/login')
->status_is(200)
->content_like(qr@Signin@);
my $token = '';
$t->post_ok('/login' => form => { login => $login, password => $pass, csrf_token => $token })
->status_is(200)
->content_like(qr@Bad CSRF token\.@);
$token = $t->ua->get('/login')->res->dom->find('input[name="csrf_token"]')->first->attr('value');
$t->post_ok('/login' => form => { login => $login, password => $pass, csrf_token => $token })
->status_is(302)
->header_is(Location => '/');
$t->get_ok('/login')
->status_is(302)
->header_is(Location => '/');
}
sub restore_config {
$config_file->spurt($config_orig);
}
sub switch_to_htpasswd {
$config_content = $config_orig;
$config_content =~ s/#?htpasswd.*/htpasswd => 't\/lufi.passwd',/gm;
$config_file->spurt($config_content);
Lufi::DB::Slice->new(app => $m)->delete_all;
Lufi::DB::File->new(app => $m)->delete_all;
$t = Test::Mojo->new('Lufi');
## Wait for short generation
sleep 5;
}
sub switch_to_ldap {
$config_content = $config_orig;
$config_content =~ s/^( +)#?ldap => \{ uri/$1ldap => { uri/gm;
$config_file->spurt($config_content);
Lufi::DB::Slice->new(app => $m)->delete_all;
Lufi::DB::File->new(app => $m)->delete_all;
$t = Test::Mojo->new('Lufi');
## Wait for short generation
sleep 5;
}
sub switch_to_swift {
$config_content = $config_orig;
$config_content =~ s/^( +)#?swift => \{ auth_url/$1swift => { auth_url/gm;
$config_file->spurt($config_content);
Lufi::DB::Slice->new(app => $m)->delete_all;
Lufi::DB::File->new(app => $m)->delete_all;
$t = Test::Mojo->new('Lufi');
## Wait for short generation
sleep 5;
}