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:
parent
a205445dd1
commit
0263d8bc5e
|
@ -8,6 +8,7 @@ const Collection = require('./collection');
|
||||||
const EnigAssert = require('../enigma_assert');
|
const EnigAssert = require('../enigma_assert');
|
||||||
const { sendFollowRequest, sendUnfollowRequest } = require('./follow_util');
|
const { sendFollowRequest, sendUnfollowRequest } = require('./follow_util');
|
||||||
const { getServer } = require('../listening_server');
|
const { getServer } = require('../listening_server');
|
||||||
|
const UserProps = require('../user_property');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -231,7 +232,13 @@ exports.getModule = class ActivityPubActorSearch extends MenuModule {
|
||||||
_toggleFollowStatus(cb) {
|
_toggleFollowStatus(cb) {
|
||||||
// catch early key presses
|
// catch early key presses
|
||||||
if (!this.selectedActorInfo) {
|
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;
|
this.selectedActorInfo._isFollowing = !this.selectedActorInfo._isFollowing;
|
||||||
|
|
|
@ -31,6 +31,7 @@ module.exports = class Collection extends ActivityPubObject {
|
||||||
const headers = {
|
const headers = {
|
||||||
Accept: ActivityStreamMediaType,
|
Accept: ActivityStreamMediaType,
|
||||||
};
|
};
|
||||||
|
|
||||||
getJson(
|
getJson(
|
||||||
collectionUrl,
|
collectionUrl,
|
||||||
{ headers, validContentTypes: [ActivityStreamMediaType] },
|
{ headers, validContentTypes: [ActivityStreamMediaType] },
|
||||||
|
|
|
@ -105,8 +105,7 @@ function _makeRequest(url, options, cb) {
|
||||||
try {
|
try {
|
||||||
httpSignature.sign(req, options.sign);
|
httpSignature.sign(req, options.sign);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
req.destroy();
|
req.destroy(Errors.Invalid(`Invalid signing material: ${e}`));
|
||||||
return cbWrapper(Errors.Invalid(`Invalid signing material: ${e}`));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +114,7 @@ function _makeRequest(url, options, cb) {
|
||||||
});
|
});
|
||||||
|
|
||||||
req.on('timeout', () => {
|
req.on('timeout', () => {
|
||||||
req.destroy();
|
req.destroy(Errors.Timeout('Timeout making HTTP request'));
|
||||||
return cbWrapper(Errors.Timeout('Timeout making HTTP request'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (options.body) {
|
if (options.body) {
|
||||||
|
|
|
@ -99,6 +99,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
this.webServer.addRoute({
|
this.webServer.addRoute({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: /^\/_enig\/ap\/users\/.+\/outbox(\?page=[0-9]+)?$/,
|
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) => {
|
handler: (req, resp) => {
|
||||||
return this._enforceMainKeySignatureValidity(
|
return this._enforceMainKeySignatureValidity(
|
||||||
req,
|
req,
|
||||||
|
@ -111,25 +112,13 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
this.webServer.addRoute({
|
this.webServer.addRoute({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: /^\/_enig\/ap\/users\/.+\/followers(\?page=[0-9]+)?$/,
|
path: /^\/_enig\/ap\/users\/.+\/followers(\?page=[0-9]+)?$/,
|
||||||
handler: (req, resp) => {
|
handler: this._followersGetHandler.bind(this),
|
||||||
return this._enforceMainKeySignatureValidity(
|
|
||||||
req,
|
|
||||||
resp,
|
|
||||||
this._followersGetHandler.bind(this)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.webServer.addRoute({
|
this.webServer.addRoute({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: /^\/_enig\/ap\/users\/.+\/following(\?page=[0-9]+)?$/,
|
path: /^\/_enig\/ap\/users\/.+\/following(\?page=[0-9]+)?$/,
|
||||||
handler: (req, resp) => {
|
handler: this._followingGetHandler.bind(this),
|
||||||
return this._enforceMainKeySignatureValidity(
|
|
||||||
req,
|
|
||||||
resp,
|
|
||||||
this._followingGetHandler.bind(this)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.webServer.addRoute({
|
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;
|
// 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
|
// If this is the case, they may be following multiple local Actor/users
|
||||||
// and we have multiple entries.
|
// and we have multiple entries.
|
||||||
|
const stats = {
|
||||||
|
deleted: [],
|
||||||
|
failed: [],
|
||||||
|
};
|
||||||
async.forEachSeries(
|
async.forEachSeries(
|
||||||
objectsInfo,
|
objectsInfo,
|
||||||
(objInfo, nextObjInfo) => {
|
(objInfo, nextObjInfo) => {
|
||||||
|
const collectionName = objInfo.info.name;
|
||||||
|
|
||||||
if (objInfo.object) {
|
if (objInfo.object) {
|
||||||
// Based on the collection we find this entry in,
|
// Based on the collection we find this entry in,
|
||||||
// we may have additional validation or actions
|
// we may have additional validation or actions
|
||||||
switch (objInfo.info.name) {
|
switch (collectionName) {
|
||||||
case Collections.Inbox:
|
case Collections.Inbox:
|
||||||
if (inboxType !== Collections.Inbox) {
|
case Collections.SharedInbox:
|
||||||
// :TODO: LOG ME
|
// 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);
|
return nextObjInfo(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate signature
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Collections.SharedInbox:
|
case Collections.Actors:
|
||||||
if (inboxType !== Collections.SharedInbox) {
|
// Validate signature; Delete Actor and Following entries if any
|
||||||
// :TODO: log me
|
|
||||||
return nextObjInfo(null);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Collection.Following:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -496,12 +500,15 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
return nextObjInfo(null);
|
return nextObjInfo(null);
|
||||||
} else {
|
} else {
|
||||||
// it's unparsable, so we'll delete it
|
// it's unparsable, so we'll delete it
|
||||||
Collection.removeById(objInfo.info.name, objectId, err => {
|
Collection.removeById(collectionName, objectId, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.log.warn(
|
this.log.warn(
|
||||||
{ objectId, collectionName: objInfo.info.name },
|
{ objectId, collectionName },
|
||||||
'Failed to remove object'
|
'Failed to remove object'
|
||||||
);
|
);
|
||||||
|
stats.failed.push({ collectionName, objectId });
|
||||||
|
} else {
|
||||||
|
stats.deleted.push({ collectionName, objectId });
|
||||||
}
|
}
|
||||||
return nextObjInfo(null);
|
return nextObjInfo(null);
|
||||||
});
|
});
|
||||||
|
@ -511,6 +518,8 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
if (err) {
|
if (err) {
|
||||||
// :TODO: log me
|
// :TODO: log me
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.log.info({ stats, inboxType }, 'Inbox Delete request complete');
|
||||||
return this.webServer.accepted(resp);
|
return this.webServer.accepted(resp);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -823,6 +832,8 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
_actorCollectionRequest(collectionName, req, resp) {
|
_actorCollectionRequest(collectionName, req, resp) {
|
||||||
|
this.log.debug({ url: req.url }, `Request for "${collectionName}"`);
|
||||||
|
|
||||||
const getCollection = Collection[collectionName];
|
const getCollection = Collection[collectionName];
|
||||||
if (!getCollection) {
|
if (!getCollection) {
|
||||||
return this.webServer.resourceNotFound(resp);
|
return this.webServer.resourceNotFound(resp);
|
||||||
|
@ -863,12 +874,10 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
_followingGetHandler(req, resp) {
|
_followingGetHandler(req, resp) {
|
||||||
this.log.debug({ url: req.url }, 'Request for "following"');
|
|
||||||
return this._actorCollectionRequest(Collections.Following, req, resp);
|
return this._actorCollectionRequest(Collections.Following, req, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
_followersGetHandler(req, resp) {
|
_followersGetHandler(req, resp) {
|
||||||
this.log.debug({ url: req.url }, 'Request for "followers"');
|
|
||||||
return this._actorCollectionRequest(Collections.Followers, req, resp);
|
return this._actorCollectionRequest(Collections.Followers, req, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue