Add basic instance actor, along with rudimentary http signature key generation support.

This commit is contained in:
Andrew Pietila 2023-03-28 23:32:02 -05:00
parent fb08c1e7ec
commit 401efee7cb
4 changed files with 117 additions and 0 deletions

49
lib/keys.js Normal file
View file

@ -0,0 +1,49 @@
'use strict';
const crypto = require('crypto');
const db = require('./db');
var generateKeyPair = (type, options) => {
return new Promise((res, rej) => {
crypto.generateKeyPair(type, options, (err, pubkey, privkey) => {
if ( err != null ) {
rej(err);
} else {
res({publicKey: pubkey, privateKey: privkey});
}
});
});
};
var getKeyPair = async (actor) => {
var result = await db('keys').where({actor}).andWhere('expiry', '>', (new Date()).getTime()/1000);
if ( result.length != 0 ) {
return {
publicKey: result[0].public,
privateKey: result[0].private
};
} else {
var {publicKey, privateKey} = await generateKeyPair('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
format: 'pem'
},
privateKeyEncoding: {
format: 'pem'
}
});
await db('keys').insert({
expiry: (new Date().setDate(new Date().getDate()+7).getTime()/1000),
public: publicKey,
private: privateKey,
actor: actor
});
return {
publicKey, privateKey
};
}
};
module.exports = {
getKeyPair
};

View file

@ -1,3 +1,5 @@
/* eslint-disable jsdoc/valid-types */
// eslint doesn't seem to understand, but vscode does.
'use strict';
/**

View file

@ -0,0 +1,25 @@
/* eslint-disable jsdoc/valid-types */
// eslint doesn't seem to understand, but vscode does.
'use strict';
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function(knex) {
return knex.schema.createTable('keys', (table) => {
table.increments('id');
table.integer('expiry');
table.string('private');
table.string('public');
table.text('actor');
});
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function(knex) {
return knex.schema.dropTable('keys');
};

41
routes/actor.js Normal file
View file

@ -0,0 +1,41 @@
'use strict';
const express = require('express');
const { getKeyPair } = require('../lib/keys');
module.exports = {
/**
* @param {express.IRoute} routeObj
*/
route: (routeObj) => {
routeObj.get((req, res, _next) => {
res.setHeader('content-type', 'application/activity+json');
res.json({
'@context': [
'https://www.w3.org/ns/activitystreams',
{
security: 'https://w3id.org/security#'
}
],
'id': `https://${req.hostname}/actor`,
'type': 'Application',
'inbox': `https://${req.hostname}/actor/inbox`,
'security:publicKey': {
'id': `https://${req.hostname}/actor#main-key`,
'security:owner': {
id: `https://${req.hostname}/actor`
},
'security:publicKeyPem': getKeyPair(`https://${req.hostname}/actor`)
},
'endpoints': {
sharedInbox: `https://${req.hostname}/inbox`
},
'as:manuallyApprovesFollowers': true,
'outbox': `https://${req.hostname}/actor/outbox`,
'preferredUsername': '${req.hostname}',
'url': `https://${req.hostname}/about/more?instance_actor=true`
});
return res.end();
});
}
};