Changeset 4407c67 in Klonkt
- Timestamp:
- 07/19/2026 03:53:49 PM (7 weeks ago)
- Branches:
- main
- Children:
- 2d66d66
- Parents:
- bf72108
- git-author:
- Robin <roboburr@…> (07/19/2026 03:53:33 PM)
- git-committer:
- Robin <roboburr@…> (07/19/2026 03:53:49 PM)
- Files:
-
- 1 added
- 5 edited
-
CHANGELOG.de.md (modified) (1 diff)
-
CHANGELOG.md (modified) (1 diff)
-
CHANGELOG.nl.md (modified) (1 diff)
-
src/routes/activitypub.js (modified) (1 diff)
-
src/services/ActivityPubService.js (modified) (4 diffs)
-
test/c2s-collections.test.js (added)
Legend:
- Unmodified
- Added
- Removed
-
CHANGELOG.de.md
rbf72108 r4407c67 7 7 8 8 ### Hinzugefügt 9 - **Der Kontoinhaber kann seine eigenen Follower und Gefolgten über C2S lesen.** 10 Die `followers`- und `following`-Sammlungen bleiben für die Öffentlichkeit 11 count-only (Datenschutz), aber eine Anfrage mit einem auf diese Seite 12 begrenzten C2S-Bearer liefert jetzt die echten Actor-URIs, damit eine App 13 (Shaer) eine Freundesliste bauen kann. Für anonyme Aufrufer ändert sich 14 nichts. 9 15 - **App-Zugriff über OAuth 2.0 (ActivityPub Client-to-Server, Phase 1).** Klonkt 10 16 spricht jetzt den standardmäßigen AP-C2S-Auth-Handshake, damit native und -
CHANGELOG.md
rbf72108 r4407c67 7 7 8 8 ### Added 9 - **The account owner can read their own followers and following over C2S.** The 10 `followers` and `following` collections stay count-only for the public 11 (privacy), but a request carrying a C2S bearer scoped to that site now returns 12 the real actor URIs, so an app (Shaer) can build a friends list. Anonymous 13 callers are unchanged. 9 14 - **App access via OAuth 2.0 (ActivityPub Client-to-Server, phase 1).** Klonkt 10 15 now speaks the standard AP C2S auth handshake so native and web clients (the -
CHANGELOG.nl.md
rbf72108 r4407c67 7 7 8 8 ### Toegevoegd 9 - **De account-eigenaar kan zijn eigen followers en following lezen via C2S.** De 10 `followers`- en `following`-collecties blijven count-only voor het publiek 11 (privacy), maar een verzoek met een C2S-bearer die op die site scoped is geeft 12 nu de echte actor-URI's terug, zodat een app (Shaer) een vriendenlijst kan 13 bouwen. Voor anonieme bezoekers verandert er niets. 9 14 - **App-toegang via OAuth 2.0 (ActivityPub Client-to-Server, fase 1).** Klonkt 10 15 spreekt nu de standaard AP C2S-authenticatie, zodat native en web-apps (de -
src/routes/activitypub.js
rbf72108 r4407c67 84 84 }); 85 85 86 // ── Followers (count only) ──────────────────────────────────────── 86 // ── Followers (count-only public, full for the owner) ───────────── 87 // A C2S bearer scoped to this site (the account owner) gets the real actor 88 // URIs so their own client can build a friends list; everyone else gets the 89 // count only (privacy). 87 90 router.get('/ap/users/:slug/followers', (req, res) => { 88 const site = publicSite(req.params.slug); 89 if (!site) return res.status(404).end(); 91 const auth = OAuth.verifyBearer(req.headers.authorization); 92 const owner = auth && auth.site.slug === req.params.slug; 93 const site = owner ? auth.site : publicSite(req.params.slug); 94 if (!site) return res.status(404).end(); 95 if (owner) { 96 const items = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ? ORDER BY created_at').all(site.slug).map((r) => r.actor_uri); 97 return AP.sendAP(res, AP.buildFollowers(baseUrl(req), site, items.length, items)); 98 } 90 99 const n = db.prepare('SELECT COUNT(*) n FROM ap_followers WHERE slug = ?').get(site.slug).n; 91 100 AP.sendAP(res, AP.buildFollowers(baseUrl(req), site, n)); 92 101 }); 93 102 94 // ── Following (count only) ────────────────────────────────────────103 // ── Following (count-only public, full for the owner) ───────────── 95 104 router.get('/ap/users/:slug/following', (req, res) => { 96 const site = publicSite(req.params.slug); 97 if (!site) return res.status(404).end(); 105 const auth = OAuth.verifyBearer(req.headers.authorization); 106 const owner = auth && auth.site.slug === req.params.slug; 107 const site = owner ? auth.site : publicSite(req.params.slug); 108 if (!site) return res.status(404).end(); 109 if (owner) { 110 let items = []; 111 try { items = db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted' ORDER BY created_at").all(site.slug).map((r) => r.actor_uri); } catch { /* table may not exist */ } 112 return AP.sendAP(res, AP.buildFollowing(baseUrl(req), site, items.length, items)); 113 } 98 114 let n = 0; 99 115 try { n = db.prepare("SELECT COUNT(*) n FROM ap_following WHERE slug = ? AND status = 'accepted'").get(site.slug).n; } catch { /* table may not exist */ } -
src/services/ActivityPubService.js
rbf72108 r4407c67 542 542 } 543 543 544 export function buildFollowers(base, site, count) { 544 // Public callers get a count-only collection (privacy). The authenticated 545 // account owner (a C2S bearer scoped to this site) gets the real actor URIs via 546 // `items`, so their own client can build a friends list. 547 export function buildFollowers(base, site, count, items = null) { 545 548 const id = `${actorId(base, site.slug)}/followers`; 546 549 return { … … 548 551 id, 549 552 type: 'OrderedCollection', 550 totalItems: count || 0,551 orderedItems: [], // hidden for privacy; count only553 totalItems: items ? items.length : (count || 0), 554 orderedItems: items || [], // count-only for the public; full for the owner 552 555 }; 553 556 } … … 555 558 // The accounts this site follows — count only, mirroring buildFollowers. The spec lists 556 559 // `following` as a standard actor property; Hubzilla/Friendica + crawlers expect it. 557 export function buildFollowing(base, site, count ) {560 export function buildFollowing(base, site, count, items = null) { 558 561 const id = `${actorId(base, site.slug)}/following`; 559 562 return { … … 561 564 id, 562 565 type: 'OrderedCollection', 563 totalItems: count || 0,564 orderedItems: [], // count only566 totalItems: items ? items.length : (count || 0), 567 orderedItems: items || [], // count-only for the public; full for the owner 565 568 }; 566 569 }
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)