Changeset e6c6e6f in Klonkt for src/services
- Timestamp:
- 07/20/2026 10:27:19 PM (7 weeks ago)
- Branches:
- main
- Children:
- 155c24e
- Parents:
- 024f4f8
- git-author:
- Robin <roboburr@…> (07/20/2026 10:27:18 PM)
- git-committer:
- Robin <roboburr@…> (07/20/2026 10:27:19 PM)
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r024f4f8 re6c6e6f 1845 1845 .filter((u) => /^https?:\/\//i.test(u) && !/\/followers\/?$/.test(u) && u !== PUBLIC); 1846 1846 if (!recipients.length) return { status: 400, error: 'no_recipients' }; 1847 const r = await deliverDirectNote(site, { recipients, text: plain, language: object.language || null, inReplyTo: typeof object.inReplyTo === 'string' ? object.inReplyTo : null }); 1847 // AS2 attachments (e.g. the help-buoy capture, uploaded via 1848 // uploadMedia): normalize our own absolute /media/ URLs to relative 1849 // so the deliverReply-style validation applies unchanged. 1850 const atts = (Array.isArray(object.attachment) ? object.attachment : []) 1851 .map((a) => a && typeof a === 'object' ? { 1852 url: String(a.url || '').replace(new RegExp('^' + base.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')), ''), 1853 mediaType: String(a.mediaType || ''), 1854 name: String(a.name || '').slice(0, 120), 1855 } : null) 1856 .filter(Boolean); 1857 const r = await deliverDirectNote(site, { recipients, text: plain, language: object.language || null, inReplyTo: typeof object.inReplyTo === 'string' ? object.inReplyTo : null, attachments: atts }); 1848 1858 if (!r || !r.id) return { status: 502, error: 'direct_failed' }; 1849 1859 return { status: 201, id: r.id, url: `${base}/ap/notes/${r.id}` }; … … 1961 1971 // The same S2S leg a Mastodon DM takes, so a guardian on any instance 1962 1972 // receives it as a private mention (the ward call-for-help path). 1963 export async function deliverDirectNote(site, { recipients, text, language, inReplyTo }) {1973 export async function deliverDirectNote(site, { recipients, text, language, inReplyTo, attachments }) { 1964 1974 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 1965 1975 const list = [...new Set((recipients || []).filter((u) => /^https?:\/\//i.test(String(u || ''))))].slice(0, 8); … … 1981 1991 const content = `<p>${mention}${linkUrls(linkHashtags(base, body))}</p>`; 1982 1992 const lang = /^[a-z]{2,3}(-[A-Za-z0-9-]+)?$/.test(String(language || '')) ? language : null; 1993 // Attachments: same rules as deliverReply (own /media/ uploads only, 1994 // image/audio/video, max 4) — the help-buoy capture rides this. 1995 const media = (Array.isArray(attachments) ? attachments : []) 1996 .filter((a) => a && typeof a.url === 'string' && /^\/media\/[\w./-]+$/.test(a.url) 1997 && /^(image|audio|video)\//.test(String(a.mediaType || ''))) 1998 .slice(0, 4) 1999 .map((a) => ({ url: a.url, mediaType: String(a.mediaType), name: String(a.name || '').slice(0, 120) })); 1983 2000 const id = crypto.randomUUID(); 1984 2001 db.prepare(`INSERT INTO ap_outbox (id, site_slug, post_id, post_slug, in_reply_to, to_actor, to_handle, content, language, attachments, visibility, to_actors, created_at) 1985 2002 VALUES (?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)`) 1986 .run(id, site.slug, '', null, inReplyTo || null, resolved[0].uri, resolved[0].handle, content, lang, null, 'direct', JSON.stringify(resolved.map((r) => r.uri)));2003 .run(id, site.slug, '', null, inReplyTo || null, resolved[0].uri, resolved[0].handle, content, lang, media.length ? JSON.stringify(media) : null, 'direct', JSON.stringify(resolved.map((r) => r.uri))); 1987 2004 const row = iStmts().getO.get(id); 1988 2005 const note = buildReplyNote(base, site, row);
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)