blogin/util.sh
2024-12-30 01:08:45 +03:00

115 lines
2.6 KiB
Bash

# BWT: bash web token
bwt_sign() {
data=$(</dev/stdin)
signature=$(ssh-keygen -Y sign -f "$SIGN_KEY" -n blogin - <<< "$data")
printf '{"d":%s,"s":%s}' \
"$(jq -Rsr @json <<< "$data")" \
"$(jq -Rsr @json <<< "$signature")" |
zstd -1 | base64 -w0 |
sed 's,=,_E,g;s,/,_S,g;s,+,_P,g' # urlsafe base64 but evil
}
bwt_verify() {
json=$(sed 's,_E,=,g;s,_S,/,g;s,_P,+,g' | base64 -d | zstd -d)
data=$(jq -r '.d' <<< "$json")
signature=$(jq -r '.s' <<< "$json")
if [[ "${data:-x}" == "x" || "${signature:-x}" == "x" ]]; then
return 1
fi
ssh-keygen -q -Y verify -I 'blogin' -f <(cat <<< "$ALLOWED_SIGNERS") -n blogin \
-s <(cat <<< "$signature") <<< "$data" &&
printf '%s' "$data" || return $?
}
db_query() {
psql "${PSQL_OPTS[@]}" --csv -qc "${1?need query}"
}
db_rows() {
db_query "${1?need query}" | yq -rp csv '@json' -
}
db_row() {
db_query "${1?need query}" | yq -rp csv '.0 | @json' -
}
escape_sql_str() {
printf "convert_from(decode('%s', 'base64'), 'UTF-8')" "$(printf '%s' "${1?}" | base64 -w0)"
}
argon2_hash() {
argon2 "$(openssl rand 16 | base64)" -id -e
}
argon2_verify() {
$(cash -O2 -pipe -largon2 <<< '
#include <argon2.h>
#include <errno.h>
#include <error.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 3) error(1, EINVAL, "expected exactly 2 arguments, got %d", argc - 1);
int result = argon2id_verify(argv[1], argv[2], strlen(argv[2]));
if (result == ARGON2_OK) return 0;
else return 1;
}') "${1?need hash}" "$(</dev/stdin)"
}
error_box() {
printf '<div class="error">%s</div>' "$(escape <<< "${1?}")"
}
info_box() {
printf '<div class="info">%s</div>' "$(escape <<< "${1?}")"
}
parse_posts() {
pipe=$(mktemp -u)
mkfifo "$pipe"
for instance in "$@"; do {
name=$(jq -r .name <<< "$instance")
endpoint=$(jq -r .feed <<< "$instance")
echo "requesting feed from instance ${name@Q}" >&2
curl -fsSL "$endpoint" | jq -r ".[] | .[5] |= $(jq -Rr @json <<< "$name") | @json" >> "$pipe"
echo "feed from ${name@Q} consumed" >&2
} & done
jq -sr 'sort_by(.[2] | sub(" "; "T") | sub("$"; "Z") | fromdate | -.) |
.[] |
"([username]=" + (.[1] | @html | @sh) +
" [timestamp]=" + (.[2] | @html | @sh) +
" [contents]=" + (.[0] | @html | @sh) +
" [instance]=" + (.[5] | @html | @sh) +
")"' < "$pipe"
wait || :
rm "$pipe"
}
json_err() {
printf '%s' "$1" | jq -R '{ error: true, reason: (if . == "" then null else . end) }'
}
check_token() {
if ! verified=$(bwt_verify <<< "$1"); then
printf 'invalid'
return 1
fi
till=$(jq -r '.till' <<< "$verified")
now=$(date '+%s')
if (( till < now )); then
printf 'expired'
return 1
fi
printf '%s' "$verified"
}