mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
refactor: split activitypub tests to subfolder files
This commit is contained in:
@@ -36,7 +36,7 @@ Actors.assert = async (ids, options = {}) => {
|
|||||||
if (id.includes('@') && !(isUri && activitypub._constants.acceptedProtocols.includes(new URL(id).protocol.slice(0, -1)))) {
|
if (id.includes('@') && !(isUri && activitypub._constants.acceptedProtocols.includes(new URL(id).protocol.slice(0, -1)))) {
|
||||||
const host = isUri ? new URL(id).host : id.split('@')[1];
|
const host = isUri ? new URL(id).host : id.split('@')[1];
|
||||||
if (host === nconf.get('url_parsed').host) { // do not assert loopback ids
|
if (host === nconf.get('url_parsed').host) { // do not assert loopback ids
|
||||||
return null;
|
return 'loopback';
|
||||||
}
|
}
|
||||||
|
|
||||||
({ actorUri: id } = await activitypub.helpers.query(id));
|
({ actorUri: id } = await activitypub.helpers.query(id));
|
||||||
@@ -53,10 +53,7 @@ Actors.assert = async (ids, options = {}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter out loopback uris
|
// Filter out loopback uris
|
||||||
ids = ids.filter((uri) => {
|
ids = ids.filter(uri => uri !== 'loopback' && new URL(uri).host !== nconf.get('url_parsed').host);
|
||||||
const { host } = new URL(uri);
|
|
||||||
return host !== nconf.get('url_parsed').host;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Filter out existing
|
// Filter out existing
|
||||||
if (!options.update) {
|
if (!options.update) {
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ Helpers.resolveLocalId = async (input) => {
|
|||||||
|
|
||||||
return { type: null, id: null };
|
return { type: null, id: null };
|
||||||
} else if (String(input).indexOf('@') !== -1) { // Webfinger
|
} else if (String(input).indexOf('@') !== -1) { // Webfinger
|
||||||
|
input = decodeURIComponent(input);
|
||||||
const [slug] = input.replace(/^acct:/, '').split('@');
|
const [slug] = input.replace(/^acct:/, '').split('@');
|
||||||
const uid = await user.getUidByUserslug(slug);
|
const uid = await user.getUidByUserslug(slug);
|
||||||
return { type: 'user', id: uid };
|
return { type: 'user', id: uid };
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ Mocks.note = async (post) => {
|
|||||||
inReplyTo = utils.isNumber(post.topic.mainPid) ? `${nconf.get('url')}/post/${post.topic.mainPid}` : post.topic.mainPid;
|
inReplyTo = utils.isNumber(post.topic.mainPid) ? `${nconf.get('url')}/post/${post.topic.mainPid}` : post.topic.mainPid;
|
||||||
to.add(utils.isNumber(post.topic.uid) ? `${nconf.get('url')}/uid/${post.topic.uid}` : post.topic.uid);
|
to.add(utils.isNumber(post.topic.uid) ? `${nconf.get('url')}/uid/${post.topic.uid}` : post.topic.uid);
|
||||||
} else { // new topic
|
} else { // new topic
|
||||||
name = await topics.getTitleByPid(post.pid);
|
({ titleRaw: name } = await topics.getTopicFields(post.tid, ['title']));
|
||||||
tag = post.topic.tags.map(tag => ({
|
tag = post.topic.tags.map(tag => ({
|
||||||
type: 'Hashtag',
|
type: 'Hashtag',
|
||||||
href: `${nconf.get('url')}/tags/${tag.valueEncoded}`,
|
href: `${nconf.get('url')}/tags/${tag.valueEncoded}`,
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const { createHash } = require('crypto');
|
|
||||||
const nconf = require('nconf');
|
const nconf = require('nconf');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
const db = require('./mocks/databasemock');
|
const db = require('./mocks/databasemock');
|
||||||
const slugify = require('../src/slugify');
|
const slugify = require('../src/slugify');
|
||||||
const utils = require('../src/utils');
|
const utils = require('../src/utils');
|
||||||
const request = require('../src/request');
|
const request = require('../src/request');
|
||||||
|
|
||||||
|
const file = require('../src/file');
|
||||||
const install = require('../src/install');
|
const install = require('../src/install');
|
||||||
const meta = require('../src/meta');
|
const meta = require('../src/meta');
|
||||||
const user = require('../src/user');
|
const user = require('../src/user');
|
||||||
const categories = require('../src/categories');
|
const categories = require('../src/categories');
|
||||||
const topics = require('../src/topics');
|
const topics = require('../src/topics');
|
||||||
const posts = require('../src/posts');
|
|
||||||
const privileges = require('../src/privileges');
|
|
||||||
const activitypub = require('../src/activitypub');
|
const activitypub = require('../src/activitypub');
|
||||||
|
|
||||||
describe('ActivityPub integration', () => {
|
describe('ActivityPub integration', () => {
|
||||||
@@ -28,59 +27,6 @@ describe('ActivityPub integration', () => {
|
|||||||
delete meta.config.activitypubEnabled;
|
delete meta.config.activitypubEnabled;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('WebFinger endpoint', () => {
|
|
||||||
let uid;
|
|
||||||
let slug;
|
|
||||||
const { host } = nconf.get('url_parsed');
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
slug = slugify(utils.generateUUID().slice(0, 8));
|
|
||||||
uid = await user.create({ username: slug });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a 404 Not Found if no user exists by that username', async () => {
|
|
||||||
const { response } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3afoobar%40${host}`);
|
|
||||||
|
|
||||||
assert(response);
|
|
||||||
assert.strictEqual(response.statusCode, 404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a 400 Bad Request if the request is malformed', async () => {
|
|
||||||
const { response } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3afoobar`);
|
|
||||||
|
|
||||||
assert(response);
|
|
||||||
assert.strictEqual(response.statusCode, 400);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 403 Forbidden if the calling user is not allowed to view the user list/profiles', async () => {
|
|
||||||
await privileges.global.rescind(['groups:view:users'], 'guests');
|
|
||||||
const { response } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3a${slug}%40${host}`);
|
|
||||||
|
|
||||||
assert(response);
|
|
||||||
assert.strictEqual(response.statusCode, 400);
|
|
||||||
await privileges.global.give(['groups:view:users'], 'guests');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a valid WebFinger response otherwise', async () => {
|
|
||||||
const { response, body } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3a${slug}%40${host}`);
|
|
||||||
|
|
||||||
assert(response);
|
|
||||||
assert.strictEqual(response.statusCode, 200);
|
|
||||||
|
|
||||||
['subject', 'aliases', 'links'].forEach((prop) => {
|
|
||||||
assert(body.hasOwnProperty(prop));
|
|
||||||
assert(body[prop]);
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.strictEqual(body.subject, `acct:${slug}@${host}`);
|
|
||||||
|
|
||||||
assert(Array.isArray(body.aliases));
|
|
||||||
assert([`${nconf.get('url')}/uid/${uid}`, `${nconf.get('url')}/user/${slug}`].every(url => body.aliases.includes(url)));
|
|
||||||
|
|
||||||
assert(Array.isArray(body.links));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Helpers', () => {
|
describe('Helpers', () => {
|
||||||
describe('.query()', () => {
|
describe('.query()', () => {
|
||||||
|
|
||||||
@@ -300,139 +246,6 @@ describe('ActivityPub integration', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('http signature signing and verification', () => {
|
|
||||||
describe('.sign()', () => {
|
|
||||||
let uid;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
uid = await user.create({ username: utils.generateUUID().slice(0, 10) });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a key-pair for a user if the user does not have one already', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', uid);
|
|
||||||
await activitypub.sign(keyData, endpoint);
|
|
||||||
const { publicKey, privateKey } = await db.getObject(`uid:${uid}:keys`);
|
|
||||||
|
|
||||||
assert(publicKey);
|
|
||||||
assert(privateKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an object with date, a null digest, and signature, if no payload is passed in', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', uid);
|
|
||||||
const { date, digest, signature } = await activitypub.sign(keyData, endpoint);
|
|
||||||
const dateObj = new Date(date);
|
|
||||||
|
|
||||||
assert(signature);
|
|
||||||
assert(dateObj);
|
|
||||||
assert.strictEqual(digest, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should also return a digest hash if payload is passed in', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
|
||||||
const payload = { foo: 'bar' };
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', uid);
|
|
||||||
const { digest } = await activitypub.sign(keyData, endpoint, payload);
|
|
||||||
const hash = createHash('sha256');
|
|
||||||
hash.update(JSON.stringify(payload));
|
|
||||||
const checksum = hash.digest('base64');
|
|
||||||
|
|
||||||
assert(digest);
|
|
||||||
assert.strictEqual(digest, `sha-256=${checksum}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create a key for NodeBB itself if a uid of 0 is passed in', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', 0);
|
|
||||||
await activitypub.sign(keyData, endpoint);
|
|
||||||
const { publicKey, privateKey } = await db.getObject(`uid:0:keys`);
|
|
||||||
|
|
||||||
assert(publicKey);
|
|
||||||
assert(privateKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return headers with an appropriate key id uri', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', uid);
|
|
||||||
const { signature } = await activitypub.sign(keyData, endpoint);
|
|
||||||
const [keyId] = signature.split(',');
|
|
||||||
|
|
||||||
assert(signature);
|
|
||||||
assert.strictEqual(keyId, `keyId="${nconf.get('url')}/uid/${uid}#key"`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the instance key id when uid is 0', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', 0);
|
|
||||||
const { signature } = await activitypub.sign(keyData, endpoint);
|
|
||||||
const [keyId] = signature.split(',');
|
|
||||||
|
|
||||||
assert(signature);
|
|
||||||
assert.strictEqual(keyId, `keyId="${nconf.get('url')}/actor#key"`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.verify()', () => {
|
|
||||||
let uid;
|
|
||||||
let username;
|
|
||||||
const baseUrl = nconf.get('relative_path');
|
|
||||||
const mockReqBase = {
|
|
||||||
method: 'GET',
|
|
||||||
// path: ...
|
|
||||||
baseUrl,
|
|
||||||
headers: {
|
|
||||||
// host: ...
|
|
||||||
// date: ...
|
|
||||||
// signature: ...
|
|
||||||
// digest: ...
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
username = utils.generateUUID().slice(0, 10);
|
|
||||||
uid = await user.create({ username });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true when the proper signature and relevant headers are passed in', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/user/${username}/inbox`;
|
|
||||||
const path = `/user/${username}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', uid);
|
|
||||||
const signature = await activitypub.sign(keyData, endpoint);
|
|
||||||
const { host } = nconf.get('url_parsed');
|
|
||||||
const req = {
|
|
||||||
...mockReqBase,
|
|
||||||
...{
|
|
||||||
path,
|
|
||||||
headers: { ...signature, host },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const verified = await activitypub.verify(req);
|
|
||||||
assert.strictEqual(verified, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true when a digest is also passed in', async () => {
|
|
||||||
const endpoint = `${nconf.get('url')}/user/${username}/inbox`;
|
|
||||||
const path = `/user/${username}/inbox`;
|
|
||||||
const keyData = await activitypub.getPrivateKey('uid', uid);
|
|
||||||
const signature = await activitypub.sign(keyData, endpoint, { foo: 'bar' });
|
|
||||||
const { host } = nconf.get('url_parsed');
|
|
||||||
const req = {
|
|
||||||
...mockReqBase,
|
|
||||||
...{
|
|
||||||
method: 'POST',
|
|
||||||
path,
|
|
||||||
headers: { ...signature, host },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const verified = await activitypub.verify(req);
|
|
||||||
assert.strictEqual(verified, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Receipt of ActivityPub events to inboxes (federating IN)', () => {
|
describe('Receipt of ActivityPub events to inboxes (federating IN)', () => {
|
||||||
describe('Create', () => {
|
describe('Create', () => {
|
||||||
describe('Note', () => {
|
describe('Note', () => {
|
||||||
@@ -526,7 +339,7 @@ describe('ActivityPub integration', () => {
|
|||||||
({ postData, topicData } = await topics.post({
|
({ postData, topicData } = await topics.post({
|
||||||
uid,
|
uid,
|
||||||
cid: category.cid,
|
cid: category.cid,
|
||||||
title: 'Lipsum title',
|
title: 'Lorem "Lipsum" Ipsum',
|
||||||
content: 'Lorem ipsum dolor sit amet',
|
content: 'Lorem ipsum dolor sit amet',
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@@ -560,6 +373,10 @@ describe('ActivityPub integration', () => {
|
|||||||
it('should return the expected Content-Type header', () => {
|
it('should return the expected Content-Type header', () => {
|
||||||
assert.strictEqual(response.headers['content-type'], 'application/activity+json; charset=utf-8');
|
assert.strictEqual(response.headers['content-type'], 'application/activity+json; charset=utf-8');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Topic title (`name`) should not be escaped', () => {
|
||||||
|
assert.strictEqual(body.name, 'Lorem "Lipsum" Ipsum');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -637,4 +454,18 @@ describe('ActivityPub integration', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ActivityPub', async () => {
|
||||||
|
let files;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
files = await file.walk(path.resolve(__dirname, './activitypub'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('subfolder tests', () => {
|
||||||
|
files.forEach((filePath) => {
|
||||||
|
require(filePath);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
143
test/activitypub/signatures.js
Normal file
143
test/activitypub/signatures.js
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const nconf = require('nconf');
|
||||||
|
const { createHash } = require('crypto');
|
||||||
|
|
||||||
|
const user = require('../../src/user');
|
||||||
|
const utils = require('../../src/utils');
|
||||||
|
const db = require('../../src/database');
|
||||||
|
const activitypub = require('../../src/activitypub');
|
||||||
|
|
||||||
|
describe('http signature signing and verification', () => {
|
||||||
|
describe('.sign()', () => {
|
||||||
|
let uid;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
uid = await user.create({ username: utils.generateUUID().slice(0, 10) });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a key-pair for a user if the user does not have one already', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', uid);
|
||||||
|
await activitypub.sign(keyData, endpoint);
|
||||||
|
const { publicKey, privateKey } = await db.getObject(`uid:${uid}:keys`);
|
||||||
|
|
||||||
|
assert(publicKey);
|
||||||
|
assert(privateKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an object with date, a null digest, and signature, if no payload is passed in', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', uid);
|
||||||
|
const { date, digest, signature } = await activitypub.sign(keyData, endpoint);
|
||||||
|
const dateObj = new Date(date);
|
||||||
|
|
||||||
|
assert(signature);
|
||||||
|
assert(dateObj);
|
||||||
|
assert.strictEqual(digest, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should also return a digest hash if payload is passed in', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
||||||
|
const payload = { foo: 'bar' };
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', uid);
|
||||||
|
const { digest } = await activitypub.sign(keyData, endpoint, payload);
|
||||||
|
const hash = createHash('sha256');
|
||||||
|
hash.update(JSON.stringify(payload));
|
||||||
|
const checksum = hash.digest('base64');
|
||||||
|
|
||||||
|
assert(digest);
|
||||||
|
assert.strictEqual(digest, `SHA-256=${checksum}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a key for NodeBB itself if a uid of 0 is passed in', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', 0);
|
||||||
|
await activitypub.sign(keyData, endpoint);
|
||||||
|
const { publicKey, privateKey } = await db.getObject(`uid:0:keys`);
|
||||||
|
|
||||||
|
assert(publicKey);
|
||||||
|
assert(privateKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return headers with an appropriate key id uri', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', uid);
|
||||||
|
const { signature } = await activitypub.sign(keyData, endpoint);
|
||||||
|
const [keyId] = signature.split(',');
|
||||||
|
|
||||||
|
assert(signature);
|
||||||
|
assert.strictEqual(keyId, `keyId="${nconf.get('url')}/uid/${uid}#key"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the instance key id when uid is 0', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', 0);
|
||||||
|
const { signature } = await activitypub.sign(keyData, endpoint);
|
||||||
|
const [keyId] = signature.split(',');
|
||||||
|
|
||||||
|
assert(signature);
|
||||||
|
assert.strictEqual(keyId, `keyId="${nconf.get('url')}/actor#key"`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.verify()', () => {
|
||||||
|
let uid;
|
||||||
|
let username;
|
||||||
|
const baseUrl = nconf.get('relative_path');
|
||||||
|
const mockReqBase = {
|
||||||
|
method: 'GET',
|
||||||
|
// path: ...
|
||||||
|
baseUrl,
|
||||||
|
headers: {
|
||||||
|
// host: ...
|
||||||
|
// date: ...
|
||||||
|
// signature: ...
|
||||||
|
// digest: ...
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
username = utils.generateUUID().slice(0, 10);
|
||||||
|
uid = await user.create({ username });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when the proper signature and relevant headers are passed in', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/user/${username}/inbox`;
|
||||||
|
const path = `/user/${username}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', uid);
|
||||||
|
const signature = await activitypub.sign(keyData, endpoint);
|
||||||
|
const { host } = nconf.get('url_parsed');
|
||||||
|
const req = {
|
||||||
|
...mockReqBase,
|
||||||
|
...{
|
||||||
|
path,
|
||||||
|
headers: { ...signature, host },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const verified = await activitypub.verify(req);
|
||||||
|
assert.strictEqual(verified, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when a digest is also passed in', async () => {
|
||||||
|
const endpoint = `${nconf.get('url')}/user/${username}/inbox`;
|
||||||
|
const path = `/user/${username}/inbox`;
|
||||||
|
const keyData = await activitypub.getPrivateKey('uid', uid);
|
||||||
|
const signature = await activitypub.sign(keyData, endpoint, { foo: 'bar' });
|
||||||
|
const { host } = nconf.get('url_parsed');
|
||||||
|
const req = {
|
||||||
|
...mockReqBase,
|
||||||
|
...{
|
||||||
|
method: 'POST',
|
||||||
|
path,
|
||||||
|
headers: { ...signature, host },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const verified = await activitypub.verify(req);
|
||||||
|
assert.strictEqual(verified, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
63
test/activitypub/webfinger.js
Normal file
63
test/activitypub/webfinger.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const nconf = require('nconf');
|
||||||
|
|
||||||
|
const request = require('../../src/request');
|
||||||
|
const utils = require('../../src/utils');
|
||||||
|
const user = require('../../src/user');
|
||||||
|
const slugify = require('../../src/slugify');
|
||||||
|
const privileges = require('../../src/privileges');
|
||||||
|
|
||||||
|
describe('WebFinger endpoint', () => {
|
||||||
|
let uid;
|
||||||
|
let slug;
|
||||||
|
const { host } = nconf.get('url_parsed');
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
slug = slugify(utils.generateUUID().slice(0, 8));
|
||||||
|
uid = await user.create({ username: slug });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a 404 Not Found if no user exists by that username', async () => {
|
||||||
|
const { response } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3afoobar%40${host}`);
|
||||||
|
|
||||||
|
assert(response);
|
||||||
|
assert.strictEqual(response.statusCode, 404);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a 400 Bad Request if the request is malformed', async () => {
|
||||||
|
const { response } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3afoobar`);
|
||||||
|
|
||||||
|
assert(response);
|
||||||
|
assert.strictEqual(response.statusCode, 400);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 403 Forbidden if the calling user is not allowed to view the user list/profiles', async () => {
|
||||||
|
await privileges.global.rescind(['groups:view:users'], 'guests');
|
||||||
|
const { response } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3a${slug}%40${host}`);
|
||||||
|
|
||||||
|
assert(response);
|
||||||
|
assert.strictEqual(response.statusCode, 400);
|
||||||
|
await privileges.global.give(['groups:view:users'], 'guests');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a valid WebFinger response otherwise', async () => {
|
||||||
|
const { response, body } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct%3a${slug}%40${host}`);
|
||||||
|
|
||||||
|
assert(response);
|
||||||
|
assert.strictEqual(response.statusCode, 200);
|
||||||
|
|
||||||
|
['subject', 'aliases', 'links'].forEach((prop) => {
|
||||||
|
assert(body.hasOwnProperty(prop));
|
||||||
|
assert(body[prop]);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(body.subject, `acct:${slug}@${host}`);
|
||||||
|
|
||||||
|
assert(Array.isArray(body.aliases));
|
||||||
|
assert([`${nconf.get('url')}/uid/${uid}`, `${nconf.get('url')}/user/${slug}`].every(url => body.aliases.includes(url)));
|
||||||
|
|
||||||
|
assert(Array.isArray(body.links));
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user