mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-26 16:41:21 +01:00
feat: proper webfinger response for instance actor
This commit is contained in:
@@ -24,7 +24,7 @@ Actors.application = async function (req, res) {
|
|||||||
|
|
||||||
type: 'Application',
|
type: 'Application',
|
||||||
name,
|
name,
|
||||||
preferredUsername: name,
|
preferredUsername: nconf.get('url_parsed').hostname,
|
||||||
|
|
||||||
publicKey: {
|
publicKey: {
|
||||||
id: `${nconf.get('url')}#key`,
|
id: `${nconf.get('url')}#key`,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const Controller = module.exports;
|
|||||||
|
|
||||||
Controller.webfinger = async (req, res) => {
|
Controller.webfinger = async (req, res) => {
|
||||||
const { resource } = req.query;
|
const { resource } = req.query;
|
||||||
const { host } = nconf.get('url_parsed');
|
const { host, hostname } = nconf.get('url_parsed');
|
||||||
|
|
||||||
if (!resource || !resource.startsWith('acct:') || !resource.endsWith(host)) {
|
if (!resource || !resource.startsWith('acct:') || !resource.endsWith(host)) {
|
||||||
return res.sendStatus(400);
|
return res.sendStatus(400);
|
||||||
@@ -23,30 +23,45 @@ Controller.webfinger = async (req, res) => {
|
|||||||
// Get the slug
|
// Get the slug
|
||||||
const slug = resource.slice(5, resource.length - (host.length + 1));
|
const slug = resource.slice(5, resource.length - (host.length + 1));
|
||||||
|
|
||||||
const uid = await user.getUidByUserslug(slug);
|
let uid = await user.getUidByUserslug(slug);
|
||||||
if (!uid) {
|
if (slug === hostname) {
|
||||||
|
uid = 0;
|
||||||
|
} else if (!uid) {
|
||||||
return res.sendStatus(404);
|
return res.sendStatus(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
subject: `acct:${slug}@${host}`,
|
subject: `acct:${slug}@${host}`,
|
||||||
aliases: [
|
};
|
||||||
|
|
||||||
|
if (uid) {
|
||||||
|
response.aliases = [
|
||||||
`${nconf.get('url')}/uid/${uid}`,
|
`${nconf.get('url')}/uid/${uid}`,
|
||||||
`${nconf.get('url')}/user/${slug}`,
|
`${nconf.get('url')}/user/${slug}`,
|
||||||
],
|
];
|
||||||
links: [
|
|
||||||
{
|
response.links = [
|
||||||
rel: 'http://webfinger.net/rel/profile-page',
|
|
||||||
type: 'text/html',
|
|
||||||
href: `${nconf.get('url')}/user/${slug}`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
rel: 'self',
|
rel: 'self',
|
||||||
type: 'application/activity+json',
|
type: 'application/activity+json',
|
||||||
href: `${nconf.get('url')}/user/${slug}`, // actor
|
href: `${nconf.get('url')}/user/${slug}`, // actor
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
};
|
rel: 'http://webfinger.net/rel/profile-page',
|
||||||
|
type: 'text/html',
|
||||||
|
href: `${nconf.get('url')}/user/${slug}`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
response.aliases = [nconf.get('url')];
|
||||||
|
response.links = [
|
||||||
|
{
|
||||||
|
rel: 'self',
|
||||||
|
type: 'application/activity+json',
|
||||||
|
href: nconf.get('url'), // actor
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
res.status(200).json(response);
|
res.status(200).json(response);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -237,19 +237,30 @@ describe('ActivityPub integration', () => {
|
|||||||
assert(body.hasOwnProperty('@context'));
|
assert(body.hasOwnProperty('@context'));
|
||||||
assert(body['@context'].includes('https://www.w3.org/ns/activitystreams'));
|
assert(body['@context'].includes('https://www.w3.org/ns/activitystreams'));
|
||||||
|
|
||||||
['id', 'url', 'inbox', 'outbox'].forEach((prop) => {
|
['id', 'url', 'inbox', 'outbox', 'name', 'preferredUsername'].forEach((prop) => {
|
||||||
assert(body.hasOwnProperty(prop));
|
assert(body.hasOwnProperty(prop));
|
||||||
assert(body[prop]);
|
assert(body[prop]);
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(body.id, body.url);
|
assert.strictEqual(body.id, body.url);
|
||||||
assert.strictEqual(body.type, 'Application');
|
assert.strictEqual(body.type, 'Application');
|
||||||
|
assert.strictEqual(body.name, meta.config.site_title || 'NodeBB');
|
||||||
|
assert.strictEqual(body.preferredUsername, nconf.get('url_parsed').hostname);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain a `publicKey` property with a public key', async () => {
|
it('should contain a `publicKey` property with a public key', async () => {
|
||||||
assert(body.hasOwnProperty('publicKey'));
|
assert(body.hasOwnProperty('publicKey'));
|
||||||
assert(['id', 'owner', 'publicKeyPem'].every(prop => body.publicKey.hasOwnProperty(prop)));
|
assert(['id', 'owner', 'publicKeyPem'].every(prop => body.publicKey.hasOwnProperty(prop)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should also have a valid WebFinger response tied to `preferredUsername`', async () => {
|
||||||
|
const { response, body: body2 } = await request.get(`${nconf.get('url')}/.well-known/webfinger?resource=acct:${body.preferredUsername}@${nconf.get('url_parsed').host}`);
|
||||||
|
|
||||||
|
assert.strictEqual(response.statusCode, 200);
|
||||||
|
assert(body2 && body2.aliases && body2.links);
|
||||||
|
assert(body2.aliases.includes(nconf.get('url')));
|
||||||
|
assert(body2.links.some(item => item.rel === 'self' && item.type === 'application/activity+json' && item.href === nconf.get('url')));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('http signature signing and verification', () => {
|
describe('http signature signing and verification', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user