Changeset cec72bc in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 08/06/2026 11:18:34 AM (5 weeks ago)
- Branches:
- main
- Children:
- f4f0a6d
- Parents:
- 434ba41
- git-author:
- Robin <roboburr@…> (08/06/2026 11:18:33 AM)
- git-committer:
- Claude (agent) <aiclaude@…> (08/06/2026 11:18:34 AM)
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r434ba41 rcec72bc 1687 1687 * geclaimde actor, dan blijft het een weigering. Geen twijfelgeval opslaan. 1688 1688 */ 1689 /** Kennen we deze note? Een eigen post, een eigen outbox-antwoord, een 1690 * gecachete post in de tijdlijn, of een reactie die al in een thread van ons 1691 * staat. Alle vier zijn een geldige reden dat iemand ons een antwoord daarop 1692 * doorstuurt; iets anders is dat niet. */ 1693 function knownNoteUri(uri) { 1694 if (!uri || typeof uri !== 'string') return false; 1695 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 1696 try { 1697 if (base && uri.startsWith(`${base}/ap/notes/`)) { 1698 const seg = decodeURIComponent(uri.slice(`${base}/ap/notes/`.length).split(/[?#]/)[0]); 1699 if (db.prepare('SELECT 1 FROM ap_outbox WHERE id = ?').get(seg)) return true; 1700 if (db.prepare('SELECT 1 FROM posts WHERE id = ?').get(seg)) return true; 1701 } 1702 if (db.prepare('SELECT 1 FROM ap_timeline WHERE id = ? LIMIT 1').get(uri)) return true; 1703 if (db.prepare('SELECT 1 FROM ap_interactions WHERE object_uri = ? LIMIT 1').get(uri)) return true; 1704 } catch { /* bij twijfel niet ophalen */ } 1705 return false; 1706 } 1707 1708 // Mislukte dereferences kort onthouden. Mastodon herhaalt een bezorging 1709 // dagenlang; zonder dit doet elke herhaling de fetch opnieuw, ook als die de 1710 // vorige twintig keer niets opleverde. Dempt meteen de scherpte van misbruik. 1711 const _derefMiss = new Map(); 1712 const DEREF_MISS_MS = 30 * 60 * 1000; 1713 function derefRecentlyFailed(uri) { 1714 const t = _derefMiss.get(uri); 1715 if (t === undefined) return false; 1716 if (Date.now() - t > DEREF_MISS_MS) { _derefMiss.delete(uri); return false; } 1717 return true; 1718 } 1719 function noteDerefFailure(uri) { 1720 if (_derefMiss.size > 500) { // simpele begrenzing: oudste helft eruit 1721 const oud = [..._derefMiss.entries()].sort((a, b) => a[1] - b[1]).slice(0, 250); 1722 for (const [k] of oud) _derefMiss.delete(k); 1723 } 1724 _derefMiss.set(uri, Date.now()); 1725 } 1726 1689 1727 async function dereferenceForwarded(act, claimedActor, type, slugParam) { 1690 1728 if (type !== 'Create' && type !== 'Update') return null; … … 1695 1733 if (new URL(objId).host !== new URL(claimedActor).host) return null; // ankereis 1696 1734 } catch { return null; } 1697 // Ondertekend als de ontvangende site wanneer we die kennen; anders anoniem, 1698 // wat voor een publieke note volstaat. Beide gaan door safeFetch. 1699 const fetched = await signedGetJson(slugParam, objId).catch(() => null); 1700 if (!fetched || fetched.id !== objId) return null; // ook: geen omleiding naar iets anders 1701 const attributed = typeof fetched.attributedTo === 'string' 1735 // Alleen dereferencen als het object beweert een antwoord te zijn op iets van 1736 // ONS (shaer-drf). Zonder die eis zijn claimedActor en object.id allebei door 1737 // de aanvaller gekozen en eist het host-anker alleen dat ze aan elkaar gelijk 1738 // zijn -- dan kan iedereen met een werkende actor ons naar elke URL sturen. 1739 // Doorsturen bestaat juist omdát wij in de thread zitten, dus deze eis kost 1740 // niets aan legitiem verkeer waarvan we de ouder kennen. 1741 const parent = typeof o === 'object' && o 1742 ? (typeof o.inReplyTo === 'string' ? o.inReplyTo : (o.inReplyTo && o.inReplyTo.id)) 1743 : null; 1744 if (!knownNoteUri(parent)) { 1745 console.log('[AP] inbox forwarded, skipped (unknown inReplyTo):', claimedActor, parent || '(none)'); 1746 return null; 1747 } 1748 if (derefRecentlyFailed(objId)) return null; 1749 // Onbetekend eerst; tekenen alleen als terugval. Anders kan een ander ons een 1750 // ONDERTEKEND verzoek naar een adres van zijn keuze laten sturen -- dezelfde 1751 // reden als bij fetchActor sinds efe5633. 1752 let fetched = await apGetJson(objId).catch(() => null); 1753 if ((!fetched || fetched.id !== objId) && slugParam) { 1754 fetched = await signedGetJson(slugParam, objId).catch(() => null); 1755 } 1756 const attributed = fetched && (typeof fetched.attributedTo === 'string' 1702 1757 ? fetched.attributedTo 1703 : (fetched.attributedTo && fetched.attributedTo.id); 1704 if (attributed !== claimedActor) return null; 1758 : (fetched.attributedTo && fetched.attributedTo.id)); 1759 if (!fetched || fetched.id !== objId || attributed !== claimedActor) { 1760 noteDerefFailure(objId); 1761 return null; 1762 } 1705 1763 return fetched; 1706 1764 }
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)