Write out queue_worker for verify_inbox, plumb necessary data.
This commit is contained in:
parent
f71c7c36fc
commit
c7cfef88ae
6 changed files with 161 additions and 11 deletions
17
app.js
17
app.js
|
@ -5,9 +5,26 @@ const glob = require('glob');
|
|||
const log4js = require('log4js');
|
||||
const { match: createPathMatch } = require('path-to-regexp');
|
||||
const log = require('./lib/log');
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
(async () => {
|
||||
const app = express();
|
||||
app.use(bodyParser.json({ type: 'application/*+json',
|
||||
verify: function (req, _res, buf, _encoding) {
|
||||
req.rawBody = buf;
|
||||
}
|
||||
}));
|
||||
app.use(bodyParser.json({
|
||||
verify: function (req, _res, buf, _encoding) {
|
||||
req.rawBody = buf;
|
||||
}
|
||||
}));
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: false,
|
||||
verify: function (req, _res, buf, _encoding) {
|
||||
req.rawBody = buf;
|
||||
}
|
||||
}));
|
||||
const routes = await glob('**/*.js', {
|
||||
cwd: './routes',
|
||||
dot: true,
|
||||
|
|
75
lib/queue_worker.js
Normal file
75
lib/queue_worker.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
'use strict';
|
||||
|
||||
var db = require('./db');
|
||||
const http_agent = require('./http_agent');
|
||||
const jsonld = require('jsonld');
|
||||
var crypto = require('crypto');
|
||||
|
||||
module.exports = {
|
||||
do_one_queue: async () => {
|
||||
var result = await db('queue').orderBy('id', 'asc').limit(1);
|
||||
if ( result[0] ) {
|
||||
await db('queue').del().where('id', '=', result[0]["id"]);
|
||||
if ( result[0]["type"] === "verify_inbox" ) {
|
||||
var data = JSON.parse(result[0]["data"]);
|
||||
var sig_header = data.sig_header;
|
||||
var signature_split = sig_header.split(/,/);
|
||||
var signature_elements = {};
|
||||
signature_split.forEach((obj) => {
|
||||
signature_elements[obj.split('"')[1].split(/=/)[0]] = obj.split('"')[1].split(/=/)[1];
|
||||
});
|
||||
var keyUrl = new URL(signature_elements["keyId"]);
|
||||
var secondKeyUrl = new URL(keyUrl);
|
||||
secondKeyUrl.hash = undefined;
|
||||
var actor = (await db("object_box").where("origin", secondKeyUrl.toString()).andWhere("expires", ">=", (new Date()).getTime()))[0]["object"];
|
||||
if ( !actor ) {
|
||||
actor = http_agent.request(secondKeyUrl, {actor: data["actor"]})["data"];
|
||||
await db("object_box").insert({
|
||||
origin: secondKeyUrl.toString(),
|
||||
to: null,
|
||||
cc: null,
|
||||
object: actor,
|
||||
signedby: "fetch",
|
||||
// TODO: We should respect the caching instructions provided by origin.
|
||||
expires: (new Date()).getTime() + 604800000 // 7 days.
|
||||
});
|
||||
}
|
||||
// TODO: Should we standardize on a primary schema at some point?
|
||||
var actor_parsed = await jsonld.compact(JSON.parse(actor), ["https://www.w3.org/ns/activitystreams", { security: "https://w3id.org/security#"}]);
|
||||
var publicKey = "";
|
||||
if ( Array.isArray(actor_parsed["security:publicKey"]) ) {
|
||||
actor_parsed["security:publicKey"].forEach((value) => {
|
||||
if ( value["id"] === keyUrl.toString() ) {
|
||||
publicKey = value["security:publicKeyPem"];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
publicKey = actor_parsed["security:publicKey"]["security:publicKeyPem"];
|
||||
}
|
||||
var valid = crypto.verify("RSA-SHA256", data["body"], publicKey, signature_elements["signature"]);
|
||||
var parsedBody = await jsonld.compact(JSON.parse(data["body"]), ["https://www.w3.org/ns/activitystreams", { security: "https://w3id.org/security#"}]);
|
||||
var to = parsedBody.to;
|
||||
if ( typeof to === "string" ) {
|
||||
to = [to];
|
||||
}
|
||||
var cc = parsedBody.cc;
|
||||
if ( typeof cc === "string" ) {
|
||||
cc = [cc];
|
||||
}
|
||||
if ( valid ) {
|
||||
// TODO: We should care that the key hostname and the object hostname match.
|
||||
await db("object_box").insert({
|
||||
origin: parsedBody.id,
|
||||
to,
|
||||
cc,
|
||||
object: parsedBody,
|
||||
signedby: keyUrl.toString(),
|
||||
expires: (new Date()).getTime() + 604800000 // 7 days.
|
||||
});
|
||||
} else {
|
||||
await db("queue").insert({task: "fetch_object", data: JSON.stringify({object: parsedBody.id, actor: data["actor"]})});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
19
migrations/20230414021844_rename_inbox_to_object_box.js
Normal file
19
migrations/20230414021844_rename_inbox_to_object_box.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* 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.renameTable("inbox", "object_box");
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.renameTable("object_box", "inbox");
|
||||
};
|
54
package-lock.json
generated
54
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
|||
"version": "0.0.1",
|
||||
"license": "WTFPL",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.2",
|
||||
"express": "^4.18.2",
|
||||
"glob": "^9.3.0",
|
||||
"jsonld": "^8.1.1",
|
||||
|
@ -439,12 +440,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
|
@ -452,7 +453,7 @@
|
|||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
|
@ -1138,11 +1139,48 @@
|
|||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"node_modules/express/node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
|
@ -2522,9 +2560,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"author": "Andrew Pietila <a.pietila@protonmail.com>",
|
||||
"license": "WTFPL",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.2",
|
||||
"express": "^4.18.2",
|
||||
"glob": "^9.3.0",
|
||||
"jsonld": "^8.1.1",
|
||||
|
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||
var signature_split = req.header("signature").split(/,/);
|
||||
var signature_elements = {};
|
||||
signature_split.forEach((obj) => {
|
||||
signature_elements[obj.split(/=/)[0]] = obj.split(/=/)[1];
|
||||
signature_elements[obj.split('"')[1].split(/=/)[0]] = obj.split('"')[1].split(/=/)[1];
|
||||
});
|
||||
var headers_to_check = signature_elements["headers"].split(/ /);
|
||||
if ( headers_to_check.includes("host") && headers_to_check.includes("date") && headers_to_check.includes("digest") && headers_to_check.includes("(request-target)")) {
|
||||
|
@ -35,7 +35,7 @@ module.exports = {
|
|||
}
|
||||
}).join('\n');
|
||||
// ... then lets dump this in the queue for now.
|
||||
await db("queue").insert({task: "verify_inbox", data: JSON.stringify({sig_header: req.header("signature"), signed_block, body: req.body, date: (new Date()).toISOString()})});
|
||||
await db("queue").insert({task: "verify_inbox", data: JSON.stringify({sig_header: req.header("signature"), signed_block, body: req.rawBody.toString("UTF-8"), date: (new Date()).toISOString(), actor: `${req.hostname}@${req.hostname}`})});
|
||||
res.status(204);
|
||||
return res.end();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ module.exports = {
|
|||
if ( !take_at_face_value ) {
|
||||
// 2. If the signature is not valid, or non-existant, then we fetch the resource manually.
|
||||
var bodyParsed = await jsonld.compact(req.body, 'https://www.w3.org/ns/activitystreams');
|
||||
await db("queue").insert({task: "fetch_object", data: bodyParsed.id});
|
||||
await db("queue").insert({task: "fetch_object", data: JSON.stringify({object: bodyParsed.id, actor: `${req.hostname}@${req.hostname}`})});
|
||||
res.status(204);
|
||||
return res.end();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue