Changeset 3b43e4c in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 08/08/2026 02:33:28 AM (5 weeks ago)
- Branches:
- main
- Children:
- 06bae1e
- Parents:
- 50e80ac
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r50e80ac r3b43e4c 2919 2919 case 'Create': { 2920 2920 if (!object || typeof object !== 'object') return { status: 400, error: 'missing_object' }; 2921 // Innamepoorten (shaer-ahy.1, 8-8): wat de ward niet mag versturen 2922 // wordt HIER geweigerd, niet in de app verstopt -- een knop die de 2923 // client alleen verbergt is geen poort. De reddingsboei gaat ALTIJD 2924 // voor: een hulpvraag aan de guardians mag door elke dichte deur heen, 2925 // anders sluit een messages-poort precies het kanaal af dat het kind 2926 // veilig houdt. 2927 { 2928 const isWard = (() => { try { return Guardianship.listGuardians(site.slug).length > 0; } catch { return false; } })(); 2929 const isHelp = object['shaer:helpRequest'] === true || object.helpRequest === true; 2930 const direct = c2sVisibility(object) === 'direct'; 2931 if (!isHelp) { 2932 if (direct && !Guardianship.wardGateAllowed(site.gate_messages, isWard)) { 2933 return { status: 403, error: 'gated_messages' }; 2934 } 2935 if (!direct && !object.inReplyTo && !Guardianship.wardGateAllowed(site.gate_compose, isWard)) { 2936 return { status: 403, error: 'gated_compose' }; 2937 } 2938 } 2939 } 2921 2940 // Client sends `source` (plain/markdown) + `content` (HTML). deliverReply 2922 2941 // re-escapes, so it needs plain text; a top-level post keeps sanitized HTML. … … 3385 3404 * De directe antwoorden op één note, genormaliseerd voor de C2S-lezer. 3386 3405 * 3387 * `circle` is de wachtwoord-vraag van shaer-vw4 in zijn veiligste stand: is de3388 * lezer een ward, dan komen alleen antwoorden door van accounts die de3389 * guardians al kennen (gevolgd of volgend). Wat er buiten valt wordt GETELD en3390 * als aantal teruggegeven, nooit stil weggelaten -- maar het besluit of dat3391 * aantal getoond wordt, en of dit de blijvende regel is, ligt bij Bart en3392 * Robin (shaer-vw4). Geblokkeerde actors zijn een andere categorie: die3393 * verdwijnen zonder telling, een blokkade is onzichtbaar.3406 * ALLEEN ophalen en normaliseren; de poorten zitten in de route. De 3407 * kringfilter (de dichte stand van shaer:externalThreads) woont in 3408 * filterThreadToCircle en de beeld/muziek/emoji-poorten in 3409 * gateAttachments/stripEmojiTags -- per verzoek, buiten deze cache om, want de 3410 * stand van een poort mag hier niet twee minuten bevriezen. Geblokkeerde 3411 * actors zijn een andere categorie en verdwijnen WEL hier, zonder telling: 3412 * een blokkade is onzichtbaar, ook als getal. 3394 3413 */ 3395 export async function getThread(slug, objectUri , { isWard = false } = {}) {3414 export async function getThread(slug, objectUri) { 3396 3415 const key = `${slug}|${objectUri}`; 3397 3416 const hit = threadViewCache.get(key); … … 3434 3453 })); 3435 3454 3436 const circle = isWard ? (() => {3437 const s = new Set();3438 try { for (const r of db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted'").all(slug)) s.add(r.actor_uri); } catch { /* geen tabel */ }3439 try { for (const r of db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ?').all(slug)) s.add(r.actor_uri); } catch { /* geen tabel */ }3440 return s;3441 })() : null;3442 3443 let hidden = 0;3444 3455 const kept = []; 3445 3456 for (const o of objs) { … … 3447 3458 const actorUri = actorUriOf(o.attributedTo); 3448 3459 if (!actorUri || isBlockedAny(actorUri)) continue; // een blokkade telt niet mee 3449 if (circle && !circle.has(actorUri)) { hidden += 1; continue; }3450 3460 kept.push({ o, actorUri }); 3451 3461 } … … 3489 3499 })).sort((a, b) => String(a.published || '').localeCompare(String(b.published || ''))); 3490 3500 3491 const out = { notes, hidden,found: !!note };3501 const out = { notes, found: !!note }; 3492 3502 threadViewCache.set(key, { at: Date.now(), out }); 3493 3503 if (threadViewCache.size > THREAD_VIEW_CACHE_MAX) { … … 3495 3505 if (oldest) threadViewCache.delete(oldest[0]); 3496 3506 } 3507 return out; 3508 } 3509 3510 /** 3511 * De thread gefilterd op de kring die de guardians al kennen (gevolgd of 3512 * volgend) -- de dichte stand van shaer:externalThreads. PER VERZOEK, buiten de 3513 * threadcache om: een poort die de guardians net dichtzetten mag niet nog twee 3514 * minuten open nawerken uit een cache. Wat er buiten valt wordt GETELD, nooit 3515 * stil weggelaten. 3516 */ 3517 export function filterThreadToCircle(slug, notes) { 3518 const circle = new Set(); 3519 try { for (const r of db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted'").all(slug)) circle.add(r.actor_uri); } catch { /* geen tabel */ } 3520 try { for (const r of db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ?').all(slug)) circle.add(r.actor_uri); } catch { /* geen tabel */ } 3521 const kept = [], out = { hidden: 0 }; 3522 for (const n of notes) { 3523 if (circle.has(n.attributedTo)) kept.push(n); 3524 else out.hidden += 1; 3525 } 3526 out.notes = kept; 3497 3527 return out; 3498 3528 } … … 3924 3954 return emojis.length ? JSON.stringify(emojis) : null; 3925 3955 } 3956 // ── Gate-filters voor de C2S-serialisatie (shaer-ahy.1, 8-8) ────── 3957 // 3958 // Dezelfde regel als bij de embeds: de poort zit bij de AFLEVERING. Een 3959 // bijlage die de client alleen verbergt is wel degelijk geleverd, dus wat 3960 // dicht is wordt hier nooit geserialiseerd. Puur, zodat de regels los van de 3961 // routes te toetsen zijn. 3962 3963 /** Bijlagen door de beeld- en muziekpoort. Leeg wordt undefined, zoals de 3964 * serialisatie dat overal doet. */ 3965 export function gateAttachments(atts, { images = true, audio = true } = {}) { 3966 if (!Array.isArray(atts)) return atts; 3967 const out = atts.filter((a) => { 3968 const mt = String((a && a.mediaType) || ''); 3969 if (!images && mt.startsWith('image/')) return false; 3970 if (!audio && (mt.startsWith('audio/') || (a && a.type === 'Audio'))) return false; 3971 return true; 3972 }); 3973 return out.length ? out : undefined; 3974 } 3975 3976 /** Tag-array zonder de FEP-9098 Emoji-tags, voor een dichte emoji-poort. De 3977 * :shortcode: blijft als tekst staan -- dat is eerlijk: er STAAT iets, het 3978 * wordt alleen niet als plaatje van een vreemde server gerenderd. */ 3979 export function stripEmojiTags(tags) { 3980 if (!Array.isArray(tags)) return tags; 3981 const out = tags.filter((t) => (Array.isArray(t && t.type) ? t.type[0] : (t && t.type)) !== 'Emoji'); 3982 return out.length ? out : undefined; 3983 } 3984 3926 3985 export function timelineEmojis(emojiJson) { 3927 3986 try { const arr = emojiJson ? JSON.parse(emojiJson) : null; return (Array.isArray(arr) && arr.length) ? arr : undefined; } … … 4976 5035 if (!base || !site || !site.slug) return { error: 'config' }; 4977 5036 try { 4978 const guardians = Guardianship.listGuardians(site.slug); 4979 if (guardians.length) { 4980 console.warn('[AP] move refused: guarded account (shaer-tge):', site.slug, '→', String(targetRaw || '')); 5037 // Was een harde weigering voor elk bewaakt account (shaer-tge); sinds 8-8 5038 // een GATE met dezelfde standaard: de automatiek weigert voor een ward, 5039 // maar de guardians kunnen shaer:accountMove expliciet openzetten -- en 5040 // expliciet dichtzetten geldt dan ook voor een account dat net geen ward 5041 // meer is, net als bij de embeds. 5042 const isWard = Guardianship.listGuardians(site.slug).length > 0; 5043 if (!Guardianship.wardGateAllowed(site.gate_account_move, isWard)) { 5044 console.warn('[AP] move refused: gated (shaer-tge):', site.slug, '→', String(targetRaw || '')); 4981 5045 return { error: 'guarded_account' }; 4982 5046 } … … 5700 5764 getNotifications, listBlocks, isBlockedAny, blockTarget, unblock, 5701 5765 deliverWithRetry, enqueueDelivery, processDeliveryQueue, startDeliveryWorker, 5702 getReplyUris, getThread, markNotificationsSeen, countUnseenNotifications, hasPlayableAudio,5766 getReplyUris, getThread, filterThreadToCircle, gateAttachments, stripEmojiTags, markNotificationsSeen, countUnseenNotifications, hasPlayableAudio, 5703 5767 linkifyBody, bakePostContent, bakePostContentWithMentions, listFollowers, removeFollower, listConnections, 5704 5768 noteVisibility, belongsInTimeline, playerUrlFor, isRejectedObject, rejectInteraction, interactionReportTarget,
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)