fix: actor assertion logic to ignore loopback urls

This commit is contained in:
Julian Lam
2024-04-05 11:37:23 -04:00
parent 983153fbba
commit f40df38786
2 changed files with 75 additions and 33 deletions

View File

@@ -1,6 +1,7 @@
'use strict'; 'use strict';
const winston = require('winston'); const winston = require('winston');
const nconf = require('nconf');
const db = require('../database'); const db = require('../database');
const user = require('../user'); const user = require('../user');
@@ -23,17 +24,27 @@ Actors.assert = async (ids, options = {}) => {
ids = ids.filter(id => !utils.isNumber(id) && !failedWebfingerCache.has(id)); ids = ids.filter(id => !utils.isNumber(id) && !failedWebfingerCache.has(id));
// Translate webfinger handles to uris // Translate webfinger handles to uris
ids = await Promise.all(ids.map(async (id) => { ids = (await Promise.all(ids.map(async (id) => {
const originalId = id; const originalId = id;
if (id.includes('@')) { if (id.includes('@')) {
const host = id.split('@')[1];
if (host === nconf.get('url_parsed').host) { // do not assert loopback ids
return null;
}
({ actorUri: id } = await activitypub.helpers.query(id)); ({ actorUri: id } = await activitypub.helpers.query(id));
} }
if (!id) { if (!id) {
failedWebfingerCache.set(originalId, true); failedWebfingerCache.set(originalId, true);
} }
return id; return id;
})); }))).filter(Boolean);
// Filter out loopback uris
ids = ids.filter((uri) => {
const { host } = new URL(uri);
return host !== nconf.get('url_parsed').host;
});
// Filter out existing // Filter out existing
if (!options.update) { if (!options.update) {

View File

@@ -564,46 +564,77 @@ describe('ActivityPub integration', () => {
}); });
describe('Actor asserton', () => { describe('Actor asserton', () => {
let uid; describe('happy path', () => {
let actorUri; let uid;
let actorUri;
before(async () => { before(async () => {
uid = utils.generateUUID().slice(0, 8); uid = utils.generateUUID().slice(0, 8);
actorUri = `https://example.org/user/${uid}`; actorUri = `https://example.org/user/${uid}`;
activitypub._cache.set(`0;${actorUri}`, { activitypub._cache.set(`0;${actorUri}`, {
'@context': 'https://www.w3.org/ns/activitystreams', '@context': 'https://www.w3.org/ns/activitystreams',
id: actorUri, id: actorUri,
url: actorUri, url: actorUri,
type: 'Person', type: 'Person',
name: 'example', name: 'example',
preferredUsername: 'example', preferredUsername: 'example',
publicKey: { publicKey: {
id: `${actorUri}#key`, id: `${actorUri}#key`,
owner: actorUri, owner: actorUri,
publicKeyPem: 'somekey', publicKeyPem: 'somekey',
}, },
});
});
it('should return true if successfully asserted', async () => {
const result = await activitypub.actors.assert([actorUri]);
assert(result);
});
it('should contain a representation of that remote user in the database', async () => {
const exists = await db.exists(`userRemote:${actorUri}`);
assert(exists);
const userData = await user.getUserData(actorUri);
assert(userData);
assert.strictEqual(userData.uid, actorUri);
});
it('should save the actor\'s publicly accessible URL in the hash as well', async () => {
const url = await user.getUserField(actorUri, 'url');
assert.strictEqual(url, actorUri);
}); });
}); });
it('should return true if successfully asserted', async () => { describe('edge case: loopback handles and uris', () => {
const result = await activitypub.actors.assert([actorUri]); let uid;
assert(result); const userslug = utils.generateUUID().slice(0, 8);
}); before(async () => {
uid = await user.create({ username: userslug });
});
it('should contain a representation of that remote user in the database', async () => { it('should return true but not actually assert the handle into the database', async () => {
const exists = await db.exists(`userRemote:${actorUri}`); const handle = `${userslug}@${nconf.get('url_parsed').host}`;
assert(exists); const result = await activitypub.actors.assert([handle]);
assert(result);
const userData = await user.getUserData(actorUri); const handleExists = await db.isObjectField('handle:uid', handle);
assert(userData); assert.strictEqual(handleExists, false);
assert.strictEqual(userData.uid, actorUri);
});
it('should save the actor\'s publicly accessible URL in the hash as well', async () => { const userRemoteHashExists = await db.exists(`userRemote:${nconf.get('url')}/uid/${uid}`);
const url = await user.getUserField(actorUri, 'url'); assert.strictEqual(userRemoteHashExists, false);
assert.strictEqual(url, actorUri); });
it('should return true but not actually assert the uri into the database', async () => {
const uri = `${nconf.get('url')}/uid/${uid}`;
const result = await activitypub.actors.assert([uri]);
assert(result);
const userRemoteHashExists = await db.exists(`userRemote:${uri}`);
assert.strictEqual(userRemoteHashExists, false);
});
}); });
}); });
}); });