diff --git a/src/activitypub.js b/src/activitypub.js index ec25ef600ff5..4f4fe7ae3748 100644 --- a/src/activitypub.js +++ b/src/activitypub.js @@ -21,7 +21,7 @@ ActivityPub.getPublicKey = async (uid) => { }; async function generateKeys(uid) { - winston.info(`[activitypub] Generating RSA key-pair for uid ${uid}`); + winston.verbose(`[activitypub] Generating RSA key-pair for uid ${uid}`); const { publicKey, privateKey, diff --git a/test/activitypub.js b/test/activitypub.js index 5276d5e15cc6..1b63aef640ab 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -1,27 +1,135 @@ 'use strict'; +const assert = require('assert'); const nconf = require('nconf'); const request = require('request-promise-native'); const db = require('./mocks/databasemock'); +const slugify = require('../src/slugify'); +const utils = require('../src/utils'); + +const user = require('../src/user'); +const privileges = require('../src/privileges'); describe('ActivityPub integration', () => { describe('WebFinger endpoint', () => { + let uid; + let slug; + const { hostname } = 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(`${nconf.get('url')}/register/complete`, { - method: 'post', - jar, + const response = await request(`${nconf.get('url')}/.well-known/webfinger?resource=acct:foobar@${hostname}`, { + method: 'get', + json: true, + followRedirect: true, + simple: false, + resolveWithFullResponse: true, + }); + + assert(response); + assert.strictEqual(response.statusCode, 404); + }); + + it('should return a 400 Bad Request if the request is malformed', async () => { + const response = await request(`${nconf.get('url')}/.well-known/webfinger?resource=acct:foobar`, { + method: 'get', + json: true, + followRedirect: true, + simple: false, + resolveWithFullResponse: true, + }); + + 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(`${nconf.get('url')}/.well-known/webfinger?resource=acct:${slug}@${hostname}`, { + method: 'get', + json: true, + followRedirect: true, + simple: false, + resolveWithFullResponse: true, + }); + + assert(response); + assert.strictEqual(response.statusCode, 403); + await privileges.global.give(['groups:view:users'], 'guests'); + }); + + it('should return a valid WebFinger response otherwise', async () => { + const response = await request(`${nconf.get('url')}/.well-known/webfinger?resource=acct:${slug}@${hostname}`, { + method: 'get', json: true, - followRedirect: false, + followRedirect: true, + simple: false, + resolveWithFullResponse: true, + }); + + assert(response); + assert.strictEqual(response.statusCode, 200); + + ['subject', 'aliases', 'links'].forEach((prop) => { + assert(response.body.hasOwnProperty(prop)); + assert(response.body[prop]); + }); + + assert.strictEqual(response.body.subject, `acct:${slug}@${hostname}`); + + assert(Array.isArray(response.body.aliases)); + assert([`${nconf.get('url')}/uid/${uid}`, `${nconf.get('url')}/user/${slug}`].every(url => response.body.aliases.includes(url))); + + assert(Array.isArray(response.body.links)); + }); + }); + + describe('ActivityPub screener middleware', () => { + let uid; + let slug; + + beforeEach(async () => { + slug = slugify(utils.generateUUID().slice(0, 8)); + uid = await user.create({ username: slug }); + }); + + it('should return regular user profile html if Accept header is not ActivityPub-related', async () => { + const response = await request(`${nconf.get('url')}/user/${slug}`, { + method: 'get', + followRedirect: true, simple: false, resolveWithFullResponse: true, headers: { - 'x-csrf-token': token, + Accept: 'text/html', }, - form: { - email: '', + }); + + assert(response); + assert.strictEqual(response.statusCode, 200); + assert(response.body.startsWith('')); + }); + + it('should return the ActivityPub Actor JSON-LD payload if the correct Accept header is provided', async () => { + const response = await request(`${nconf.get('url')}/user/${slug}`, { + method: 'get', + json: true, + followRedirect: true, + simple: false, + resolveWithFullResponse: true, + headers: { + Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', }, }); + + assert(response); + assert.strictEqual(response.statusCode, 200); + assert(response.body.hasOwnProperty('@context')); + assert(response.body['@context'].includes('https://www.w3.org/ns/activitystreams')); }); }); });