Added HTTP util: postJson(), post Accept Activity to server with signing
This commit is contained in:
parent
3a70cc6939
commit
44c67f5327
|
@ -1,4 +1,3 @@
|
|||
const { selfUrl } = require('./activitypub_util');
|
||||
const UserProps = require('./user_property');
|
||||
|
||||
module.exports = class ActivityPubSettings {
|
||||
|
|
|
@ -42,7 +42,7 @@ exports.Errors = {
|
|||
UnexpectedState: (reason, reasonCode) =>
|
||||
new EnigError('Unexpected state', -32007, reason, reasonCode),
|
||||
MissingParam: (reason, reasonCode) =>
|
||||
new EnigError('Missing paramter(s)', -32008, reason, reasonCode),
|
||||
new EnigError('Missing parameter(s)', -32008, reason, reasonCode),
|
||||
MissingMci: (reason, reasonCode) =>
|
||||
new EnigError('Missing required MCI code(s)', -32009, reason, reasonCode),
|
||||
BadLogin: (reason, reasonCode) =>
|
||||
|
@ -51,6 +51,9 @@ exports.Errors = {
|
|||
new EnigError('User interrupted', -32011, reason, reasonCode),
|
||||
NothingToDo: (reason, reasonCode) =>
|
||||
new EnigError('Nothing to do', -32012, reason, reasonCode),
|
||||
HttpError: (reason, reasonCode) =>
|
||||
new EnigError('HTTP error', -32013, reason, reasonCode),
|
||||
Timeout: (reason, reasonCode) => new EnigError('Timeout', -32014, reason, reasonCode),
|
||||
};
|
||||
|
||||
exports.ErrorReasons = {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
const { Errors } = require('./enig_error.js');
|
||||
|
||||
// deps
|
||||
const { isString, isObject } = require('lodash');
|
||||
const https = require('https');
|
||||
const httpSignature = require('http-signature');
|
||||
const crypto = require('crypto');
|
||||
|
||||
exports.postJson = postJson;
|
||||
|
||||
function postJson(url, json, options, cb) {
|
||||
if (!isString(json)) {
|
||||
json = JSON.stringify(json);
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
method: 'POST',
|
||||
body: json,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
options = Object.assign({}, defaultOptions, options);
|
||||
|
||||
if (options?.sign?.headers?.includes('digest')) {
|
||||
options.headers['Digest'] = `SHA-256=${crypto
|
||||
.createHash('sha256')
|
||||
.update(json)
|
||||
.digest('base64')}`;
|
||||
}
|
||||
|
||||
options.headers['Content-Length'] = json.length;
|
||||
|
||||
const req = https.request(url, options, res => {
|
||||
let body = [];
|
||||
res.on('data', d => {
|
||||
body.push(d);
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
body = Buffer.concat(body).toString();
|
||||
|
||||
if (res.statusCode < 200 || res.statusCode > 299) {
|
||||
return cb(Errors.HttpError(`HTTP error ${res.statusCode}: ${body}`));
|
||||
}
|
||||
|
||||
return cb(null, body, res);
|
||||
});
|
||||
});
|
||||
|
||||
if (isObject(options.sign)) {
|
||||
try {
|
||||
httpSignature.sign(req, options.sign);
|
||||
} catch (e) {
|
||||
req.destroy();
|
||||
return cb(Errors.Invalid(`Invalid signing material: ${e}`));
|
||||
}
|
||||
}
|
||||
|
||||
req.on('error', err => {
|
||||
return cb(err);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
return cb(Errors.Timeout('Timeout making HTTP request'));
|
||||
});
|
||||
|
||||
req.write(json);
|
||||
req.end();
|
||||
}
|
|
@ -4,18 +4,20 @@ const {
|
|||
getUserProfileTemplatedBody,
|
||||
DefaultProfileTemplate,
|
||||
accountFromSelfUrl,
|
||||
selfUrl,
|
||||
} = require('../../../activitypub_util');
|
||||
const Config = require('../../../config').get;
|
||||
const Activity = require('../../../activitypub_activity');
|
||||
const ActivityPubSettings = require('../../../activitypub_settings');
|
||||
const Actor = require('../../../activitypub_actor');
|
||||
const { postJson } = require('../../../http_util');
|
||||
const UserProps = require('../../../user_property');
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
const enigma_assert = require('../../../enigma_assert');
|
||||
const httpSignature = require('http-signature');
|
||||
const https = require('https');
|
||||
const { Errors } = require('../../../enig_error');
|
||||
const Actor = require('../../../activitypub_actor');
|
||||
|
||||
exports.moduleInfo = {
|
||||
name: 'ActivityPub',
|
||||
|
@ -220,12 +222,67 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
|||
return;
|
||||
}
|
||||
|
||||
// user must have a Private Key
|
||||
const privateKey = user.getProperty(UserProps.PrivateKeyMain);
|
||||
if (_.isEmpty(privateKey)) {
|
||||
// :TODO: Log me
|
||||
return;
|
||||
}
|
||||
|
||||
const accept = Activity.makeAccept(
|
||||
this.webServer,
|
||||
localActor,
|
||||
activity
|
||||
);
|
||||
console.log(accept);
|
||||
|
||||
const keyId = selfUrl(this.webServer, user) + '#main-key';
|
||||
|
||||
const reqOpts = {
|
||||
headers: {
|
||||
'Content-Type': 'application/activity+json',
|
||||
},
|
||||
sign: {
|
||||
// :TODO: Make a helper for this
|
||||
key: privateKey,
|
||||
keyId,
|
||||
authorizationHeaderName: 'Signature',
|
||||
headers: [
|
||||
'(request-target)',
|
||||
'host',
|
||||
'date',
|
||||
'digest',
|
||||
'content-type',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
postJson(
|
||||
actor.inbox,
|
||||
JSON.stringify(accept),
|
||||
reqOpts,
|
||||
(err, respBody, res) => {
|
||||
if (err) {
|
||||
return this.log.warn(
|
||||
{
|
||||
inbox: actor.inbox,
|
||||
statusCode: res.statusCode,
|
||||
error: err.message,
|
||||
},
|
||||
'Failed POSTing "Accept" to inbox'
|
||||
);
|
||||
}
|
||||
|
||||
if (res.statusCode != 202) {
|
||||
return this.log.warn(
|
||||
{
|
||||
inbox: actor.inbox,
|
||||
statusCode: res.statusCode,
|
||||
},
|
||||
'Unexpected status code'
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue