Fix local Actor URLs, add addFollowing() API

This commit is contained in:
Bryan Ashby 2023-02-05 10:42:30 -07:00
parent bd2dc27477
commit 41cd0f7f33
No known key found for this signature in database
GPG Key ID: C2C1B501E4EFD994
4 changed files with 65 additions and 38 deletions

View File

@ -19,7 +19,6 @@ const ActivityPubSettings = require('./settings');
const ActivityPubObject = require('./object'); const ActivityPubObject = require('./object');
const { ActivityStreamMediaType } = require('./const'); const { ActivityStreamMediaType } = require('./const');
const apDb = require('../database').dbs.activitypub; const apDb = require('../database').dbs.activitypub;
const Config = require('../config').get;
// deps // deps
const _ = require('lodash'); const _ = require('lodash');
@ -132,11 +131,13 @@ module.exports = class Actor extends ActivityPubObject {
// value: 'Mateo@21:1/121', // value: 'Mateo@21:1/121',
// }, // },
// ], // ],
bbsInfo: {
boardName: Config().general.boardName, // :TODO: re-enable once a spec is defined; board should prob be a object with connection info, etc.
memberSince: user.getProperty(UserProps.AccountCreated), // bbsInfo: {
affiliations: user.getProperty(UserProps.Affiliations) || '', // boardName: Config().general.boardName,
}, // memberSince: user.getProperty(UserProps.AccountCreated),
// affiliations: user.getProperty(UserProps.Affiliations) || '',
// },
}; };
addImage(obj, 'icon'); addImage(obj, 'icon');

View File

@ -26,13 +26,14 @@ module.exports = class Collection extends ActivityPubObject {
const headers = { const headers = {
Accept: ActivityStreamMediaType, Accept: ActivityStreamMediaType,
}; };
getJson(collectionUrl, { headers }, (err, collection) => { getJson(
collectionUrl,
{ headers, validContentTypes: [ActivityStreamMediaType] },
(err, collection) => {
if (err) { if (err) {
return cb(err); return cb(err);
} }
// :TODO: validate headers?
collection = new Collection(collection); collection = new Collection(collection);
if (!collection.isValid()) { if (!collection.isValid()) {
return cb(Errors.Invalid('Invalid Collection')); return cb(Errors.Invalid('Invalid Collection'));
@ -46,7 +47,8 @@ module.exports = class Collection extends ActivityPubObject {
id, id,
summary, summary,
}); });
}); }
);
} }
static followers(collectionId, page, cb) { static followers(collectionId, page, cb) {
@ -71,14 +73,14 @@ module.exports = class Collection extends ActivityPubObject {
static addFollower(owningUser, followingActor, webServer, ignoreDupes, cb) { static addFollower(owningUser, followingActor, webServer, ignoreDupes, cb) {
const collectionId = const collectionId =
makeUserUrl(webServer, owningUser, '/ap/collections/') + '/followers'; makeUserUrl(webServer, owningUser, '/ap/users/') + '/followers';
return Collection.addToCollection( return Collection.addToCollection(
'followers', 'followers',
owningUser, owningUser,
collectionId, collectionId,
followingActor.id, followingActor.id, // Actor following owningUser
followingActor, followingActor,
false, false, // we'll check dynamically when queried
ignoreDupes, ignoreDupes,
cb cb
); );
@ -86,12 +88,12 @@ module.exports = class Collection extends ActivityPubObject {
static addFollowRequest(owningUser, requestingActor, webServer, ignoreDupes, cb) { static addFollowRequest(owningUser, requestingActor, webServer, ignoreDupes, cb) {
const collectionId = const collectionId =
makeUserUrl(webServer, owningUser, '/ap/collections/') + '/follow-requests'; makeUserUrl(webServer, owningUser, '/ap/users/') + '/follow-requests';
return Collection.addToCollection( return Collection.addToCollection(
'follow-requests', 'follow-requests',
owningUser, owningUser,
collectionId, collectionId,
requestingActor.id, requestingActor.id, // Actor requesting to follow owningUser
requestingActor, requestingActor,
true, true,
ignoreDupes, ignoreDupes,
@ -99,13 +101,27 @@ module.exports = class Collection extends ActivityPubObject {
); );
} }
static addFollowing(owningUser, followingActor, webServer, ignoreDupes, cb) {
const collectionId =
makeUserUrl(webServer, owningUser, '/ap/users/') + '/following';
return Collection.addToCollection(
'following',
owningUser,
collectionId,
followingActor.id, // Actor owningUser is following
followingActor,
false, // we'll check dynamically when queried
ignoreDupes,
cb
);
}
static outbox(collectionId, page, cb) { static outbox(collectionId, page, cb) {
return Collection.publicOrderedById('outbox', collectionId, page, null, cb); return Collection.publicOrderedById('outbox', collectionId, page, null, cb);
} }
static addOutboxItem(owningUser, outboxItem, isPrivate, webServer, ignoreDupes, cb) { static addOutboxItem(owningUser, outboxItem, isPrivate, webServer, ignoreDupes, cb) {
const collectionId = const collectionId = makeUserUrl(webServer, owningUser, '/ap/users/') + '/outbox';
makeUserUrl(webServer, owningUser, '/ap/collections/') + '/outbox';
return Collection.addToCollection( return Collection.addToCollection(
'outbox', 'outbox',
owningUser, owningUser,
@ -119,8 +135,7 @@ module.exports = class Collection extends ActivityPubObject {
} }
static addInboxItem(inboxItem, owningUser, webServer, ignoreDupes, cb) { static addInboxItem(inboxItem, owningUser, webServer, ignoreDupes, cb) {
const collectionId = const collectionId = makeUserUrl(webServer, owningUser, '/ap/users/') + '/inbox';
makeUserUrl(webServer, owningUser, '/ap/collections/') + '/inbox';
return Collection.addToCollection( return Collection.addToCollection(
'inbox', 'inbox',
owningUser, owningUser,
@ -282,9 +297,9 @@ module.exports = class Collection extends ActivityPubObject {
); );
} }
// e.g. http://somewhere.com/_enig/ap/collections/NuSkooler/followers // e.g. http://somewhere.com/_enig/ap/users/NuSkooler/followers
const collectionId = const collectionId =
makeUserUrl(webServer, owningUser, '/ap/collections/') + `/${collectionName}`; makeUserUrl(webServer, owningUser, '/ap/users/') + `/${collectionName}`;
if (!page) { if (!page) {
return apDb.get( return apDb.get(

View File

@ -493,7 +493,7 @@ dbs.message.run(
// ActivityPub Collections of various types such as followers, following, likes, ... // ActivityPub Collections of various types such as followers, following, likes, ...
dbs.activitypub.run( dbs.activitypub.run(
`CREATE TABLE IF NOT EXISTS collection ( `CREATE TABLE IF NOT EXISTS collection (
collection_id VARCHAR NOT NULL, -- ie: http://somewhere.com/_enig/ap/collections/NuSkooler/followers collection_id VARCHAR NOT NULL, -- ie: http://somewhere.com/_enig/ap/users/NuSkooler/followers
name VARCHAR NOT NULL, -- examples: followers, follows, ... name VARCHAR NOT NULL, -- examples: followers, follows, ...
timestamp DATETIME NOT NULL, -- Timestamp in which this entry was created timestamp DATETIME NOT NULL, -- Timestamp in which this entry was created
owner_actor_id VARCHAR NOT NULL, -- Local, owning Actor ID, or the #Public magic collection ID owner_actor_id VARCHAR NOT NULL, -- Local, owning Actor ID, or the #Public magic collection ID

View File

@ -18,6 +18,17 @@ function getJson(url, options, cb) {
return cb(err); return cb(err);
} }
if (Array.isArray(options.validContentTypes)) {
const contentType = res.headers['content-type'] || '';
if (
!options.validContentTypes.some(ct => {
return contentType.startsWith(ct);
})
) {
return cb(Errors.HttpError(`Invalid Content-Type: ${contentType}`));
}
}
Log.debug({ url: url, body: body }, 'Response from getJson'); Log.debug({ url: url, body: body }, 'Response from getJson');
let parsed; let parsed;
try { try {