#!/usr/bin/perl # This file is part of sakisafe. use if $^O eq "openbsd", OpenBSD::Pledge, qw(pledge); use Mojolicious::Lite -signatures; use Mojolicious::Routes::Pattern; use List::MoreUtils qw(uniq); use Carp; use Term::ANSIColor; use English; use MIME::Types; use Path::Tiny; use warnings; use experimental 'signatures'; use feature 'say'; plugin 'RenderFile'; # OpenBSD promises. pledge("stdio prot_exec cpath rpath wpath inet flock fattr") if $^O eq "openbsd"; # 500 MBs my $MAX_SIZE = 1024 * 1024 * 1000; my @BANNED = eval { path('banned.txt')->slurp_utf8 } or qw(79.117.57.61); # Add banned IP addresses here my @BANNED_EXTS = eval { path('banned_exts.txt')->slurp_utf8 } or qw(); # Add forbidden files extensions here my $dirname; my $link; mkdir "f"; # Function to handle file uploads sub logger ( $level, $address, $message ) { open( my $fh, ">>", "sakisafe.log" ); printf( $fh "[%s]: %s has uploaded file %s\n", $level, $address, $message ); printf("[%s]: %s has uploaded file %s\n", $level, $address, $message ); close($fh); } sub handle_file { my $c = shift; my $filedata = $c->param("file"); if ( $filedata->size > $MAX_SIZE ) { return $c->render( text => "Max upload size: $MAX_SIZE", status => 400 ); } if ( List::MoreUtils::any { /$c->req->headers->header('X-Forwarded-For')/ } uniq @BANNED ) { $c->render( text => "Hi! Seems like the server admin added your IP address to the banned IP array." . "As the developer of sakisafe, I can't do anything.", status => 403 ); return; } # Generate random string for the directory my @chars = ( '0' .. '9', 'a' .. 'Z' ); $dirname .= $chars[ rand @chars ] for 1 .. 5; my $filename = $filedata->filename; my ($ext) = $filename =~ /(\.[^.]+)$/; if ( List::MoreUtils::any { /$ext/ } uniq @BANNED_EXTS ) { $c->render( text => "You cannot this filetype.\n", status => 415 ); say $ext; logger( "WARN", $c->req->headers->header('X-Forwarded-For'), $dirname . "/" . $filename ); return; } carp( color("bold yellow"), "sakisafe warning: could not create directory: $ERRNO", color("reset") ) unless mkdir( "f/" . $dirname ); $filename .= ".txt" if $filename eq "-"; # TODO: get whether the server is http or https # There's a CGI ENV variable for that. my $host = $c->req->url->to_abs->host; my $ua = $c->req->headers->user_agent; $filedata->move_to( "f/" . $dirname . "/" . $filename ); $link = "http://$host/f/$dirname/$filename"; $c->stash( link => $link, host => $host, dirname => $dirname ); $c->res->headers->header( 'Location' => "$link" . $filename ); # Only give the link to curl, html template for others. if ( $ua =~ m/curl/ || $ua eq "" ) { $c->render( text => $link . "\n", status => 201, ); $dirname = ""; } else { $c->render( template => 'file', status => 201, ); } logger( "INFO", $c->req->headers->header('X-Forwarded-For'), $dirname . "/" . $filename ); $dirname = ""; } # Function to log uploaded files get '/' => 'index'; post '/' => sub ($c) { handle_file($c) }; # Allow files to be downloaded. get '/f/:dir/#name' => sub ($c) { my $dir = $c->param("dir"); my $file = $c->param("name"); my $ext = $file; $ext =~ s/.*\.//; my $path = "f/" . $dir . "/" . $file; #carp "sakisafe warning: could not get file: $ERRNO" unless $c->render( text => "file not found", status => 404 ) unless -e $path; $c->render_file( filepath => $path, format => $ext, content_disposition => 'inline' ); }; app->max_request_size( 1024 * 1024 * 100 ); post '/upload' => sub ($c) { handle_file($c) }; app->start; # Index template # By default Mojolicious gets the "directory root" from the "public" # directory, so the css and the favicon from the "public" directory, # in the root of this repo. # Not sure why I have to do this filthy hack, could not get Mojolicious # to get the template here. So a TODO is to fix this. __DATA__ @@ file.html.ep sakisafe

sakisafe

shitless file upload, pastebin and url shorter

LINK

<%= $link %>

Running sakisafe 2.4.0

__END__ @@ index.html.ep sakisafe

sakisafe

shitless file upload, pastebin and url shorter

USAGE

POST a file:

curl -F 'file=@yourfile.png' https://<%= $c->req->url->to_abs->host; %>

Post your text directly

curl -F 'file=@-' https://<%= $c->req->url->to_abs->host; %>
Git repository

Running sakisafe 2.4.0

FAQ

(No one has ever asked these questions)

How long are the files stored? Until the heat death of the universe

Do you log IP addresses? Yes. Blame the people uploading illegal stuff to this

Or just upload a file here

__END__ =pod =head1 sakisafe sakisafe is a web application using the Mojolicious framework which allow users to simply upload and share files. =head2 synopsis C<./sakisafe.pl daemon -m production> This will start sakisafe in port 3000. Which should be proxied with nginx or any reverse proxy software. =head2 license The Unlicense. =head2 author Raoul Vaughn =cut