Compare commits

...

51 Commits
v1.3 ... master

Author SHA1 Message Date
qorg11 491e309c9d
nixx1 | Oh yeah I changed that to 'file' now by the way
I_NEED_MONEY | ...
I_NEED_MONEY | I added a `if` statement for that.
2022-05-24 14:17:12 +02:00
qorg11 68e00034bb
Added support for up.concealed.world 2022-05-11 16:13:10 +02:00
qorg11 efc3ac374d
Added config file support 2022-05-06 14:03:05 +02:00
qorg11 0d1e07fe51
Rebranded 2022-05-05 20:04:29 +02:00
qorg11 0987a4cfa3
Fixed all valgrind's complains 2022-02-09 15:23:52 +01:00
qorg11 fdf5264e18
Remove newline from printinng buffer 2021-10-19 19:00:37 +02:00
qorg11 1c896a7b32
make the donation thing more tidy 2021-10-17 19:52:47 +02:00
qorg11 1d4b10b9a2
Removed info about lsd 2021-10-17 19:51:55 +02:00
qorg11 46162aab5f
damn 2021-10-17 19:05:51 +02:00
qorg11 54b4b7cf86
renamed the readme 2021-10-17 19:05:11 +02:00
qorg11 3d5593abc9
Fixed shebang 2021-10-17 19:01:28 +02:00
qorg11 6e67fb78ed
Fixed the shit lol 2021-10-17 19:00:54 +02:00
qorg11 d041a216f7
Modified the thing so you can easily paste and new index 2021-10-17 18:13:39 +02:00
qorg11 3f3d173e5d
append .txt if the filename is "-"
This is to allow pastes like `curl -F'file=@-;' https://ls.qorg11.net`
2021-10-17 14:47:28 +02:00
qorg11 20b30be2f5
Modified index 2021-10-12 13:58:57 +02:00
qorg11 d9afa6076a
changed puts("") but putchar('\n')
and added clang format so the formatting changed
2021-07-07 16:23:39 +02:00
qorg11 50a2682cab
Removed tor and I2P flags, repleaced by --socks-proxy and --httproxy
which both take them a full address (127.0.0.1:9050 for example)
2021-05-20 13:56:23 +02:00
qorg11 807e1302fe
Updated readme 2021-05-01 20:37:09 +02:00
qorg11 c81acdd4fd
Added token support 2021-04-04 14:50:24 +02:00
qorg11 89ad06ce23
whoops 2021-03-27 16:48:38 +01:00
qorg11 efbcccbe03
Now you can add pass more files to clainsafecli 2021-03-26 01:36:38 +01:00
qorg11 082d1ae23a
Make lainsafe change the name repleace the spaces in the url with %20
for weird browsers and weird clients (poezio i'm looking at you)
2021-03-23 12:43:31 +01:00
qorg11 a5b0de143b
* Modified the makefile so you can add custom CFLAGS
* Added manpage for clainsafecli
* Removed lainsafecli
2021-03-10 14:56:35 +01:00
qorg11 7f96695e4e
whoops 2021-03-10 09:55:14 +01:00
qorg11 018f0d64e4
Tabs, makefile modification and no warnings 2021-03-10 09:49:56 +01:00
qorg11 3e27f25236
Added makefile for clainsafecli 2021-03-10 09:38:43 +01:00
qorg11 7f88127116
lots 2021-02-22 16:56:57 +01:00
qorg11 8c9529a7ba
Use stdbool.h things instead of ints for true/false args 2021-02-14 20:26:45 +01:00
qorg11 fbc96d4b47
Added -4 and -6 options to force ipv4 or ipv6. 2021-02-14 03:13:30 +01:00
qorg11 3c03246af4
Added a more user friendly progress bar (in bytes so kinda to do) but
it shows the % at least.
2021-02-14 00:48:22 +01:00
qorg11 6608a22922
Added -S|--silent option to clainsafecli
This allows you not to print the progress bar
2021-02-10 22:42:59 +01:00
qorg11 7fec1f8e01
Added deprecation notice to lainsafecli 2021-02-09 19:36:44 +01:00
qorg11 0658b5f237
fugging strlen :DDDD 2021-02-09 19:01:49 +01:00
qorg11 5f840b01da
Never used that function 2021-02-09 18:39:15 +01:00
qorg11 acb47dd5bb
Added a header for clainsafecli which contains the functions. Also
added the default curl progress bar.

Added deprecation note for lainsafecli.
2021-02-09 18:23:43 +01:00
qorg11 e87c6c9b1c
fug 2021-02-06 00:15:41 +01:00
qorg11 8170a8a935
Created configuration file for clainsafecli and added option to store
links
2021-02-06 00:13:56 +01:00
qorg11 d2c48dcb66
Added --i2p to the --help message in clainsafecli and improved usage
message

starting # with '#' will be ignored, and an empty message aborts the
commit.  # # On branch master # Your branch is up to date with
'origin/master'.  # # Changes to be committed: # modified:
clainsafecli.c # # Untracked files: # clainsafecli #
2021-02-05 00:58:44 +01:00
qorg11 4535b267a9
Check if malloc() was succesful 2021-02-03 17:39:34 +01:00
qorg11 509c6e9c68
Add --i2p flag 2021-02-02 23:28:17 +01:00
qorg11 693be32ee3
Add --tor|-t flag to clainsafecli
(or you can use torsocks but well, proxies are good)
2021-02-02 14:40:58 +01:00
qorg11 6aafa6783b
Added help, usage and comments 2021-02-01 23:52:28 +01:00
qorg11 e136eebd2c
Added implementation of lainsafecli written in c, so it's faster or something
compile with gcc clainsafecli.c -lcurl -o clainsafecli
2021-02-01 23:31:14 +01:00
qorg11 ffd96c69cc
Modified the way that lainsafe stores files
Now it creates a directory for the new file, with a random name, and
and stores the file with the original filename in there, so .tar.gz
issue is fixed.
2021-01-30 22:25:07 +01:00
qorg11 bdc0246971
fix grammar, lol and isntructions on using curl and hlainsafecli 2020-11-30 10:13:00 +01:00
qorg11 551ed15a5a
I no longer mantain the debian repo 2020-11-30 10:10:23 +01:00
qorg11 100c1666f3
Default file size to 100MB 2020-11-26 21:57:53 +01:00
qorg11 bb3ac7f248
s/github.com/codeberg.org/
some idiot will tell me that ACKSHUALLY is s/github\.com/codeberg.org

fuck you
2020-11-24 22:20:41 +01:00
qorg11 7a39f6a32c
fix typo lol 2020-11-18 19:00:23 +01:00
qorg11 267a7807d6
Update the example in readme.md 2020-11-18 18:58:58 +01:00
qorg11 ac4c841e64
Stop if request method is GET 2020-11-15 02:48:42 +01:00
26 changed files with 783 additions and 695 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
sakisafecli
*.o
*.d

View File

@ -1,4 +0,0 @@
install: lainsafecli
cp lainsafecli /usr/bin/
gzip -k doc/lainsafecli.1
cp doc/lainsafecli.1.gz /usr/share/man/man1

110
README.MD
View File

@ -1,110 +0,0 @@
# Lainsafe
### simple file upload.
### Installation:
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.
For more detailed information, look at the
[manpage](https://codeberg.org/qorg11/lainsafe/src/branch/master/doc/lainsafe.md)
## lainsafecli
### Installation
#### Debian
Lainsafe has official packages for Debian, they shold work for any
dpkg-based distro, such as Ubuntu and so on
You can download a possible outdated deb package
[here](http://repo.qorg11.net/debian/pool/main/l/lainsafecli/lainsafecli_0.3_all.deb)
If you want updates for your package, you have to add
`repo.qorg11.net` to your sources.list:
~~~
echo "deb http://repo.qorg11.net/debian stable main" >> /etc/apt/sources.list
wget http://repo.qorg11.net/repo.key -q -O - | sudo apt-key add
sudo apt updates
sudo apt install lainsafecli
~~~
#### Arch
[AUR - `lainsafecli`](https://aur.archlinux.org/packages/lainsafecli/)
### lainsafecli configuration
edit the file with your favorite text editor and change these
variables:
```$DEFAULT_SERVER``` This is the server where lainsafecli will try to
upload the files.
```$DISPLAY_ASCII``` By default 1, change to 0 if you don't want the
Lain ascii art to appear when you upload a file.
### Command line arguments
```--server``` If given, it will be used instead of $DEFAULT_SERVER
```--help``` Displays a simple help message and exits.
```--file``` the file you want to upload (useless in newer versions)
### Example
~~~
$ lainsafecli --server https://lainsafe.delegao.moe sicp.png
_..-- ----- --.._
,-'' `-.
, \
/ \
/ ` . \
' / || ;
; ^/| |/ | |
| /v /\`-'v√\'-|\ ,
| /v` ,--- ---- .^.| ;
: | /´@@`, ,@@`\ | ;
' | '. @@ / \@@ / |\ |;
| ^| ----- --- | \/||
` |` | /\ /
\ \ |/ |,
' ; \ /| |
` \ -- / | |
` `. .-' | /
v,- `;._ _.; | |
`'`\ |-_ -^'^'| |
------ |/
https://lainsafe.delegao.moe/files/EWwEnBHk.png
~~~
# Automatically removing files
Try [lsd](https://git.kalli.st/czar/lsd) (lainsafe daemon)
usage: `lsd <path> days`
lsd wont work with versions before 8a557ca
# but perl sux!!
No problem, [Lainsafe rewritten in
PHP](https://ech1.github.io/blog/servers/phpfilesafe/index.html)
(Not sure if it is compatible with lainsafecli, probably not)
# Donate
Thanks!
[Liberapay](https://liberapay.com/qorg11)
Bitcoin: bc1qghl6f27dpgktynpvkrxte2s3gm9pcv8vlwuzum
Monero: 47QTumjtqJabbo1s9pLDdXeJarLVLfs1AaEcbi1xrEiV852mqcbe5AHLNXTk7tH9MscxcxQDfJQnvH5LpxvfgwSJQZ3zbS6

38
README.md Normal file
View File

@ -0,0 +1,38 @@
# Sakisafe (formerly lainsafe)
## Simple file upload
## Features
* Written in perl
* Can be used as pastebin
* Or as a URL shorter
* Runs with CGI
* Tor access ;)
## Installation:
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 the command line interface for sakisafe (and other
filesharing services)
## usage
`sakisafecli --server=http://server <file>`
(for more info see -h)
# Donate
Thanks!
**Bitcoin**: bc1qghl6f27dpgktynpvkrxte2s3gm9pcv8vlwuzum
**Monero**: 47QTumjtqJabbo1s9pLDdXeJarLVLfs1AaEcbi1xrEiV852mqcbe5AHLNXTk7tH9MscxcxQDfJQnvH5LpxvfgwSJQZ3zbS6

View File

@ -1,94 +0,0 @@
.\"Manpage for lainsafe
.TH lainsafe 1
.SH NAME
lainsafe \- Simple file upload
.SH DESCRIPTION
lainsafe is a simple file upload server written in Perl + CGI.
It runs in a Web server (i.e. nginx) with a CGI handler
(i.e. fcgiwrap)
You also have to install the dependencies, in Debian:
.in +4n
.EX
apt install nginx libcgi-pm-perl fcgiwrap
.EE
.SH INSTALLATION
You can use any web server for running lainsafe. However, nginx is
recommended. The following configuration should work for nginx:
.I /etc/nginx/sites-enabled/lainsafe.conf
.in +4n
.EX
server
{
server_name lainsafe.foo.tld;
listen 80;
listen [::]:80;
client_max_body_size 100m; # max size 100MBs, change 10 to 100
# in upload.cgi in line 30
root /var/www/lainsafe;
location ~ \.cgi$ {
gzip off;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
fastcgi_index index.cgi;
fastcgi_param SCRIPT_FILENAME /var/www/lainsafe/$fastcgi_script_name;
}
}
.EE
.PP
The document root will be /var/www/lainsafe (be sure to change it in
.I root
and
.I fastcgi_param SCRIPT_FILENAME if you're going to use another directory
You also have to give the .cgi files +x permissions:
.in +4n
.EX
chmod +x *.cgi
.EE
.PP
And also, create the "files" directory manually, and give it
permissions so the user that is running nginx (usually)
.I www-data
can write on it.
.EX
chown www-data:www-data files
.EE
.SH TROUBLESHOOTING
.SS 502 Bad Gateway
Probably you're missing the
.I CGI
dependence, so install it with CPAN or apt
.in +4n
.EX
cpan -i CGI
apt install libcgi-pm-perl
.EE
.PP
If you still get this problem, run
.in +4n
.EX
perl <file>.cgi
.EE
.PP
so perl can help you debug the problem.
.SS 403 is returned
You probably forgot to give the files execution permissions.

View File

@ -1,79 +0,0 @@
NAME
====
lainsafe - Simple file upload
DESCRIPTION
===========
lainsafe is a simple file upload server written in Perl + CGI.
It runs in a Web server (i.e. nginx) with a CGI handler (i.e. fcgiwrap)
You also have to install the dependencies, in Debian:
apt install nginx libcgi-pm-perl fcgiwrap
INSTALLATION
============
You can use any web server for running lainsafe. However, nginx is
recommended. The following configuration should work for nginx:
*/etc/nginx/sites-enabled/lainsafe.conf*
server
{
server_name lainsafe.foo.tld;
listen 80;
listen [::]:80;
client_max_body_size 100m; # max size 100MBs, change 10 to 100
# in upload.cgi in line 30
root /var/www/lainsafe;
location ~ .cgi$ {
gzip off;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
fastcgi_index index.cgi;
fastcgi_param SCRIPT_FILENAME /var/www/lainsafe/$fastcgi_script_name;
}
}
The document root will be /var/www/lainsafe (be sure to change it in
*root* and *fastcgi_param SCRIPT_FILENAME if you\'re going to use
another directory*
You also have to give the .cgi files +x permissions:
chmod +x *.cgi
And also, create the \"files\" directory manually, and give it
permissions so the user that is running nginx (usually) *www-data* can
write on it.
chown www-data:www-data files
TROUBLESHOOTING
===============
502 Bad Gateway
---------------
Probably you\'re missing the *CGI* dependence, so install it with CPAN
or apt
cpan -i CGI
apt install libcgi-pm-perl
If you still get this problem, run
perl <file>.cgi
so perl can help you debug the problem.
403 is returned
---------------
You probably forgot to give the files execution permissions.

View File

@ -1,94 +0,0 @@
.\" Manpage for lainsafecli.
.TH lainsafecli 1
.SH NAME
lainsafecli \- Command line interface for lainsafe
.SH SYNOPSIS
lainsafecli
.I
[--tor | --i2p] [--server]
file
.SH DESCRIPTION
.I lainsafecli
uploads a file to a given lainsafe server. This server may
be specified with the
.I --server
flag. If
.I --server
is not given. The content of the variable
.I $DEFAULT_SERVER
will be used instead. This variable is in the script. In the official
packages. this is https://lainsafe.delegao.moe
.SH OPTIONS
.I --server
Sets the server to use. If it is not given $DEFAULT_SERVER will be used instead.
.I --help
Displays a simple help message and exits. This also specify which
server will be used if no
.I --server
is given.
.I --tor
Uses tor to upload the file. This requires
.I LWP::Protocol::socks
to be installed on your system. You also need to have tor running at
127.0.0.1:9050
If LWP::Protocol::socks is not installed, --tor is ignored, so don't
try it
.I --i2p
Routes the traffic through I2P. This uses the HTTP proxy (which is
normally in port 4444). So
.I LWP::Protocol::socks
is not necessary.
.I --get-response
If the server returned an error, --get-response will make lainsafecli
print the content, so it can help you find out why
lainsafecli isn't working!
.SH CONFIGURATION
there are configuration values in
.I lainsafecli
line 34.
.I $DISPLAY_ASCII
If true (Any number but 0), It will display an ASCII art if no error
returned.
.I $STORE_LINKS
If true, lainsafecli will store the links on a file, specified by
.I $LINKS_FILE
.SH TROUBLESHOOTING
.SS "whatever" is not running lainsafe. But works in the browser.
This only happens with https lainsafe instances. To solve that. Make
sure that the module
.I LWP::UserAgent::https
is installed. You can install it using
.I cpan(1)
.SS HTTP 413 is returned
The file you specified is too big for the instance. Try using another
instance. By default lainsafe supports up to 100MBs. But this can be configured in lainsafe
.B AND
the web server. If the file exceds whatever your
.B server
allows. lainsafe can set another limit. If the lainsafe limit is less
than the server limit. lainsafe will return its own error message.
.SH AUTHORS
qorg11 <qorg@vxempire.xyz>
.SH LICENSE
GPLv3 or later.

Binary file not shown.

View File

@ -1,80 +0,0 @@
NAME
====
lainsafecli - Command line interface for lainsafe
SYNOPSIS
========
lainsafecli *\[\--tor \| \--i2p\] \[\--server\]* file
DESCRIPTION
===========
*lainsafecli* uploads a file to a given lainsafe server. This server may
be specified with the *\--server* flag. If *\--server* is not given. The
content of the variable *\$DEFAULT_SERVER* will be used instead. This
variable is in the script. In the official packages. this is
https://lainsafe.delegao.moe
OPTIONS
=======
*\--server* Sets the server to use. If it is not given \$DEFAULT_SERVER
will be used instead.
*\--help* Displays a simple help message and exits. This also specify
which server will be used if no *\--server* is given.
*\--tor* Uses tor to upload the file. This requires
*LWP::Protocol::socks* to be installed on your system. You also need to
have tor running at 127.0.0.1:9050 If LWP::Protocol::socks is not
installed, \--tor is ignored, so don\'t try it
*\--i2p* Routes the traffic through I2P. This uses the HTTP proxy (which
is normally in port 4444). So *LWP::Protocol::socks* is not necessary.
*\--get-response* If the server returned an error, \--get-response will
make lainsafecli print the content, so it can help you find out why
lainsafecli isn\'t working!
CONFIGURATION
=============
there are configuration values in *lainsafecli* line 34.
*\$DISPLAY_ASCII* If true (Any number but 0), It will display an ASCII
art if no error returned.
*\$STORE_LINKS* If true, lainsafecli will store the links on a file,
specified by *\$LINKS_FILE*
TROUBLESHOOTING
===============
whatever is not running lainsafe. But works in the browser.
-----------------------------------------------------------
This only happens with https lainsafe instances. To solve that. Make
sure that the module *LWP::UserAgent::https* is installed. You can
install it using *cpan(1)*
HTTP 413 is returned
--------------------
The file you specified is too big for the instance. Try using another
instance. By default lainsafe supports up to 100MBs. But this can be
configured in lainsafe **AND** the web server. If the file exceds
whatever your **server** allows. lainsafe can set another limit. If the
lainsafe limit is less than the server limit. lainsafe will return its
own error message.
AUTHORS
=======
qorg11 \<qorg\@vxempire.xyz\>
LICENSE
=======
GPLv3 or later.

51
doc/sakisafecli.1 Normal file
View File

@ -0,0 +1,51 @@
.\"Manpage for lainsafe
.TH sakisafecli 1
.SH NAME
sakisafecli \- File uploader
.SH DESCRIPTION
sakisafecli is a file uploader. Intended for lainsafe, but also works
for 0x0.st, i.kalli.st and probably others.
.SH INSTALLATION
.in +4n
.EX
make
(or gcc sakisafecli.c -lcurl -o sakisafecli)
cp sakisafecli ~/.local/bin
.EE
.SH OPTIONS
.PP
.B
--server=<SERVER>
Specifies which server to use, can be a lainsafe instance, 0x0.st
instance or i.kalli.st. Probably other similar software.
.B
--tor
Routes all the traffic on the socks proxy at 127.0.0.1:9050,
which is usually tor. This can be edited in the
.B options.h
file
.B
--i2p
Routes all the traffic on the http proxy at 127.0.0.1:4444,
which is usually I2P. This can be edited in the
.B options.h
file
.B
--ipv6 or -6
Forces curl to use IPv6 only.
.B
--ipv4 or -4
Forces curl to use IPv4 only.
.B
--silent or -S
tells sakisafecli to be silent. This means, it won't
print the progress.

View File

@ -1,6 +1,6 @@
#!/usr/bin/perl
# This file is part of lainsafe.
# 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
@ -14,36 +14,15 @@
# You should have received a copy of the GNU General Public License
# along with lainsafe. If not, see <https://www.gnu.org/licenses/>.
my $disk_size = `df -h | awk 'NR==2 {print \$2; exit}'`;
my $disk_usage = `df -h | awk 'NR==2 {print \$3; exit}'`;
my $disk_free = `df -h | awk 'NR==2 {print \$4; exit}'`;
my $disk_percentage = `df -h | awk 'NR==2 {print \$5; exit}'`;
if ($ENV{REQUEST_METHOD} eq "POST") {
do "./upload.cgi";
exit;
}
my $SITE_URL = $ENV{REMOTE_ADDR};
print "Content-type: text/html\n\n";
print "<!DOCTYPE html>
<html lang=\"en\">
<head>
<title>lainsafe</title>
</head>
<body>
<h1>lainsafe</h1>
open(my $fh, "<index.html");
<img src='https://lainchan.org/static/lain_is_cute_datass_small.png'
width=200 alt='cool lain' />
<form ENCTYPE='multipart/form-data' method='post' action='upload.cgi'>
<input type='file' name='file' size='30'>
<input type='submit' value='upload'>
</form>
<a href='https://github.com/qorg11/lainsafe'>star me</a>
<h2>Terminal usage</h2>
<p>I recommend using lainsafecli to upload files to lainsafe, however, there is more than one way to do it.</p>
<code>curl -F 'file=@1605388889.png' $ENV{HTTP_HOST}$ENV{REQUEST_URI}</code><br/>
print $disk_free . available from . $disk_size . total;
</body>
</html>";
print while <$fh>;

38
http/index.css Normal file
View File

@ -0,0 +1,38 @@
p {
color: white;
display: block;
}
/* p code {display: block;} */
code {
background: #4e4e4e;
font-family: monospace;
color: #e3e3e3;
margin: 30px;
}
body, input, select, textarea {
color: #333;
font-size: 10pt;
line-height: 1.65em;
letter-spacing: -0.015em;
}
body {
background:#040304;
}
h1, h2 {
color: #e3e3e3;
}
.left {
position: absolute;
top: 0;
right: 30px;
border-left-color: #333;
border-left-width: 2px;
border-left-style: solid;
padding: 10px;
}

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>

BIN
http/saki.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -1,93 +1,108 @@
#!/usr/bin/perl
# This file is part of lainsafe.
# This file is part of sakisafe.
# lainsafe is free software: you can redistribute it and/or modify
# 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.
# lainsafe is distributed in the hope that it will be useful,
# 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 lainsafe. If not, see <https://www.gnu.org/licenses/>.
# along with sakisafe. If not, see <https://www.gnu.org/licenses/>.
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use Time::HiRes qw(gettimeofday);
my $q = CGI->new;
my $filename = $q->param('file');
# TODO: fix 502
my $url = $q->param('url');
my $upload_dir = "files/";
print $q->header();
$size = $ENV{CONTENT_LENGTH};
# Configuration
our $MAX_SIZE = 1024*1024*10; # Change for your size
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);
if($filename eq "")
{
print("What are you looking for?");
exit;
print $q->header();
# do something better
if ($url ne "") {
goto url_shorter;
}
if($size > $MAX_SIZE)
{
print("Max size for a file is $MAX_SIZE_MB MBs");
exit;
if ($filename eq "" || $ENV{REQUEST_METHOD} eq "GET") {
print("What are you looking for?");
exit;
}
my $extension = $filename;
$extension =~ s/.*\.//; # tar.gz sucks with this
$extension = "notcgi" if $extension eq "cgi";
# Get unix time in miliseconds
my $string;
$string = gettimeofday; # perl, what?
$string =~ s/\.//g;
my $upload_filehandle = $q->upload("file");
# onion urls will be http
my $prot = length $ENV{HTTPS} ? "https" : "http";
if ($filename) {
if ($size > $MAX_SIZE) {
print("Max size for a file is $MAX_SIZE_MB MBs");
exit;
}
$filename = $string . "." . $extension;
my $allowed_extension = 1;
my @chars = ("A"..."z","a"..."z");
my $dirname;
my $extension = $filename;
foreach(@not_allowed_extensions)
{
if($filename =~ /\.$_$/i)
{
$allowed_extension = 0;
last;
}
$dirname .= $chars[rand @chars] for 1..8;
$extension =~ s/.*\.//;
$filename .= ".notcgi" if $extension eq "cgi";
}
if($allowed_extension)
{
open(FILE,">$upload_dir/$filename");
binmode(FILE);
while(<$upload_filehandle>)
{
print FILE;
}
close FILE;
print $prot. "://" . $ENV{HTTP_HOST} . "/$upload_dir$filename";
}
else
{
print "The file extension .$extension is not allowed in this instance.";
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,150 +0,0 @@
#!/usr/bin/perl
# Lainsafe cli
# This file is part of lainsafe.
# 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/>.
use Getopt::Long;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
use strict;
use warnings;
# variables
my $help;
my $tor;
my $i2p;
my $get_response;
my $DEFAULT_SERVER;
my $file;
my $DISPLAY_ASCII;
my $STORE_LINKS;
my $LINKS_FILE;
my $proxy_enabled = 1;
# Default options, if no specified.
$DEFAULT_SERVER = "https://lainsafe.delegao.moe";
$DISPLAY_ASCII = 1; # 0 if you don't want the ascii
$STORE_LINKS = 1; # 0 if you don't want to keep track of your upload
$LINKS_FILE = "$ENV{HOME}/.cache/lainsafelinks";
eval "use LWP::Protocol::socks; 1" or $proxy_enabled = 0;
my $ASCII_ART = <<'EOF';
_..-- ----- --.._
,-'' `-.
, \
/ \
/ ` . \
' / || ;
; ^/| |/ | |
| /v /\`-'v√\'-|\ ,
| /v` ,--- ---- .^.| ;
: | /´@@`, ,@@`\ | ;
' | '. @@ / \@@ / |\ |;
| ^| ----- --- | \/||
` |` | /\ /
\ \ |/ |,
' ; \ /| |
` \ -- / | |
` `. .-' | /
v,- `;._ _.; | |
`'`\ |-_ -^'^'| |
------ |/
EOF
# Subs
sub help
{
print "lainsafecli, a command line interface for lainsafe.\n";
print "USAGE: lainsafecli [--tor | --i2p] [--server] FILE\n\n";
print "if --server not given, $DEFAULT_SERVER is used.\n";
print "--tor and --i2p are available\n" if $proxy_enabled;
print "--tor and --i2p are unavailable, flag are ignored\n" unless $proxy_enabled;
exit;
}
sub enable_tor
{
my $checker = $ua->proxy([qw(http https)] => 'socks://localhost:9050');
}
sub enable_i2p
{
my $checker = $ua->proxy([qw(http https)] => 'http://localhost:4444');
}
## PROGRAM
GetOptions ("server=s" => \$DEFAULT_SERVER,
"help|" => \$help,
"tor"=> \$tor,
"i2p"=>\$i2p,
"get-response"=>\$get_response
);
&help if $help || not defined $ARGV[0];
if ($i2p and $tor) {
print "What are you trying to do? I don't really get you sometimes...\n";
exit;
}
&enable_tor if $tor and $proxy_enabled;
&enable_i2p if $i2p and $proxy_enabled;
# check if file is given
$file = $ARGV[@ARGV-1];
die "File does not exist\n" unless -e $file;
my $req;
# Fake user agent
$ua->agent("Mozilla/5.0 (X11; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0");
# modify url if necessary
substr($DEFAULT_SERVER, 0, 0, 'https://') unless $DEFAULT_SERVER =~ /^(http|https):\/\//;
# check if server is running lainsafe
my $url_to_upload = $DEFAULT_SERVER . "/upload.cgi";
if (!$ua->get($url_to_upload)->is_success) {
print "$url_to_upload is not running lainsafe. (--get-response to check the error)\n";
print $ua->get($url_to_upload)->decoded_content if $get_response;
exit;
}
$req = $ua->post($url_to_upload,
Content_Type => 'form-data',
Content => [
"file" => [ $file ],
],
);
print $ASCII_ART if $DISPLAY_ASCII;
if ($req->{_content} =~ /instance/) # If someone knows how to do it another way, I'm all ears
{
print $req->{_content} . "\n";
exit;
}
print $req->{_content} . "\n";
if ($STORE_LINKS) {
open FILE,'>>',$LINKS_FILE or die $!;
print FILE $req->{_content} . " $file" ."\n";
close FILE;
}

166
sakisafecli/.clang-format Normal file
View File

@ -0,0 +1,166 @@
---
Language: Cpp
# BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Mozilla
BreakBeforeInheritanceComma: true
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 5
ContinuationIndentWidth: 5
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 5
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 5
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 5
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 5
UseCRLF: false
UseTab: Always
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

24
sakisafecli/Makefile Normal file
View File

@ -0,0 +1,24 @@
# sakisafecli makefile
TARGET = sakisafecli
OBJS = sakisafecli.o funcs.o
CC = cc
CFLAGSDEF += -MD -std=c11 -Wall -Wextra -lcurl -lconfig
CFLAGS += -O2 -ggdb
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(CFLAGSDEF) $(OBJS) -o $(TARGET)
%.o: %.c
$(CC) -c $(CFLAGS) $(CFLAGSDEF) $< -o $@
-include *.d
install: all
@cp sakisafecli /usr/local/bin/
.PHONY: clean install
clean:
rm -f *.d *.o sakisafecli

65
sakisafecli/funcs.c Normal file
View File

@ -0,0 +1,65 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <libconfig.h>
#include "sakisafecli.h"
size_t
write_data(void *buffer, size_t size, size_t nmemb,
void *userp)
{
memcpy(userp, buffer, nmemb*size);
return 0;
}
void
print_usage()
{
printf("USAGE: sakisafecli [--socks-proxy=socks_address|--http_proxy=proxy_address] [-6|-4] [--server] file\n");
return;
}
int
store_link(const char *path, const char *buf)
{
FILE *fp = fopen(path,"a+");
if(fp == NULL) {
fprintf(stderr,"Error opening file %i: %s\n",errno,
strerror(errno));
return -1;
}
fwrite(buf,strlen(buf),1,fp);
fputc('\n',fp);
fclose(fp);
return 0;
}
void
print_help()
{
printf("--server <server>: specifies the sakisafe server\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
"-t|--token: Authentication token (https://u.kalli.st)",
"--tor: uses tor.",
"--i2p: uses i2p.",
"-6|--ipv6: uses IPv6 only.",
"-4|--ipv6: uses IPv4 only.",
"--silent: doesn't print progress.",
"--help: print this message.\n");
return;
}
void
progress(void *clientp,
double dltotal,
double dlnow,
double ultotal,
double ulnow)
{
/* So I don't get a warning */
dltotal += 1;
dlnow += 1;
printf("\r%0.f uploaded of %0.f (\E[32;1m%0.f%%\E[30;0m)",ulnow,ultotal,
ulnow*100/ultotal);
fflush(stdout);
}

17
sakisafecli/options.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
/* clainsafecli options */
/* Default server you'll upload files to */
char *server = "https://lainsafe.kalli.st";
/* proxy urls, socks and http. in that order, by default they're
* configured to be used for tor and i2p, but if you have another
* socks/http proxy, you can set it here.
*/
/* Enable "history" files and where to store that file */
char history_file_path[256];
const int enable_links_history = 1;
const char *path = ".cache/lainsafelinks";

254
sakisafecli/sakisafecli.c Normal file
View File

@ -0,0 +1,254 @@
#include <libconfig.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <curl/curl.h>
#include "options.h"
#include "sakisafecli.h"
/* Config variables */
char *socks_proxy_url, *http_proxy_url;
bool socks_proxy_flag = false, http_proxy_flag = false;
bool ipv6_flag = false, ipv4_flag = false;
bool silent_flag = false;
config_t runtime_config;
int
main(int argc, char **argv)
{
struct curl_httppost *post = NULL;
struct curl_httppost *last = NULL;
char *token = NULL;
char *form_key = "file";
char *buffer = (char *)calloc(1024, sizeof(char));
if(buffer == NULL) {
fprintf(stderr, "Error allocating memory!\n");
return -1;
}
char config_location[512];
char *sakisafeclirc_env = getenv("SAKISAFECLIRC");
if(sakisafeclirc_env == NULL) {
snprintf(config_location, 512, "%s/.sakisafeclirc", getenv("HOME"));
FILE *fp = fopen(config_location, "r");
if(fp != NULL) {
parse_config_file(fp);
fclose(fp);
}
} else {
strncpy(config_location, sakisafeclirc_env, 512);
FILE *fp = fopen(config_location, "r");
if(fp != NULL) {
parse_config_file(fp);
fclose(fp);
}
}
CURL *easy_handle = curl_easy_init();
if(!easy_handle) {
fprintf(stderr, "Error initializing libcurl\n");
return -1;
}
if(argc == optind) {
print_usage();
free(buffer);
curl_easy_cleanup(easy_handle);
return -1;
}
int option_index = 0;
static struct option long_options[] = {
{ "server", required_argument, 0, 's' },
{ "help", no_argument, 0, 'h' },
{ "socks-proxy", required_argument, 0, 'p' },
{ "token", required_argument, 0, 'T' },
{ "http-proxy", required_argument, 0, 'P' },
{ "silent", no_argument, 0, 'S' },
{ "ipv4", no_argument, 0, '4' },
{ "ipv6", no_argument, 0, '6' },
{ 0, 0, 0, 0 }
};
int c = 0;
while((c = getopt_long(
argc, argv, "46hT:p:P:Ss:", long_options, &option_index)) !=
-1) {
switch(c) {
case 's':
server = optarg;
break;
case 'h':
print_help();
free(buffer);
curl_easy_cleanup(easy_handle);
return 0;
break;
case 'p':
socks_proxy_url = optarg;
socks_proxy_flag = true;
break;
case 'P':
http_proxy_url = optarg;
http_proxy_flag = true;
break;
case 'S':
silent_flag = true;
break;
case 'T':
token = optarg;
break;
case '4':
ipv4_flag = true;
break;
case '6':
ipv6_flag = true;
break;
case '?':
print_usage();
return 0;
break;
default:
print_usage();
return 0;
break;
}
}
if(access(argv[optind], F_OK)) {
fprintf(stderr, "Error opening file\n");
return -1;
}
/* curl options */
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);
/* Proxy options */
if(socks_proxy_flag && http_proxy_flag) {
fprintf(stderr, "Socks_Proxy and HTTP_PROXY can't be used at once\n");
return -1;
} else if(socks_proxy_flag) {
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) {
curl_easy_setopt(easy_handle, CURLOPT_PROXY, http_proxy_url);
curl_easy_setopt(easy_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
/* Which address to use */
if(ipv6_flag)
curl_easy_setopt(easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
else if(ipv4_flag)
curl_easy_setopt(easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
else
curl_easy_setopt(
easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
/* Form parameters */
/* File name */
/* TODO: make it iterate on args so you can upload multiple files
* at once (sakisafecli file1 file2 ... filen)
*/
for(int i = optind; i < argc; i++) {
curl_formadd(&post,
&last,
CURLFORM_COPYNAME,
form_key,
CURLFORM_FILE,
argv[i],
CURLFORM_END);
/* Actual file content */
curl_formadd(&post,
&last,
CURLFORM_COPYNAME,
form_key,
CURLFORM_COPYCONTENTS,
argv[i],
CURLFORM_END);
if(token)
curl_formadd(&post,
&last,
CURLFORM_COPYNAME,
"token",
CURLFORM_COPYCONTENTS,
token,
CURLFORM_END);
curl_easy_setopt(easy_handle, CURLOPT_NOPROGRESS, silent_flag);
curl_easy_setopt(easy_handle, CURLOPT_PROGRESSFUNCTION, progress);
curl_easy_setopt(easy_handle, CURLOPT_HTTPPOST, post);
curl_easy_perform(easy_handle);
if(!silent_flag)
putchar('\n');
printf("%s", buffer);
}
curl_formfree(post);
curl_easy_cleanup(easy_handle);
/* Store link if needed */
if(enable_links_history) {
snprintf(history_file_path, 256, "%s/%s", getenv("HOME"), path);
store_link(history_file_path, buffer);
}
free(buffer);
config_destroy(&runtime_config);
return 0;
}
void
parse_config_file(FILE *config)
{
config_init(&runtime_config);
config_read(&runtime_config, config);
config_setting_t *cur;
cur = config_lookup(&runtime_config, "server");
if(config != NULL) {
if(cur != NULL)
server = (char *)config_setting_get_string(cur);
cur = config_lookup(&runtime_config, "socks_proxy");
if(cur != NULL)
socks_proxy_url = (char *)config_setting_get_string(cur);
cur = config_lookup(&runtime_config, "http_proxy");
if(cur != NULL)
http_proxy_url = (char *)config_setting_get_string(cur);
cur = config_lookup(&runtime_config, "use_socks_proxy");
if(cur != NULL)
socks_proxy_flag = config_setting_get_bool(cur);
cur = config_lookup(&runtime_config, "use_http_proxy");
if(cur != NULL)
http_proxy_flag = config_setting_get_bool(cur);
cur = config_lookup(&runtime_config, "silent");
if(cur != NULL)
silent_flag = config_setting_get_bool(cur);
cur = config_lookup(&runtime_config, "force_ipv6");
if(cur != NULL)
ipv6_flag = config_setting_get_bool(cur);
cur = config_lookup(&runtime_config, "force_ipv4");
if(cur != NULL)
ipv4_flag = config_setting_get_bool(cur);
}
}

22
sakisafecli/sakisafecli.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <stdlib.h>
#include <stdio.h>
size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp);
void
print_usage();
int
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);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 KiB