Various fixes:

* Fix socket hangup bug in http_util requests
* Disallow users to follow themselves
* GET's to /followers, /following, etc. are not signed; don't try to enforce it
* Fix a couple callbacks
* WIP: Start more on Delete of inbox items
This commit is contained in:
Bryan Ashby 2023-02-25 11:50:30 -07:00
parent a205445dd1
commit 0263d8bc5e
No known key found for this signature in database
GPG Key ID: C2C1B501E4EFD994
4 changed files with 46 additions and 31 deletions

View File

@ -8,6 +8,7 @@ const Collection = require('./collection');
const EnigAssert = require('../enigma_assert');
const { sendFollowRequest, sendUnfollowRequest } = require('./follow_util');
const { getServer } = require('../listening_server');
const UserProps = require('../user_property');
// deps
const async = require('async');
@ -231,7 +232,13 @@ exports.getModule = class ActivityPubActorSearch extends MenuModule {
_toggleFollowStatus(cb) {
// catch early key presses
if (!this.selectedActorInfo) {
return;
return cb(Errors.UnexpectedState('No Actor selected'));
}
// Don't allow users to follow themselves
const currentActorId = this.client.user.getProperty(UserProps.ActivityPubActorId);
if (currentActorId === this.selectedActorInfo.id) {
return cb(Errors.Invalid('You cannot follow yourself!'));
}
this.selectedActorInfo._isFollowing = !this.selectedActorInfo._isFollowing;

View File

@ -31,6 +31,7 @@ module.exports = class Collection extends ActivityPubObject {
const headers = {
Accept: ActivityStreamMediaType,
};
getJson(
collectionUrl,
{ headers, validContentTypes: [ActivityStreamMediaType] },

View File

@ -105,8 +105,7 @@ function _makeRequest(url, options, cb) {
try {
httpSignature.sign(req, options.sign);
} catch (e) {
req.destroy();
return cbWrapper(Errors.Invalid(`Invalid signing material: ${e}`));
req.destroy(Errors.Invalid(`Invalid signing material: ${e}`));
}
}
@ -115,8 +114,7 @@ function _makeRequest(url, options, cb) {
});
req.on('timeout', () => {
req.destroy();
return cbWrapper(Errors.Timeout('Timeout making HTTP request'));
req.destroy(Errors.Timeout('Timeout making HTTP request'));
});
if (options.body) {

View File

@ -99,6 +99,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
this.webServer.addRoute({
method: 'GET',
path: /^\/_enig\/ap\/users\/.+\/outbox(\?page=[0-9]+)?$/,
// :TODO: fix me: What are we exposing to the outbox? Should be public only; GET's don't have signatures
handler: (req, resp) => {
return this._enforceMainKeySignatureValidity(
req,
@ -111,25 +112,13 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
this.webServer.addRoute({
method: 'GET',
path: /^\/_enig\/ap\/users\/.+\/followers(\?page=[0-9]+)?$/,
handler: (req, resp) => {
return this._enforceMainKeySignatureValidity(
req,
resp,
this._followersGetHandler.bind(this)
);
},
handler: this._followersGetHandler.bind(this),
});
this.webServer.addRoute({
method: 'GET',
path: /^\/_enig\/ap\/users\/.+\/following(\?page=[0-9]+)?$/,
handler: (req, resp) => {
return this._enforceMainKeySignatureValidity(
req,
resp,
this._followingGetHandler.bind(this)
);
},
handler: this._followingGetHandler.bind(this),
});
this.webServer.addRoute({
@ -469,26 +458,41 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
// possible for example, that we're being asked to delete an Actor;
// If this is the case, they may be following multiple local Actor/users
// and we have multiple entries.
const stats = {
deleted: [],
failed: [],
};
async.forEachSeries(
objectsInfo,
(objInfo, nextObjInfo) => {
const collectionName = objInfo.info.name;
if (objInfo.object) {
// Based on the collection we find this entry in,
// we may have additional validation or actions
switch (objInfo.info.name) {
switch (collectionName) {
case Collections.Inbox:
if (inboxType !== Collections.Inbox) {
// :TODO: LOG ME
case Collections.SharedInbox:
// Validate the inbox this was sent to
if (inboxType !== collectionName) {
this.log.warn(
{ inboxType, collectionName, objectId },
'Will not Delete object(s) from mismatched collection!'
);
return nextObjInfo(null);
}
// Validate signature
break;
case Collections.SharedInbox:
if (inboxType !== Collections.SharedInbox) {
// :TODO: log me
return nextObjInfo(null);
}
case Collections.Actors:
// Validate signature; Delete Actor and Following entries if any
break;
case Collection.Following:
break;
default:
break;
}
@ -496,12 +500,15 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
return nextObjInfo(null);
} else {
// it's unparsable, so we'll delete it
Collection.removeById(objInfo.info.name, objectId, err => {
Collection.removeById(collectionName, objectId, err => {
if (err) {
this.log.warn(
{ objectId, collectionName: objInfo.info.name },
{ objectId, collectionName },
'Failed to remove object'
);
stats.failed.push({ collectionName, objectId });
} else {
stats.deleted.push({ collectionName, objectId });
}
return nextObjInfo(null);
});
@ -511,6 +518,8 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
if (err) {
// :TODO: log me
}
this.log.info({ stats, inboxType }, 'Inbox Delete request complete');
return this.webServer.accepted(resp);
}
);
@ -823,6 +832,8 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
}
_actorCollectionRequest(collectionName, req, resp) {
this.log.debug({ url: req.url }, `Request for "${collectionName}"`);
const getCollection = Collection[collectionName];
if (!getCollection) {
return this.webServer.resourceNotFound(resp);
@ -863,12 +874,10 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
}
_followingGetHandler(req, resp) {
this.log.debug({ url: req.url }, 'Request for "following"');
return this._actorCollectionRequest(Collections.Following, req, resp);
}
_followersGetHandler(req, resp) {
this.log.debug({ url: req.url }, 'Request for "followers"');
return this._actorCollectionRequest(Collections.Followers, req, resp);
}