t4t

minimal, consent-based webpaste
git clone git://git.girlpoison.org/t4t
Log | Files | Refs | README | LICENSE

commit ead63f21453971163c9235d9b7ea4ea866f81055
parent 90fff06c0d5d196c7d021595858ac06094e364f3
Author: Giygas <mvk@girlpoison.org>
Date:   Tue,  4 Jun 2024 01:46:36 +0200

Source profile, command line options, bugfixes...

Diffstat:
MREADME | 104++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mmime.types | 3---
Mt4t | 26+++++++++++---------------
Mt4t-receive | 94+++++++++++++++++++++++++++++++++++++++++++------------------------------------
4 files changed, 136 insertions(+), 91 deletions(-)

diff --git a/README b/README @@ -5,11 +5,11 @@ It consists of two scripts: t4t, and t4t-receive. t4t uploads files to T4T_HOST over ssh, which prompts t4t-receive to write the received data to the specified file. This is accomplished through setting up your authorized_keys in a certain way; -see 'SETUP' below. +see 'SIMPLE SETUP' below. Usage - t4t ------------ -t4t [-u user] [-h host] [-N] [files...] +t4t [-u user] [-h host] [files...] DESCRIPTION Pipes the given files to user@host through ssh. If no files are specified, @@ -24,44 +24,88 @@ OPTIONS T4T_USER. -h host Specify which host to connect to over ssh. This overrides T4T_HOST. - -N - Do not retain file names when uploading. This will prompt t4t to - generate one for you. Usage - t4t-receive -------------------- -t4t-receive [-D] [-l limit] name +SYNOPSIS + t4t-receive [-B blacklist] [-d dir] [-l limit] [-M | -m mimefile] [-r root] + [-S | -s profile] [-t tmp] [-u url] [name] DESCRIPTION - Writes file data from stdin to name in T4T_ROOT ($HOME/www by default). - If name does not have an extension, t4t-receive will attempt to identify - the data and pick an appropriate extension. + Writes file data from stdin to root/name (~/www by default). + + Name is inferred through SSH_ORIGINAL_COMMAND. If this variable is unset, + t4t-receive will use the command line option. If no name has been specified + on the command line, it will generate a random name automatically. + + If a file with the given name exists, t4t-receive appends random characters + to the given name until it is unique. After a successful write, t4t-receive prints a URL to the uploaded file, - constructed with the help of T4T_URL. + constructed with the help of url. + + If -S is not set, t4t-receive sources the shell profile (~/.profile + by default) for relevant variables. All shell variables are overridden by + their command line option counterparts (see below) OPTIONS - -D - If the name does not have a file extension, do not attempt to guess - one. + -B blacklist + Defines a space-delimited list of extensions to be stripped from name. + Its corresponding shell variable is T4T_BLACKLIST. + + -d dir + Write to subdirectory dir in root. Its corresponding shell variable + is T4T_DIR. + -l limit - Specifies the maximum file size for the incoming data. limit may + Defines the maximum file size for the incoming data. limit may optionally be followed by a unit multiplier, much like dd. e.g. - KB, MB, GB, TB - -SETUP - Uncomment and define the variables at the start of the script. T4T_ROOT is - described above. T4T_URL defines the URL displayed in the output. - - T4T_MIMETYPES specifies which file to look for extensions in. It defaults - to '/etc/mime.types', but it is recommended to set it to the saner - mime.types provided with t4t. - - Create an account and home directory for the user account that clients - will connect to. It is recommended to choose 't4t' as the name. Ensure - that this user is able to accept incoming ssh connections, and set up the - .ssh/authorized_keys file like so: - command="$HOME/t4t-receive" ssh-rsa ...public key for user 1... - command="$HOME/t4t-receive -l 20M" ssh-rsa ...public key for user 2... + KB, MB, GB, TB. Negative numbers correspond to unlimited file size. + Its corresponding shell variable is T4T_LIMIT. The default is '-1'. + + -M + Do not attempt to guess an appropriate extension based on the file's + MIME type. + + -m + Defines the file to consult for extensions. Its corresponding shell + variable is T4T_MIME. The default is '/usr/share/t4t/mime.types'. + Using '/etc/mime.types' may result in nonsensical extensions. + + -r root + Defines the root directory to write to. Its corresponding shell + variable is T4T_ROOT. + + -S + Do not source profile for environment variables. + + -s profile + Defines the file to source for environment variables. + + -t tmp + Defines the directory to store intermediary files in. Its corresponding + shell variable is T4T_TMP. The default is '/tmp'. + + -u url + Defines the url to display in the output. Its corresponding shell + variable is T4T_URL. + +SIMPLE SETUP + Create a user account and home directory that clients will connect to. + It is recommended to choose 't4t' as the name. Ensure that this user is able + to accept incoming ssh connections. + + Define the default variables in .profile. T4T_ROOT and T4T_URL are required. + It is recommended to change T4T_MIME to the correct path depending on your + distribution and installation. + + Create a line for each authorised user in your .ssh/authorized_keys file like so: + command="t4t-receive -l -1 -B ''" ssh-rsa ...public key for owner + command="t4t-receive -l 100M -d aaron" ssh-rsa ...public key for aaron + command="t4t-receive -d bill" ssh-rsa ...public key for bill + command="t4t-receive -d cynthia" ssh-rsa ...public key for cynthia ...etc + Users may now leverage the t4t script described above, or upload directly + over ssh: + ssh -T t4t@[host] [name] <FILE diff --git a/mime.types b/mime.types @@ -25,9 +25,6 @@ image/png png image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd -text/html html -text/html htm -text/javascript js text/plain txt text/xml dtd text/xml xml diff --git a/t4t b/t4t @@ -2,20 +2,14 @@ PROGNAME="$(basename $0)" err() { echo "$PROGNAME: $*" >&2; } -usage() { err "usage: $PROGNAME [-u user] [-h host] [-N] [files...]"; } +usage() { err "usage: $PROGNAME [-u user] [-h host] [files...]"; } randstring() { tr -dc 'A-Za-z0-9_\-' </dev/urandom | head -c "${1-8}"; } -KEEPNAMES=1 -while getopts "u:h:N" OPT; do +while getopts "u:h:" OPT; do case ${OPT} in - u) - T4T_USER="${OPTARG}";; - h) - T4T_HOST="${OPTARG}";; - N) - unset KEEPNAMES;; - *) - usage; exit 1;; + u) T4T_USER="${OPTARG}";; + h) T4T_HOST="${OPTARG}";; + *) usage; exit 1;; esac done shift $((OPTIND-1)) @@ -23,9 +17,11 @@ shift $((OPTIND-1)) [ "$T4T_HOST" ] || { err "set T4T_HOST or pass -h"; exit 1; } for F in "${@:--}"; do - if [ "$F" != "-" ] && [ ! -e "$F" ]; then err "no such file '$F'"; continue; fi - if [ ! "$KEEPNAMES" ] || [ "$F" == "-" ]; then NAME="$(randstring)" - else NAME="$(basename "$F")"; fi + unset NAME + if [ "$F" != "-" ]; then + [ ! -e "$F" ] && { err "no such file '$F'"; continue; } + NAME="$(basename "$F")"; + fi - cat "$F" | ssh "${T4T_USER-t4t}@$T4T_HOST" "$NAME" + cat "$F" | ssh -T "${T4T_USER-t4t}@$T4T_HOST" "$NAME" done diff --git a/t4t-receive b/t4t-receive @@ -1,56 +1,64 @@ #!/bin/bash -# Set these variables to your liking. -#T4T_ROOT="$HOME/www" -#T4T_URL="https://t4t.fun" -#T4T_MIMETYPES="$HOME/mime.types" - PROGNAME="$(basename $0)" -err() { echo "$PROGNAME: $*" >&2; } -usage() { err "usage: $PROGNAME [-D] [-l limit] name"; } +panic() { echo "$PROGNAME: $*" >&2; exit 1; } +usage() { panic "usage: $PROGNAME [-B blacklist] [-d dir] [-l limit] [-M | -m mimefile]"\ + "[-r root] [-S | -s profile] [-t tmp] [-u url] name"; } randstring() { tr -dc 'A-Za-z0-9_\-' </dev/urandom | head -c ${1-8}; } +clean() { [ -e "$TMPFILE" ] && rm "$TMPFILE"; } +trap 'clean; exit' INT TERM EXIT QUIT HUP -[ "$T4T_ROOT" ] && [ -d "$T4T_ROOT" ] || { err "T4T_ROOT not set or directory doesn't exist"; exit 1; } -[ "$T4T_URL" ] || { err "T4T_URL not set."; exit 1; } - -MIMEDETECT=1; -while getopts "Dl:" OPT; do +OPTS=("BLACKLIST DETECT DIR LIMIT MIME PROFILE ROOT TMP URL") +unset $OPTS +DETECT=1; SOURCE=1 +while getopts "B:d:l:Mm:r:Ss:t:u:" OPT; do case ${OPT} in - D) - unset MIMEDETECT;; - l) - T4T_LIMIT="${OPTARG}";; - *) - usage; exit 1;; + B) BLACKLIST="${OPTARG}";; + d) DIR="${OPTARG}";; + l) LIMIT="${OPTARG}";; + M) DETECT=0;; + m) MIME="${OPTARG}";; + r) ROOT="${OPTARG}";; + S) SOURCE=0;; + s) PROFILE="${OPTARG}";; + t) TMP="${OPTARG}";; + u) URL="${OPTARG}";; + *) usage;; esac -done -shift $((OPTIND-1)) +done; shift $((OPTIND-1)) + +[ $SOURCE -ne 0 ] && { source "${PROFILE-"$HOME/.profile"}" || exit 1; } +for V in $OPTS; do eval "$(printf 'T4T_%s=${%s-"$T4T_%s"}\n' "$V" "$V" "$V")"; done + +[ "$T4T_ROOT" ] || panic "T4T_ROOT not set."; +[ -d "$T4T_ROOT" ] || panic "T4T_ROOT: '$T4T_DIR' no such directory" +[ "$T4T_DIR" ] && [ ! -d "$T4T_ROOT/$T4T_DIR" ] && panic "T4T_DIR: '$T4T_ROOT/$T4T_DIR' no such directory" +TARGETDIR="$T4T_ROOT${T4T_DIR:+"/$T4T_DIR"}" +[ "$T4T_URL" ] || panic "T4T_URL not set." +[ "${T4T_MIME:="/usr/share/t4t/mime.types"}" ] && [ ! -f "$T4T_MIME" ] && panic "T4T_MIME: no such file '$T4T_MIME'" +[ -d "${T4T_TMP:=/tmp}" ] || panic "T4T_TMP: '$T4T_TMP' no such directory" +T4T_BLACKLIST=("$T4T_BLACKLIST") -NAME="$(tr -dc 'A-Za-z0-9_\-.' <<<"$SSH_ORIGINAL_COMMAND")" -[ "$NAME" ] || { err "no name specified"; exit 1; } -[ "$NAME" == "." ] || [ "$NAME" == ".." ] && err "illegal file name" && exit 1 +NAME="$(tr -dc 'A-Za-z0-9_\-.' <<<"${SSH_ORIGINAL_COMMAND:-"$*"}")" +[ "$NAME" ] || NAME="$(randstring 4)" EXT="$(grep -Eo '\.[a-zA-Z0-9]+$' <<<"$NAME")" +BNAME="$(basename ${EXT:+-s$EXT} "$NAME")" -while test -e "$T4T_ROOT/$NAME"; do - SNAME="$(basename ${EXT:+-s$EXT} "$NAME")" - NAME="$SNAME$(randstring 1)$EXT" -done -FILE="$T4T_ROOT/$NAME" - -head -c ${T4T_LIMIT-10M} > "$FILE" -[ -e "$FILE" ] || { err "could not write file '$NAME'"; exit 1; } -if [ $(du "$FILE" | cut -f1) -eq 0 ]; then - rm "$FILE" - err "empty file discarded" - exit 1 -fi +for E in $T4T_BLACKLIST; do [ "$EXT" == "$E" ] && unset EXT; done + +TMPFILE="$T4T_TMP/t4t-$(randstring 8)" +head -c ${T4T_LIMIT:--1} > "$TMPFILE" +[ -e "$TMPFILE" ] || panic "could not write temporary file" +[ $(du "$TMPFILE" | cut -f1) -eq 0 ] && { panic "empty file discarded"; } -if [ "$MIMEDETECT" ] && [ ! "$EXT" ]; then - MIME="$(file -b --mime-type "$FILE")" - EXT=".$(cat "${T4T_MIMETYPES-/etc/mime.types}" | awk -v m="$MIME" '$1==m{print $NF}')" - [ ! "$EXT" ] && EXT=".txt" - mv "$FILE" "$FILE$EXT" || exit 1; - NAME="$(basename "$FILE")$EXT" +if [ $DETECT -ne 0 ] && [ ! "$EXT" ]; then + TYPE="$(file -b --mime-type "$TMPFILE")" + EXT=".$(cat "$T4T_MIME" | awk -v t="$TYPE" '$1==t{print $NF; exit}')" + [ "$EXT" == "." ] && EXT=".txt" fi -echo "$T4T_URL/$NAME" +# security note: test -e $TARGETDIR/. and $TARGETDIR/.. always eval to true +while test -e "$TARGETDIR/$BNAME$EXT"; do BNAME="$BNAME$(randstring 1)"; done +mv "$TMPFILE" "$TARGETDIR/$BNAME$EXT" + +echo "$T4T_URL/${T4T_DIR:+"$T4T_DIR/"}$BNAME$EXT"