diff options
| -rw-r--r-- | _shared/build.py | 2 | ||||
| -rw-r--r-- | irc.gumx.cc/body.html | 5 | ||||
| -rw-r--r-- | irc.gumx.cc/index.html | 7 | ||||
| -rw-r--r-- | mail.gumx.cc/index.html | 2 | ||||
| -rwxr-xr-x | pgp.gumx.cc/cgi-bin/pgp-hkp.sh | 2 | ||||
| -rw-r--r-- | pgp.gumx.cc/index.html | 2 | ||||
| -rw-r--r-- | vpn.gumx.cc/index.html | 2 | ||||
| -rw-r--r-- | wk.fo/body.html | 8 | ||||
| -rw-r--r-- | wk.fo/index.html | 10 | ||||
| -rw-r--r-- | wk.fo/pgp/cgi-bin/pgp-hkp.sh | 138 | ||||
| -rw-r--r-- | wk.fo/pgp/index.html | 61 |
11 files changed, 224 insertions, 15 deletions
diff --git a/_shared/build.py b/_shared/build.py index 935bf5c..fcf53d4 100644 --- a/_shared/build.py +++ b/_shared/build.py @@ -4,7 +4,7 @@ import json import os import sys -FAVICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+" +FAVICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg==" def render(title, breadcrumb, style, extra_css, body, footer): diff --git a/irc.gumx.cc/body.html b/irc.gumx.cc/body.html index ee66fec..48440ca 100644 --- a/irc.gumx.cc/body.html +++ b/irc.gumx.cc/body.html @@ -1,7 +1,10 @@ <p>Personal IRC server running <a href="https://ngircd.barton.de/">ngircd</a>, fronted by a <a href="https://soju.im/">Soju</a> bouncer. Access is by invitation.</p> -<h2>connect</h2> +<h2>web client</h2> +<p><a href="/chat">open gamja</a> — no account needed. Connect with any nick.</p> +<h2>connect via IRC client</h2> <table> <tr><th>server</th><td>irc.gumx.cc:6697 (TLS)</td></tr> +<tr><th>auth</th><td>SASL PLAIN (invite only)</td></tr> </table> <h2>request access</h2> <p>Send a message to <a href="mailto:hi@gumx.cc">hi@gumx.cc</a> with your nick and preferred IRC client.</p> diff --git a/irc.gumx.cc/index.html b/irc.gumx.cc/index.html index efb2b69..de477f1 100644 --- a/irc.gumx.cc/index.html +++ b/irc.gumx.cc/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8"> -<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+"> +<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg=="> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>irc.gumx.cc</title> <style> @@ -37,9 +37,12 @@ a { color: inherit; } </header> <main> <p>Personal IRC server running <a href="https://ngircd.barton.de/">ngircd</a>, fronted by a <a href="https://soju.im/">Soju</a> bouncer. Access is by invitation.</p> -<h2>connect</h2> +<h2>web client</h2> +<p><a href="/chat">open gamja</a> — no account needed. Connect with any nick.</p> +<h2>connect via IRC client</h2> <table> <tr><th>server</th><td>irc.gumx.cc:6697 (TLS)</td></tr> +<tr><th>auth</th><td>SASL PLAIN (invite only)</td></tr> </table> <h2>request access</h2> <p>Send a message to <a href="mailto:hi@gumx.cc">hi@gumx.cc</a> with your nick and preferred IRC client.</p> diff --git a/mail.gumx.cc/index.html b/mail.gumx.cc/index.html index e22b67a..5ef4ad2 100644 --- a/mail.gumx.cc/index.html +++ b/mail.gumx.cc/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8"> -<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+"> +<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg=="> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>mail.gumx.cc</title> <style> diff --git a/pgp.gumx.cc/cgi-bin/pgp-hkp.sh b/pgp.gumx.cc/cgi-bin/pgp-hkp.sh index c4e74d7..90d79d8 100755 --- a/pgp.gumx.cc/cgi-bin/pgp-hkp.sh +++ b/pgp.gumx.cc/cgi-bin/pgp-hkp.sh @@ -5,7 +5,7 @@ KEYS_DIR=/var/pgp/keys -FAVICON="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+" +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; } diff --git a/pgp.gumx.cc/index.html b/pgp.gumx.cc/index.html index fcc8bcc..c5f01bb 100644 --- a/pgp.gumx.cc/index.html +++ b/pgp.gumx.cc/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8"> -<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+"> +<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg=="> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>pgp.gumx.cc</title> <style> diff --git a/vpn.gumx.cc/index.html b/vpn.gumx.cc/index.html index 0d33729..6181d56 100644 --- a/vpn.gumx.cc/index.html +++ b/vpn.gumx.cc/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8"> -<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+"> +<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg=="> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>vpn.gumx.cc</title> <style> diff --git a/wk.fo/body.html b/wk.fo/body.html index 40ac3f3..158927c 100644 --- a/wk.fo/body.html +++ b/wk.fo/body.html @@ -1,14 +1,16 @@ -<p>File sharing, IRC bouncer, and VPN for friends. All services require an invitation.</p> +<p>File sharing, IRC, VPN, and tools for friends. Invite required for most services.</p> <h2>file sharing</h2> <p>Upload via HTTPS (token required):</p> <pre><code>curl -F "file=@photo.jpg" -H "Authorization: YOUR_TOKEN" https://wk.fo/</code></pre> <p>Files expire after 24 hours by default (max 48h with <code>expires</code> param). Max 256 MB.</p> <h2>irc</h2> +<p><a href="/chat">web client</a> — no account needed. Or connect directly:</p> <table> <tr><th>server</th><td>wk.fo:6697 (TLS)</td></tr> -<tr><th>type</th><td>Soju bouncer</td></tr> +<tr><th>auth</th><td>SASL PLAIN (invite only)</td></tr> </table> -<p>Use the credentials provided to you on invite. Works with any IRC client that supports SASL PLAIN.</p> +<h2>pgp</h2> +<p>Curated keyserver — keys added after in-person verification. <a href="/pgp">search or browse</a>.</p> <h2>vpn</h2> <table> <tr><th>server</th><td>wk.fo:51820 (UDP)</td></tr> diff --git a/wk.fo/index.html b/wk.fo/index.html index fbb74cb..af02a48 100644 --- a/wk.fo/index.html +++ b/wk.fo/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8"> -<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+"> +<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg=="> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>wk.fo</title> <style> @@ -36,17 +36,19 @@ a { color: inherit; } <h1><a href="https://gumx.cc">gumx</a> / wk.fo</h1> </header> <main> -<p>File sharing, IRC bouncer, and VPN for friends. All services require an invitation.</p> +<p>File sharing, IRC, VPN, and tools for friends. Invite required for most services.</p> <h2>file sharing</h2> <p>Upload via HTTPS (token required):</p> <pre><code>curl -F "file=@photo.jpg" -H "Authorization: YOUR_TOKEN" https://wk.fo/</code></pre> <p>Files expire after 24 hours by default (max 48h with <code>expires</code> param). Max 256 MB.</p> <h2>irc</h2> +<p><a href="/chat">web client</a> — no account needed. Or connect directly:</p> <table> <tr><th>server</th><td>wk.fo:6697 (TLS)</td></tr> -<tr><th>type</th><td>Soju bouncer</td></tr> +<tr><th>auth</th><td>SASL PLAIN (invite only)</td></tr> </table> -<p>Use the credentials provided to you on invite. Works with any IRC client that supports SASL PLAIN.</p> +<h2>pgp</h2> +<p>Curated keyserver — keys added after in-person verification. <a href="/pgp">search or browse</a>.</p> <h2>vpn</h2> <table> <tr><th>server</th><td>wk.fo:51820 (UDP)</td></tr> diff --git a/wk.fo/pgp/cgi-bin/pgp-hkp.sh b/wk.fo/pgp/cgi-bin/pgp-hkp.sh new file mode 100644 index 0000000..155c820 --- /dev/null +++ b/wk.fo/pgp/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/<FINGERPRINT_UPPERCASE>.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='<footer> +<hr> +<a href="https://twt.gumx.cc">twt</a> / +<a href="https://git.gumx.cc">git</a> / +<a href="https://mail.gumx.cc">mail</a> / +<a href="https://irc.gumx.cc">irc</a> / +<a href="https://files.gumx.cc">files</a> / +<a href="https://vpn.gumx.cc">vpn</a> / +<a href="/pgp">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / +<a href="https://wk.fo">wk.fo</a> +</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 '<!DOCTYPE html>\n<html lang="en">\n<head>\n' + printf '<meta charset="utf-8">\n' + printf '<link rel="icon" type="image/svg+xml" href="%s">\n' "$FAVICON" + printf '<meta name="viewport" content="width=device-width,initial-scale=1">\n' + printf '<title>wk.fo / pgp / keys</title>\n' + printf '<style>\n%s\n</style>\n' "$CSS" + printf '</head>\n<body>\n' + printf '<header>\n<h1><a href="https://wk.fo">wk.fo</a> / <a href="/pgp">pgp</a> / keys</h1>\n</header>\n' + printf '<main>\n<table>\n<tr><th>fingerprint</th><th>uid</th></tr>\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 '<tr><td><a href="/pks/lookup?op=get&search=0x%s"><code>%s</code></a></td><td>%s</td></tr>\n' \ + "$FP" "$FP" "$KEY_UID" + done + [[ $found -eq 0 ]] && printf '<tr><td colspan="2">no keys</td></tr>\n' + printf '</table>\n</main>\n' + printf '%s\n' "$FOOTER" + printf '</body>\n</html>\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 new file mode 100644 index 0000000..2847b9f --- /dev/null +++ b/wk.fo/pgp/index.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMTQwIiBzdHJva2U9IiMwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iMTIyIiBzdHJva2UtZGFzaGFycmF5PSIyLDM4IiBkPSJtOSw3MGgxMjJNNzAsOXYxMjIiLz48cGF0aCBzdHJva2Utd2lkdGg9IjMzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGQ9Im03MCwzMGgwbTQwLDQwaDBtLTgwLDQwdjBtNDAsMGgwbTQwLDBoMCIvPjwvc3ZnPg=="> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>wk.fo / pgp</title> +<style> +@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; } +pre { margin: 1em 0; } +pre code { border: thin solid; padding: 1em; display: block; text-align: start; overflow-x: scroll; } +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; } +input[type="text"], button { font-family: inherit; font-size: inherit; border: thin solid; padding: 0.3em 0.6em; background: transparent; color: inherit; } +button { cursor: pointer; } +@media (max-width: 600px) { body { font-size: 0.9em; } h1 { font-size: 1.8em; } } +@media (prefers-color-scheme: dark) { html { filter: invert(1); } } +</style> +</head> +<body> +<header> +<h1><a href="https://wk.fo">wk.fo</a> / pgp</h1> +</header> +<main> +<p>Curated HKP keyserver. Keys are added after in-person verification only.</p> +<h2>search</h2> +<form action="/pks/lookup" method="get"> +<input type="hidden" name="op" value="get"> +<p><input type="text" name="search" placeholder="0x fingerprint"> <button type="submit">lookup</button></p> +</form> +<p><a href="/pks/lookup?op=vindex&search=">browse all keys</a></p> +<h2>via gpg</h2> +<pre><code>gpg --keyserver hkps://wk.fo --recv-keys <fingerprint></code></pre> +<h2>submit</h2> +<p>Keys are not accepted without prior arrangement. Contact <a href="mailto:hi@gumx.cc">hi@gumx.cc</a>.</p> +</main> +<footer> +<hr> +<a href="https://twt.gumx.cc">twt</a> / +<a href="https://git.gumx.cc">git</a> / +<a href="https://mail.gumx.cc">mail</a> / +<a href="https://irc.gumx.cc">irc</a> / +<a href="https://files.gumx.cc">files</a> / +<a href="https://vpn.gumx.cc">vpn</a> / +<a href="/pgp">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / +<a href="https://wk.fo">wk.fo</a> +</footer> +</body> +</html> |
