mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 19:46:01 +01:00
feat: actor cache, method to resolve inboxes, stub code for sending requests. Now base64 encoding digest as expected by Mastodon
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const request = require('request-promise-native');
|
||||
const { generateKeyPairSync, sign } = require('crypto');
|
||||
const { generateKeyPairSync } = require('crypto');
|
||||
const winston = require('winston');
|
||||
|
||||
const db = require('../database');
|
||||
|
||||
@@ -7,12 +7,18 @@ const { createHash, createSign, createVerify } = require('crypto');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const ttl = require('../cache/ttl');
|
||||
|
||||
const actorCache = ttl({ ttl: 1000 * 60 * 60 * 24 }); // 24 hours
|
||||
const ActivityPub = module.exports;
|
||||
|
||||
ActivityPub.helpers = require('./helpers');
|
||||
|
||||
ActivityPub.getActor = async (id) => {
|
||||
if (actorCache.has(id)) {
|
||||
return actorCache.get(id);
|
||||
}
|
||||
|
||||
const { hostname, actorUri: uri } = await ActivityPub.helpers.query(id);
|
||||
if (!uri) {
|
||||
return false;
|
||||
@@ -28,9 +34,15 @@ ActivityPub.getActor = async (id) => {
|
||||
|
||||
actor.hostname = hostname;
|
||||
|
||||
actorCache.set(id, actor);
|
||||
return actor;
|
||||
};
|
||||
|
||||
ActivityPub.resolveInboxes = async ids => await Promise.all(ids.map(async (id) => {
|
||||
const actor = await ActivityPub.getActor(id);
|
||||
return actor.inbox;
|
||||
}));
|
||||
|
||||
ActivityPub.getPublicKey = async (uid) => {
|
||||
let publicKey;
|
||||
|
||||
@@ -84,7 +96,7 @@ ActivityPub.sign = async (uid, url, payload) => {
|
||||
if (payload) {
|
||||
const payloadHash = createHash('sha256');
|
||||
payloadHash.update(JSON.stringify(payload));
|
||||
digest = payloadHash.digest('hex');
|
||||
digest = `sha-256=${payloadHash.digest('base64')}`;
|
||||
headers += ' digest';
|
||||
signed_string += `\ndigest: ${digest}`;
|
||||
}
|
||||
@@ -146,26 +158,43 @@ ActivityPub.verify = async (req) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is just some code to test signing and verification. This should really be in the test suite.
|
||||
*/
|
||||
// setTimeout(async () => {
|
||||
// const payload = {
|
||||
// foo: 'bar',
|
||||
// };
|
||||
// const signature = await ActivityPub.sign(1, 'http://127.0.0.1:4567/user/julian/inbox', payload);
|
||||
ActivityPub.send = async (uid, targets, payload) => {
|
||||
if (!Array.isArray(targets)) {
|
||||
targets = [targets];
|
||||
}
|
||||
|
||||
// const res = await request({
|
||||
// uri: 'http://127.0.0.1:4567/user/julian/inbox',
|
||||
// method: 'post',
|
||||
// headers: {
|
||||
// Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
// ...signature,
|
||||
// },
|
||||
// json: true,
|
||||
// body: payload,
|
||||
// simple: false,
|
||||
// });
|
||||
const userslug = await user.getUserField(uid, 'userslug');
|
||||
const inboxes = await ActivityPub.resolveInboxes(targets);
|
||||
|
||||
// console.log(res);
|
||||
// }, 1000);
|
||||
payload = {
|
||||
...{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
actor: {
|
||||
type: 'Person',
|
||||
name: `${userslug}@${nconf.get('url_parsed').host}`,
|
||||
},
|
||||
},
|
||||
...payload,
|
||||
};
|
||||
|
||||
await Promise.all(inboxes.map(async (uri) => {
|
||||
const { date, digest, signature } = await ActivityPub.sign(uid, uri, payload);
|
||||
|
||||
const response = await request(uri, {
|
||||
method: payload ? 'post' : 'get',
|
||||
headers: {
|
||||
date,
|
||||
digest,
|
||||
signature,
|
||||
'content-type': 'application/ld+json; profile="http://www.w3.org/ns/activitystreams',
|
||||
accept: 'application/ld+json; profile="http://www.w3.org/ns/activitystreams',
|
||||
},
|
||||
json: true,
|
||||
body: payload,
|
||||
simple: false,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
|
||||
console.log(response.statusCode, response.body);
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
const nconf = require('nconf');
|
||||
|
||||
const user = require('../user');
|
||||
const user = require('../../user');
|
||||
const activitypub = require('../../activitypub');
|
||||
|
||||
const Controller = module.exports;
|
||||
@@ -103,3 +103,24 @@ Controller.postInbox = async (req, res) => {
|
||||
|
||||
res.sendStatus(201);
|
||||
};
|
||||
|
||||
/**
|
||||
* Main ActivityPub verbs
|
||||
*/
|
||||
|
||||
Controller.follow = async (req, res) => {
|
||||
await activitypub.send(req.uid, req.params.uid, {
|
||||
type: 'Follow',
|
||||
object: {
|
||||
type: 'Person',
|
||||
name: req.params.uid,
|
||||
},
|
||||
});
|
||||
|
||||
res.sendStatus(201);
|
||||
};
|
||||
|
||||
Controller.unfollow = async (req, res) => {
|
||||
console.log('got here');
|
||||
res.sendStatus(201);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@ const user = require('../../user');
|
||||
|
||||
const helpers = require('../helpers');
|
||||
|
||||
const activitypubController = require('../activitypub');
|
||||
|
||||
const Users = module.exports;
|
||||
|
||||
Users.redirectBySlug = async (req, res) => {
|
||||
@@ -92,11 +94,19 @@ Users.changePassword = async (req, res) => {
|
||||
};
|
||||
|
||||
Users.follow = async (req, res) => {
|
||||
if (req.params.uid.indexOf('@') !== -1) {
|
||||
return await activitypubController.follow(req, res);
|
||||
}
|
||||
|
||||
await api.users.follow(req, req.params);
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Users.unfollow = async (req, res) => {
|
||||
if (req.params.uid.indexOf('@') !== -1) {
|
||||
return await activitypubController.unfollow(req, res);
|
||||
}
|
||||
|
||||
await api.users.unfollow(req, req.params);
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
@@ -251,14 +251,14 @@ describe('ActivityPub integration', () => {
|
||||
const { digest } = await activitypub.sign(uid, endpoint, payload);
|
||||
const hash = createHash('sha256');
|
||||
hash.update(JSON.stringify(payload));
|
||||
const checksum = hash.digest('hex');
|
||||
const checksum = hash.digest('base64');
|
||||
|
||||
assert(digest);
|
||||
assert.strictEqual(digest, checksum);
|
||||
assert.strictEqual(digest, `sha-256=${checksum}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe.only('.verify()', () => {
|
||||
describe('.verify()', () => {
|
||||
let uid;
|
||||
let username;
|
||||
const mockReqBase = {
|
||||
|
||||
Reference in New Issue
Block a user