source: Klonkt/src/services/guardianship/notes.js@ 3f32994

main
Last change on this file since 3f32994 was fc40410, checked in by Robin Genis <roboburr@…>, 6 weeks ago

Externe embeds: thumbnail-only, en gated aan de serverkant

Fase 2 van shaer-277. Een note zonder fediverse-quote maar met een externe link
levert nu een embed-kaart op, via dezelfde resolver (oEmbed of een bekende
provider). Twee besluiten zitten erin verankerd:

THUMBNAIL-ONLY. Nooit de iframe van de aanbieder. Een willekeurig
derde-partij-frame in een kindveilige app is een gat dat je niet meer dicht
krijgt, dus de kaart draagt een afbeelding en een titel en niets uitvoerbaars.

GATED AAN DE SERVERKANT. Externe embeds zijn een gated feature: de wereld van
een ward buiten de fediverse is aan de guardians. Cruciaal is WAAR die gate zit:
bij het serialiseren, niet in de client. Een embed die de client alleen maar
verbergt, is wel degelijk al op het toestel afgeleverd. Staat de gate dicht, dan
gaat shaer:embed simpelweg niet mee.

De regel zelf (externalEmbedsAllowed) is puur en apart getest: null = auto, wat
uit staat voor een ward en aan voor ieder ander; een expliciet guardian-besluit
wint beide kanten op.

Changed files:
src/config/database.js

  • ap_timeline.embed_json en sites.external_embeds (NULL = auto)

src/services/guardianship/notes.js

  • externalEmbedsAllowed(setting, isWard), puur en geexporteerd

src/services/guardianship/index.js

  • doorgeexporteerd

src/services/ActivityPubService.js

  • resolveExternalEmbed + firstExternalUrl + timelineEmbed
  • inbound: geen quote maar wel een externe link -> embed resolven (out of band)

src/routes/activitypub.js

  • inbox-read past de gate toe en serveert shaer:embed alleen als die open staat

New file:
test/external-embeds.test.js

  • 5 tests: de auto-regel, het expliciete besluit, link-selectie (mentions en hashtags overslaan), en dat een kaart zonder url geen kaart is

remarks: 205 tests groen. Nog te doen: de clients laten shaer:embed renderen met
de bestaande QuoteCard, en een UI voor guardians om de gate te bedienen (hoort
bij shaer-3kp).

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

  • Property mode set to 100644
File size: 2.6 KB
RevLine 
[6b5d7da]1/**
2 * Guardianship (FEP-633c) — note properties.
3 *
4 * The shaer:helpRequest flag (spec 5.2.1): a ward's call for help, only ever
5 * on direct notes. Everyone who does not speak shaer can ignore it.
6 */
[af5b79b]7import { listGuardians } from './relations.js';
8
9/**
10 * shaer:hasGuardians (§2.2): an advisory OBJECT hint that the author is a ward,
11 * so a remote server can route interactions to the guardians WITHOUT fetching
12 * the actor. Stamped on every object a ward publishes; MUST be safely ignorable.
13 */
14export function hasGuardiansProps(slug) {
15 try { return (slug && listGuardians(slug).length) ? { 'shaer:hasGuardians': true } : {}; }
16 catch { return {}; }
17}
18
[fc40410]19/**
20 * May EXTERNAL (non-fediverse) embeds be shown to this account?
21 *
22 * A gated feature in the FEP-633c sense: a ward's world outside the fediverse
23 * is the guardians' call. `setting` is `sites.external_embeds`:
24 * null/undefined → auto: off for a ward, on for anyone else
25 * 0 → off, 1 → on (the guardians decided)
26 *
27 * Pure, so the rule is testable on its own. The gate is applied SERVER-side:
28 * a blocked embed is never serialised into the feed, because an embed that the
29 * client merely hides has still been delivered.
30 */
31export function externalEmbedsAllowed(setting, isWard) {
32 if (setting === 0 || setting === 1) return setting === 1;
33 return !isWard;
34}
35
[af5b79b]36/** True when an incoming object carries the ward hint (§2.2). Register-only for
37 * now; acted on later at reddings-boei / escalation routing. */
38export function objectHasGuardians(o) {
39 return !!o && (o['shaer:hasGuardians'] === true || o.hasGuardians === true);
40}
[6b5d7da]41
42/** Extra JSON-LD properties for an outgoing note built from an ap_outbox row. */
43export function helpRequestProps(post) {
44 return (post && post.visibility === 'direct' && post.help_request)
45 ? { 'shaer:helpRequest': true }
46 : {};
47}
48
49/** True when an incoming (C2S or S2S) note object carries the flag. */
50export function isHelpRequest(object) {
51 return !!object && (object['shaer:helpRequest'] === true || object.helpRequest === true);
52}
53
[e62f65d]54/** shaer:wave: a gentle "thinking of you" from a guardian to its ward. A
55 * private nudge, never a feed post; non-shaer clients see a plain DM. */
56export function waveProps(post) {
57 return (post && post.visibility === 'direct' && post.wave)
58 ? { 'shaer:wave': true }
59 : {};
60}
61
62/** True when an incoming note is a wave. */
63export function isWave(object) {
64 return !!object && (object['shaer:wave'] === true || object.wave === true);
65}
66
[fc40410]67export default { helpRequestProps, isHelpRequest, waveProps, isWave, hasGuardiansProps, objectHasGuardians, externalEmbedsAllowed };
Note: See TracBrowser for help on using the repository browser.