Files
2026-10-18 23:18:34 -05:00

66 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 13ft — OTM's fork
A self-hosted "read the article" fetcher (Python/Flask + gunicorn, ~200 lines
in `app/` (`portable.py` is the entrypoint)): it refetches a URL as Googlebot and serves the page
without the paywall/ad cruft. Forked 2026-10-14 from
[wasi-master/13ft](https://github.com/wasi-master/13ft) (the original project
was taken down once already — wasm-fyi → wasi-master — which is WHY we hold a
fork, not a dependency on GitHub/Docker Hub).
- **Remotes:** `gitea` = `tonym/13ft` on git.poweredbyotm.com (ours, push here);
`upstream` = GitHub wasi-master/13ft (pull only: `git fetch upstream && git
merge upstream/main`). Token for Gitea lives in `~/Projects/CLAUDE.md`.
- **Running today (since 2026-10-19, v0.4.0):** https://13ft.poweredbyotm.com on
**anvil** as a FIRST-PARTY APP built from this repo (`platform-13ft:latest`,
catalogue entry in otm-admin 0.148.0) behind **Sign in with OTM** — grant
`app:13ft` on /users. The old stock-image + Caddy basic-auth stack
(`platform/infra/13ft/setup-13ft-anvil.sh`, platform#91) is gone; the script is
marked SUPERSEDED. Deploy = push → `build_app 13ft` → `deploy_app 13ft`.
## Where this is going (the reason for the fork)
Make it a proper **OTM first-party app** per
`platform/docs/first-party-app-guide.md` (house rules are CI-enforced by
`platform/test/first-party-house-rules.test.ts`):
1. **Build from this repo** — catalogue entry in
`platform/apps/otm-admin/lib/first-party-apps.ts` (`id: "13ft"`, repo
`tonym/13ft`, image `platform-13ft:latest`, port 5000, `hostname:
13ft.poweredbyotm.com`), then `build_app 13ft` / `deploy_app 13ft` via the
platform MCP. **First: destroy or rename the hand-provisioned `13ft` stack**
(same slug + hostname + container name) or the two will fight over the
Caddy site and the container name.
2. **Sign in with OTM** replaces Caddy basic auth: `needsAuthSecret` →
`OTM_SSO_SECRET`; add `/api/auth/otm-sso` (verify the HS256 ticket for aud
`app:13ft` — port `pickup/src/sso.js`, or in Python: HMAC-SHA256 over
`header.payload`, base64url, check `exp`/`aud`/`jti`, single-use) and a
session cookie; gate every fetch route on it. Grant-only (NOT
`publicAccess`) — a stranger's OTM account must not get a free fetch proxy.
3. **tides** (`needsAnalytics`) — the beacon `<script defer
src="${TIDES_HOST}/t.js" data-site="${TIDES_SITE_ID}">` in the page
template. **Ideas** (`needsSuggestions`) — a lightbulb that files Gitea
issues (see `pickup/src/ideas.js` for the plain-HTTP shape). Version +
`/changelog` + `/api/health` reporting the version + footer "Powered by OTM".
4. Keep the Dockerfile's non-root user (`thirteener`) and gunicorn; add a
`HEALTHCHECK`.
**Status 2026-10-18 (v0.4.0): steps 1–4 are built.** `app/otm.py` holds the ticket
verifier + session cookie + health/changelog/footer/Ideas; `portable.py` mounts the
`before_request` gate (everything but `otm.PUBLIC_PATHS` needs a session; no secret =
503, never open) and the routes. Tests: `cd app && ../.venv/bin/python -m unittest`
(pure `test_otm.py` + Flask test-client `test_app.py`). The platform catalogue entry
landed in otm-admin 0.148.0. Deploy = stop the hand stack (`cd /srv/otm/clients/13ft
&& docker compose down`), then `build_app 13ft` + `deploy_app 13ft`; grant `app:13ft`
to each reader on /users. The in-memory jti guard assumes gunicorn's single worker.
## Dev
```sh
python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt
cd app && python portable.py # http://127.0.0.1:5000 (the app lives in app/)
docker build -t 13ft-dev . && docker run --rm -p 5000:5000 13ft-dev
```
Upstream README (below in this repo's `README.md`) covers the rest. Keep
upstream's MIT license file.