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.

438 lines
9.5 KiB

  1. #!/usr/bin/bash
  2. # Copyright (c) 2012 fbt <fbt@fleshless.org>
  3. # License: ISC
  4. #
  5. # About:
  6. # A simple upload script for UFW (http://zerofiles.org)
  7. _cat() {
  8. while read; do
  9. printf '%s\n' "$REPLY"
  10. done
  11. }
  12. is_url() {
  13. [[ "$1" =~ $cfg_url_regex ]]
  14. }
  15. msg() {
  16. if ! (( flag_quiet )); then
  17. printf '%s\n' "$1"
  18. fi
  19. }
  20. err() { printf '(error) %s\n' "$*" >&2; }
  21. curl() { command curl -sL "$@"; }
  22. usage() {
  23. _cat <<- EOF
  24. Usage: ufw [-RsF] [-D num] [file/url]
  25. Flags:
  26. -R|--remove-file # Remove the file after uploading.
  27. -d|--description # Supply a description.
  28. -p|--public # Make the file public.
  29. -n|--no-notify # Don't send immediate notifications for this upload.
  30. --notify # Force a notification for this upload.
  31. -u|--shorten <URL> # Generate a shortlink from URL.
  32. -S|--short-url # Get a shortlink when uploading a file.
  33. -P|--page-url # Get a link to the file page instead of a direct one.
  34. -m|--max-filesize <num>[suf] # Maximum filesize (takes K, M and G suffixes).
  35. -a|--album-id # Add the file to an album.
  36. -A|--album-name # Add the file to an album by name. The album will be created, if necessary.
  37. -t|--tags "<tag1[, tag2,..]>" # Add tags to the file.
  38. -q|--quiet # Be quiet.
  39. -v|--void # Don't add the file to my files.
  40. Config options (~/.config/ufw):
  41. secret # Your personal token. Get it at https://zfh.so/settings_form
  42. cfg_max_filesize # Maximum filesize (takes K, M and G suffixes).
  43. # Others are self-explanatory:
  44. cfg_url_regex
  45. cfg_tmp_dir
  46. cfg_service_url
  47. Environment variables:
  48. UFW_CFG_FILE # Config file to read, defaults to \$XDG_CONFIG_DIR/ufw
  49. UFW_SECRET # Your API secret
  50. UFW_TMP_DIR
  51. UFW_URL
  52. EOF
  53. }
  54. get_file_hash() {
  55. read file_hash _ < <( sha1sum "$1" )
  56. }
  57. get_max_filesize() {
  58. if [[ $cfg_max_filesize =~ ^[0-9]+[BKMG]?$ ]]; then
  59. max_filesize_base="${cfg_max_filesize//[BKMG]/}"
  60. case "$cfg_max_filesize" in
  61. *K) max_filesize_bytes=$(( max_filesize_base * 1024 ));;
  62. *M) max_filesize_bytes=$(( max_filesize_base * 1024 * 1024 ));;
  63. *G) max_filesize_bytes=$(( max_filesize_base * 1024 * 1024 * 1024 ));;
  64. *) max_filesize_bytes=$max_filesize_base;;
  65. esac
  66. else
  67. err "Wrong cfg_max_filesize: $cfg_max_filesize"
  68. return 1
  69. fi
  70. }
  71. get_album_id() {
  72. declare api_response api_status api_status_message
  73. api_response=$( curl -f "$cfg_service_url/albumctl.json?m=new&name=$1&secret=$secret" )
  74. get_api_status <<< "$api_response"
  75. if (( api_status == 200 )); then
  76. album_id=$( jq -r '.data.album.id' <<< "$api_response" )
  77. misc_curl_args+=( -F album_id="$album_id" )
  78. else
  79. printf 'Error [album]: %s %s\n' "$api_status" "$api_status_message"
  80. return 1
  81. fi
  82. }
  83. upload() {
  84. declare api_response api_status api_status_message
  85. (( $# )) || {
  86. usage
  87. return 1
  88. }
  89. target="$1"
  90. if is_url "$target"; then
  91. flag_rm=1
  92. file=$(_mktemp "$cfg_tmp_dir")
  93. get_max_filesize || { return 1; }
  94. curl --max-filesize "$max_filesize_bytes" "$target" > "$file"
  95. curl_result=$?
  96. if (( curl_result )); then
  97. case "$curl_result" in
  98. 63) err "File exceeds cfg_max_filesize";;
  99. *) err "Could not download file.";;
  100. esac
  101. return 1
  102. fi
  103. else
  104. file="$target"
  105. [[ -f "$file" ]] || {
  106. err "No such file: ${file}"
  107. return 1
  108. }
  109. fi
  110. get_file_hash "$file"
  111. if [[ "$album_name" ]]; then
  112. get_album_id "$album_name"
  113. fi
  114. api_response=$( curl \
  115. -F file="@$file" \
  116. -F api_format='json' \
  117. -F flag_private="$flag_private" \
  118. -F secret="$secret" \
  119. -F tags="$tags" \
  120. -F notify="$flag_notify" \
  121. -F void="${flag_void:-0}" \
  122. -F submit="" \
  123. "${misc_curl_args[@]}" \
  124. -A 'zerofiles.org upload script' \
  125. "$cfg_service_url/maw.json" )
  126. if (( flag_shortlink )); then
  127. if (( flag_directlink )); then
  128. file_url_request='short_url'
  129. else
  130. file_url_request='page_short_url'
  131. fi
  132. else
  133. file_url_request='url'
  134. fi
  135. get_api_status <<< "$api_response"
  136. if (( api_status == 200 )); then
  137. file_link=$( jq -r ".data.${file_url_request}" <<< "$api_response" )
  138. (( flag_shortlink )) || {
  139. (( flag_directlink )) || file_link="${file_link#*.}"
  140. }
  141. printf '%s\n' "$file_link"
  142. if (( flag_rm )); then
  143. msg "Removing file: $file"
  144. rm "$file"
  145. fi
  146. else
  147. printf 'Error: %s %s\n' "$api_status" "$api_status_message"
  148. return 1
  149. fi
  150. }
  151. get_shortlink() {
  152. declare url=$1 api_response api_status api_status_message
  153. api_response=$( curl "$cfg_service_url/shrink.json?url=${url}&secret=$secret" )
  154. get_api_status <<< "$api_response"
  155. if (( api_status == 200 )); then
  156. read -r short_url real_url < <(
  157. jq -r '.data.short_url' <<< "$api_response"
  158. )
  159. printf '%s\n' "$short_url"
  160. else
  161. printf 'Error: %s %s\n' "$api_status" "$api_status_message"
  162. fi
  163. }
  164. get_api_status() {
  165. read -d '' -r api_status api_status_message < <(
  166. jq -r '.status.code, .status.message'
  167. )
  168. if (( api_status >= 400 )); then
  169. return 1
  170. fi
  171. }
  172. _mktemp() {
  173. declare tmp_file_name tmp_file_name_extra="$2" tmp_dir="$1"
  174. [[ -d "$tmp_dir" ]] || {
  175. err "${tmp_dir} does not exist or is not a directory."
  176. return 1
  177. }
  178. until [[ ! -e "${tmp_dir}/${tmp_file_name}" ]]; do
  179. tmp_file_name="${RANDOM}${RANDOM}${tmp_file_name_extra}"
  180. done
  181. printf '%s\n' "${tmp_dir}/${tmp_file_name}"
  182. }
  183. get_my_ip() {
  184. declare api_response api_status api_status_message my_ip
  185. api_response=$( curl "$cfg_service_url/ip.json" )
  186. get_api_status <<< "$api_response"
  187. if (( api_status == 200 )); then
  188. my_ip=$( jq -r '.data.ip' <<< "$api_response" )
  189. printf '%s\n' "$my_ip"
  190. else
  191. printf 'Error: %s %s\n' "$api_status" "$api_status_message"
  192. fi
  193. }
  194. login() {
  195. declare api_response
  196. api_response=$( curl "$cfg_service_url/token_request.json?login=$login" )
  197. if get_api_status <<< "$api_response"; then
  198. printf 'Check your email.\n'
  199. else
  200. printf 'Error: %s %s\n' "$api_status" "$api_status_message"
  201. fi
  202. }
  203. get_token() {
  204. [[ $secret ]] && return 0
  205. [[ -f $cfg_file ]] && return 1
  206. declare api_response login password
  207. printf "First-time setup...\n"
  208. read -p 'Username: ' login
  209. read -sp 'Password: ' password
  210. printf '\n'
  211. login_response=$(curl -c "$cfg_file.cookiejar" -d "login=$login" -d "password=$password" -sl "$cfg_service_url/login.json")
  212. get_api_status <<< "$login_response" || {
  213. jq -r '.status.message' <<< "$login_response"
  214. return 1
  215. }
  216. api_response=$(curl -b "$cfg_file.cookiejar" -sl "$cfg_service_url/api_token.json")
  217. rm -f "$cfg_file.cookiejar"
  218. if get_api_status <<< "$api_response"; then
  219. secret=$(jq -r '.data.token' <<< "$api_response")
  220. printf 'export secret="%s"' "$secret" >> "$cfg_file"
  221. chmod 600 "$cfg_file"
  222. printf 'Done\n'
  223. else
  224. printf 'Error: %s %s\n' "$api_status" "$api_status_message"
  225. return 1
  226. fi
  227. }
  228. set_argv() {
  229. declare arg opt c
  230. declare -g argv
  231. while (( $# )); do
  232. unset -v arg opt c
  233. case "$1" in
  234. (--) argv+=( "$1" ); break;;
  235. (--*)
  236. IFS='=' read arg opt <<< "$1"
  237. argv+=( "$arg" )
  238. [[ "$opt" ]] && {
  239. argv+=( "$opt" )
  240. }
  241. ;;
  242. (-*)
  243. while read -n1 c
  244. do
  245. case "$c" in
  246. -|'') :;;
  247. *) argv+=( "-$c" );;
  248. esac
  249. done <<< "$1"
  250. ;;
  251. (*) argv+=( "$1" );;
  252. esac
  253. shift
  254. done
  255. }
  256. main() {
  257. declare args file target flag_private flag_rm flag_notify
  258. declare flag_shortlink
  259. # Defaults for XDG
  260. if ! [[ "$XDG_RUNTIME_DIR" ]]; then
  261. XDG_RUNTIME_DIR="/run/user/$UID"
  262. fi
  263. if ! [[ "$XDG_CONFIG_DIR" ]]; then
  264. XDG_CONFIG_DIR="$HOME/.config"
  265. fi
  266. cfg_url_regex='^[A-Za-z]([A-Za-z0-9+.-]+)?://.+'
  267. cfg_file=${UFW_CFG_FILE:-"$XDG_CONFIG_DIR/ufw"}
  268. [[ $UFW_SECRET ]] && secret=$UFW_SECRET
  269. [[ $UFW_TMP_DIR ]] && cfg_tmp_dir=$UFW_TMP_DIR
  270. [[ $UFW_URL ]] && cfg_service_url=$UFW_URL
  271. [[ $1 ]] || { usage; return 1; }
  272. if [[ -f "$cfg_file" ]]; then
  273. if ! source "$cfg_file"; then
  274. printf 'Failed to source configuration file: %s\n' "$cfg_file"
  275. return $?
  276. fi
  277. fi
  278. # Defaults
  279. : ${cfg_file:="$XDG_CONFIG_DIR/ufw"}
  280. : ${cfg_tmp_dir:="$XDG_RUNTIME_DIR/ufw"}
  281. : ${cfg_service_url:='https://8fw.me'}
  282. : ${cfg_max_filesize:='200M'}
  283. : ${flag_shortlink:=0}
  284. : ${flag_directlink:=1}
  285. while [[ "$1" ]]; do
  286. case "$1" in
  287. (-h|--help|--usage) usage; return;;
  288. (-m|--max-filesize) cfg_max_filesize=$2; shift;;
  289. (-A|--album-name) album_name=$2; shift;;
  290. (-t|--tags) tags=$2; shift;;
  291. (--tmp-dir) cfg_tmp_dir=$2; shift;;
  292. (--url) cfg_service_url=$2; shift;;
  293. (--max-filesize) cfg_max_filesize=$2; shift;;
  294. (-i|--my-ip) action='getmyip';;
  295. (-u|--shorten) action='url';;
  296. (-p|--public) flag_private='false';;
  297. (-R|--remove-file) flag_rm='1';;
  298. (-S|--short-url) flag_shortlink=1;;
  299. (-P|--page-url) flag_directlink=0;;
  300. (-q|--quiet) flag_quiet=1;;
  301. (-v|--void) flag_void=1;;
  302. (--notify) flag_notify=1;;
  303. (--no-notify|-n) flag_notify=0;;
  304. (-a|--album-id)
  305. misc_curl_args+=( -F "album_id=$2" )
  306. shift
  307. ;;
  308. (-d|--description)
  309. misc_curl_args+=( -F "description=$2" )
  310. shift
  311. ;;
  312. --) shift; break;;
  313. -*)
  314. err "Unknown flag: $1"
  315. usage
  316. return 1
  317. ;;
  318. *) break;;
  319. esac
  320. shift
  321. done
  322. TEMPDIR="$cfg_tmp_dir"
  323. for i in "$cfg_tmp_dir"; do
  324. [[ -d "$i" ]] || { mkdir -p "$i"; }
  325. done
  326. case "${action:-upload}" in
  327. upload)
  328. get_token || return $?
  329. if (( $# )); then
  330. for t in "$@"; do
  331. upload "$t"
  332. done
  333. else
  334. upload
  335. fi
  336. ;;
  337. url)
  338. get_token || return $?
  339. for t in "$@"; do
  340. get_shortlink "$1"
  341. done
  342. ;;
  343. getmyip) get_my_ip;;
  344. login) login;;
  345. esac
  346. }
  347. set_argv "$@"
  348. main "${argv[@]}"