115 lines
2.6 KiB
Bash
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"
|
|
}
|