feat: support remote "Video" type objects in note assertion, #13120

- handle array attributedTo (plus per-object actor assertion instead of batched)
- explicit "Video" type handling to automatically save URL as post attachment
- handle array url property
This commit is contained in:
Julian Lam
2025-02-26 13:55:39 -05:00
parent bad0a4c2d2
commit 95f2c4edb5
3 changed files with 44 additions and 5 deletions

View File

@@ -37,7 +37,7 @@ ActivityPub._constants = Object.freeze({
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
], ],
acceptedPostTypes: [ acceptedPostTypes: [
'Note', 'Page', 'Article', 'Question', 'Note', 'Page', 'Article', 'Question', 'Video',
], ],
acceptableActorTypes: new Set(['Application', 'Group', 'Organization', 'Person', 'Service']), acceptableActorTypes: new Set(['Application', 'Group', 'Organization', 'Person', 'Service']),
requiredActorProps: ['inbox', 'outbox'], requiredActorProps: ['inbox', 'outbox'],

View File

@@ -153,9 +153,6 @@ Mocks.post = async (objects) => {
objects = [objects]; objects = [objects];
} }
const actorIds = new Set(objects.map(object => object.attributedTo).filter(Boolean));
await activitypub.actors.assert(Array.from(actorIds));
const posts = await Promise.all(objects.map(async (object) => { const posts = await Promise.all(objects.map(async (object) => {
if ( if (
!activitypub._constants.acceptedPostTypes.includes(object.type) || !activitypub._constants.acceptedPostTypes.includes(object.type) ||
@@ -170,13 +167,30 @@ Mocks.post = async (objects) => {
attributedTo: uid, attributedTo: uid,
inReplyTo: toPid, inReplyTo: toPid,
published, updated, name, content, source, published, updated, name, content, source,
to, cc, audience, attachment, tag, image, type, to, cc, audience, attachment, tag, image,
} = object; } = object;
if (Array.isArray(uid)) { // Handle array attributedTo
uid = uid.reduce((valid, cur) => {
if (typeof cur === 'string') {
valid.push(cur);
} else if (typeof cur === 'object') {
if (cur.type === 'Person' && cur.id) {
valid.push(cur.id);
}
}
return valid;
}, []);
uid = uid.shift(); // take first valid uid
await activitypub.actors.assert(uid);
}
const resolved = await activitypub.helpers.resolveLocalId(toPid); const resolved = await activitypub.helpers.resolveLocalId(toPid);
if (resolved.type === 'post') { if (resolved.type === 'post') {
toPid = resolved.id; toPid = resolved.id;
} }
const timestamp = new Date(published).getTime(); const timestamp = new Date(published).getTime();
let edited = new Date(updated); let edited = new Date(updated);
edited = Number.isNaN(edited.valueOf()) ? undefined : edited; edited = Number.isNaN(edited.valueOf()) ? undefined : edited;
@@ -215,6 +229,30 @@ Mocks.post = async (objects) => {
} }
} }
if (url) { // Handle url array
if (Array.isArray(url)) {
url = url.reduce((valid, cur) => {
if (typeof cur === 'string') {
valid.push(cur);
} else if (typeof cur === 'object') {
if (cur.type === 'Link' && cur.href) {
if (!cur.mediaType || (cur.mediaType && cur.mediaType === 'text/html')) {
valid.push(cur.href);
}
}
}
return valid;
}, []);
url = url.shift(); // take first valid url
}
}
if (type === 'Video') {
attachment = attachment || [];
attachment.push({ url });
}
const payload = { const payload = {
uid, uid,
pid, pid,

View File

@@ -137,6 +137,7 @@ middleware.resolveObjects = async function (req, res, next) {
next(); next();
}; };
// todo: deprecate... this should be handled in actor and note assertion methods instead, or perhaps via helper fn
middleware.normalize = async function (req, res, next) { middleware.normalize = async function (req, res, next) {
// Normalizes the received data structure // Normalizes the received data structure
const { body } = req; const { body } = req;