1
0
Fork 0
mirror of https://github.com/notwa/rc synced 2024-11-05 06:39:02 -08:00
rc/sh/notice

308 lines
11 KiB
Bash
Executable file

#!/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_urlencode2() {
while test "$1"; do
case "$1" in
([:/a-zA-Z0-9~_.-]*) printf '%.1s' "$1";; # : and / added here
(*) 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
normal="$(__notice_urlencode2 "$normal")"
aux="$(__notice_urlencode2 "$aux")"
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