mirror of
https://github.com/notwa/rc
synced 2024-11-05 06:29:02 -08:00
297 lines
10 KiB
Text
297 lines
10 KiB
Text
|
#!/usr/bin/env sh
|
||
|
# YES_ZSH YES_BASH YES_DASH YES_ASH
|
||
|
|
||
|
__notice_warn() {
|
||
|
printf 'notice: %s\n' >&2 "$*"
|
||
|
}
|
||
|
|
||
|
__notice_curl() {
|
||
|
curl -q --no-progress-meter 0.0.0.0 >/dev/null 2>&1
|
||
|
if [ $? = 2 ]
|
||
|
then __notice_curl() { curl -sS "$@"; }
|
||
|
else __notice_curl() { curl --no-progress-meter "$@"; }
|
||
|
fi
|
||
|
__notice_curl "$@"
|
||
|
}
|
||
|
|
||
|
__notice_commaize() { # fun with POSIX shell
|
||
|
while [ -n "$1" ]; do
|
||
|
set -- "${1%???}" "${1#"${1%???}"},$2" "$1"
|
||
|
if [ "$1" = "$3" ]; then
|
||
|
set -- "" "$1$2"
|
||
|
break
|
||
|
fi
|
||
|
done
|
||
|
REPLY="${2%,}"
|
||
|
}
|
||
|
|
||
|
__notice_escape() {
|
||
|
# doesn't work in posh. it doesn't like "${1%%[$2]*}", bug?
|
||
|
# warning: mksh is O(n^2) with string length!
|
||
|
# note: bash is horribly slow without `export LC_ALL=C`. zsh is fastest.
|
||
|
set -- "" "" "$1" "$2"
|
||
|
while :; do
|
||
|
set -- "$1" "${3%%[$4]*}" "$3" "$4"
|
||
|
[ "$2" != "$3" ] || break
|
||
|
set -- "$1$2\\" "${3#"$2"}" "$3" "$4"
|
||
|
set -- "$1${2%"${2#?}"}" "$2" "${2#?}" "$4"
|
||
|
done
|
||
|
REPLY="$1$3"
|
||
|
}
|
||
|
|
||
|
__notice_urlencode() {
|
||
|
while test "$1"; do
|
||
|
case "$1" in
|
||
|
([a-zA-Z0-9~_.-]*) printf '%.1s' "$1";; # RFC 3986
|
||
|
(*) printf '%%%02X' "'$1";; # bash complains but works
|
||
|
esac
|
||
|
set -- "${1#?}"
|
||
|
done
|
||
|
} 2>&- # send bash's complaints to the abyss
|
||
|
|
||
|
__notice_generate_id() { # wraps around every 25 years
|
||
|
: "${1:?missing seed}"
|
||
|
REPLY=""
|
||
|
while [ "${#REPLY}" -lt 8 ]; do
|
||
|
case "$(($1%13))" in
|
||
|
(0) REPLY="${REPLY}a";; (1) REPLY="${REPLY}c";; (2) REPLY="${REPLY}e";;
|
||
|
(3) REPLY="${REPLY}m";; (4) REPLY="${REPLY}n";; (5) REPLY="${REPLY}o";;
|
||
|
(6) REPLY="${REPLY}r";; (7) REPLY="${REPLY}s";; (8) REPLY="${REPLY}u";;
|
||
|
(9) REPLY="${REPLY}v";; (10) REPLY="${REPLY}w";; (11) REPLY="${REPLY}x";;
|
||
|
(12) REPLY="${REPLY}z";;
|
||
|
esac
|
||
|
set -- "$(($1/13))"
|
||
|
done
|
||
|
}
|
||
|
|
||
|
__notice_log() {
|
||
|
printf '## [%s](%s)\\n\\nUploaded %s byte%s to %s [(aux)](%s) with hashes:\\n* sha1sum: `%s`' \
|
||
|
"$sanitized" "$normal" "$pretty" "$fancy" "$target" "$aux" "$sha1"
|
||
|
}
|
||
|
|
||
|
# __notice_upload_to_...
|
||
|
# org_c_net_paste 50000000 or 47 MiB (approx)
|
||
|
# se_uguu 67108864 or 64 MiB
|
||
|
# at_x0 104857600 or 100 MiB
|
||
|
# com_cockfile 134217728 or 128 MiB
|
||
|
# sh_envs 536870912 or 512 MiB
|
||
|
# io_file 2000000000 or 1907 MiB (approx)
|
||
|
# at_oshi 5000000000 or 4768 MiB (approx)
|
||
|
# com_bashupload 50000000000 or 47 GiB (approx)
|
||
|
# net_filebin unlimited?
|
||
|
|
||
|
__notice_upload_to_org_c_net_paste() {
|
||
|
# defaults: 180 days, permanent (remains after download)
|
||
|
# TODO: retrieve deletion key from json response (see docs).
|
||
|
# WARNING: there seems to be a bug where files with a hash collision
|
||
|
# are not uploaded, and you get someone else's file instead!
|
||
|
[ "${bytes:-0}" -le 50000000 ] || return 128 # approx, untested
|
||
|
target=paste.c-net.org
|
||
|
#normal="$(__notice_curl -gT "$1" "https://$target")" || return
|
||
|
normal="$(__notice_curl -g --data-binary "@$filepath" -H "X-FileName: ${1##*/}" "https://$target")" || return
|
||
|
normal="https:${normal#*http*:}"; normal="${normal%%[!!-~]*}"
|
||
|
aux="$normal"
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_io_file() {
|
||
|
# defaults: 14 days, ephemeral (deletes after 1 download)
|
||
|
# wget should use --content-disposition when downloading
|
||
|
[ "${bytes:-0}" -le 2000000000 ] || return 128 # approx, untested
|
||
|
target=file.io
|
||
|
normal="$(__notice_curl -F "file=@$1" "https://$target")" || return
|
||
|
[ "${normal#'{"success":true,"status":200,'}" ] || return
|
||
|
normal="https:${normal#*\"link\":\"https:}"; normal="${normal%%[\"]*}"
|
||
|
aux="$normal" # no direct link, i think it's based on User-Agent
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_at_oshi() {
|
||
|
# defaults: 1 day, semi-permanent (remains up to 1000 downloads?)
|
||
|
# configured: 14 days instead
|
||
|
# TODO: retrieve admin URL from response (suffixed with " [Admin]")
|
||
|
# NOTE: spaces are automatically converted (by the server) to underscores.
|
||
|
[ "${bytes:-0}" -le 5000000000 ] || return 128 # approx, untested
|
||
|
target=oshi.at
|
||
|
normal="$(__notice_curl -fF "f=@$1" -F expire=20160 "https://$target")" || return
|
||
|
normal="https:${normal##*DL: http*:}"; normal="${normal%%[!!-~]*}"
|
||
|
aux="$normal"
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_com_bashupload() {
|
||
|
# defaults: 3 days, ephemeral (deletes after 1 download)
|
||
|
# it also seems to accept `-F file=blah` multipart form-data
|
||
|
# note that filenames with spaces are treated as if no filename was given!
|
||
|
# TODO: when name contains spaces, replace with underscores and append to URL?
|
||
|
[ "${bytes:-0}" -le 50000000000 ] || return 128 # approx, untested
|
||
|
target=bashupload.com
|
||
|
# https://$target/${${1##*/}// /%20}
|
||
|
normal="$(__notice_curl -gT "$1" "https://$target")" || return
|
||
|
normal="https:${normal#*http*:}"; normal="${normal%%[!!-~]*}"
|
||
|
aux="$normal?download=1"
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_net_filebin() {
|
||
|
# defaults: 7 days, permament (but can be deleted by anyone with the link)
|
||
|
# note that the site says 6 days, but this is rounded down. the API shows 7 days.
|
||
|
# spaces are converted to underscores, and perhaps other characters are as well.
|
||
|
# note that you need curl -L to retrieve the files; they redirect to an s3 store.
|
||
|
target=filebin.net
|
||
|
__notice_generate_id "$(date -u +%s)" || return
|
||
|
aux="https://$target/$REPLY"
|
||
|
#normal="$(__notice_curl -gfT "$1" "$aux/$(__notice_urlencode ${1##*/})")" || return
|
||
|
normal="$(__notice_curl -gfT "$1" "$aux/")" || return
|
||
|
normal="${normal##*\"filename\": \"}"; normal="$aux/${normal%%\"*}"
|
||
|
# optional: lock the bin so nobody can edit it, but anyone can still delete it.
|
||
|
curl -sSX PUT "$aux" >/dev/null || true
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_at_x0() {
|
||
|
# defaults: 100 days, permanent
|
||
|
# note that file retention decreases as file size increases.
|
||
|
# 100 MiB files are kept for 3 days, and 0 byte files are kept for 100 days.
|
||
|
# filenames are randomized. cannot manually delete nor specify expiry.
|
||
|
[ "${bytes:-0}" -le 104857600 ] || return 128
|
||
|
target=x0.at
|
||
|
normal="$(__notice_curl -fF "file=@$1" "https://$target")" || return
|
||
|
aux="$normal"
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_se_uguu() {
|
||
|
# defaults: 3 hours, permanent
|
||
|
# filenames are randomized. cannot manually delete nor specify expiry.
|
||
|
[ "${bytes:-0}" -le 67108864 ] || return 128
|
||
|
target=uguu.se
|
||
|
normal="$(__notice_curl -fF "files[]=@$1" "https://$target/upload?output=text")" || return
|
||
|
aux="$normal"
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_com_cockfile() {
|
||
|
# defaults: 12 hours, permanent
|
||
|
# filenames are randomized. cannot manually delete nor specify expiry.
|
||
|
[ "${bytes:-0}" -le 134217728 ] || return 128
|
||
|
target=cockfile.com
|
||
|
normal="$(__notice_curl -fF "files[]=@$1" "https://$target/upload.php?output=text")" || return
|
||
|
aux="$normal"
|
||
|
}
|
||
|
|
||
|
__notice_upload_to_sh_envs() {
|
||
|
# configured: 14 days, permanent (TODO: add "defaults" to match other docs)
|
||
|
# does not remember filenames in any capacity, BUT we can tack on our own to the URL.
|
||
|
# you can delete files if you extract the X-Token field from the response HTTP headers.
|
||
|
# banned MIME types: application/java-archive, application/java-vm
|
||
|
[ "${bytes:-0}" -le 536870912 ] || return 128
|
||
|
target=envs.sh
|
||
|
normal="$(__notice_curl -fF "file=@$1" -Fsecret= -Fexpires=336 "https://$target")" || return
|
||
|
aux="$normal"
|
||
|
normal="$normal/${1##*/}"
|
||
|
}
|
||
|
|
||
|
__notice_retrying() {
|
||
|
case $? in
|
||
|
(0) return 0;;
|
||
|
# https://curl.se/libcurl/c/libcurl-errors.html
|
||
|
(127)
|
||
|
interrupt=1
|
||
|
__notice_warn "interrupted, exiting."
|
||
|
return 0;;
|
||
|
(128)
|
||
|
__notice_warn "file unsuitable for $target, skipping to next service..."
|
||
|
return 1;;
|
||
|
(*)
|
||
|
__notice_warn "failed to upload to $target, trying next service..."
|
||
|
return 1;;
|
||
|
esac
|
||
|
}
|
||
|
|
||
|
__notice_upload() {
|
||
|
unset REPLY aux bytes fancy file filepath interrupt normal pretty sanitized sha1 target
|
||
|
file="${1:-missing argument}"
|
||
|
|
||
|
file="$(readlink -f "$file")" || return 2 # also converts `\`s to `/`s
|
||
|
# i have no idea why, but mingw64 curl on msys2 is replacing each unicode codepoint with a question mark.
|
||
|
# the irony is that it seems to be properly decoding the UTF-8 encoding and then replacing it all anyway.
|
||
|
[ -d /C ] && filepath="$(LC_ALL= cygpath -ws "$file")" || filepath="$file"
|
||
|
|
||
|
REPLY="${file##*/}"
|
||
|
# ksh and mksh dictate that the characters must be in this order:
|
||
|
__notice_escape "$REPLY" '][!#()*+.<>_`{|}\\\-'
|
||
|
__notice_escape "$REPLY" '\\"'
|
||
|
sanitized="$REPLY"
|
||
|
|
||
|
bytes="$(du -b -- "$file")" || return 2
|
||
|
sha1="$(sha1sum -- "$file")" || return 2
|
||
|
bytes="${bytes%%[!!-~]*}"
|
||
|
sha1="${sha1%%[!!-~]*}"
|
||
|
|
||
|
__notice_commaize "$bytes"; pretty="$REPLY"
|
||
|
test "$bytes" -ge 0 || return 2
|
||
|
if [ "$bytes" -ge 10200547328 ]; then
|
||
|
fancy="s ($(( (bytes + 536870912) / 1073741824)) GiB)"
|
||
|
elif [ "$bytes" -ge 9961472 ]; then
|
||
|
fancy="s ($(( (bytes + 524288) / 1048576)) MiB)"
|
||
|
elif [ "$bytes" -ge 9728 ]; then
|
||
|
fancy="s ($(( (bytes + 512) / 1024)) KiB)"
|
||
|
elif [ "$bytes" -ne 1 ]; then
|
||
|
fancy="s"
|
||
|
fi
|
||
|
|
||
|
REPLY=
|
||
|
__notice_upload_to_sh_envs "$file" || __notice_retrying || \
|
||
|
__notice_upload_to_net_filebin "$file" || __notice_retrying || \
|
||
|
__notice_upload_to_at_oshi "$file" || __notice_retrying || \
|
||
|
__notice_upload_to_org_c_net_paste "$file" || __notice_retrying || \
|
||
|
__notice_upload_to_io_file "$file" || __notice_retrying || \
|
||
|
__notice_upload_to_com_bashupload "$file" || __notice_retrying || \
|
||
|
{
|
||
|
__notice_warn "failed to upload to every service, exiting."
|
||
|
return 1
|
||
|
}
|
||
|
[ "$interrupt" != 1 ] || return 127
|
||
|
REPLY="$(__notice_log)"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
__notice() {
|
||
|
unset LC_ALL REPLY aux code message normal title token url
|
||
|
export LC_ALL=C
|
||
|
url='https://eaguru.guru/gotify/message?token='
|
||
|
#token="$(cat ~/.gotify.secret)" || return
|
||
|
read -r token <~/.gotify.secret
|
||
|
test "$token" || return # TODO: give an actual error message.
|
||
|
if [ $# != 1 ] && [ $# != 2 ]; then
|
||
|
printf 'usage:\n' >&2
|
||
|
printf ' %s %s\n' >&2 "$0" '{message}' "$0" '{title} {message}' "$0" '@{file}'
|
||
|
return 64
|
||
|
fi
|
||
|
|
||
|
[ $# != 2 ] || { title="$1"; shift ;}
|
||
|
message="${1:?missing message}"
|
||
|
if [ $# = 1 ] && [ "${message#@}" != "$message" ]; then
|
||
|
__notice_upload "${message#@}" || return
|
||
|
printf '%s\n' >&2 "$normal"
|
||
|
fi
|
||
|
|
||
|
set -- -qLo /dev/null -w '%{http_code}'
|
||
|
set -- "$@" "$url$token"
|
||
|
if [ -n "$REPLY" ]; then
|
||
|
set -- "$@" --data '{"title": "New file uploaded", "message": "'"$REPLY"'", "extras": {"client::display": {"contentType": "text/markdown"}, "client::notification": {"click": {"url": "'"$aux"'"}}}}'
|
||
|
set -- "$@" -H 'Content-Type: application/json'
|
||
|
else
|
||
|
[ -z "$title" ] || set -- "$@" --form-string "title=$title"
|
||
|
[ -z "$message" ] || set -- "$@" --form-string "message=$message"
|
||
|
fi
|
||
|
set -- "$@" -H "Accept: application/json"
|
||
|
|
||
|
if code="$(__notice_curl "$@")" && [ "$code" = 200 ]; then
|
||
|
:
|
||
|
else
|
||
|
__notice_warn "failed to upload message to ${url%%\?*} (\$code=$code, \$?=$?)"
|
||
|
return 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
notice()(__notice "$@")
|
||
|
[ -n "${preload+-}" ] || __notice "$@"
|
||
|
|
||
|
# cursed modeline:
|
||
|
# vim:ft=bash ts=3 sw=3 noet sts=3
|