diff --git a/lith/Caddyfile b/lith/Caddyfile index 036b3dc388..43c602f67f 100644 --- a/lith/Caddyfile +++ b/lith/Caddyfile @@ -1313,3 +1313,41 @@ gym.anthonyzollo.com { redir https://{host}{uri} 301 } } + +# --- mime.ac --- +# DNS-only on Cloudflare; serve MIME at the apex with its own public TLS. +mime.ac { + tls { + issuer acme { + dir https://acme-v02.api.letsencrypt.org/directory + } + protocols tls1.2 tls1.3 + } + encode zstd gzip + handle / { + root * /opt/ac/system/public/mime + header Cache-Control "no-cache" + file_server + } + handle /mime { + redir / 302 + } + handle /mime/ { + redir / 302 + } + handle /prompt { + redir https://aesthetic.computer/prompt 302 + } + handle { + import lith_proxy + } +} + +www.mime.ac { + tls { + issuer acme { + dir https://acme-v02.api.letsencrypt.org/directory + } + } + redir https://mime.ac{uri} 308 +} diff --git a/system/backend/MIME.md b/system/backend/MIME.md index 1384bbc0d2..6fe56dc820 100644 --- a/system/backend/MIME.md +++ b/system/backend/MIME.md @@ -1,6 +1,7 @@ # Mime -Discussion on AC media. The frontend is `/mime/`; the API is `/api/mime`. +Discussion on AC media. The frontend is `/mime/` and the `https://mime.ac/` +apex; the API is `/api/mime`. `www.mime.ac` redirects to the apex. The main feed snaps to one viewport per media item without cropping, following the tape viewer (`disks/tv.mjs`). It loads 12 posts at a time and preserves the current item across thread visits and orientation changes. Videos play muted @@ -70,3 +71,19 @@ MIME_TEST_MONGO_URI=mongodb://127.0.0.1:27017 node --test system/backend/tests/m Tests cover automatic discovery without writes, attribution, concurrent first replies, attachment rejection, verified authorship, source visibility, storage URLs, legacy uploads, pagination, and identity across tape conversion. + +## Auth0 domains + +MIME uses the existing AC SPA client (`LVdZaMbyXctkGfZDnpzDATB5nR0ZhmMt`) +through `hi.aesthetic.computer`. Keep all existing application URL entries; +append these exact values in the Auth0 application settings: + +- Allowed Callback URLs: `https://mime.ac/`, `https://aesthetic.computer/mime/` +- Allowed Logout URLs: `https://mime.ac/`, `https://aesthetic.computer/mime/` +- Allowed Web Origins and Allowed Origins (CORS): `https://mime.ac` + +The SDK handles authorization-code callbacks and validates OAuth state. The +return hash and an in-progress comment survive the login redirect. Account +handles are still resolved by the API from the verified access token. Browser +storage is origin-scoped, so MIME offers sign-in on the new domain; it does +not copy tokens between domains. The wordmark returns to AC's prompt. diff --git a/system/public/mime/index.html b/system/public/mime/index.html index 00037301e8..791d35b048 100644 --- a/system/public/mime/index.html +++ b/system/public/mime/index.html @@ -46,7 +46,11 @@ a:hover { color: var(--ink); } :focus-visible { outline: 2px solid var(--link); outline-offset: 3px; } ::selection { background: var(--ink); color: var(--paper); } - header { text-align: left; padding: 1em 1em 0.4em; } + header { display: flex; align-items: center; justify-content: space-between; gap: 1em; text-align: left; padding: 1em 1em 0.4em; } + .account { display: flex; align-items: center; justify-content: flex-end; gap: 0.5em; flex-wrap: wrap; font-size: 0.85em; } + .account button { font: inherit; color: var(--link); background: var(--paper); border: 1px solid var(--card-edge); border-radius: 4px; min-height: 36px; padding: 0.3em 0.6em; cursor: pointer; } + .account [role="status"] { max-width: 24ch; color: var(--accent); } + .account [hidden] { display: none; } header h1 { margin: 0; color: var(--ink); line-height: 1; } .wordmark { display: inline-flex; align-items: center; min-height: 44px; color: inherit; text-decoration: none; } .wordmark svg { display: block; width: 108px; height: 33px; overflow: visible; } @@ -121,7 +125,8 @@ border: 1px dashed var(--card-edge); padding: 0.8em 1.2em; } body.feed { padding: 0; overflow: hidden; } - body.feed header { position: fixed; top: 0; left: 0; z-index: 2; padding-top: max(0.6em, env(safe-area-inset-top)); } + body.feed header { width: 100%; pointer-events: none; position: fixed; top: 0; left: 0; z-index: 2; padding-top: max(0.6em, env(safe-area-inset-top)); } + body.feed header a, body.feed .account { pointer-events: auto; } body.feed header a { background: var(--paper); } body.feed main { max-width: none; padding: 0; height: 100vh; height: 100dvh; @@ -148,7 +153,7 @@ .feed-post > .meta { margin: 0 0.75rem; } .feed-post > .body { margin: 0 0.75rem; max-height: 15vh; overflow: auto; } .feed-post > .discussion { align-self: center; flex-shrink: 0; margin: 0; } - .feed-more { position: absolute; top: max(0.6em, env(safe-area-inset-top)); right: 0.75rem; display: flex; align-items: center; gap: 0.5em; max-width: calc(100% - 9rem); } + .feed-more { position: absolute; top: max(3.75rem, calc(env(safe-area-inset-top) + 3rem)); right: 0.75rem; display: flex; align-items: center; gap: 0.5em; max-width: calc(100% - 9rem); } .feed-more button { padding: 0.3em 0.6em; } .feed-more [role="status"] { color: var(--dim); font-size: 0.85em; } body.feed main > p { margin: 4rem 0.75rem; } @@ -166,7 +171,7 @@