From 2ec1b6ee59066d79f93a119f1f8eac95e31b2345 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Wed, 26 Aug 2026 05:36:12 -0400 Subject: litterbox: Added. Wrapper for litter.catbox.moe temporary file storage API. --- litterbox | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100755 litterbox diff --git a/litterbox b/litterbox new file mode 100755 index 0000000..826619a --- /dev/null +++ b/litterbox @@ -0,0 +1,264 @@ +#!/bin/bash + +# API spec: https://litterbox.catbox.moe/tools.php +# curl -F "reqtype=fileupload" -F "time=1h" -F "fileToUpload=@filename" \ +# https://litterbox.catbox.moe/resources/internals/api.php +# time can be 1h, 12h, 24h, or 72h +# The following file types are currently not allowed: +# .exe, .scr, .cpl, .doc*, .jar +# ...so this script will gzip those automatically. otherwise, use -z +# to gzip and -Z to zip. + +SELF="$( basename $0 )" +APIURL="https://litterbox.catbox.moe/resources/internals/api.php" +URLS="" +EXPIRE="1" +DELAY="${DELAY:-2}" +UPLOAD_COUNT=0 + +die() { + echo "$SELF: fatal: $@" 1>&2 + exit 1 +} + +warn() { + echo "$SELF: warning: $@" 1>&2 +} + +info() { + [ "$VERBOSE" = "1" ] && echo "$SELF: info: $@" 1>&2 +} + +usage() { + cat < + +Each file can be a filename, a directory name, or "-" for standard +input. If no files are given, $SELF reads from standard input. + +Once a file is uploaded, its URL is printed on stdout. +If xsel is installed, it's also copied to the X paste buffer. + +When uploading multiple files, all the URLs are copied to +the X buffer (separated by spaces). Also, a delay of $DELAY +seconds is added between uploads, to avoid hammering the site. + +Options: + -e Set expiration time in hours. Allowed values are 1, 12, + 24, or 72. Default is $EXPIRE. + + -g Upload gzipped files. This is automatically enabled + when uploading files whose names end in .exe, .scr, + .cpl, .doc*, .jar (unless -z is given). Also, directories + are automatically tarred/gzipped (unless -z is given). + + -z Upload zipped files or dirs. + + -t Upload tarred and gzipped directory. Won't work with + single files (use -g or -z for those). + + -c Upload encrypted file. Currently this means the file + is encrypted with 'openssl enc -pbkdf2 -aes-256-cbc', and + you're prompted for an encryption key. Whoever downloads + the encrypted file will have to decrypt it manually, + e.g. with: + openssl enc -d -pbkdf2 -aes-256-cbc < file.encrypted > file.decrypt + + -v Verbose operation. + +Author: B. Watson +License: WTFPL (Do WTF you want with this) +EOF +} + +set_expiration() { + case "$1" in + 1|12|24|72) ;; # OK + *) die "invalid expiration time, allowed values are: 1 12 24 72" ;; + esac + EXPIRE="$1" +} + +add_url() { + if [ "$URLS" = "" ]; then + URLS="$1" + else + URLS+=" $1" + fi + : $(( UPLOAD_COUNT++ )) +} + +copy_urls() { + if ! xsel --version &>/dev/null; then + warn "xsel not found in PATH, not copying URL(s) to clipboard" + return + fi + + if [ "$DISPLAY" = "" ]; then + warn "DISPLAY not set in env, not copying URL(s) to clipboard" + return + fi + + echo -n "$URLS" | xsel -i +} + +compress_file() { + local ext + local basefile + local is_dir + + [ -d "$FILE" ] && is_dir=1 + + if [ "$ZIP" = "1" ]; then + ext=.zip + else + ext=.gz + fi + + basefile="$( basename "$FILE" )" + + # TODO: create a random tmp dir, don't use /tmp! + TMPFILE="${TMP:-/tmp}/$basefile$ext" + rm -f "$TMPFILE" + if [ "$ZIP" = "1" ]; then + zip -qr "$TMPFILE" "$FILE" + info "zipped $FILE as $TMPFILE" + else + if [ "$is_dir" = 1 ]; then + tar cfz "$TMPFILE" "$FILE" + info "tarred up $FILE as $TMPFILE" + else + gzip -9 < "$FILE" > "$TMPFILE" + info "gzipped $FILE as $TMPFILE" + fi + fi + FILE="$TMPFILE" +} + +# TODO: curl options: +# --max-time --retry --retry-max-time +upload_file() { + local url + local use_compression + + info "preparing to upload $FILE" + + case "$FILE" in + *.exe|*.scr|*.cpl|*.doc*|*.jar) + warn "forbidden file extension, compression forced" + use_compression=1 ;; + *) + use_compression="$COMPRESS" ;; + esac + + if [ "$use_compression" = 1 ]; then + # can't easily zip stdin, write it to a file + if [ "$FILE" = "-" ]; then + FILE="${TMP:-/tmp}/$SELF.stdin" + cat > "$FILE" + if [ "$?" != 0 ]; then + rm -f "$FILE" + return + fi + fi + compress_file # resets FILE, sets TMPFILE + fi + + # at this point, we have an actual file, even if input was stdin, + # so we can encrypt it. + if [ "$ENC" = "1" ]; then + CRYPTFILE="$FILE.aes" + openssl enc -pbkdf2 -aes-256-cbc < "$FILE" > "$CRYPTFILE" + if [ "$?" != "0" ]; then + warn "encryption failed, skipping file" + return + fi + FILE="$CRYPTFILE" + fi + + if [ "$URLS" != "" ]; then + info "sleeping $DELAY sec between uploads" + sleep "$DELAY" + fi + + info "uploading $FILE" + + url="$( + cat "$FILE" | \ + curl --silent \ + -F "reqtype=fileupload" \ + -F "time=${EXPIRE}h" \ + -F "fileToUpload=@-" \ + "$APIURL" + )" + # TODO: check curl's exit status! + + case "$url" in + https://litter.catbox.moe/*) add_url "$url" ;; + *) warn "upload failed" ;; + esac +} + +# main() +if [ "$1" = "--help" ]; then + usage ; exit 0 +fi + +while getopts ":e:gzcv" OPT; do + case "$OPT" in + e) set_expiration "$OPTARG" ;; + g) GZIP=1 ;; + z) ZIP=1 ;; + c) ENC=1 ;; + v) VERBOSE=1 ;; + *) die "invalid option -$OPTARG, try --help" ;; + esac +done + +[ "$GZIP" = 1 -a "$ZIP" = 1 ] && die "can't give both -g and -z" +[ "$GZIP" = 1 -o "$ZIP" = 1 ] && COMPRESS=1 + +info "expire time set to $EXPIRE hour(s)" + +shift $(($OPTIND - 1)) + +[ "$1" = "" ] && set -- - +for arg; do + TMPFILE="" + CRYPTFILE="" + + if [ "$arg" = "-" -o -f "$arg" ]; then + FILE="$arg" + elif [ -d "$arg" ]; then + FILE="$arg" + compress_file # sets FILE + else + warn "$arg not a regular file, ignoring" + continue + fi + + upload_file + + if [ "$TMPFILE" != "" ]; then + info "removing temp file $TMPFILE" + rm -f "$TMPFILE" + fi + + if [ "$TMPFILE" != "" ]; then + info "removing temp encrypted file $CRYPTFILE" + rm -f "$CRYPTFILE" + fi +done + +if [ "$UPLOAD_COUNT" = "0" ]; then + die "no files uploaded" +fi + +echo "$URLS" +copy_urls + +info "$UPLOAD_COUNT file(s) uploaded" + +exit 0 -- cgit v1.2.3