npaste is a simple pastebin for text and images, supporting end-to-end encryption using GPG.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

334 lines
11 KiB

#!/bin/sh
usage() {
echo "Quick CLI for sending data to npaste"
echo ""
echo "Requires: curl"
echo ""
echo "npaste [OPTIONS] file"
printf "\t-h --help\n"
printf "\t-p --plaintext No syntax highlighting.\n"
printf "\t--get PASTE_ID Downloads a paste and (optionally decrypts it and) saves it to the current folder.\n"
printf "\t--age When to delete this item. Syntax: n[m|h|d|y], where n is an integer. minutes, hours, days, years. Example: 1h. Default: 0, ie. never deleted.\n"
printf "\t--max-opens Restrict how many times this paste can be opened.\n"
printf "\t--encrypt The paste will be encrypted using a secret key not known to the server.\n"
printf "\t--vault If using --encrypt, this will also encrypt it with a password that is not in the URL.\n"
printf "\t--archive The paste will be restorable for the submitter with the archive flag.\n"
printf "\t--no-archive The paste will NOT be archived, regardless of default defined in config file.\n"
printf "\t--no-auto-pipe Don't use auto pipe command as defined in config file\n"
printf "\t--config Default: $HOME/.config/npaste/cli.conf\n"
echo ""
echo "The supplied file may be a file with or without suffix or simply '-' for STDIN. Default if omitted is STDIN."
}
ntharg() {
# clever hack from: https://stackoverflow.com/a/14649955
shift $1
printf '%s\n' "$1"
}
LAST_ARG=$(ntharg $# "$@")
api_request() {
# parameters to this function
local NPASTE_username=$1
local NPASTE_apikey=$2
local NPASTE_url=$3
# $n... parameters directly to curl
# get curl opts
local NPASTE_opts=""
while [ "$4" != "" ]; do
NPASTE_opts="$NPASTE_opts $4"
shift
done
curl --basic --user "$NPASTE_username:$NPASTE_apikey" --silent $NPASTE_opts "$NPASTE_url"
return $?
}
# defaults
NPASTE_IS_PLAINTEXT=0
NPASTE_AGE=0
NPASTE_CONFIG="$HOME/.config/npaste/cli.conf"
NPASTE_VAULTS="$HOME/.config/npaste/vaults"
NPASTE_FILE="-" # default stdin
NPASTE_USE_AUTO_PIPE_COMMAND=1
NPASTE_ARCHIVE=0
NPASTE_MAX_OPENS=0
NPASTE_NO_ARCHIVE=0
# override from config if no value has been set
NPASTE_AGE_HAS_BEEN_SET=0
NPASTE_MAX_OPENS_HAS_BEEN_SET=0
# get parameters
while [ "$1" != "" ]; do
PARAM=$(echo $1 | awk -F= '{print $1}')
VALUE=$(echo $1 | awk -F= '{print $2}')
case $PARAM in
-h | --help)
usage
exit
;;
-p | --plaintext)
NPASTE_IS_PLAINTEXT=1
;;
--get)
if [ "$2" == "" ]; then
echo "Must specify PASTE_ID"
exit 1
fi
NPASTE_PASTE_ID="$2"
;;
--output)
NPASTE_GET_OUTPUT=1
;;
--max-opens)
NPASTE_MAX_OPENS=$VALUE
NPASTE_MAX_OPENS_HAS_BEEN_SET=1
;;
--age)
NPASTE_AGE=$VALUE
NPASTE_AGE_HAS_BEEN_SET=1
;;
--encrypt)
NPASTE_ENCRYPT=1
;;
--vault)
NPASTE_VAULT=$VALUE
;;
--archive)
NPASTE_ARCHIVE=1
;;
--no-archive)
NPASTE_NO_ARCHIVE=1
;;
--config)
NPASTE_CONFIG=$VALUE
;;
--no-auto-pipe)
NPASTE_USE_AUTO_PIPE_COMMAND=0
;;
*)
if [ "$1" = "$LAST_ARG" ]; then
NPASTE_FILE="$1"
else
if [ "$NPASTE_PASTE_ID" == "" ]; then
echo "ERROR: unknown parameter \"$PARAM\""
usage
exit 1
fi
fi
;;
esac
shift
done
NPASTE_USERNAME=""
NPASTE_APIKEY=""
NPASTE_URL=""
NPASTE_AUTO_PIPE_COMMAND=""
NPASTE_DEFAULT_ARCHIVE=0
NPASTE_DEFAULT_ENCRYPT=0
NPASTE_ENCRYPTION_KEY_LENGTH=16
# read config file
while read -r line || [[ -n $line ]]; do
PARAM=$(echo $line | awk -F= '{print $1}')
VALUE=$(echo $line | awk -F= '{print $2}')
case $PARAM in
username)
NPASTE_USERNAME=$VALUE
;;
apikey)
NPASTE_APIKEY=$VALUE
;;
url)
NPASTE_URL=$VALUE
;;
default_age)
if [ $NPASTE_AGE_HAS_BEEN_SET -eq 0 ]; then
# override age, as no age has been provided at runtime
NPASTE_AGE=$VALUE
fi
;;
default_archive)
NPASTE_DEFAULT_ARCHIVE=$VALUE
;;
default_encrypt)
NPASTE_DEFAULT_ENCRYPT=$VALUE
;;
default_max_opens)
if [ $NPASTE_MAX_OPENS_HAS_BEEN_SET -eq 0 ]; then
# override max opens, as no max opens has been provided at runtime
NPASTE_MAX_OPENS=$VALUE
fi
;;
encryption_key_length)
NPASTE_ENCRYPTION_KEY_LENGTH=$VALUE
;;
auto_pipe_command)
if [ $NPASTE_USE_AUTO_PIPE_COMMAND -eq 1 ]; then
NPASTE_AUTO_PIPE_COMMAND=$VALUE
fi
esac
done < "$NPASTE_CONFIG"
# check if we have info for auth
if [ -z "$NPASTE_USERNAME" ] || [ -z "$NPASTE_APIKEY" ] || [ -z "$NPASTE_URL" ]; then
echo "Invalid config."
echo ""
echo "Example:"
printf "\tusername=johndoe\n"
printf "\tapikey=abcd\n"
printf "\turl=https://paste.example.com/\n"
printf "\tdefault_age=8h\n"
printf "\tdefault_archive=0\n"
printf "\tauto_pipe_command=xsel -i -b\n"
echo ""
echo "All options are required, except default_age, default_archive and auto_pipe_command, which are optional."
exit 2
fi
# If $NPASTE_PASTE_ID has been set, get the paste and exit
if [ "$NPASTE_PASTE_ID" != "" ]; then
PASTE_URL="$NPASTE_URL$NPASTE_PASTE_ID/download"
PASTE_KEY=""
if [[ "$NPASTE_PASTE_ID" == *"://"* ]]; then
PASTE_URL=$(echo "$NPASTE_PASTE_ID" | cut -d \# -f 1)
PASTE_KEY=$(echo "$NPASTE_PASTE_ID" | cut -d \# -f 2)
if [ "$PASTE_URL" == "$PASTE_KEY" ]; then
PASTE_KEY=""
fi
PASTE_URL="$PASTE_URL/download"
fi
FILENAME=$(curl -s "$PASTE_URL/filename")
STATUSCODE=$(curl -s -o /tmp/"$FILENAME" -w "%{http_code}" "$PASTE_URL")
if [ "$STATUSCODE" == "200" ]; then
LOCAL_FILE="/tmp/$FILENAME"
if [ "$PASTE_KEY" != "" ]; then
# Encrypted file with key in URL. Decrypt
gpg -q --decrypt --batch --yes --passphrase "$PASTE_KEY" "$LOCAL_FILE" | base64 --decode > "${FILENAME%.gpg}"
rm "$LOCAL_FILE"
if [ "$NPASTE_GET_OUTPUT" == "1" ]; then
cat "${FILENAME%.gpg}"
else
echo "${FILENAME%.gpg}"
fi
else
# Possibly encrypted file using only PASTE_ID. Check if should be decrypted.
gpg -q --decrypt < "$LOCAL_FILE" > /dev/null 2>&1
if [ "$?" == "0" ]; then
# This is an encrypted file. Use GPG to decrypt it..
gpg -q --decrypt "$LOCAL_FILE" | base64 --decode > "${FILENAME%.gpg}"
rm "$LOCAL_FILE"
if [ "$NPASTE_GET_OUTPUT" == "1" ]; then
cat "${FILENAME%.gpg}"
else
echo "${FILENAME%.gpg}"
fi
else
# Ordinary file. Move it.
mv "$LOCAL_FILE" "$FILENAME"
if [ "$NPASTE_GET_OUTPUT" == "1" ]; then
cat "$FILENAME"
else
echo "$FILENAME"
fi
fi
fi
fi
if [ "$STATUSCODE" == "404" ]; then
echo "Paste not found or server does not support downloads."
exit 1
fi
exit 0
fi
# determine archive status
NPASTE_DO_ARCHIVE=$NPASTE_DEFAULT_ARCHIVE # follow default as... well, default
if [ "$NPASTE_ARCHIVE" = "1" ]; then
NPASTE_DO_ARCHIVE="1" # archive if asked to
fi
if [ "$NPASTE_NO_ARCHIVE" = "1" ]; then
NPASTE_DO_ARCHIVE="0" # if asked not to, never archive
fi
# determine if we need to encrypt file
NPASTE_DO_ENCRYPT=$NPASTE_DEFAULT_ENCRYPT # default value
if [ "$NPASTE_ENCRYPT" = "1" ]; then
NPASTE_DO_ENCRYPT="1" # encrypt if asked to
fi
# create temporary file to determine mime type
# TODO: Better solution?
if [ "$NPASTE_FILE" = "-" ]; then
MIME_TYPE="text/plain"
else
MIME_TMP=$(mktemp)
cat $NPASTE_FILE > $MIME_TMP
MIME_TYPE=$(file -b --mime-type "$MIME_TMP")
rm $MIME_TMP
fi
if [ "$NPASTE_DO_ENCRYPT" = "1" ]; then
NPASTE_VAULT_KEY=""
if [ "$NPASTE_VAULT" ]; then
while IFS=':' read -ra VAULTS; do
if [ "${VAULTS[0]}" = "$NPASTE_VAULT" ]; then
NPASTE_VAULT_KEY="${VAULTS[1]}"
fi
done <<< $(cat $NPASTE_VAULTS)
if [ -z "$NPASTE_VAULT_KEY" ]; then
echo "Unable to find vault key for $NPASTE_VAULT"
exit
fi
fi
# create random encryption key
#KEY=$(cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | fold -w $NPASTE_ENCRYPTION_KEY_LENGTH | head -n 1)
KEY=$(openssl rand -hex $NPASTE_ENCRYPTION_KEY_LENGTH)
# upload file to npaste
NPASTE_PASTE_URL=$(cat $NPASTE_FILE | base64 | /usr/local/bin/gpg --armor --batch --passphrase "$KEY$NPASTE_VAULT_KEY" --symmetric | api_request $NPASTE_USERNAME $NPASTE_APIKEY $NPASTE_URL "-F paste=@-" "-F plain=$NPASTE_IS_PLAINTEXT" "-F maxopens=$NPASTE_MAX_OPENS" "-F age=$NPASTE_AGE" "-F archive=$NPASTE_DO_ARCHIVE" "-F mimetype=$MIME_TYPE" "-F encrypted=1" "-F vault=$NPASTE_VAULT")
else
NPASTE_PASTE_URL=$(cat $NPASTE_FILE | api_request $NPASTE_USERNAME $NPASTE_APIKEY $NPASTE_URL "-F paste=@-" "-F plain=$NPASTE_IS_PLAINTEXT" "-F maxopens=$NPASTE_MAX_OPENS" "-F age=$NPASTE_AGE" "-F archive=$NPASTE_DO_ARCHIVE" "-F encrypted=0")
fi
case "$NPASTE_PASTE_URL" in
http*)
if [ -t 1 ] && [ -z "$NPASTE_AUTO_PIPE_COMMAND" ]; then
# this is in a terminal, and we'd prefer a newline at the end,
# and we're not intending to pipe it ourself with an auto pipe command
NPASTE_TERMINAL_NEWLINE="\n"
else
# this is in a pipe, and we'd just like the raw url
NPASTE_TERMINAL_NEWLINE=""
fi
if [ "$NPASTE_DO_ENCRYPT" = "1" ]; then
# we've encrypted the file. add key to url
NPASTE_URL_KEY="#$KEY"
else
NPASTE_URL_KEY=""
fi
if [ -z "$NPASTE_AUTO_PIPE_COMMAND" ]; then
# no auto pipe command. print to stdout
printf "$NPASTE_PASTE_URL$NPASTE_TERMINAL_NEWLINE$NPASTE_URL_KEY"
exit 0
else
# auto pipe the data to the selected command. exit with the auto pipe's exit code
printf "$NPASTE_PASTE_URL$NPASTE_URL_KEY" | $NPASTE_AUTO_PIPE_COMMAND
printf "$NPASTE_PASTE_URL$NPASTE_TERMINAL_NEWLINE$NPASTE_URL_KEY$NPASTE_TERMINAL_NEWLINE"
exit $?
fi
;;
*)
echo "API error: $NPASTE_PASTE_URL"
exit 3
;;
esac