Changeset 1e194e4 in Klonkt
- Timestamp:
- 08/23/2026 06:13:26 PM (2 weeks ago)
- Branches:
- main
- Children:
- 4cc4bcf
- Parents:
- 5e72413
- File:
-
- 1 edited
-
.beads/issues.jsonl (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
.beads/issues.jsonl
r5e72413 r1e194e4 19 19 {"_type":"issue","id":"prutfolio-src-txh","title":"Fediverse: rate-limiting on public AP endpoints","description":"Hardening follow-up. Specifics are intentionally kept in the maintainer's private notes, not in this public tracker. Priority medium/low; the critical fediverse issues (SSRF, stored-XSS, cross-actor delete) are already fixed.","status":"closed","priority":2,"issue_type":"task","owner":"roboburr@gmail.com","created_at":"2026-06-25T09:53:15Z","created_by":"roboburr","updated_at":"2026-06-25T20:45:53Z","closed_at":"2026-06-25T20:45:53Z","close_reason":"rate-limiting added to /ap/* (inbox + reads), per-IP with IPv6 /64 keying","dependency_count":0,"dependent_count":0,"comment_count":0} 20 20 {"_type":"issue","id":"prutfolio-src-5qp","title":"Premium anti-bypass hardening (demotiveren) — lagen 1+2+4","description":"Doel (Robin 2026-06-21): bypassen van de premium-gate DEMOTIVEREN, niet 100% voorkomen (kan niet bij open self-host-code). Economie = $10 \u003c moeite-om-te-kraken (Duo-logica) is de hoofdlever; prijs laag houden.\n\nAKKOORD — implementeren:\n- LAAG 1 (HEB JE AL): Ed25519-getekend entitlement-token, OFFLINE geverifieerd met publieke sleutel. Niemand kan een geldig token vervalsen (geen private key). Kost 0 calls bij gebruik -\u003e schaalt gratis. Evt. pubkey bundelen i.p.v. /pubkey-fetch = nul server-contact op verify-pad.\n- LAAG 2: verspreide/inline checks i.p.v. één premiumUnlocked()-chokepoint -\u003e één 'return true'-patch unlockt niet meer alles; kraker moet ~10 plekken vinden.\n- LAAG 4: integriteits-zelfcheck (hash van gating-bestanden) + permanente 'niet-gelicenseerd'-banner/zachte degradatie bij geforceerd premium zonder geldig token.\n- (bonus) obfuscatie/minify van de gate + token-verify in de GEPUBLICEERDE build.\n- NETWERK-LEVER (al voor Cirkels): cracked instance = verkeerde proto = ongeldige handtekeningen = doet niet mee aan het echte netwerk. Geldt alleen voor netwerk-features.\n\nGESCHRAPT:\n- LAAG 5 (server-afhankelijke feature / phone-home): schaalt mee met GEBRUIK, niet met koppelingen -\u003e bij 1M users continu verkeer + 24/7-beschikbaarheid verplicht + centraal storingspunt + breekt 'no phone-home'. Niet de moeite voor een $10 massa-product.\n\nWAARSCHUWING: niet overinvesteren in DRM -\u003e raakt eerder eerlijke self-hosters (false positives/support) dan krakers, en ondermijnt de gratis-\u0026-open funnel. Volgorde: na Patreon Fase 0 + GitHub-migratie (prutfolio-src-aaj). Context: memory project_klonkt_monetization.","status":"open","priority":2,"issue_type":"feature","owner":"roboburr@gmail.com","created_at":"2026-06-21T23:01:36Z","created_by":"roboburr","updated_at":"2026-06-21T23:01:36Z","dependency_count":0,"dependent_count":0,"comment_count":0} 21 {"_type":"issue","id":"prutfolio-src-da7","title":"C2S: keep the client's AS2 source on top-level posts, as replies already do","description":"A C2S client may send the authoring original beside the rendered markup:\nAS2 `source`, an object with `content` and `mediaType`. Klonkt keeps it on\none path and drops it on the other.\n\n## The asymmetry\n\n`src/services/ActivityPubService.js`, both in `ingestOutboxActivity`:\n\n // reply path, :3513 — source is PREFERRED\n const plain = (object.source \u0026\u0026 object.source.content)\n || HtmlSanitizerService.toPlainText(object.content || '');\n // ...passed to deliverReply as `text`, stored beside `html`\n\n // top-level path, c2sCreatePost :3740 — source is a FALLBACK, then sanitised\n const html = HtmlSanitizerService.sanitize(\n object.content || (object.source \u0026\u0026 object.source.content) || '');\n\nA reply keeps the client's plain text. A top-level post has nowhere to put\nit: `posts` has no plain column, `content` takes `html + mediaHtml`, and\neven `posts_fts` (:3798) is fed `toPlainText(html)` — the author's words\nround-tripped through markup rather than the words themselves.\n\nThe same client, posting the same text, is treated differently depending on\nwhether it happened to be answering someone.\n\n## What\n\n* `ensureColumn('posts', 'c2s_source', 'TEXT')` — the existing idiom\n (`src/config/database.js:1105`), same as `c2s_attachments` beside it.\n* In `c2sCreatePost`, store `object.source.content` when the client sent one.\n Nothing about how `content` is rendered needs to change.\n* Prefer it for `posts_fts` when present, so search indexes what was written.\n* Serve it back as `source` on the note representation, to the authenticated\n owner at least. Today `GET /ap/notes/:id` returns no `source` key at all,\n so a client cannot read back what it sent.\n\n## Why (Update needs it)\n\n`Update` is on the C2S roadmap, and an edit affordance needs the original.\nOffering \"edit\" over sanitised HTML means the author gets back markup they\ndid not write, and every edit round-trip degrades the text a little more.\nThe one moment the original is guaranteed available is the moment it\narrives, which is the moment it is currently discarded.\n\nAlso plain interop: Mastodon populates `source` for exactly this, and a\nclient that cannot retrieve what it posted cannot offer editing without\nkeeping its own shadow copy of everything — which is a second source of\ntruth about the same post.\n\n## Acceptance\n\n* A top-level `Create` carrying `source.content` is retrievable with that\n text intact; one without still behaves exactly as today.\n* Replies keep working as they already do — the point is to match them.\n* `posts_fts` indexes the source when there is one, the stripped HTML when\n there is not.\n* No migration: the column arrives via ensureColumn, and existing posts\n simply have NULL, which reads as \"no source was sent\".\n\n## Discovered while\n\nR9999 posted a note whose words were wrapped in `\u003ccode\u003e` with the plain\ntext sent alongside in `source`. Reading it back, `source` was absent —\nonly the HTML survived. Not lossy in that particular case, since `\u003ccode\u003e`\nstripped to text reads as intended, but nothing downstream could recover\nthe unmarked original, and the reply path in the same file would have kept\nit.\n","status":"open","priority":3,"issue_type":"feature","owner":"bart@bedrijfzondernaam.nl","created_at":"2026-08-23T18:10:06Z","created_by":"Bart","updated_at":"2026-08-23T18:10:06Z","dependency_count":0,"dependent_count":0,"comment_count":0} 22 {"_type":"issue","id":"prutfolio-src-086","title":"Following/followers: make count-only-public a per-site toggle","description":"Today `followers` and `following` are count-only for everyone except the\nauthenticated owner. That is a deliberate disclosure choice and the right\ndefault, but it is currently hard-coded, so a site owner who *wants* a public\nsocial graph cannot have one.\n\n## Current behaviour\n\n`src/routes/activitypub.js`, both handlers, identical in shape:\n\n const owner = auth \u0026\u0026 auth.site.slug === req.params.slug;\n if (owner) -\u003e full list (FEP-9876 enrich on request)\n otherwise -\u003e buildFollowers/buildFollowing(..., n, null, ...)\n\n`totalItems` is served truthfully; the members are withheld. An anonymous\nclient therefore sees a non-zero count and an empty `orderedItems`, which\nreads like a broken page unless you know the policy. It is not broken.\n\n## What\n\nA per-site setting — `public_social_graph`, or one column per collection if\nfollowers and following should be separable — that lets the owner opt into\nserving members to anonymous clients. Default stays as it is now: count only.\n\nNothing else about the handlers changes; the owner branch already produces\nexactly the payload the public branch would need.\n\n## Why\n\n* Mastodon exposes both collections publicly by default, so Klonkt currently\n looks like a dead end to anything walking the graph. For an artist site that\n wants to be found, that is a cost with no matching benefit.\n* prutfolio-src-7cz (Discovery, layer 1) proposes friend-of-a-friend over the\n Cirkel graph. Walking a social graph needs somebody to publish one. That\n layer is unbuildable across instances while every Klonkt is opaque.\n* The privacy-preserving default is the valuable part and should survive. What\n is missing is consent to the other choice, not a change of default.\n\n## Not this\n\n`gate_following` and the other `gate_*` columns are Guardianship ward gates —\nwhether a supervised account may *perform* an action. This is about what a\ncollection *discloses* to an unauthenticated reader. Two different axes; do\nnot fold them into one column.\n\n## Acceptance\n\n* Default unchanged: an existing site's collections stay count-only after\n upgrade, with no migration that silently widens disclosure.\n* With the setting on, an anonymous `GET` of both collections returns members\n and paginates the same way the owner view does.\n* With it off, the current behaviour is byte-identical to today.\n* The owner view keeps working via bearer token regardless of the setting.\n* FEP-9876 enrichment behaves the same in both branches.\n\n## Discovered while\n\nBuilding R9999, a C2S client, which read the collection anonymously and got\nan empty page. That was the client's own omission — sending the bearer token\nreturns all 43 — so this is not a bug report. The toggle is the feature that\nwas actually missing.\n","status":"open","priority":3,"issue_type":"feature","owner":"bart@bedrijfzondernaam.nl","created_at":"2026-08-23T05:58:22Z","created_by":"Bart","updated_at":"2026-08-23T05:58:22Z","dependencies":[{"issue_id":"prutfolio-src-086","depends_on_id":"prutfolio-src-7cz","type":"related","created_at":"2026-08-23T07:58:21Z","created_by":"Bart","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} 21 23 {"_type":"issue","id":"prutfolio-src-ls6","title":"postAudioFediOpen telt playlist-tracks van andere sites mee","description":"src/routes/posts.js regel ~299: de playlist-tak van postAudioFediOpen (die de begintoestand van het editor-vinkje bepaalt) joint playlist_tracks op audio_tracks zonder t.site_id = ?, net als het cross-tenant gat dat in prutfolio-src-cke is gedicht. Dit is een LEES-pad, geen schrijf-pad, dus geen poort die opengaat: het gevolg is een boolean die meetelt wat van een andere site is. Sinds cke is er wel een inconsistentie: bij een vreemde playlist kan het vinkje uit staan, de gebruiker vinkt aan, en er gebeurt stilzwijgend niets. Bewust buiten de scope van cke gehouden.","status":"open","priority":3,"issue_type":"task","owner":"roboburr@gmail.com","created_at":"2026-08-08T00:48:09Z","created_by":"Robin","updated_at":"2026-08-08T00:48:09Z","dependency_count":0,"dependent_count":0,"comment_count":0} 22 24 {"_type":"issue","id":"prutfolio-src-2t1","title":"Agenda: richer event types","description":"Extend shows/agenda with event types (show large/small, signing, workshop, generic) and fields like tickets/participation, location, theme, notes. Possibly external calendar integrations later.","status":"open","priority":3,"issue_type":"feature","owner":"roboburr@gmail.com","created_at":"2026-07-01T22:03:02Z","created_by":"roboburr","updated_at":"2026-07-01T22:03:02Z","dependency_count":0,"dependent_count":0,"comment_count":0}
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)