Compare commits
54 commits
Author | SHA1 | Date | |
---|---|---|---|
0f29851a37 | |||
77819962cc | |||
838d9da904 | |||
99868f3fe7 | |||
ec299f915f | |||
47065f1c07 | |||
dd26aa599e | |||
74a654ea5c | |||
b7f0e62177 | |||
9c0fcc3528 | |||
6d16b0a97d | |||
b40f3e7001 | |||
c237b9d8c5 | |||
d5da9a9574 | |||
968a288866 | |||
![]() |
47d733b2f4 | ||
12d506219a | |||
72a3b42d36 | |||
![]() |
ac77cbfe4b | ||
338c4c2771 | |||
![]() |
1d53129435 | ||
![]() |
deb4318cd9 | ||
9af44501cc | |||
![]() |
d67de26e90 | ||
82422e6d37 | |||
a804518ef6 | |||
e62bcfa9d8 | |||
5605143ffa | |||
4b06627b0a | |||
4fcd649b0b | |||
dcea6b2a24 | |||
f52dcbb721 | |||
b8dd0be83b | |||
c8f7473690 | |||
92c502b4a6 | |||
5aece18736 | |||
e8f03c430c | |||
2d9e3fc94c | |||
e28e8f54f8 | |||
6d5632ee81 | |||
e361669b87 | |||
80ef5e6ba2 | |||
db06f1cdc4 | |||
7ef35ba9bd | |||
5fbb1f5257 | |||
868ba54822 | |||
84ec3c9bc1 | |||
b39bd3bc5b | |||
955985b825 | |||
9c8749e664 | |||
957b87161c | |||
300f9fe78c | |||
cdb7bdd148 | |||
81e2129dd5 |
28 changed files with 756 additions and 309 deletions
19
.github/workflows/c-cpp.yml
vendored
Normal file
19
.github/workflows/c-cpp.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
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
|
37
.github/workflows/sakisafe_http.yml
vendored
Normal file
37
.github/workflows/sakisafe_http.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# 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
12
.gitignore
vendored
|
@ -3,3 +3,15 @@
|
||||||
obj/
|
obj/
|
||||||
.clangd
|
.clangd
|
||||||
.depend
|
.depend
|
||||||
|
http/f/*
|
||||||
|
blib/
|
||||||
|
pm_to_blib
|
||||||
|
Makefile
|
||||||
|
Makefile.old
|
||||||
|
MANIFEST*
|
||||||
|
!MANIFEST.SKIP
|
||||||
|
META.*/
|
||||||
|
MYMETA.*
|
||||||
|
pm_to_blib
|
||||||
|
sakisafe.log
|
||||||
|
f/
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
Copyright $CURRENT_YEAR qorg11.
|
Copyright $CURRENT_YEAR SURAGU Enterprises
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
|
122
README.md
122
README.md
|
@ -6,34 +6,133 @@
|
||||||
|
|
||||||
* Written in perl
|
* Written in perl
|
||||||
* Can be used as pastebin
|
* Can be used as pastebin
|
||||||
* Or as a URL shorter
|
* Easy installation (just a simple daemon and use a reverse proxy)
|
||||||
* Runs with CGI
|
* Does not bully Tor users ;)
|
||||||
* Tor access ;)
|
|
||||||
* If running OpenBSD, sakisafecli will use pledge()
|
|
||||||
|
|
||||||
|
|
||||||
## Installation:
|
# Installation
|
||||||
|
|
||||||
1. Configure your webserver to run CGI
|
sakisafe is written in Perl, so it is its first dependency. But if you're
|
||||||
2. If running nginx, set `client_max_body_size` to the max size of
|
using a real operating system you should have it by default.
|
||||||
the file
|
|
||||||
2. There you go.
|
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.
|
||||||
|
|
||||||
# sakisafecli
|
# sakisafecli
|
||||||
|
|
||||||
sakisafecli is a command line interface for sakisafe servers (and
|
sakisafecli is a command line interface for sakisafe servers (and
|
||||||
other file upload services).
|
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.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Compilation
|
### 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
|
### Repositories
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
TODO: Add the thing to Debian repositories ;)
|
||||||
|
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Just create a pull request in GitHub or send a diff file.
|
||||||
|
|
||||||
# Donate
|
# Donate
|
||||||
|
|
||||||
Thanks!
|
Thanks!
|
||||||
|
@ -41,3 +140,4 @@ Thanks!
|
||||||
**Bitcoin**: bc1qghl6f27dpgktynpvkrxte2s3gm9pcv8vlwuzum
|
**Bitcoin**: bc1qghl6f27dpgktynpvkrxte2s3gm9pcv8vlwuzum
|
||||||
|
|
||||||
**Monero**: 47QTumjtqJabbo1s9pLDdXeJarLVLfs1AaEcbi1xrEiV852mqcbe5AHLNXTk7tH9MscxcxQDfJQnvH5LpxvfgwSJQZ3zbS6
|
**Monero**: 47QTumjtqJabbo1s9pLDdXeJarLVLfs1AaEcbi1xrEiV852mqcbe5AHLNXTk7tH9MscxcxQDfJQnvH5LpxvfgwSJQZ3zbS6
|
||||||
|
|
||||||
|
|
15
SERVERS.org
15
SERVERS.org
|
@ -1,10 +1,9 @@
|
||||||
* Known lainsafe instances
|
* Known sakisafe instances
|
||||||
|
|
||||||
In this document i'll add all the lainsafe instance i know :)
|
In this document i'll add all the sakisafe instance i know :)
|
||||||
|
|
||||||
- https://lainsafe.delegao.moe
|
Feel free to add more. I do not know about many others.
|
||||||
- https://lainsafe.duckdns.org (don't use it, old lainsafe version
|
|
||||||
and a bit incompatible with lainsafecli)
|
- https://ss.suragu.net
|
||||||
- https://lainsafe.kalli.st
|
- https://files.getimiskon.xyuz
|
||||||
- http://lainsafe.kallist4mcluuxbjnr5p2asdlmdhaos3pcrvhk3fbzmiiiftwg6zncid.onion/ (onion mirror)
|
-
|
||||||
- http://gnaumuq27fagoo24pb2mmf25rdic7lrthq2fsfolgrpzycc2hwga.b32.i2p/
|
|
||||||
|
|
14
http/.perltidyrc
Normal file
14
http/.perltidyrc
Normal 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
15
http/Dockerfile
Normal 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
17
http/Makefile.PL
Normal 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']
|
||||||
|
);
|
1
http/hypnotoad.pid
Normal file
1
http/hypnotoad.pid
Normal file
|
@ -0,0 +1 @@
|
||||||
|
16143
|
|
@ -1,28 +0,0 @@
|
||||||
#!/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>;
|
|
|
@ -1,27 +0,0 @@
|
||||||
<!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>
|
|
24
http/init/sakisafe_bsd
Normal file
24
http/init/sakisafe_bsd
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#
|
||||||
|
# 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"
|
BIN
http/public/favicon.ico
Normal file
BIN
http/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -1,4 +1,4 @@
|
||||||
p {
|
p, ul, li {
|
||||||
color: white;
|
color: white;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2 {
|
h1, h2 {
|
||||||
color: #e3e3e3;
|
color: #e3e3e3;
|
||||||
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
.left {
|
.left {
|
||||||
position: absolute;
|
position: absolute;
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
268
http/sakisafe.pl
Executable file
268
http/sakisafe.pl
Executable file
|
@ -0,0 +1,268 @@
|
||||||
|
#!/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
108
http/upload.cgi
|
@ -1,108 +0,0 @@
|
||||||
#!/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;
|
|
||||||
}
|
|
|
@ -1,8 +1,18 @@
|
||||||
PROG = sakisafecli
|
PROG += sakisafecli
|
||||||
SRCS += funcs.c sakisafecli.c config.c
|
SRCS += funcs.c sakisafecli.c config.c
|
||||||
MAN = sakisafecli.1 sakisafeclirc.5
|
MAN += sakisafecli.1 sakisafeclirc.5
|
||||||
LDADD = -lssl -lz -lpthread -lnghttp2 -lcurl -lconfig -lcrypto -L/usr/local/lib
|
LDADD += -lpthread -lcurl -lconfig -L/usr/local/lib -fPIC
|
||||||
PREFIX = /usr/local
|
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
|
BINDIR = $(PREFIX)/bin
|
||||||
MANDIR = $(PREFIX)/man/man
|
MANDIR = $(PREFIX)/man/man
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
|
|
@ -28,13 +28,11 @@ print_config()
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
config_t runtime_config;
|
||||||
void
|
void
|
||||||
parse_config_file(FILE *config)
|
parse_config_file(FILE *config)
|
||||||
{
|
{
|
||||||
|
|
||||||
config_t runtime_config;
|
|
||||||
|
|
||||||
config_init(&runtime_config);
|
config_init(&runtime_config);
|
||||||
config_read(&runtime_config, config);
|
config_read(&runtime_config, config);
|
||||||
config_setting_t *cur;
|
config_setting_t *cur;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
#include <curl/curl.h>
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
/* Parse the config file */
|
/* Parse the config file */
|
||||||
void
|
void
|
||||||
|
@ -6,4 +10,21 @@ parse_config_file(FILE *config);
|
||||||
|
|
||||||
/* Print the current settings */
|
/* Print the current settings */
|
||||||
void
|
void
|
||||||
print_config();
|
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;
|
||||||
|
|
||||||
|
|
|
@ -1,54 +1,152 @@
|
||||||
|
#include <curl/system.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include "sakisafecli.h"
|
#include "sakisafecli.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
write_data(void *buffer, size_t size, size_t nmemb,
|
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||||
void *userp)
|
|
||||||
{
|
{
|
||||||
memcpy(userp, buffer, nmemb*size);
|
memcpy(userp, buffer, nmemb * size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
print_usage()
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
print_help()
|
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",
|
printf("-s|--server: specifies the sakisafe "
|
||||||
"-t|--token: Authentication token (https://u.kalli.st)",
|
"server\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
|
||||||
"-P|--http-proxy: http proxy to use e.g. http://127.0.0.1:4444",
|
"-t|--token: Authentication token (https://u.kalli.st)",
|
||||||
"-p|--socks-proxy: SOCK proxy to use e.g. 127.0.0.1:9050",
|
"-P|--http-proxy: http proxy to use e.g. http://127.0.0.1:4444",
|
||||||
"-6|--ipv6: uses IPv6 only",
|
"-p|--socks-proxy: SOCK proxy to use e.g. 127.0.0.1:9050",
|
||||||
"-4|--ipv6: uses IPv4 only",
|
"-6|--ipv6: uses IPv6 only",
|
||||||
"-S|--silent: doesn't print progress",
|
"-4|--ipv6: uses IPv4 only",
|
||||||
"-x|--paste: read file from stdin",
|
"-S|--silent: doesn't print progress",
|
||||||
"-C: print current settings",
|
"-x|--paste: read file from stdin",
|
||||||
"-h|--help: print this message.\n");
|
"-C: print current settings",
|
||||||
|
"-h|--help: print this message.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
size_t
|
||||||
progress(void *clientp,
|
progress(void *clientp,
|
||||||
double dltotal,
|
curl_off_t dltotal,
|
||||||
double dlnow,
|
curl_off_t dlnow,
|
||||||
double ultotal,
|
curl_off_t ultotal,
|
||||||
double ulnow)
|
curl_off_t ulnow)
|
||||||
{
|
{
|
||||||
/* So I don't get a warning */
|
/* I don't know why the fuck I have to do this */
|
||||||
dltotal += 1;
|
if(ultotal == 0) {
|
||||||
dlnow += 1;
|
ultotal++;
|
||||||
printf("\r%0.f uploaded of %0.f (\033[32;1m%0.f%%\033[30;0m)",ulnow,ultotal,
|
}
|
||||||
ulnow*100/ultotal);
|
printf("\r%li uploaded of %li (\033[32;1m%li%%\033[30;0m)",
|
||||||
|
ulnow,
|
||||||
|
ultotal,
|
||||||
|
ulnow * 100 / ultotal);
|
||||||
fflush(stdout);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -22,3 +22,18 @@ progress(
|
||||||
/* Print config */
|
/* Print config */
|
||||||
void
|
void
|
||||||
print_config();
|
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);
|
||||||
|
|
|
@ -26,6 +26,6 @@ extern bool http_proxy_flag;
|
||||||
extern bool ipv6_flag;
|
extern bool ipv6_flag;
|
||||||
extern bool ipv4_flag;
|
extern bool ipv4_flag;
|
||||||
extern bool silent_flag;
|
extern bool silent_flag;
|
||||||
extern config_t runtime_config;
|
|
||||||
extern char *ssh_key_path;
|
extern char *ssh_key_path;
|
||||||
|
extern config_t runtime_config;
|
||||||
#endif /* OPTIONS_H */
|
#endif /* OPTIONS_H */
|
||||||
|
|
|
@ -56,6 +56,6 @@ was rebranded to
|
||||||
.Sy sakisafecli
|
.Sy sakisafecli
|
||||||
in 2022-05-05
|
in 2022-05-05
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
qorg11 <teru-sama at riseup dot net>
|
Raoul Vaughn <chief_keef at riseup dot net>
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
sakisafeclirc(5)
|
sakisafeclirc(5)
|
||||||
|
|
|
@ -8,24 +8,31 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#ifdef use_libbsd
|
||||||
|
#include <bsd/string.h>
|
||||||
|
#endif
|
||||||
#include "curl/easy.h"
|
#include "curl/easy.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "funcs.h"
|
#include "funcs.h"
|
||||||
#include "sakisafecli.h"
|
#include "sakisafecli.h"
|
||||||
|
|
||||||
|
CURL *easy_handle;
|
||||||
|
|
||||||
|
char *buffer;
|
||||||
/* Config variables */
|
/* Config variables */
|
||||||
|
|
||||||
bool ipv6_flag = false, ipv4_flag = false, http_proxy_flag = false,
|
bool ipv6_flag, ipv4_flag, http_proxy_flag,
|
||||||
socks_proxy_flag = false, silent_flag = false, paste_flag = false;
|
socks_proxy_flag, silent_flag, paste_flag;
|
||||||
|
|
||||||
char *http_proxy_url, *socks_proxy_url;
|
char *http_proxy_url, *socks_proxy_url;
|
||||||
char *ssh_key_path = NULL;
|
char *ssh_key_path;
|
||||||
config_t runtime_config;
|
|
||||||
|
char *server;
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
|
||||||
char *server = "https://lainsafe.delegao.moe";
|
|
||||||
const char *path = ".cache/sakisafelinks";
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -36,12 +43,10 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *form_key = "file";
|
buffer = (char *)calloc(1024, sizeof(char));
|
||||||
|
|
||||||
char *buffer = (char *)calloc(1024, sizeof(char));
|
|
||||||
|
|
||||||
if(buffer == NULL) {
|
if(buffer == NULL) {
|
||||||
fprintf(stderr, "Error allocating memory!\n");
|
fprintf(stderr, "Error allocating memory for buffer!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
char config_location[512];
|
char config_location[512];
|
||||||
|
@ -55,7 +60,7 @@ main(int argc, char **argv)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if defined(__OpenBSD__) || defined(__FreeBSD__)
|
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(use_libbsd)
|
||||||
strlcpy(config_location, sakisafeclirc_env, 512);
|
strlcpy(config_location, sakisafeclirc_env, 512);
|
||||||
#else /* Linux sucks! */
|
#else /* Linux sucks! */
|
||||||
strncpy(config_location, sakisafeclirc_env, 512);
|
strncpy(config_location, sakisafeclirc_env, 512);
|
||||||
|
@ -68,26 +73,20 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
/* libcurl initialization */
|
/* libcurl initialization */
|
||||||
|
|
||||||
CURL *easy_handle = curl_easy_init();
|
easy_handle = curl_easy_init();
|
||||||
curl_mime *mime;
|
|
||||||
mime = curl_mime_init(easy_handle);
|
|
||||||
|
|
||||||
if(!easy_handle) {
|
if(!easy_handle) {
|
||||||
fprintf(stderr, "Error initializing libcurl\n");
|
fprintf(stderr, "Error initializing libcurl\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!mime) {
|
|
||||||
fprintf(stderr, "Error initializing curl_mime\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc == optind) {
|
if(argc == optind) {
|
||||||
print_usage();
|
print_usage();
|
||||||
free(buffer);
|
free(buffer);
|
||||||
curl_easy_cleanup(easy_handle);
|
curl_easy_cleanup(easy_handle);
|
||||||
curl_mime_free(mime);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
init_sakisafe_options();
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{ "server", required_argument, 0, 's' },
|
{ "server", required_argument, 0, 's' },
|
||||||
|
@ -157,24 +156,23 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(access(argv[optind], F_OK) && !paste_flag) {
|
if(access(argv[optind], F_OK) && !paste_flag) {
|
||||||
fprintf(stderr, "Error opening file\n");
|
fprintf(stderr, "Error opening file: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* curl options */
|
/* curl options */
|
||||||
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, write_data);
|
if(curl_easy_setopt(easy_handle, CURLOPT_USERAGENT, "curl") != 0)
|
||||||
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer);
|
die("Error setting CURLOPT_USERAGENT");
|
||||||
|
if(curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, write_data) != 0)
|
||||||
curl_easy_setopt(easy_handle, CURLOPT_URL, server);
|
die("Error setting CURLOPT_WRITEFUNCTION");
|
||||||
|
if(curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer) != 0)
|
||||||
|
die("error setting CURLOPT_WRITEDATA");
|
||||||
|
|
||||||
|
if(curl_easy_setopt(easy_handle, CURLOPT_URL, server) != 0)
|
||||||
|
die("error setting CURLOPT_URL");
|
||||||
|
|
||||||
int protocol = get_protocol(server);
|
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 */
|
/* Proxy options */
|
||||||
|
|
||||||
if(socks_proxy_flag && http_proxy_flag) {
|
if(socks_proxy_flag && http_proxy_flag) {
|
||||||
|
@ -184,8 +182,7 @@ main(int argc, char **argv)
|
||||||
curl_easy_setopt(easy_handle, CURLOPT_PROXY, socks_proxy_url);
|
curl_easy_setopt(easy_handle, CURLOPT_PROXY, socks_proxy_url);
|
||||||
curl_easy_setopt(
|
curl_easy_setopt(
|
||||||
easy_handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
|
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_PROXY, http_proxy_url);
|
||||||
curl_easy_setopt(easy_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
curl_easy_setopt(easy_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +197,12 @@ main(int argc, char **argv)
|
||||||
curl_easy_setopt(
|
curl_easy_setopt(
|
||||||
easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
|
easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
|
||||||
|
|
||||||
/* Form parameters */
|
/* 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);
|
||||||
|
|
||||||
/* File name */
|
/* File name */
|
||||||
|
|
||||||
|
@ -210,65 +212,20 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
/* Process HTTP uploads */
|
/* Process HTTP uploads */
|
||||||
|
|
||||||
if(protocol == CURLPROTO_HTTP || protocol == CURLPROTO_HTTPS) {
|
if(protocol == CURLPROTO_HTTP) {
|
||||||
curl_mimepart *file_data;
|
upload_file_http(argc, argv);
|
||||||
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 */
|
/* Process SCP uploads */
|
||||||
else if(protocol == CURLPROTO_SCP) {
|
else if(protocol == CURLPROTO_SCP) {
|
||||||
char path[256];
|
upload_file_scp(argc, argv);
|
||||||
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 {
|
} else {
|
||||||
puts("Unsupported protocol");
|
puts("Unsupported protocol");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_cleanup(easy_handle);
|
curl_easy_cleanup(easy_handle);
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
config_destroy(&runtime_config);
|
config_destroy(&runtime_config);
|
||||||
|
free(buffer);
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
#define SAKISAFECLI_H
|
#define SAKISAFECLI_H
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
struct progress
|
||||||
|
{
|
||||||
|
char *_private;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
size_t
|
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);
|
||||||
|
@ -15,9 +22,6 @@ store_link(const char *path, const char *buf);
|
||||||
void
|
void
|
||||||
print_help();
|
print_help();
|
||||||
|
|
||||||
void
|
|
||||||
progress(
|
|
||||||
void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_config_file(FILE *config);
|
parse_config_file(FILE *config);
|
||||||
|
|
|
@ -61,13 +61,13 @@ and with the
|
||||||
127.0.0.1:9050
|
127.0.0.1:9050
|
||||||
|
|
||||||
.Bd -literal -offset indent;
|
.Bd -literal -offset indent;
|
||||||
server="https://ls.qorg11.net"
|
server="https://ss.suragu.net"
|
||||||
socks_proxy="127.0.0.1:9050"
|
socks_proxy="127.0.0.1:9050"
|
||||||
force_ipv4=true
|
force_ipv4=true
|
||||||
use_socks_proxy=true
|
use_socks_proxy=true
|
||||||
.Ed
|
.Ed
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
qorg11 <teru-sama at riseup dot net>
|
Raoul Vaughn <chief_keef at riseup dot net>
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
sakisafecli(1)
|
sakisafecli(1)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue