Compare commits
10 Commits
a804518ef6
...
47d733b2f4
Author | SHA1 | Date |
---|---|---|
Rawley | 47d733b2f4 | |
Barrington | 12d506219a | |
Barrington | 72a3b42d36 | |
Rawley | ac77cbfe4b | |
Barrington | 338c4c2771 | |
Rawley | 1d53129435 | |
Rawley | deb4318cd9 | |
Barrington | 9af44501cc | |
psydbernz | d67de26e90 | |
Barrington | 82422e6d37 |
|
@ -0,0 +1,17 @@
|
|||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: bmake
|
||||
run: bmake
|
|
@ -4,3 +4,14 @@ obj/
|
|||
.clangd
|
||||
.depend
|
||||
http/f/*
|
||||
blib/
|
||||
pm_to_blib
|
||||
Makefile
|
||||
Makefile.old
|
||||
MANIFEST*
|
||||
!MANIFEST.SKIP
|
||||
META.*/
|
||||
MYMETA.*
|
||||
pm_to_blib
|
||||
sakisafe.log
|
||||
f/
|
||||
|
|
11
README.md
11
README.md
|
@ -69,7 +69,15 @@ other file upload services). It also supports file uploading via scp
|
|||
|
||||
### Compilation
|
||||
|
||||
Clone the repo and run `make` (or `bmake` in linux systems)
|
||||
Clone the repo and run `make`.
|
||||
|
||||
#### Linux-specific
|
||||
|
||||
Use `bmake` instead of `make`, and you'll also need these deps:
|
||||
|
||||
* `libcurl-devel`
|
||||
* `libconfig-dev`
|
||||
* `libnghttp2-dev`
|
||||
|
||||
### Repositories
|
||||
|
||||
|
@ -86,3 +94,4 @@ Thanks!
|
|||
**Bitcoin**: bc1qghl6f27dpgktynpvkrxte2s3gm9pcv8vlwuzum
|
||||
|
||||
**Monero**: 47QTumjtqJabbo1s9pLDdXeJarLVLfs1AaEcbi1xrEiV852mqcbe5AHLNXTk7tH9MscxcxQDfJQnvH5LpxvfgwSJQZ3zbS6
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: bmake
|
||||
run: bmake
|
|
@ -0,0 +1,14 @@
|
|||
-pbp # Start with Perl Best Practices
|
||||
-w # Show all warnings
|
||||
-iob # Ignore old breakpoints
|
||||
-l=120 # 120 characters per line
|
||||
-mbl=2 # No more than 2 blank lines
|
||||
-i=5 # Indentation is 2 columns
|
||||
-ci=2 # Continuation indentation is 2 columns
|
||||
-vt=0 # Less vertical tightness
|
||||
-pt=2 # High parenthesis tightness
|
||||
-bt=2 # High brace tightness
|
||||
-sbt=2 # High square bracket tightness
|
||||
-wn # Weld nested containers
|
||||
-isbc # Don't indent comments without leading space
|
||||
-nst # Don't output to STDOUT
|
|
@ -0,0 +1,15 @@
|
|||
FROM perl:latest AS build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
COPY . /sakisafe
|
||||
COPY ./public /sakisafe/public
|
||||
|
||||
WORKDIR /sakisafe
|
||||
|
||||
RUN perl "Makefile.PL"
|
||||
RUN make install
|
||||
RUN cpan List::MoreUtils Path::Tiny MIME::Types Mojolicious Mojolicious::Plugin::RenderFile Mojolicious::Routes::Pattern
|
||||
|
||||
FROM build
|
||||
CMD ["perl", "sakisafe.pl", "daemon"]
|
|
@ -0,0 +1,17 @@
|
|||
use v5.36;
|
||||
|
||||
use ExtUtils::MakeMaker;
|
||||
|
||||
WriteMakefile(
|
||||
NAME => 'sakisafe',
|
||||
CONFIGURE_REQUIRES => {
|
||||
"Mojolicious" => 0,
|
||||
"List::MoreUtils" => 0,
|
||||
"Term::ANSIColor" => 0,
|
||||
"MIME::Types" => 0,
|
||||
"Path::Tiny" => 0,
|
||||
"Mojolicious::Plugin::RenderFile" => 0,
|
||||
"Mojolicious::Routes::Pattern" => 0
|
||||
},
|
||||
EXE_FILES => ['sakisafe.pl']
|
||||
);
|
194
http/sakisafe.pl
194
http/sakisafe.pl
|
@ -1,100 +1,105 @@
|
|||
#!/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 Mojo::Log;
|
||||
use Time::HiRes;
|
||||
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.
|
||||
my $openbsd = 0;
|
||||
$openbsd = 1 if $^O eq "openbsd";
|
||||
pledge("stdio cpath rpath wpath inet flock fattr") if $openbsd;
|
||||
pledge("stdio cpath rpath wpath inet flock fattr") if $^O eq "openbsd";
|
||||
|
||||
# 100 MBs
|
||||
|
||||
my $MAX_SIZE = 1024 * 1024 * 100;
|
||||
|
||||
my @BANNED = qw(); # Add banned IP addresses here
|
||||
my @BANNED = eval { path('banned.txt')->slurp_utf8 } || qw(); # Add banned IP addresses here
|
||||
my $dirname;
|
||||
my $link;
|
||||
|
||||
mkdir "f";
|
||||
|
||||
# Mojo logger
|
||||
my $log = Mojo::Log->new(path => 'sakisafe.log', level => 'trace');
|
||||
$log->color(1);
|
||||
|
||||
# Forward logs to STDERR or STDOUT while also writing to the `sakisafe.log` file.
|
||||
$log->on(
|
||||
message => sub ($l, $level, @lines) {
|
||||
my $time = time;
|
||||
my ($s, $m, $h, $day, $month, $year) = localtime time;
|
||||
$time = sprintf(
|
||||
'%04d-%02d-%02d %02d:%02d:%08.5f',
|
||||
$year + 1900,
|
||||
$month + 1, $day, $h, $m, "$s." . ((split '.', $time)[1] // 0)
|
||||
);
|
||||
my $log_to_print = '[' . $time . '] ' . '[' . $level . '] ' . join(' ', @lines);
|
||||
if ($level eq 'trace' || $level eq 'info') {
|
||||
say $log_to_print;
|
||||
}
|
||||
else {
|
||||
print \*STDERR, $log_to_print . "\n";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# 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 );
|
||||
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->tx->remote_address/ } 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;
|
||||
}
|
||||
my $c = shift;
|
||||
my $filedata = $c->param("file");
|
||||
if ($filedata->size > $MAX_SIZE) {
|
||||
return $c->render(text => "Max upload size: $MAX_SIZE", status => 400);
|
||||
}
|
||||
|
||||
# Generate random string for the directory
|
||||
my @chars = ( '0' .. '9', 'a' .. 'Z' );
|
||||
$dirname .= $chars[ rand @chars ] for 1 .. 5;
|
||||
my $filename = $filedata->filename;
|
||||
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);
|
||||
|
||||
if (List::MoreUtils::any { $c->tx->remote_address } uniq @BANNED) {
|
||||
$log->info("Attempt to upload by banned IP: " . $c->tx->remote_address);
|
||||
$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;
|
||||
}
|
||||
|
||||
$c->res->headers->header(
|
||||
'Location' => "$link" . $filename );
|
||||
# Generate random string for the directory
|
||||
my @chars = ('0' .. '9', 'a' .. 'Z');
|
||||
$dirname .= $chars[rand @chars] for 1 .. 5;
|
||||
my $filename = $filedata->filename;
|
||||
$log->warn("sakisafe warning: could not create directory: $ERRNO") unless mkdir("f/" . $dirname);
|
||||
$filename .= ".txt" if $filename eq "-";
|
||||
|
||||
# Only give the link to curl, html template for others.
|
||||
|
||||
if($ua =~ m/curl/) {
|
||||
$c->render(
|
||||
text => $link . "\n",
|
||||
status => 201,
|
||||
);
|
||||
# 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);
|
||||
|
||||
$dirname = "";
|
||||
} else {
|
||||
$c->render(
|
||||
template => 'file',
|
||||
status => 201,
|
||||
);
|
||||
}
|
||||
logger( "INFO", $c->tx->remote_address, $dirname . "/" . $filename );
|
||||
$dirname = "";
|
||||
$c->res->headers->header('Location' => "$link" . $filename);
|
||||
|
||||
# Only give the link to curl, html template for others.
|
||||
if ($ua =~ m/curl/) {
|
||||
$c->render(text => $link . "\n", status => 201,);
|
||||
|
||||
$dirname = "";
|
||||
}
|
||||
else {
|
||||
$c->render(template => 'file', status => 201,);
|
||||
}
|
||||
|
||||
$log->info($c->tx->remote_address . " " . $dirname . "/" . $filename);
|
||||
$dirname = "";
|
||||
}
|
||||
|
||||
# Function to log uploaded files
|
||||
|
@ -105,23 +110,19 @@ 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;
|
||||
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'
|
||||
);
|
||||
#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 );
|
||||
app->log($log);
|
||||
app->max_request_size(1024 * 1024 * 100);
|
||||
|
||||
post '/upload' => sub ($c) { handle_file($c) };
|
||||
|
||||
|
@ -129,7 +130,7 @@ app->start;
|
|||
|
||||
# Index template
|
||||
|
||||
#By default Mojolicious gets the "directory root" from the "public"
|
||||
# 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.
|
||||
|
||||
|
@ -157,9 +158,6 @@ __DATA__
|
|||
</body>
|
||||
</html>
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
@@ index.html.ep
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
@ -183,10 +181,34 @@ __DATA__
|
|||
<div class="left">
|
||||
<h2>Or just upload a file here</h2>
|
||||
<form ENCTYPE='multipart/form-data' method='post' action='/upload'>
|
||||
<input type='file' name='file' size='30'/>
|
||||
<input type='file' name='file' size='30' required/>
|
||||
<input type='submit' value='upload'/>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
__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
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include <curl/system.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libconfig.h>
|
||||
#include <curl/curl.h>
|
||||
#include <stdbool.h>
|
||||
#include "sakisafecli.h"
|
||||
|
||||
size_t
|
||||
|
@ -27,7 +29,7 @@ print_help()
|
|||
"server\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
|
||||
"-t|--token: Authentication token (https://u.kalli.st)",
|
||||
"-P|--http-proxy: http proxy to use e.g. http://127.0.0.1:4444",
|
||||
"-p|--socks-proxy: SOCK proxy to use e.g.I 127.0.0.1:9050",
|
||||
"-p|--socks-proxy: SOCK proxy to use e.g. 127.0.0.1:9050",
|
||||
"-6|--ipv6: uses IPv6 only",
|
||||
"-4|--ipv6: uses IPv4 only",
|
||||
"-S|--silent: doesn't print progress",
|
||||
|
@ -37,16 +39,18 @@ print_help()
|
|||
return;
|
||||
}
|
||||
|
||||
void
|
||||
size_t
|
||||
progress(
|
||||
void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
/* So I don't get a warning */
|
||||
dltotal += 1;
|
||||
dlnow += 1;
|
||||
printf("\r%0.f uploaded of %0.f (\033[32;1m%0.f%%\033[30;0m)",
|
||||
/* I don't know why the fuck I have to do this */
|
||||
if(ultotal == 0) {
|
||||
ultotal++;
|
||||
}
|
||||
printf("\r%li uploaded of %li (\033[32;1m%li%%\033[30;0m)",
|
||||
ulnow,
|
||||
ultotal,
|
||||
ulnow * 100 / ultotal);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -194,7 +194,9 @@ main(int argc, char **argv)
|
|||
/* Common options for both HTTP and SCP transfers */
|
||||
|
||||
curl_easy_setopt(easy_handle, CURLOPT_NOPROGRESS, silent_flag);
|
||||
curl_easy_setopt(easy_handle, CURLOPT_PROGRESSFUNCTION, progress);
|
||||
struct progress mem;
|
||||
curl_easy_setopt(easy_handle, CURLOPT_XFERINFODATA, &mem);
|
||||
curl_easy_setopt(easy_handle, CURLOPT_XFERINFOFUNCTION, progress);
|
||||
|
||||
/* File name */
|
||||
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
#define SAKISAFECLI_H
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct progress
|
||||
{
|
||||
char *_private;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
size_t
|
||||
write_data(void *buffer, size_t size, size_t nmemb, void *userp);
|
||||
|
@ -15,9 +22,12 @@ store_link(const char *path, const char *buf);
|
|||
void
|
||||
print_help();
|
||||
|
||||
void
|
||||
progress(
|
||||
void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
size_t
|
||||
progress(void *clientp,
|
||||
curl_off_t dltotal,
|
||||
curl_off_t dlnow,
|
||||
curl_off_t ultotal,
|
||||
curl_off_t ulnow);
|
||||
|
||||
void
|
||||
parse_config_file(FILE *config);
|
||||
|
|
Loading…
Reference in New Issue