mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-02 03:55:55 +01:00
144 lines
4.5 KiB
JavaScript
144 lines
4.5 KiB
JavaScript
'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);
|
|
});
|
|
});
|
|
});
|