From 12b6af597d9f3c463fdae9e59e3f5a432bf6c004 Mon Sep 17 00:00:00 2001 From: Ahmed Date: Tue, 16 Jun 2026 23:18:06 +0300 Subject: fix: moved wk.fo/pgp to wk.fo/pks --- wk.fo/pgp/cgi-bin/pgp-hkp.sh | 138 ------------------------------------------- wk.fo/pgp/index.html | 61 ------------------- wk.fo/pks/cgi-bin/pgp-hkp.sh | 138 +++++++++++++++++++++++++++++++++++++++++++ wk.fo/pks/index.html | 61 +++++++++++++++++++ 4 files changed, 199 insertions(+), 199 deletions(-) delete mode 100644 wk.fo/pgp/cgi-bin/pgp-hkp.sh delete mode 100644 wk.fo/pgp/index.html create mode 100644 wk.fo/pks/cgi-bin/pgp-hkp.sh create mode 100644 wk.fo/pks/index.html diff --git a/wk.fo/pgp/cgi-bin/pgp-hkp.sh b/wk.fo/pgp/cgi-bin/pgp-hkp.sh deleted file mode 100644 index 155c820..0000000 --- a/wk.fo/pgp/cgi-bin/pgp-hkp.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash -# HKP keyserver CGI for wk.fo/pks -# Implements: GET /pks/lookup?op=get|index|vindex and POST /pks/add -# Keys live in /var/pgp/keys/.asc - -KEYS_DIR=/var/pgp/keys - -FAVICON="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg==" - -CSS='@font-face { font-family: "Kawkab Mono"; src: url(/fonts/KawkabMono-Regular.woff2); font-weight: normal; } -@font-face { font-family: "Kawkab Mono"; src: url(/fonts/KawkabMono-Bold.woff2); font-weight: bold; } -* { unicode-bidi: plaintext; box-sizing: border-box; } -html { color: black; background-color: white; } -body { font-family: "Kawkab Mono"; font-size: 16px; line-height: 1.4; margin: 0; padding: 4rem 0; min-height: 100%; overflow-wrap: break-word; } -main, header, footer { max-width: 800px; margin-inline: auto; padding: 0 2rem; } -h1, header, footer { text-align: center; } -main { text-align: justify; } -p, h2, h3, h4 { margin: 1em 0 0 0; } -table { margin: 1em auto; border-collapse: collapse; } -th, td { border: 1px solid; padding: 0.3em 0.8em; } -code { font-size: 85%; } -hr { border: none; border-top: thin solid; margin: 1.25rem 0; } -header { margin-bottom: 1em; } -footer { margin-top: 3em; } -a { color: inherit; } -@media (max-width: 600px) { body { font-size: 0.9em; } h1 { font-size: 1.8em; } } -@media (max-width: 400px) { body { font-size: 0.8em; } h1 { font-size: 1.6em; } } -@media (prefers-color-scheme: dark) { html { filter: invert(1); } }' - -FOOTER='' - -qs_get() { - echo "$QUERY_STRING" \ - | tr '&' '\n' \ - | grep -E "^$1=" \ - | head -1 \ - | cut -d= -f2- \ - | sed 's/+/ /g; s/%20/ /g' -} - -op=$(qs_get op) -search=$(qs_get search | sed 's/^0x//i; s/^0X//i') - -case "$REQUEST_METHOD" in - GET) - case "$op" in - get) - printf "Content-Type: text/plain\r\n\r\n" - FP="${search^^}" - keyfile="$KEYS_DIR/$FP.asc" - if [[ -f "$keyfile" ]]; then - cat "$keyfile" - else - printf "Error: No key found for %s\n" "$search" - fi - ;; - index) - printf "Content-Type: text/plain\r\n\r\n" - total=$(find "$KEYS_DIR" -name '*.asc' 2>/dev/null | wc -l) - echo "info:1:$total" - for f in "$KEYS_DIR"/*.asc; do - [[ -f "$f" ]] || continue - gpg --with-colons --import-options show-only \ - --import < "$f" 2>/dev/null \ - | awk -F: '/^pub/{print "pub:" $5 ":" $6 ":::" $10 "::"}' - done - ;; - vindex) - printf "Content-Type: text/html\r\n\r\n" - printf '\n\n\n' - printf '\n' - printf '\n' "$FAVICON" - printf '\n' - printf 'wk.fo / pgp / keys\n' - printf '\n' "$CSS" - printf '\n\n' - printf '
\n

wk.fo / pgp / keys

\n
\n' - printf '
\n\n\n' - found=0 - for f in "$KEYS_DIR"/*.asc; do - [[ -f "$f" ]] || continue - found=1 - FP=$(basename "$f" .asc) - KEY_UID=$(gpg --with-colons --import-options show-only --import < "$f" 2>/dev/null \ - | awk -F: '/^uid/{print $10; exit}') - printf '\n' \ - "$FP" "$FP" "$KEY_UID" - done - [[ $found -eq 0 ]] && printf '\n' - printf '
fingerprintuid
%s%s
no keys
\n
\n' - printf '%s\n' "$FOOTER" - printf '\n\n' - ;; - *) - printf "Content-Type: text/plain\r\n\r\n" - echo "Error: unknown op" - ;; - esac - ;; - - POST) - printf "Content-Type: text/plain\r\n\r\n" - read -r -d '' -n "${CONTENT_LENGTH:-4096}" SUBMITTED_KEY - - TMPDIR_GPG=$(mktemp -d) - FINGERPRINT=$(echo "$SUBMITTED_KEY" \ - | gpg --homedir "$TMPDIR_GPG" \ - --with-colons --import-options show-only \ - --import 2>/dev/null \ - | awk -F: '/^fpr/{print $10; exit}') - rm -rf "$TMPDIR_GPG" - - if [[ -z "$FINGERPRINT" ]]; then - echo "Error: Could not parse submitted key" - exit 0 - fi - - KEYFILE="$KEYS_DIR/${FINGERPRINT^^}.asc" - if [[ -f "$KEYFILE" ]]; then - echo "$SUBMITTED_KEY" > "$KEYFILE" - echo "Key updated successfully" - else - echo "Error: Fingerprint not registered." - echo "Contact hi@gumx.cc to arrange a key signing meeting." - fi - ;; -esac diff --git a/wk.fo/pgp/index.html b/wk.fo/pgp/index.html deleted file mode 100644 index 2847b9f..0000000 --- a/wk.fo/pgp/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - -wk.fo / pgp - - - -
-

wk.fo / pgp

-
-
-

Curated HKP keyserver. Keys are added after in-person verification only.

-

search

-
- -

-
-

browse all keys

-

via gpg

-
gpg --keyserver hkps://wk.fo --recv-keys <fingerprint>
-

submit

-

Keys are not accepted without prior arrangement. Contact hi@gumx.cc.

-
- - - diff --git a/wk.fo/pks/cgi-bin/pgp-hkp.sh b/wk.fo/pks/cgi-bin/pgp-hkp.sh new file mode 100644 index 0000000..155c820 --- /dev/null +++ b/wk.fo/pks/cgi-bin/pgp-hkp.sh @@ -0,0 +1,138 @@ +#!/bin/bash +# HKP keyserver CGI for wk.fo/pks +# Implements: GET /pks/lookup?op=get|index|vindex and POST /pks/add +# Keys live in /var/pgp/keys/.asc + +KEYS_DIR=/var/pgp/keys + +FAVICON="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg==" + +CSS='@font-face { font-family: "Kawkab Mono"; src: url(/fonts/KawkabMono-Regular.woff2); font-weight: normal; } +@font-face { font-family: "Kawkab Mono"; src: url(/fonts/KawkabMono-Bold.woff2); font-weight: bold; } +* { unicode-bidi: plaintext; box-sizing: border-box; } +html { color: black; background-color: white; } +body { font-family: "Kawkab Mono"; font-size: 16px; line-height: 1.4; margin: 0; padding: 4rem 0; min-height: 100%; overflow-wrap: break-word; } +main, header, footer { max-width: 800px; margin-inline: auto; padding: 0 2rem; } +h1, header, footer { text-align: center; } +main { text-align: justify; } +p, h2, h3, h4 { margin: 1em 0 0 0; } +table { margin: 1em auto; border-collapse: collapse; } +th, td { border: 1px solid; padding: 0.3em 0.8em; } +code { font-size: 85%; } +hr { border: none; border-top: thin solid; margin: 1.25rem 0; } +header { margin-bottom: 1em; } +footer { margin-top: 3em; } +a { color: inherit; } +@media (max-width: 600px) { body { font-size: 0.9em; } h1 { font-size: 1.8em; } } +@media (max-width: 400px) { body { font-size: 0.8em; } h1 { font-size: 1.6em; } } +@media (prefers-color-scheme: dark) { html { filter: invert(1); } }' + +FOOTER='' + +qs_get() { + echo "$QUERY_STRING" \ + | tr '&' '\n' \ + | grep -E "^$1=" \ + | head -1 \ + | cut -d= -f2- \ + | sed 's/+/ /g; s/%20/ /g' +} + +op=$(qs_get op) +search=$(qs_get search | sed 's/^0x//i; s/^0X//i') + +case "$REQUEST_METHOD" in + GET) + case "$op" in + get) + printf "Content-Type: text/plain\r\n\r\n" + FP="${search^^}" + keyfile="$KEYS_DIR/$FP.asc" + if [[ -f "$keyfile" ]]; then + cat "$keyfile" + else + printf "Error: No key found for %s\n" "$search" + fi + ;; + index) + printf "Content-Type: text/plain\r\n\r\n" + total=$(find "$KEYS_DIR" -name '*.asc' 2>/dev/null | wc -l) + echo "info:1:$total" + for f in "$KEYS_DIR"/*.asc; do + [[ -f "$f" ]] || continue + gpg --with-colons --import-options show-only \ + --import < "$f" 2>/dev/null \ + | awk -F: '/^pub/{print "pub:" $5 ":" $6 ":::" $10 "::"}' + done + ;; + vindex) + printf "Content-Type: text/html\r\n\r\n" + printf '\n\n\n' + printf '\n' + printf '\n' "$FAVICON" + printf '\n' + printf 'wk.fo / pgp / keys\n' + printf '\n' "$CSS" + printf '\n\n' + printf '
\n

wk.fo / pgp / keys

\n
\n' + printf '
\n\n\n' + found=0 + for f in "$KEYS_DIR"/*.asc; do + [[ -f "$f" ]] || continue + found=1 + FP=$(basename "$f" .asc) + KEY_UID=$(gpg --with-colons --import-options show-only --import < "$f" 2>/dev/null \ + | awk -F: '/^uid/{print $10; exit}') + printf '\n' \ + "$FP" "$FP" "$KEY_UID" + done + [[ $found -eq 0 ]] && printf '\n' + printf '
fingerprintuid
%s%s
no keys
\n
\n' + printf '%s\n' "$FOOTER" + printf '\n\n' + ;; + *) + printf "Content-Type: text/plain\r\n\r\n" + echo "Error: unknown op" + ;; + esac + ;; + + POST) + printf "Content-Type: text/plain\r\n\r\n" + read -r -d '' -n "${CONTENT_LENGTH:-4096}" SUBMITTED_KEY + + TMPDIR_GPG=$(mktemp -d) + FINGERPRINT=$(echo "$SUBMITTED_KEY" \ + | gpg --homedir "$TMPDIR_GPG" \ + --with-colons --import-options show-only \ + --import 2>/dev/null \ + | awk -F: '/^fpr/{print $10; exit}') + rm -rf "$TMPDIR_GPG" + + if [[ -z "$FINGERPRINT" ]]; then + echo "Error: Could not parse submitted key" + exit 0 + fi + + KEYFILE="$KEYS_DIR/${FINGERPRINT^^}.asc" + if [[ -f "$KEYFILE" ]]; then + echo "$SUBMITTED_KEY" > "$KEYFILE" + echo "Key updated successfully" + else + echo "Error: Fingerprint not registered." + echo "Contact hi@gumx.cc to arrange a key signing meeting." + fi + ;; +esac diff --git a/wk.fo/pks/index.html b/wk.fo/pks/index.html new file mode 100644 index 0000000..2847b9f --- /dev/null +++ b/wk.fo/pks/index.html @@ -0,0 +1,61 @@ + + + + + + +wk.fo / pgp + + + +
+

wk.fo / pgp

+
+
+

Curated HKP keyserver. Keys are added after in-person verification only.

+

search

+
+ +

+
+

browse all keys

+

via gpg

+
gpg --keyserver hkps://wk.fo --recv-keys <fingerprint>
+

submit

+

Keys are not accepted without prior arrangement. Contact hi@gumx.cc.

+
+ + + -- cgit v1.2.3