Add basic instance actor, along with rudimentary http signature key generation support.
This commit is contained in:
parent
fb08c1e7ec
commit
401efee7cb
4 changed files with 117 additions and 0 deletions
49
lib/keys.js
Normal file
49
lib/keys.js
Normal 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
|
||||
};
|
|
@ -1,3 +1,5 @@
|
|||
/* eslint-disable jsdoc/valid-types */
|
||||
// eslint doesn't seem to understand, but vscode does.
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
|
|
25
migrations/20230329035124_keys.js
Normal file
25
migrations/20230329035124_keys.js
Normal 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
41
routes/actor.js
Normal 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();
|
||||
});
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue