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