Compare commits

...

10 Commits

Author SHA1 Message Date
Rawley 47d733b2f4
Add .perltidyrc, and format (#24)
* Add .perltidyrc, and format

* Format code

* Change tab size
2023-04-26 18:02:41 +02:00
Barrington 12d506219a
Create c-cpp.yml
this is a test it might be nuked
2023-04-24 16:26:07 +02:00
Barrington 72a3b42d36
Create c-cpp.yml
this is a test it might be nuked
2023-04-24 16:25:58 +02:00
Rawley ac77cbfe4b
Improve logging (#23)
* Greatly improve logging with Mojo::Log
2023-03-24 08:05:01 +01:00
Barrington 338c4c2771
Added POD documentation to sakisafe.pl 2023-03-15 14:54:25 +01:00
Rawley 1d53129435
Add Dockerfile (#22)
* added perl makefile

* fixup gitignore and eval

* add docker file
2023-03-14 13:14:48 +01:00
Rawley deb4318cd9
Add Makefile.PL and allow banned IP's to be derived from a file (#21)
* added perl makefile

* fixup gitignore and eval
2023-03-13 14:18:46 +01:00
Barrington 9af44501cc
Deleted a I that was there for free and removed an useless line 2023-03-10 14:57:17 +01:00
psydbernz d67de26e90
added Linux-specific build hints (#20)
Co-authored-by: Bernz Pallek <dev@berniepallek.ca>
2023-03-09 16:36:18 +01:00
Barrington 82422e6d37
Curl devs were very smart and decided to deprecated the
CURL_PROGRESSFUNCTION option that had 0 problems in my opinion and
decided to change it with CURL_XFERINFOFUNCTION thing which barely
works and had to do a very weird workaround so I don't get a floating
point exception just because. Well, it works and that's what matters.
2023-03-09 15:39:38 +01:00
11 changed files with 236 additions and 98 deletions

17
.github/workflows/c-cpp.yml vendored Normal file
View File

@ -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

11
.gitignore vendored
View File

@ -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/

View File

@ -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

17
c-cpp.yml Normal file
View File

@ -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

14
http/.perltidyrc Normal file
View File

@ -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

15
http/Dockerfile Normal file
View File

@ -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"]

17
http/Makefile.PL Normal file
View File

@ -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']
);

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);