Compare commits

..

No commits in common. "master" and "scp" have entirely different histories.
master ... scp

28 changed files with 309 additions and 756 deletions

View file

@ -1,19 +0,0 @@
name: C/C++ CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: install dependencies
run: sudo apt-get update && sudo apt-get install -y bmake libcurl4-openssl-dev libconfig-dev
- name: bmake
run: bmake

View file

@ -1,37 +0,0 @@
# This was written by an AI. HA!
# I hate writing yaml. I'm glad a computer can do it for me.
name: Test Mojolicious Application
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
web:
image: perl:latest
ports:
- 8080:8080
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libmojolicious-perl liblist-moreutils-perl libmojolicious-plugin-renderfile-perl libpath-tiny-perl libmime-types-perl
- name: Start Sakisafe
run: |
hypnotoad http/sakisafe.pl
- name: Test Sakisafe
run: |
curl --retry 10 --retry-delay 5 --retry-connrefused http://localhost:8080
# LOLOLOLOLOLOLOLO
curl -X POST -F "file=@/etc/passwd" http://localhost:8080
- name: Read log entry
run: |
cat http/sakisafe.log

12
.gitignore vendored
View file

@ -3,15 +3,3 @@
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

@ -1,4 +1,4 @@
Copyright $CURRENT_YEAR SURAGU Enterprises
Copyright $CURRENT_YEAR qorg11.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are

122
README.md
View file

@ -6,133 +6,34 @@
* Written in perl
* Can be used as pastebin
* Easy installation (just a simple daemon and use a reverse proxy)
* Does not bully Tor users ;)
* Or as a URL shorter
* Runs with CGI
* Tor access ;)
* If running OpenBSD, sakisafecli will use pledge()
# Installation
## Installation:
sakisafe is written in Perl, so it is its first dependency. But if you're
using a real operating system you should have it by default.
1. install the dependencies using `cpan`:
~~~
cpan -i Mojolicious::Lite Mojolicious::Routes::Pattern Mojoliciuos::Plugin::RenderFile
~~~
If you're running Debian or FreeBSD you can install the dependencies with
your package manager:
~~~bash
apt install libmojolicious-perl libmojolicious-plugin-renderfile-perl liblist-moreutils-perl # Debian, Ubuntu...
pkg install p5-Mojolicious p5-List-MoreUtils p5-Path-Tiny # FreeBSD
# You'll have to run cpan to install the RenderFile plugin in FreeBSD
cpan -Ti Mojolicious::Plugin::Renderfile
~~~
2. Clone the repo and start the daemon:
~~~
git clone https://git.suragu.net/sosa/sakisafe
cd sakisafe/http
./sakisafe.pl daemon -m production
~~~
You can also use `hypnotoad` or `morbo` to run the thing:
~~~
morbo -l http://*:3000 sakisafe.pl.
hypnotoad sakisafe.pl # This will daemonize the thing in port 8080.
~~~
2.2. In FreeBSD, you can use the rc script located in
http/scripts/sakisafe_bsd to create a sakisafe service. The service is
loaded by the user "saki", whose home is `/usr/local/share/sakisafe`:
~~~bash
mkdir -p /usr/local/share/sakisafe
cp -r http/* /usr/local/share/sakisafe
cp http/init/sakisafe_bsd /usr/local/etc/rc.d
touch /var/run/sakisafe.pid
chmod 777 /var/run/sakisafe.pid # How to fix this? Please tell me
service sakisafe enable
service sakisafe start
~~~
Please contribute more init scripts for sakisafe!!! (for systemd,
openbsd...)
2.3. You can also use Docker. I am not a Docker advocate. But apparently
running "docker build-x" or something like that just works.
3. Create a 'f' directory in the directory sakisafe will run with
`mkdir f`. Make sure that the user which will run sakisafe.pl can
write in that directory.
By default, sakisafe will bind in 127.0.0.1 port 3000. Because that's
the default bind Mojolicious uses.
4. Create a proxy rule in nginx configuration (If you're using another
HTTP server, you're on your own.)
~~~conf
server {
server_name sakisafe.whatever.tld;
listen 443 ssl;
# ssl configuration here
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # Important for logging!
proxy_set_header X-Forwarded-for $remote_addr; # Idem
proxy_pass http://127.0.0.1:3000$request_uri;
}
}
~~~
And restart nginx. Going to `sakisafe.whatever.tld` should work.
1. Configure your webserver to run CGI
2. If running nginx, set `client_max_body_size` to the max size of
the file
2. There you go.
# sakisafecli
sakisafecli is a command line interface for sakisafe servers (and
other file upload services). It also supports file uploading via scp
(ssh).
## Features
* Written in C so is fast.
* HTTP and SCP support (FTP support is planned)
* Highly configurable
* Lightweight
* If using OpenBSD, it will run `pledge()` for security reasons.
* As far as I know, runs in any *NIX operating system.
other file upload services).
## Installation
### Compilation
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`
Clone the repo and run `make` (or `bmake` in linux systems)
### Repositories
![](https://repology.org/badge/vertical-allrepos/sakisafe.svg)
TODO: Add the thing to Debian repositories ;)
# Contributing
Just create a pull request in GitHub or send a diff file.
# Donate
Thanks!
@ -140,4 +41,3 @@ Thanks!
**Bitcoin**: bc1qghl6f27dpgktynpvkrxte2s3gm9pcv8vlwuzum
**Monero**: 47QTumjtqJabbo1s9pLDdXeJarLVLfs1AaEcbi1xrEiV852mqcbe5AHLNXTk7tH9MscxcxQDfJQnvH5LpxvfgwSJQZ3zbS6

View file

@ -1,9 +1,10 @@
* Known sakisafe instances
* Known lainsafe instances
In this document i'll add all the sakisafe instance i know :)
In this document i'll add all the lainsafe instance i know :)
Feel free to add more. I do not know about many others.
- https://ss.suragu.net
- https://files.getimiskon.xyuz
-
- https://lainsafe.delegao.moe
- https://lainsafe.duckdns.org (don't use it, old lainsafe version
and a bit incompatible with lainsafecli)
- https://lainsafe.kalli.st
- http://lainsafe.kallist4mcluuxbjnr5p2asdlmdhaos3pcrvhk3fbzmiiiftwg6zncid.onion/ (onion mirror)
- http://gnaumuq27fagoo24pb2mmf25rdic7lrthq2fsfolgrpzycc2hwga.b32.i2p/

View file

@ -1,14 +0,0 @@
-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

View file

@ -1,15 +0,0 @@
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"]

View file

@ -1,17 +0,0 @@
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 +0,0 @@
16143

28
http/index.cgi Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/perl
# This file is part of sakisafe.
# lainsafe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# lainsafe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with lainsafe. If not, see <https://www.gnu.org/licenses/>.
if ($ENV{REQUEST_METHOD} eq "POST") {
do "./upload.cgi";
exit;
}
my $SITE_URL = $ENV{REMOTE_ADDR};
print "Content-type: text/html\n\n";
open(my $fh, "<index.html");
print while <$fh>;

View file

@ -1,4 +1,4 @@
p, ul, li {
p {
color: white;
display: block;
}
@ -24,8 +24,7 @@ body {
}
h1, h2 {
color: #e3e3e3;
font-family: monospace;
color: #e3e3e3;
}
.left {
position: absolute;

27
http/index.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>sakisafe</title>
<link rel="stylesheet" type="text/css" href="index.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>sakisafe</h1>
<h2>shitless file upload, pastebin and url shorter</h2>
<img src="saki.png"/>
<h2>USAGE</h2>
<p>POST a file:</p>
<code>curl -F 'file=@yourfile.png' $SITE_URL</code>
<p>Shorten URL:</p>
<code>curl -F 'url=https://example.org' $SITE_URL</code>
<p>Post your text directly</p>
<code>curl -F 'file=@-' $SITE_URL</code>
<div class="left">
<h2>Or just upload a file here</h2>
<form ENCTYPE='multipart/form-data' method='post' action='upload.cgi'>
<input type='file' name='file' size='30'/>
<input type='submit' value='upload'/>
</form>
</div>
</body>
</html>

View file

@ -1,24 +0,0 @@
#
# Add the following lines to /etc/rc.conf to enable sakisafe:
#
#sakisafe_enable="YES"
. /etc/rc.subr
name="sakisafe"
rcvar="sakisafe_enable"
load_rc_config $name
: ${sakisafe_user:=saki}
: ${sakisafe_group:=saki}
: ${sakisafe_enable:=NO}
: ${sakisafe_flags:= -P /var/run/sakisafe.pid -f /usr/local/bin/morbo -l http://*:3000 /usr/local/share/sakisafe/sakisafe.pl }
: ${sakisafe_chdir:= /usr/local/share/sakisafe }
command="/usr/sbin/daemon"
command_args="${sakisafe_flags}"
pidfile="/var/run/${name}.pid"
PATH="${PATH}"
run_rc_command "$1"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View file

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View file

@ -1,268 +0,0 @@
#!/usr/bin/env 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.
pledge("stdio prot_exec cpath rpath wpath inet flock fattr")
if $^O eq "openbsd";
# INSTANCE CONFIGURATION
our $name = "sakisafe";
our $version = "2.6.0";
# Domain and port, for output link
our $domain = "XXXXXXXXXXX";
our $port = 443;
# Contact info
# Change this with whatever you want
our $contact_info = 'email: saki@sakisafe.lol';
# 1 GiBs
my $MAX_SIZE = 1024 * 1024 * 1000;
my @BANNED = eval { path('banned.txt')->slurp_utf8 }
or qw(); # 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";
# 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 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 );
$log->info("Attempt to upload by banned extension: " . $c->req->headers->header('X-Forwarded-For'));
say $ext;
return;
}
$c->req->headers->header('X-Forwarded-For')
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,
);
}
$log->info($c->req->headers->header('X-Forwarded-For') . " " . $dirname . "/" . $filename );
$dirname = "";
}
# Function to log uploaded files
get '/' => sub ($c) {
$c->stash(name => $name, contact_info => $contact_info, version => $version);
$c->render(template => '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->log($log);
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
<!DOCTYPE html>
<html lang="en">
<head>
<title>sakisafe</title>
<link rel="stylesheet" type="text/css" href="index.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<center>
<h1>sakisafe</h1>
<h2>shitless file upload, pastebin and url shorter</h2>
<img src="saki.png"/>
<h2>LINK</h2>
<code><%= $link %></code>
</center>
<p>Running sakisafe 2.6.0</p>
</body>
</html>
@@ index.html.ep
% layout 'index', name => $name, contact_info => $contact_info, version => $version;
<!DOCTYPE html>
<html lang="en">
<head>
<title>sakisafe</title>
<link rel="stylesheet" type="text/css" href="index.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<center>
<h1>sakisafe</h1>
<h2>shitless file upload, pastebin and url shorter</h2>
<img src="saki.png"/>
<h2>USAGE</h2>
<p>POST a file:</p>
<code>curl -F 'file=@yourfile.png' https://<%= $c->req->url->to_abs->host; %></code>
<p>Post your text directly</p>
<code>curl -F 'file=@-' https://<%= $c->req->url->to_abs->host; %></code><br/>
<a href="https://git.suragu.net/svragv/sakisafe">Git repository</a>
</center>
<h2>FAQ</h2>
<p>(No one has ever asked these questions)</p>
<p><b>How long are the files stored?</b> Until the heat death of the universe</b></p>
<p><b>Do you log IP addresses?</b> Yes. Blame the people uploading illegal stuff to this</p>
<p><b>Do you log all the requests?</b> Nah. Only file uploads are logged.</p>
<p><b>Can you delete a file I uploaded?</b><p>That depends on the instance administrator</b></p>
<h2>Instance info</h2>
<ul>
<li>Name: <%= $name %></li>
<li>Contact info: <%= $contact_info%>
</ul>
<p>Running sakisafe <%=$version%></p>
<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='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

108
http/upload.cgi Executable file
View file

@ -0,0 +1,108 @@
#!/usr/bin/perl
# This file is part of sakisafe.
# sakisafe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# sakisafe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with sakisafe. If not, see <https://www.gnu.org/licenses/>.
use CGI;
use CGI::Carp qw(fatalsToBrowser);
my $q = CGI->new;
my $filename = $q->param('file');
my $url = $q->param('url');
my $upload_dir = "files/";
$size = $ENV{CONTENT_LENGTH};
# Configuration
our $MAX_SIZE = 1024*1024*100; # Change for your size
our $MAX_SIZE_MB = $MAX_SIZE / 1024 / 1024; # Don't change this
our @not_allowed_extensions = qw(sh out exe);
print $q->header();
# do something better
if ($url ne "") {
goto url_shorter;
}
if ($filename eq "" || $ENV{REQUEST_METHOD} eq "GET") {
print("What are you looking for?");
exit;
}
if ($filename) {
if ($size > $MAX_SIZE) {
print("Max size for a file is $MAX_SIZE_MB MBs");
exit;
}
my @chars = ("A"..."z","a"..."z");
my $dirname;
my $extension = $filename;
$dirname .= $chars[rand @chars] for 1..8;
$extension =~ s/.*\.//;
$filename .= ".notcgi" if $extension eq "cgi";
mkdir("$upload_dir/$dirname");
my $upload_filehandle = $q->upload("file");
# onion urls will be http
my $prot = length $ENV{HTTPS} ? "https" : "http";
my $allowed_extension = 1;
foreach (@not_allowed_extensions) {
if ($filename =~ /\.$_$/i) {
$allowed_extension = 0;
last;
}
}
if ($filename eq "-") {
$filename .= ".txt"; # for pastes
}
if ($allowed_extension) {
open(FILE,">$upload_dir/$dirname/$filename");
binmode(FILE);
while (<$upload_filehandle>) {
print FILE;
}
close FILE;
$filename =~ s/ /%20/g;
print $prot. "://" . $ENV{HTTP_HOST} . "/$upload_dir$dirname/$filename" . "\n";
} else {
print "The file extension .$extension is not allowed in this instance.";
}
exit;
} elsif ($url != "" && !$filename) {
url_shorter:
my $template = "<meta http-equiv=\"Refresh\" content=\"0; url='$url'\"/>";
my @chars = ("A"..."z","a"..."z",1..9);
my $dirname;
$dirname .= $chars[rand @chars] for 1..4;
mkdir($dirname);
open(my $fh, ">$dirname/index.html");
print $fh $template;
my $prot = length $ENV{HTTPS} ? "https" : "http";
print $prot. "://" . $ENV{HTTP_HOST} . "/$dirname" . "\n";
exit;
}

View file

@ -1,18 +1,8 @@
PROG += sakisafecli
SRCS += funcs.c sakisafecli.c config.c
MAN += sakisafecli.1 sakisafeclirc.5
LDADD += -lpthread -lcurl -lconfig -L/usr/local/lib -fPIC
PROG = sakisafecli
SRCS += funcs.c sakisafecli.c config.c
MAN = sakisafecli.1 sakisafeclirc.5
LDADD = -lssl -lz -lpthread -lnghttp2 -lcurl -lconfig -lcrypto -L/usr/local/lib
PREFIX = /usr/local
# Use libbsd features if wanted
use-libbsd ?= no
.if ${use-libbsd} == "yes"
CFLAGS += -Duse_libbsd
LDADD += -lbsd
.endif
BINMODE = 755
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/man/man
.include <bsd.prog.mk>

View file

@ -28,11 +28,13 @@ print_config()
return;
}
config_t runtime_config;
void
parse_config_file(FILE *config)
{
config_t runtime_config;
config_init(&runtime_config);
config_read(&runtime_config, config);
config_setting_t *cur;

View file

@ -1,8 +1,4 @@
#pragma once
#include <curl/curl.h>
#include <libconfig.h>
#include <stdbool.h>
/* Parse the config file */
void
@ -10,21 +6,4 @@ parse_config_file(FILE *config);
/* Print the current settings */
void
print_config();
/* Internal variables */
extern CURL *easy_handle;
extern char *buffer;
/* Config variables */
extern bool ipv6_flag, ipv4_flag, http_proxy_flag,
socks_proxy_flag, silent_flag, paste_flag;
extern char *http_proxy_url, *socks_proxy_url;
extern char *ssh_key_path;
extern char *server;
extern const char *path;
print_config();

View file

@ -1,152 +1,54 @@
#include <curl/system.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <libconfig.h>
#include <curl/curl.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <getopt.h>
#include "sakisafecli.h"
#include "config.h"
size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
write_data(void *buffer, size_t size, size_t nmemb,
void *userp)
{
memcpy(userp, buffer, nmemb * size);
memcpy(userp, buffer, nmemb*size);
return 0;
}
void
print_usage()
{
printf("USAGE: sakisafecli [-p socks proxy|-P http proxy] [-x] [-s] "
"[-6|-4] [--server] FILE\n");
printf("USAGE: sakisafecli [-p socks proxy|-P http proxy] [-x] [-s] [-6|-4] [--server] FILE\n");
return;
}
void
print_help()
{
printf("-s|--server: specifies the sakisafe "
"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. 127.0.0.1:9050",
"-6|--ipv6: uses IPv6 only",
"-4|--ipv6: uses IPv4 only",
"-S|--silent: doesn't print progress",
"-x|--paste: read file from stdin",
"-C: print current settings",
"-h|--help: print this message.\n");
printf("-s|--server: specifies the sakisafe 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. 127.0.0.1:9050",
"-6|--ipv6: uses IPv6 only",
"-4|--ipv6: uses IPv4 only",
"-S|--silent: doesn't print progress",
"-x|--paste: read file from stdin",
"-C: print current settings",
"-h|--help: print this message.\n");
return;
}
size_t
void
progress(void *clientp,
curl_off_t dltotal,
curl_off_t dlnow,
curl_off_t ultotal,
curl_off_t ulnow)
double dltotal,
double dlnow,
double ultotal,
double ulnow)
{
/* 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);
/* 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)",ulnow,ultotal,
ulnow*100/ultotal);
fflush(stdout);
return 0;
}
int
get_protocol(char *server)
{
if(strstr(server, "http://") != NULL || strstr(server, "https://"))
return CURLPROTO_HTTP;
else if(strstr(server, "scp://") != NULL)
return CURLPROTO_SCP;
else
return -1;
}
void
die(const char *msg)
{
fprintf(stderr, "%i: %s", errno, msg);
}
void
init_sakisafe_options()
{
ipv6_flag = http_proxy_flag,
socks_proxy_flag = paste_flag = silent_flag = false;
ipv4_flag = true;
ssh_key_path = NULL;
server = "https://meth.cat";
path = ".cache/sakisafelinks";
}
int
upload_file_http(int argc, char **argv)
{
curl_mime *mime;
mime = curl_mime_init(easy_handle);
curl_easy_setopt(easy_handle, CURLOPT_MIMEPOST, mime);
if(!mime) {
fprintf(stderr, "Error initializing curl_mime\n");
return -1;
}
curl_mimepart *file_data;
file_data = curl_mime_addpart(mime);
char *filename = argv[optind - 1];
/* Get file from stdin */
if(paste_flag)
filename = "/dev/stdin";
curl_mime_filedata(file_data, filename);
curl_mime_name(file_data, "file");
if(paste_flag)
curl_mime_filename(file_data, "-");
curl_easy_perform(easy_handle);
if(!silent_flag)
putchar('\n');
puts(buffer);
curl_mime_free(mime);
return 0;
}
int
upload_file_scp(int argc, char **argv)
{
curl_easy_setopt(easy_handle, CURLOPT_SSH_PRIVATE_KEYFILE, ssh_key_path);
char path[256];
char *filename = argv[optind];
curl_easy_setopt(easy_handle, CURLOPT_UPLOAD, true);
FILE *fp = fopen(filename, "r");
if(fp == NULL) {
fprintf(stderr, "%s", strerror(errno));
exit(-1);
}
struct stat st;
stat(argv[optind], &st);
snprintf(path, 256, "%s/%s", server, filename);
curl_easy_setopt(easy_handle, CURLOPT_READDATA, fp);
curl_easy_setopt(
easy_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)st.st_size);
int ret = curl_easy_perform(easy_handle);
putchar('\n');
if(ret != 0) {
fprintf(stderr, "%i: %s\n", ret, curl_easy_strerror(ret));
}
fclose(fp);
return 0;
}

View file

@ -22,18 +22,3 @@ progress(
/* Print config */
void
print_config();
int
init_sakisafe_options();
int
get_protocol(char *server);
int
die(char *msg);
int
upload_file_http(int argc, char **argv);
int
upload_file_scp(int argc, char **argv);

View file

@ -26,6 +26,6 @@ extern bool http_proxy_flag;
extern bool ipv6_flag;
extern bool ipv4_flag;
extern bool silent_flag;
extern char *ssh_key_path;
extern config_t runtime_config;
extern char *ssh_key_path;
#endif /* OPTIONS_H */

View file

@ -56,6 +56,6 @@ was rebranded to
.Sy sakisafecli
in 2022-05-05
.Sh AUTHORS
Raoul Vaughn <chief_keef at riseup dot net>
qorg11 <teru-sama at riseup dot net>
.Sh SEE ALSO
sakisafeclirc(5)

View file

@ -8,31 +8,24 @@
#include <unistd.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef use_libbsd
#include <bsd/string.h>
#endif
#include "curl/easy.h"
#include "options.h"
#include "config.h"
#include "funcs.h"
#include "sakisafecli.h"
CURL *easy_handle;
char *buffer;
/* Config variables */
bool ipv6_flag, ipv4_flag, http_proxy_flag,
socks_proxy_flag, silent_flag, paste_flag;
bool ipv6_flag = false, ipv4_flag = false, http_proxy_flag = false,
socks_proxy_flag = false, silent_flag = false, paste_flag = false;
char *http_proxy_url, *socks_proxy_url;
char *ssh_key_path;
char *server;
const char *path;
char *ssh_key_path = NULL;
config_t runtime_config;
char *server = "https://lainsafe.delegao.moe";
const char *path = ".cache/sakisafelinks";
int
main(int argc, char **argv)
{
@ -43,10 +36,12 @@ main(int argc, char **argv)
}
#endif
buffer = (char *)calloc(1024, sizeof(char));
char *form_key = "file";
char *buffer = (char *)calloc(1024, sizeof(char));
if(buffer == NULL) {
fprintf(stderr, "Error allocating memory for buffer!\n");
fprintf(stderr, "Error allocating memory!\n");
return -1;
}
char config_location[512];
@ -60,7 +55,7 @@ main(int argc, char **argv)
fclose(fp);
}
} else {
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(use_libbsd)
#if defined(__OpenBSD__) || defined(__FreeBSD__)
strlcpy(config_location, sakisafeclirc_env, 512);
#else /* Linux sucks! */
strncpy(config_location, sakisafeclirc_env, 512);
@ -73,20 +68,26 @@ main(int argc, char **argv)
}
/* libcurl initialization */
easy_handle = curl_easy_init();
CURL *easy_handle = curl_easy_init();
curl_mime *mime;
mime = curl_mime_init(easy_handle);
if(!easy_handle) {
fprintf(stderr, "Error initializing libcurl\n");
return -1;
}
if(!mime) {
fprintf(stderr, "Error initializing curl_mime\n");
}
if(argc == optind) {
print_usage();
free(buffer);
curl_easy_cleanup(easy_handle);
curl_mime_free(mime);
return -1;
}
init_sakisafe_options();
int option_index = 0;
static struct option long_options[] = {
{ "server", required_argument, 0, 's' },
@ -156,23 +157,24 @@ main(int argc, char **argv)
}
if(access(argv[optind], F_OK) && !paste_flag) {
fprintf(stderr, "Error opening file: %s\n", strerror(errno));
fprintf(stderr, "Error opening file\n");
return -1;
}
/* curl options */
if(curl_easy_setopt(easy_handle, CURLOPT_USERAGENT, "curl") != 0)
die("Error setting CURLOPT_USERAGENT");
if(curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, write_data) != 0)
die("Error setting CURLOPT_WRITEFUNCTION");
if(curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer) != 0)
die("error setting CURLOPT_WRITEDATA");
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer);
curl_easy_setopt(easy_handle, CURLOPT_URL, server);
if(curl_easy_setopt(easy_handle, CURLOPT_URL, server) != 0)
die("error setting CURLOPT_URL");
int protocol = get_protocol(server);
/* If using SCP, set the ssh key */
if(protocol == CURLPROTO_SCP && ssh_key_path != NULL) {
curl_easy_setopt(
easy_handle, CURLOPT_SSH_PRIVATE_KEYFILE, ssh_key_path);
}
/* Proxy options */
if(socks_proxy_flag && http_proxy_flag) {
@ -182,7 +184,8 @@ main(int argc, char **argv)
curl_easy_setopt(easy_handle, CURLOPT_PROXY, socks_proxy_url);
curl_easy_setopt(
easy_handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
} else if(http_proxy_flag && protocol == CURLPROTO_HTTP) {
} else if(http_proxy_flag && ((protocol == CURLPROTO_HTTP) ||
(protocol == CURLPROTO_HTTPS))) {
curl_easy_setopt(easy_handle, CURLOPT_PROXY, http_proxy_url);
curl_easy_setopt(easy_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
@ -197,12 +200,7 @@ main(int argc, char **argv)
curl_easy_setopt(
easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
/* Common options for both HTTP and SCP transfers */
curl_easy_setopt(easy_handle, CURLOPT_NOPROGRESS, silent_flag);
struct progress mem;
curl_easy_setopt(easy_handle, CURLOPT_XFERINFODATA, &mem);
curl_easy_setopt(easy_handle, CURLOPT_XFERINFOFUNCTION, progress);
/* Form parameters */
/* File name */
@ -212,20 +210,65 @@ main(int argc, char **argv)
/* Process HTTP uploads */
if(protocol == CURLPROTO_HTTP) {
upload_file_http(argc, argv);
if(protocol == CURLPROTO_HTTP || protocol == CURLPROTO_HTTPS) {
curl_mimepart *file_data;
file_data = curl_mime_addpart(mime);
char *filename = argv[optind];
if(paste_flag)
filename = "/dev/stdin";
curl_mime_filedata(file_data, filename);
curl_mime_name(file_data, form_key);
if(paste_flag)
curl_mime_filename(file_data, "-");
curl_easy_setopt(easy_handle, CURLOPT_NOPROGRESS, silent_flag);
curl_easy_setopt(easy_handle, CURLOPT_PROGRESSFUNCTION, progress);
curl_easy_setopt(easy_handle, CURLOPT_MIMEPOST, mime);
curl_easy_perform(easy_handle);
if(!silent_flag)
putchar('\n');
puts(buffer);
curl_mime_free(mime);
}
/* Process SCP uploads */
else if(protocol == CURLPROTO_SCP) {
upload_file_scp(argc, argv);
char path[256];
char *filename = argv[optind];
curl_easy_setopt(easy_handle, CURLOPT_UPLOAD, true);
FILE *fp = fopen(filename, "r");
struct stat st;
stat(argv[optind], &st);
snprintf(path, 256, "%s/%s", server, filename);
curl_easy_setopt(easy_handle, CURLOPT_READDATA, fp);
curl_easy_setopt(easy_handle, CURLOPT_NOPROGRESS, silent_flag);
curl_easy_setopt(easy_handle, CURLOPT_PROGRESSFUNCTION, progress);
curl_easy_setopt(
easy_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)st.st_size);
curl_easy_setopt(easy_handle, CURLOPT_URL, path);
curl_easy_perform(easy_handle);
} else {
puts("Unsupported protocol");
return -1;
}
curl_easy_cleanup(easy_handle);
config_destroy(&runtime_config);
free(buffer);
config_destroy(&runtime_config);
return 0;
}
int
get_protocol(char *server)
{
if(strstr(server, "http://") != NULL || strstr(server, "https://"))
return CURLPROTO_HTTP;
else if(strstr(server, "scp://") != NULL)
return CURLPROTO_SCP;
else
return -1;
}

View file

@ -2,13 +2,6 @@
#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);
@ -22,6 +15,9 @@ store_link(const char *path, const char *buf);
void
print_help();
void
progress(
void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
void
parse_config_file(FILE *config);

View file

@ -61,13 +61,13 @@ and with the
127.0.0.1:9050
.Bd -literal -offset indent;
server="https://ss.suragu.net"
server="https://ls.qorg11.net"
socks_proxy="127.0.0.1:9050"
force_ipv4=true
use_socks_proxy=true
.Ed
.Sh AUTHORS
Raoul Vaughn <chief_keef at riseup dot net>
qorg11 <teru-sama at riseup dot net>
.Sh SEE ALSO
sakisafecli(1)