mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
fix: actor assertion logic to ignore loopback urls
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user