diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | _shared/build.py | 94 | ||||
| -rw-r--r-- | _shared/footer.html | 12 | ||||
| -rw-r--r-- | _shared/style.css | 22 | ||||
| -rw-r--r-- | build.sh | 2 | ||||
| -rw-r--r-- | demo.gumx.cc/demos.json | 9 | ||||
| -rw-r--r-- | demo.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | files.gumx.cc/body.html | 6 | ||||
| -rw-r--r-- | files.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | hooks/post-receive | 19 | ||||
| -rw-r--r-- | irc.gumx.cc/body.html | 9 | ||||
| -rw-r--r-- | irc.gumx.cc/index.html | 16 | ||||
| -rw-r--r-- | irc.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | mail.gumx.cc/.well-known/autoconfig/mail/config-v1.1.xml | 22 | ||||
| -rw-r--r-- | mail.gumx.cc/body.html | 12 | ||||
| -rw-r--r-- | mail.gumx.cc/index.html | 12 | ||||
| -rw-r--r-- | mail.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | pgp.gumx.cc/body.html | 7 | ||||
| -rw-r--r-- | pgp.gumx.cc/index.html | 14 | ||||
| -rw-r--r-- | pgp.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | twt.gumx.cc/body.html | 49 | ||||
| -rw-r--r-- | twt.gumx.cc/extra.css | 4 | ||||
| -rw-r--r-- | twt.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | vpn.gumx.cc/body.html | 19 | ||||
| -rw-r--r-- | vpn.gumx.cc/index.html | 15 | ||||
| -rw-r--r-- | vpn.gumx.cc/meta | 2 | ||||
| -rw-r--r-- | wk.fo/body.html | 19 | ||||
| -rw-r--r-- | wk.fo/index.html | 16 | ||||
| -rw-r--r-- | wk.fo/meta | 2 |
29 files changed, 383 insertions, 12 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52cdfdb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*/index.html diff --git a/_shared/build.py b/_shared/build.py new file mode 100644 index 0000000..935bf5c --- /dev/null +++ b/_shared/build.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""Build sites from body.html + meta into index.html using shared templates.""" +import json +import os +import sys + +FAVICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+" + + +def render(title, breadcrumb, style, extra_css, body, footer): + css = style + ("\n" + extra_css if extra_css.strip() else "") + return f"""<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<link rel="icon" type="image/svg+xml" href="{FAVICON}"> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>{title}</title> +<style> +{css} +</style> +</head> +<body> +<header> +<h1><a href="https://gumx.cc">gumx</a> / {breadcrumb}</h1> +</header> +<main> +{body} +</main> +{footer} +</body> +</html> +""" + + +def build_demo_body(demos_file): + demos = json.load(open(demos_file)) + parts = [] + for d in demos: + url = d.get("url", "#") + title = d.get("title", d.get("name", "")) + desc = d.get("description", "") + src = d.get("source", "") + src_link = f' / <a href="{src}">source</a>' if src else "" + parts.append(f'<p><a href="{url}">{title}</a>{src_link}</p>\n<p>{desc}</p>') + return "\n".join(parts) + + +def build(sites_dir): + shared = os.path.join(sites_dir, "_shared") + style = open(os.path.join(shared, "style.css")).read() + footer = open(os.path.join(shared, "footer.html")).read() + + for site in sorted(os.listdir(sites_dir)): + if site.startswith("_") or site == "fonts" or site == "hooks": + continue + site_dir = os.path.join(sites_dir, site) + if not os.path.isdir(site_dir): + continue + + body_file = os.path.join(site_dir, "body.html") + demos_file = os.path.join(site_dir, "demos.json") + + if site == "demo.gumx.cc" and os.path.exists(demos_file): + body = build_demo_body(demos_file) + elif os.path.exists(body_file): + body = open(body_file).read() + else: + continue + + title = site + breadcrumb = site + meta_file = os.path.join(site_dir, "meta") + if os.path.exists(meta_file): + for line in open(meta_file): + k, _, v = line.strip().partition("=") + if k == "TITLE": + title = v.strip('"') + elif k == "BREADCRUMB": + breadcrumb = v.strip('"') + + extra_css = "" + extra_file = os.path.join(site_dir, "extra.css") + if os.path.exists(extra_file): + extra_css = open(extra_file).read() + + out = render(title, breadcrumb, style, extra_css, body, footer) + with open(os.path.join(site_dir, "index.html"), "w") as f: + f.write(out) + print(f"built: {site}") + + +if __name__ == "__main__": + build(sys.argv[1] if len(sys.argv) > 1 else ".") diff --git a/_shared/footer.html b/_shared/footer.html new file mode 100644 index 0000000..3aedfc6 --- /dev/null +++ b/_shared/footer.html @@ -0,0 +1,12 @@ +<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="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / +<a href="https://wk.fo">wk.fo</a> +</footer> diff --git a/_shared/style.css b/_shared/style.css new file mode 100644 index 0000000..0f7e7cf --- /dev/null +++ b/_shared/style.css @@ -0,0 +1,22 @@ +@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; } +ol { margin: 0.5em 0 0 0; } +table { margin: auto; border-collapse: collapse; } +th, td { border: 1px solid; padding: 0.3em 0.8em; } +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; } +@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); } img { filter: invert(1); } } diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..6de6968 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +python3 "$(dirname "$0")/_shared/build.py" "$(dirname "$0")" diff --git a/demo.gumx.cc/demos.json b/demo.gumx.cc/demos.json new file mode 100644 index 0000000..ae6d7df --- /dev/null +++ b/demo.gumx.cc/demos.json @@ -0,0 +1,9 @@ +[ + { + "name": "no-style-please", + "title": "zola-no-style-please", + "url": "/no-style-please/", + "description": "a Zola theme with no style, or rather, just a little style.", + "source": "https://git.gumx.cc/zola-no-style-please" + } +] diff --git a/demo.gumx.cc/meta b/demo.gumx.cc/meta new file mode 100644 index 0000000..496fc7e --- /dev/null +++ b/demo.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="demo.gumx.cc" +BREADCRUMB="demo" diff --git a/files.gumx.cc/body.html b/files.gumx.cc/body.html new file mode 100644 index 0000000..3c34353 --- /dev/null +++ b/files.gumx.cc/body.html @@ -0,0 +1,6 @@ +<p>File hosting via <a href="https://github.com/mia-0/0x0">0x0</a>. Uploads require a token.</p> +<h2>upload</h2> +<pre><code>curl -F "file=@photo.jpg" -H "Authorization: YOUR_TOKEN" https://files.gumx.cc/</code></pre> +<p>Files expire after 24 hours by default. Max 256 MB.</p> +<h2>access</h2> +<p>Contact <a href="mailto:hi@gumx.cc">hi@gumx.cc</a> to request a token.</p> diff --git a/files.gumx.cc/meta b/files.gumx.cc/meta new file mode 100644 index 0000000..2c19518 --- /dev/null +++ b/files.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="files.gumx.cc" +BREADCRUMB="files" diff --git a/hooks/post-receive b/hooks/post-receive new file mode 100644 index 0000000..aa142ed --- /dev/null +++ b/hooks/post-receive @@ -0,0 +1,19 @@ +#!/bin/sh +set -e + +WORK=/home/git/build/sites + +cd "$WORK" +python3 _shared/build.py . + +for SITE in irc.gumx.cc vpn.gumx.cc mail.gumx.cc pgp.gumx.cc wk.fo twt.gumx.cc files.gumx.cc demo.gumx.cc; do + if [ -d "$SITE" ]; then + WEBROOT="/var/www/$SITE" + mkdir -p "$WEBROOT" + rsync -rlptD --delete --exclude="/fonts" "$SITE/" "$WEBROOT/" + mkdir -p "$WEBROOT/fonts" + rsync -rlptD fonts/ "$WEBROOT/fonts/" + fi +done + +echo "sites deployed" diff --git a/irc.gumx.cc/body.html b/irc.gumx.cc/body.html new file mode 100644 index 0000000..ee66fec --- /dev/null +++ b/irc.gumx.cc/body.html @@ -0,0 +1,9 @@ +<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> +<table> +<tr><th>server</th><td>irc.gumx.cc:6697 (TLS)</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> +<h2>bots</h2> +<p><a href="/bots">irc bots</a></p> diff --git a/irc.gumx.cc/index.html b/irc.gumx.cc/index.html index a18a309..efb2b69 100644 --- a/irc.gumx.cc/index.html +++ b/irc.gumx.cc/index.html @@ -2,6 +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+"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>irc.gumx.cc</title> <style> @@ -14,15 +15,20 @@ 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; } +ol { margin: 0.5em 0 0 0; } table { margin: auto; border-collapse: collapse; } th, td { border: 1px solid; padding: 0.3em 0.8em; } +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; } @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); } img { filter: invert(1); } } + </style> </head> <body> @@ -33,20 +39,26 @@ a { color: inherit; } <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> <table> -<tr><th>server</th><td>wk.fo:6697 (TLS)</td></tr> +<tr><th>server</th><td>irc.gumx.cc:6697 (TLS)</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> +<h2>bots</h2> +<p><a href="/bots">irc bots</a></p> + </main> <footer> <hr> -<a href="https://gumx.cc">gumx.cc</a> / +<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="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / <a href="https://wk.fo">wk.fo</a> </footer> + </body> </html> diff --git a/irc.gumx.cc/meta b/irc.gumx.cc/meta new file mode 100644 index 0000000..fdf1428 --- /dev/null +++ b/irc.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="irc.gumx.cc" +BREADCRUMB="irc" diff --git a/mail.gumx.cc/.well-known/autoconfig/mail/config-v1.1.xml b/mail.gumx.cc/.well-known/autoconfig/mail/config-v1.1.xml new file mode 100644 index 0000000..8098148 --- /dev/null +++ b/mail.gumx.cc/.well-known/autoconfig/mail/config-v1.1.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<clientConfig version="1.1"> + <emailProvider id="gumx.cc"> + <domain>gumx.cc</domain> + <displayName>gumx mail</displayName> + <displayShortName>gumx</displayShortName> + <incomingServer type="imap"> + <hostname>mail.gumx.cc</hostname> + <port>993</port> + <socketType>SSL</socketType> + <authentication>password-cleartext</authentication> + <username>%EMAILADDRESS%</username> + </incomingServer> + <outgoingServer type="smtp"> + <hostname>mail.gumx.cc</hostname> + <port>587</port> + <socketType>STARTTLS</socketType> + <authentication>password-cleartext</authentication> + <username>%EMAILADDRESS%</username> + </outgoingServer> + </emailProvider> +</clientConfig> diff --git a/mail.gumx.cc/body.html b/mail.gumx.cc/body.html new file mode 100644 index 0000000..7a3e9fe --- /dev/null +++ b/mail.gumx.cc/body.html @@ -0,0 +1,12 @@ +<p>Self-hosted mail running <a href="http://www.postfix.org/">Postfix</a> and <a href="https://www.dovecot.org/">Dovecot</a>.</p> +<h2>contact</h2> +<p><a href="mailto:hi@gumx.cc">hi@gumx.cc</a></p> +<h2>IMAP / SMTP</h2> +<table> +<tr><th>IMAP</th><td>mail.gumx.cc:993 (TLS)</td></tr> +<tr><th>SMTP</th><td>mail.gumx.cc:587 (STARTTLS)</td></tr> +</table> +<h2>CalDAV / CardDAV</h2> +<p>Available at <code><a href="https://mail.gumx.cc/dav/">/dav/</a></code> via <a href="https://www.xandikos.org/">Xandikos</a>. Credentials on request.</p> +<h2>mailing list</h2> +<p>Site updates and discussion: <a href="/list">gumx.cc mailing list</a>.</p> diff --git a/mail.gumx.cc/index.html b/mail.gumx.cc/index.html index 9e5597c..e22b67a 100644 --- a/mail.gumx.cc/index.html +++ b/mail.gumx.cc/index.html @@ -2,6 +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+"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>mail.gumx.cc</title> <style> @@ -14,15 +15,20 @@ 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; } +ol { margin: 0.5em 0 0 0; } table { margin: auto; border-collapse: collapse; } th, td { border: 1px solid; padding: 0.3em 0.8em; } +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; } @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); } img { filter: invert(1); } } + </style> </head> <body> @@ -42,16 +48,20 @@ a { color: inherit; } <p>Available at <code><a href="https://mail.gumx.cc/dav/">/dav/</a></code> via <a href="https://www.xandikos.org/">Xandikos</a>. Credentials on request.</p> <h2>mailing list</h2> <p>Site updates and discussion: <a href="/list">gumx.cc mailing list</a>.</p> + </main> <footer> <hr> -<a href="https://gumx.cc">gumx.cc</a> / +<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="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / <a href="https://wk.fo">wk.fo</a> </footer> + </body> </html> diff --git a/mail.gumx.cc/meta b/mail.gumx.cc/meta new file mode 100644 index 0000000..50375b1 --- /dev/null +++ b/mail.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="mail.gumx.cc" +BREADCRUMB="mail" diff --git a/pgp.gumx.cc/body.html b/pgp.gumx.cc/body.html new file mode 100644 index 0000000..df5b04d --- /dev/null +++ b/pgp.gumx.cc/body.html @@ -0,0 +1,7 @@ +<p>Curated HKP keyserver. Keys are added after in-person verification only.</p> +<h2>lookup</h2> +<pre><code>gpg --keyserver hkps://pgp.gumx.cc --recv-keys <fingerprint></code></pre> +<p>Or via HTTPS:</p> +<pre><code>curl "https://pgp.gumx.cc/pks/lookup?op=get&search=0x<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> diff --git a/pgp.gumx.cc/index.html b/pgp.gumx.cc/index.html index 7c3db3b..96e7623 100644 --- a/pgp.gumx.cc/index.html +++ b/pgp.gumx.cc/index.html @@ -2,6 +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+"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>pgp.gumx.cc</title> <style> @@ -14,15 +15,20 @@ 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; } +ol { margin: 0.5em 0 0 0; } +table { margin: auto; border-collapse: collapse; } +th, td { border: 1px solid; padding: 0.3em 0.8em; } 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; } @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); } img { filter: invert(1); } } + </style> </head> <body> @@ -34,19 +40,23 @@ a { color: inherit; } <h2>lookup</h2> <pre><code>gpg --keyserver hkps://pgp.gumx.cc --recv-keys <fingerprint></code></pre> <p>Or via HTTPS:</p> -<pre><code>curl "https://pgp.gumx.cc/pks/lookup?op=get&search=0x<fingerprint>"</code></pre> +<pre><code>curl "https://pgp.gumx.cc/pks/lookup?op=get&search=0x<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://gumx.cc">gumx.cc</a> / +<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="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / <a href="https://wk.fo">wk.fo</a> </footer> + </body> </html> diff --git a/pgp.gumx.cc/meta b/pgp.gumx.cc/meta new file mode 100644 index 0000000..6cbe97d --- /dev/null +++ b/pgp.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="pgp.gumx.cc" +BREADCRUMB="pgp" diff --git a/twt.gumx.cc/body.html b/twt.gumx.cc/body.html new file mode 100644 index 0000000..7f3adc3 --- /dev/null +++ b/twt.gumx.cc/body.html @@ -0,0 +1,49 @@ +<p> +<a href="/twtxt.txt">twtxt.txt</a> / +follow: <code>twtxt follow gumx https://twt.gumx.cc/twtxt.txt</code> +</p> +<div id="feed"></div> + +<script> +async function loadFeed() { + const feed = document.getElementById('feed'); + try { + const res = await fetch('/twtxt.txt'); + if (!res.ok) throw new Error('HTTP ' + res.status); + const text = await res.text(); + const lines = text.split('\n') + .filter(l => l && !l.startsWith('#')) + .map(l => { + const tab = l.indexOf('\t'); + if (tab === -1) return null; + return { time: l.slice(0, tab), text: l.slice(tab + 1) }; + }) + .filter(Boolean) + .reverse(); + + if (lines.length === 0) { + feed.innerHTML = '<p id="error">no twts yet.</p>'; + return; + } + + feed.innerHTML = lines.map(t => { + const d = new Date(t.time); + const dateStr = d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }); + const timeStr = d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' }); + return `<div class="twt"> +<hr> +<span class="twt-time">${dateStr} ${timeStr}</span> +<span class="twt-text">${escapeHtml(t.text)}</span> +</div>`; + }).join(''); + } catch (e) { + feed.innerHTML = '<p id="error">could not load feed.</p>'; + } +} + +function escapeHtml(s) { + return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); +} + +loadFeed(); +</script> diff --git a/twt.gumx.cc/extra.css b/twt.gumx.cc/extra.css new file mode 100644 index 0000000..39c27d7 --- /dev/null +++ b/twt.gumx.cc/extra.css @@ -0,0 +1,4 @@ +.twt { margin: 1.5em 0 0 0; } +.twt-time { font-size: 0.85em; opacity: 0.6; display: block; } +.twt-text { display: block; margin-top: 0.25em; } +#error { opacity: 0.5; } diff --git a/twt.gumx.cc/meta b/twt.gumx.cc/meta new file mode 100644 index 0000000..1721f95 --- /dev/null +++ b/twt.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="twt.gumx.cc" +BREADCRUMB="twt" diff --git a/vpn.gumx.cc/body.html b/vpn.gumx.cc/body.html new file mode 100644 index 0000000..49fb589 --- /dev/null +++ b/vpn.gumx.cc/body.html @@ -0,0 +1,19 @@ +<p><a href="https://www.wireguard.com/">WireGuard</a> VPN. Endpoint: <code>vpn.gumx.cc:51820</code>. Access is by invitation.</p> +<h2>setup</h2> +<ol> +<li>Generate a keypair: <code>wg genkey | tee private.key | wg pubkey > public.key</code></li> +<li>Send your public key to <a href="mailto:hi@gumx.cc">hi@gumx.cc</a></li> +<li>Receive your assigned IP (<code>10.0.0.x/32</code>) and the server public key</li> +<li>Create <code>/etc/wireguard/wg0.conf</code> and bring it up with <code>wg-quick up wg0</code></li> +</ol> +<h2>example client config</h2> +<pre><code>[Interface] +PrivateKey = <your private key> +Address = 10.0.0.x/32 +DNS = 1.1.1.1 + +[Peer] +PublicKey = <server public key> +Endpoint = vpn.gumx.cc:51820 +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 25</code></pre> diff --git a/vpn.gumx.cc/index.html b/vpn.gumx.cc/index.html index c2a3ce3..0d33729 100644 --- a/vpn.gumx.cc/index.html +++ b/vpn.gumx.cc/index.html @@ -2,6 +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+"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>vpn.gumx.cc</title> <style> @@ -15,15 +16,19 @@ h1, header, footer { text-align: center; } main { text-align: justify; } p, h2, h3, h4 { margin: 1em 0 0 0; } ol { margin: 0.5em 0 0 0; } +table { margin: auto; border-collapse: collapse; } +th, td { border: 1px solid; padding: 0.3em 0.8em; } 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; } @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); } img { filter: invert(1); } } + </style> </head> <body> @@ -31,7 +36,7 @@ a { color: inherit; } <h1><a href="https://gumx.cc">gumx</a> / vpn</h1> </header> <main> -<p><a href="https://www.wireguard.com/">WireGuard</a> VPN. Endpoint: <code>wk.fo:51820</code>. Access is by invitation.</p> +<p><a href="https://www.wireguard.com/">WireGuard</a> VPN. Endpoint: <code>vpn.gumx.cc:51820</code>. Access is by invitation.</p> <h2>setup</h2> <ol> <li>Generate a keypair: <code>wg genkey | tee private.key | wg pubkey > public.key</code></li> @@ -47,19 +52,23 @@ DNS = 1.1.1.1 [Peer] PublicKey = <server public key> -Endpoint = wk.fo:51820 +Endpoint = vpn.gumx.cc:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25</code></pre> + </main> <footer> <hr> -<a href="https://gumx.cc">gumx.cc</a> / +<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="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / <a href="https://wk.fo">wk.fo</a> </footer> + </body> </html> diff --git a/vpn.gumx.cc/meta b/vpn.gumx.cc/meta new file mode 100644 index 0000000..3c1ebbc --- /dev/null +++ b/vpn.gumx.cc/meta @@ -0,0 +1,2 @@ +TITLE="vpn.gumx.cc" +BREADCRUMB="vpn" diff --git a/wk.fo/body.html b/wk.fo/body.html new file mode 100644 index 0000000..40ac3f3 --- /dev/null +++ b/wk.fo/body.html @@ -0,0 +1,19 @@ +<p>File sharing, IRC bouncer, and VPN for friends. All services require an invitation.</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> +<table> +<tr><th>server</th><td>wk.fo:6697 (TLS)</td></tr> +<tr><th>type</th><td>Soju bouncer</td></tr> +</table> +<p>Use the credentials provided to you on invite. Works with any IRC client that supports SASL PLAIN.</p> +<h2>vpn</h2> +<table> +<tr><th>server</th><td>wk.fo:51820 (UDP)</td></tr> +<tr><th>type</th><td>WireGuard</td></tr> +</table> +<p>A config file is provided to you on invite. Import it into any WireGuard client.</p> +<h2>access</h2> +<p>Contact <a href="mailto:hi@gumx.cc">hi@gumx.cc</a>.</p> diff --git a/wk.fo/index.html b/wk.fo/index.html index c79d706..fbb74cb 100644 --- a/wk.fo/index.html +++ b/wk.fo/index.html @@ -2,6 +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+"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>wk.fo</title> <style> @@ -14,22 +15,25 @@ 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; } +ol { margin: 0.5em 0 0 0; } table { margin: auto; border-collapse: collapse; } th, td { border: 1px solid; padding: 0.3em 0.8em; } +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; } @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); } img { filter: invert(1); } } + </style> </head> <body> <header> -<h1>wk.fo</h1> +<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> @@ -51,16 +55,20 @@ a { color: inherit; } <p>A config file is provided to you on invite. Import it into any WireGuard client.</p> <h2>access</h2> <p>Contact <a href="mailto:hi@gumx.cc">hi@gumx.cc</a>.</p> + </main> <footer> <hr> -<a href="https://gumx.cc">gumx.cc</a> / +<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="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / <a href="https://wk.fo">wk.fo</a> </footer> + </body> </html> diff --git a/wk.fo/meta b/wk.fo/meta new file mode 100644 index 0000000..e068cc2 --- /dev/null +++ b/wk.fo/meta @@ -0,0 +1,2 @@ +TITLE="wk.fo" +BREADCRUMB="wk.fo" |
