diff --git a/test/activitypub.js b/test/activitypub.js index ce1c51ab98..075fca975f 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -1,6 +1,7 @@ 'use strict'; const assert = require('assert'); +const { createHash } = require('crypto'); const nconf = require('nconf'); const request = require('request-promise-native'); @@ -11,6 +12,7 @@ const utils = require('../src/utils'); const meta = require('../src/meta'); const user = require('../src/user'); const privileges = require('../src/privileges'); +const activitypub = require('../src/activitypub'); describe('ActivityPub integration', () => { before(() => { @@ -213,4 +215,102 @@ describe('ActivityPub integration', () => { assert(['id', 'owner', 'publicKeyPem'].every(prop => response.body.publicKey.hasOwnProperty(prop))); }); }); + + describe.only('http signature signing and verification', () => { + describe('.sign()', () => { + let uid; + let username; + + before(async () => { + username = utils.generateUUID().slice(0, 10); + uid = await user.create({ username }); + }); + + it('should create a key-pair for a user if the user does not have one already', async () => { + const endpoint = `${nconf.get('url')}/user/${username}/inbox`; + await activitypub.sign(uid, 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')}/user/${username}/inbox`; + const { date, digest, signature } = await activitypub.sign(uid, 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')}/user/${username}/inbox`; + const payload = { foo: 'bar' }; + const { digest } = await activitypub.sign(uid, endpoint, payload); + const hash = createHash('sha256'); + hash.update(JSON.stringify(payload)); + const checksum = hash.digest('hex'); + + assert(digest); + assert.strictEqual(digest, checksum); + }); + }); + + describe.only('.verify()', () => { + let uid; + let username; + const mockReqBase = { + method: 'GET', + // path: ... + 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 signature = await activitypub.sign(uid, 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 signature = await activitypub.sign(uid, 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); + }); + }); + }); });