#!/usr/bin/bash # Copyright (c) 2012 fbt # License: ISC # # About: # A simple upload script for UFW (http://zerofiles.org) _cat() { while read; do printf '%s\n' "$REPLY" done } is_url() { [[ "$1" =~ $cfg_url_regex ]] } msg() { if ! (( flag_quiet )); then printf '%s\n' "$1" fi } err() { printf '(error) %s\n' "$*" >&2; } curl() { command curl -sL "$@"; } usage() { _cat <<- EOF Usage: ufw [-RsF] [-D num] [file/url] Flags: -R|--remove-file # Remove the file after uploading. -d|--description # Supply a description. -p|--public # Make the file public. -n|--no-notify # Don't send immediate notifications for this upload. --notify # Force a notification for this upload. -u|--shorten # Generate a shortlink from URL. -S|--short-url # Get a shortlink when uploading a file. -P|--page-url # Get a link to the file page instead of a direct one. -m|--max-filesize [suf] # Maximum filesize (takes K, M and G suffixes). -a|--album-id # Add the file to an album. -A|--album-name # Add the file to an album by name. The album will be created, if necessary. -t|--tags "" # Add tags to the file. -q|--quiet # Be quiet. -v|--void # Don't add the file to my files. Config options (~/.config/ufw): secret # Your personal token. Get it at https://zfh.so/settings_form cfg_max_filesize # Maximum filesize (takes K, M and G suffixes). # Others are self-explanatory: cfg_url_regex cfg_tmp_dir cfg_service_url Environment variables: UFW_CFG_FILE # Config file to read, defaults to \$XDG_CONFIG_DIR/ufw UFW_SECRET # Your API secret UFW_TMP_DIR UFW_URL EOF } get_file_hash() { read file_hash _ < <( sha1sum "$1" ) } get_max_filesize() { if [[ $cfg_max_filesize =~ ^[0-9]+[BKMG]?$ ]]; then max_filesize_base="${cfg_max_filesize//[BKMG]/}" case "$cfg_max_filesize" in *K) max_filesize_bytes=$(( max_filesize_base * 1024 ));; *M) max_filesize_bytes=$(( max_filesize_base * 1024 * 1024 ));; *G) max_filesize_bytes=$(( max_filesize_base * 1024 * 1024 * 1024 ));; *) max_filesize_bytes=$max_filesize_base;; esac else err "Wrong cfg_max_filesize: $cfg_max_filesize" return 1 fi } get_album_id() { declare api_response api_status api_status_message api_response=$( curl -f "$cfg_service_url/albumctl.json?m=new&name=$1&secret=$secret" ) get_api_status <<< "$api_response" if (( api_status == 200 )); then album_id=$( jq -r '.data.album.id' <<< "$api_response" ) misc_curl_args+=( -F album_id="$album_id" ) else printf 'Error [album]: %s %s\n' "$api_status" "$api_status_message" return 1 fi } upload() { declare api_response api_status api_status_message (( $# )) || { usage return 1 } target="$1" if is_url "$target"; then flag_rm=1 file=$(_mktemp "$cfg_tmp_dir") get_max_filesize || { return 1; } curl --max-filesize "$max_filesize_bytes" "$target" > "$file" curl_result=$? if (( curl_result )); then case "$curl_result" in 63) err "File exceeds cfg_max_filesize";; *) err "Could not download file.";; esac return 1 fi else file="$target" [[ -f "$file" ]] || { err "No such file: ${file}" return 1 } fi get_file_hash "$file" if [[ "$album_name" ]]; then get_album_id "$album_name" fi api_response=$( curl \ -F file="@$file" \ -F format='json' \ -F flag_private="$flag_private" \ -F secret="$secret" \ -F tags="$tags" \ -F notify="$flag_notify" \ -F void="${flag_void:-0}" \ -F submit="" \ "${misc_curl_args[@]}" \ -A 'zerofiles.org upload script' \ "$cfg_service_url/maw.json" ) if (( flag_shortlink )); then if (( flag_directlink )); then file_url_request='short_url' else file_url_request='page_short_url' fi else file_url_request='url' fi get_api_status <<< "$api_response" if (( api_status == 200 )); then file_link=$( jq -r ".data.${file_url_request}" <<< "$api_response" ) (( flag_shortlink )) || { (( flag_directlink )) || file_link="${file_link#*.}" } printf '%s\n' "$file_link" if (( flag_rm )); then msg "Removing file: $file" rm "$file" fi else printf 'Error: %s %s\n' "$api_status" "$api_status_message" return 1 fi } get_shortlink() { declare url=$1 api_response api_status api_status_message api_response=$( curl "$cfg_service_url/shrink.json?url=${url}&secret=$secret" ) get_api_status <<< "$api_response" if (( api_status == 200 )); then read -r short_url real_url < <( jq -r '.data.short_url' <<< "$api_response" ) printf '%s\n' "$short_url" else printf 'Error: %s %s\n' "$api_status" "$api_status_message" fi } get_api_status() { read -d '' -r api_status api_status_message < <( jq -r '.status.code, .status.message' ) if (( api_status >= 400 )); then return 1 fi } _mktemp() { declare tmp_file_name tmp_file_name_extra="$2" tmp_dir="$1" [[ -d "$tmp_dir" ]] || { err "${tmp_dir} does not exist or is not a directory." return 1 } until [[ ! -e "${tmp_dir}/${tmp_file_name}" ]]; do tmp_file_name="${RANDOM}${RANDOM}${tmp_file_name_extra}" done printf '%s\n' "${tmp_dir}/${tmp_file_name}" } get_my_ip() { declare api_response api_status api_status_message my_ip api_response=$( curl "$cfg_service_url/ip.json" ) get_api_status <<< "$api_response" if (( api_status == 200 )); then my_ip=$( jq -r '.data.ip' <<< "$api_response" ) printf '%s\n' "$my_ip" else printf 'Error: %s %s\n' "$api_status" "$api_status_message" fi } login() { declare api_response api_response=$( curl "$cfg_service_url/token_request.json?login=$login" ) if get_api_status <<< "$api_response"; then printf 'Check your email.\n' else printf 'Error: %s %s\n' "$api_status" "$api_status_message" fi } get_token() { [[ $secret ]] && return 0 [[ -f $cfg_file ]] && return 1 declare api_response login password printf "First-time setup...\n" read -p 'Username: ' login read -sp 'Password: ' password printf '\n' login_response=$(curl -c "$cfg_file.cookiejar" -d "login=$login" -d "password=$password" -sl "$cfg_service_url/login.json") get_api_status <<< "$login_response" || { jq -r '.status.message' <<< "$login_response" return 1 } api_response=$(curl -b "$cfg_file.cookiejar" -sl "$cfg_service_url/api_token.json") rm -f "$cfg_file.cookiejar" if get_api_status <<< "$api_response"; then secret=$(jq -r '.data.token' <<< "$api_response") printf 'export secret="%s"' "$secret" >> "$cfg_file" chmod 600 "$cfg_file" printf 'Done\n' else printf 'Error: %s %s\n' "$api_status" "$api_status_message" return 1 fi } set_argv() { declare arg opt c declare -g argv while (( $# )); do unset -v arg opt c case "$1" in (--) argv+=( "$1" ); shift; break;; (--*) IFS='=' read arg opt <<< "$1" argv+=( "$arg" ) [[ "$opt" ]] && { argv+=( "$opt" ) } ;; (-*) while read -n1 c do case "$c" in -|'') :;; *) argv+=( "-$c" );; esac done <<< "$1" ;; (*) argv+=( "$1" );; esac shift done if (( $# )); then argv+=( "$@" ) fi } main() { declare args file target flag_private flag_rm flag_notify declare flag_shortlink # Defaults for XDG if ! [[ "$XDG_RUNTIME_DIR" ]]; then XDG_RUNTIME_DIR="/run/user/$UID" fi if ! [[ "$XDG_CONFIG_DIR" ]]; then XDG_CONFIG_DIR="$HOME/.config" fi cfg_url_regex='^[A-Za-z]([A-Za-z0-9+.-]+)?://.+' cfg_file=${UFW_CFG_FILE:-"$XDG_CONFIG_DIR/ufw"} [[ $UFW_SECRET ]] && secret=$UFW_SECRET [[ $UFW_TMP_DIR ]] && cfg_tmp_dir=$UFW_TMP_DIR [[ $UFW_URL ]] && cfg_service_url=$UFW_URL [[ $1 ]] || { usage; return 1; } if [[ -f "$cfg_file" ]]; then if ! source "$cfg_file"; then printf 'Failed to source configuration file: %s\n' "$cfg_file" return $? fi fi # Defaults : ${cfg_file:="$XDG_CONFIG_DIR/ufw"} : ${cfg_tmp_dir:="$XDG_RUNTIME_DIR/ufw"} : ${cfg_service_url:='https://8fw.me'} : ${cfg_max_filesize:='200M'} : ${flag_shortlink:=0} : ${flag_directlink:=1} while [[ "$1" ]]; do case "$1" in (-h|--help|--usage) usage; return;; (-m|--max-filesize) cfg_max_filesize=$2; shift;; (-A|--album-name) album_name=$2; shift;; (-t|--tags) tags=$2; shift;; (--tmp-dir) cfg_tmp_dir=$2; shift;; (--url) cfg_service_url=$2; shift;; (--max-filesize) cfg_max_filesize=$2; shift;; (-i|--my-ip) action='getmyip';; (-u|--shorten) action='url';; (-p|--public) flag_private='false';; (-R|--remove-file) flag_rm='1';; (-S|--short-url) flag_shortlink=1;; (-P|--page-url) flag_directlink=0;; (-q|--quiet) flag_quiet=1;; (-v|--void) flag_void=1;; (--notify) flag_notify=1;; (--no-notify|-n) flag_notify=0;; (-a|--album-id) misc_curl_args+=( -F "album_id=$2" ) shift ;; (-d|--description) misc_curl_args+=( -F "description=$2" ) shift ;; --) shift; break;; -*) err "Unknown flag: $1" usage return 1 ;; *) args+=( "$1" );; esac shift done # Catch the args after -- if (( $# )); then args+=( "$@" ) shift fi TEMPDIR="$cfg_tmp_dir" for i in "$cfg_tmp_dir"; do [[ -d "$i" ]] || { mkdir -p "$i"; } done case "${action:-upload}" in upload) get_token || return $? (( ${#args[@]} )) || return 1 for t in "${args[@]}"; do upload "$t" done ;; url) get_token || return $? for t in "${args[@]}"; do get_shortlink "$1" done ;; getmyip) get_my_ip;; login) login;; esac } set_argv "$@" main "${argv[@]}"