#!/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; } usage() { _cat <<- EOF Usage: ufw [-RsF] [-D num] [file/url]" Flags: -R|--remove-file # Remove the file after uploading. -s|--screenshot # Make a screenshot and upload it instead of a file. -F|--fullscreen # Make a fullscreen shot instead of prompting for a window/area. Implies -s. -d|--description # Supply a description. -D|--screenshot-delay # Delay the shot by seconds. -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_screenshot_ext # Screenshot file type, used by maim. 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 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 -fsL "$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 if (( flag_scn )); then flag_rm=1 file=$(take_screenshot) || { return 1; } else (( $# )) || { 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" -sL "$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 fi get_file_hash "$file" if [[ "$album_name" ]]; then get_album_id "$album_name" fi api_response=$( curl -sL \ -F file="@$file" \ -F api_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 -sL "$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 } take_screenshot() { declare tmp_file [[ "$scn_exec" ]] || { scn_exec=$(type -P maim); } [[ "$scn_exec" ]] || { err "Please install maim to use this function" return 1 } (( "$flag_scn_fullscreen" )) || { scn_args+=( '-s' ); } [[ "$cfg_scn_delay" ]] && { scn_args+=( "-d $cfg_scn_delay" ); } tmp_file="$(_mktemp "${cfg_tmp_dir}" ".${cfg_screenshot_ext}")" maim "${scn_args[@]}" "$tmp_file" || { err "Failed to take a screenshot." return 1 } printf '%s\n' "$tmp_file" } 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 -sl "$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 -sl "$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" ); 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 } main() { declare args file target flag_private flag_rm flag_scn flag_scn_fullscreen cfg_scn_delay 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"} [[ $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_screenshot_ext:='png'} : ${cfg_max_filesize:='200M'} : ${flag_shortlink:=0} : ${flag_directlink:=1} while [[ "$1" ]]; do case "$1" in -h|--help|--usage) usage; return;; -D|--screenshot-delay) cfg_scn_delay="$2"; shift;; -m|--max-filesize) cfg_max_filesize=$2; shift;; -A|--album-name) album_name=$2; shift;; -t|--tags) tags=$2; shift;; -i|--my-ip) action='getmyip';; -u|--shorten) action='url';; -p|--public) flag_private='false';; -R|--remove-file) flag_rm='1';; -s|--screenshot) flag_scn='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;; -F|--fullscreen) flag_scn='1' flag_scn_fullscreen='1' ;; -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 ;; *) break;; esac shift done 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 $? if (( $# )); then for t in "$@"; do upload "$t" done else upload fi ;; url) get_token || return $? for t in "$@"; do get_shortlink "$1" done ;; getmyip) get_my_ip;; login) login;; esac } set_argv "$@" main "${argv[@]}"