From a205445dd145b834ebfd1a37e70a3d6c9fafa75e Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Fri, 24 Feb 2023 22:54:19 -0700 Subject: [PATCH] Fix up message header for public AP, Undo following, some bugs around following local Actors... --- core/activitypub/actor.js | 4 ++ core/activitypub/follow_util.js | 61 ++++++++++++------- core/activitypub/util.js | 1 + core/fse.js | 26 ++++++-- core/message.js | 4 ++ .../content/web_handlers/activitypub.js | 7 ++- 6 files changed, 75 insertions(+), 28 deletions(-) diff --git a/core/activitypub/actor.js b/core/activitypub/actor.js index f5c9b88c..998aa6f5 100644 --- a/core/activitypub/actor.js +++ b/core/activitypub/actor.js @@ -176,6 +176,10 @@ module.exports = class Actor extends ActivityPubObject { } }; + if (!id) { + return cb(Errors.Invalid('Invalid Actor ID')); + } + Actor._fromCache(id, (err, actor, subject, needsRefresh) => { if (!err) { // cache hit diff --git a/core/activitypub/follow_util.js b/core/activitypub/follow_util.js index 8256ea1e..666f6a09 100644 --- a/core/activitypub/follow_util.js +++ b/core/activitypub/follow_util.js @@ -20,18 +20,19 @@ function sendFollowRequest(fromUser, toActor, webServer, cb) { // We always add to the following collection; // We expect an async follow up request to our server of // Accept or Reject but it's not guaranteed + const followRequest = new ActivityPubObject({ + id: ActivityPubObject.makeObjectId(webServer, 'follow'), + type: WellKnownActivity.Follow, + actor: fromActorId, + object: toActor.id, + }); + + toActor._followRequest = followRequest; Collection.addFollowing(fromUser, toActor, webServer, true, err => { if (err) { return cb(err); } - const followRequest = new ActivityPubObject({ - id: ActivityPubObject.makeObjectId(webServer, 'follow'), - type: WellKnownActivity.Follow, - actor: fromActorId, - object: toActor.id, - }); - return followRequest.sendTo(toActor.inbox, fromUser, webServer, cb); }); } @@ -46,19 +47,37 @@ function sendUnfollowRequest(fromUser, toActor, webServer, cb) { ); } - // Always remove from the local collection, notify the remote server - Collection.removeOwnedById(Collections.Following, fromUser, toActor.inbox, err => { - if (err) { - return cb(err); + // Fetch previously saved 'Follow'; We're going to Undo it & + // need a copy. + Collection.ownedObjectByNameAndId( + Collections.Following, + fromUser, + toActor.id, + (err, followedActor) => { + if (err) { + return cb(err); + } + + // Always remove from the local collection, notify the remote server + Collection.removeOwnedById( + Collections.Following, + fromUser, + toActor.id, + err => { + if (err) { + return cb(err); + } + + const undoRequest = new ActivityPubObject({ + id: ActivityPubObject.makeObjectId(webServer, 'undo'), + type: WellKnownActivity.Undo, + actor: fromActorId, + object: followedActor._followRequest, + }); + + return undoRequest.sendTo(toActor.inbox, fromUser, webServer, cb); + } + ); } - - const undoRequest = new ActivityPubObject({ - id: ActivityPubObject.makeObjectId(webServer, 'undo'), - type: WellKnownActivity.Undo, - actor: fromActorId, - object: toActor.id, - }); - - return undoRequest.sendTo(toActor.inbox, fromUser, webServer, cb); - }); + ); } diff --git a/core/activitypub/util.js b/core/activitypub/util.js index 0f6564bb..8adfd6f0 100644 --- a/core/activitypub/util.js +++ b/core/activitypub/util.js @@ -17,6 +17,7 @@ const { encode, decode } = require('html-entities'); const { isString } = require('lodash'); const { stripHtml } = require('string-strip-html'); +exports.getActorId = o => o.actor?.id || o.actor; exports.parseTimestampOrNow = parseTimestampOrNow; exports.isValidLink = isValidLink; exports.userFromActorId = userFromActorId; diff --git a/core/fse.js b/core/fse.js index fceb7fac..ad7149d8 100644 --- a/core/fse.js +++ b/core/fse.js @@ -37,7 +37,7 @@ const moment = require('moment'); const fse = require('fs-extra'); const fs = require('graceful-fs'); const paths = require('path'); -const sanatizeFilename = require('sanitize-filename'); +const sanitizeFilename = require('sanitize-filename'); const { ErrorReasons } = require('./enig_error.js'); exports.moduleInfo = { @@ -350,7 +350,7 @@ exports.FullScreenEditorModule = return { // :TODO: ensure we show real names for form/to if they are enforced in the area fromUserName: this.message.fromUserName, - toUserName: this.message.toUserName, + toUserName: this._viewModeToField(), // :TODO: //fromRealName //toRealName @@ -1108,6 +1108,24 @@ exports.FullScreenEditorModule = this.setViewText('header', id, text); } + _viewModeToField() { + // Imported messages may have no explicit 'to' on various public forums + if (this.message.toUserName) { + return this.message.toUserName; + } + + const toRemoteUser = _.get(this.message, 'meta.System.remote_to_user'); + if (toRemoteUser) { + return toRemoteUser; + } + + if (this.message.isPublic()) { + return '(Public)'; + } + + this.menuConfig.config.remoteUserNotAvail || 'N/A'; + } + initHeaderViewMode() { // Only set header text for from view if it is on the form if ( @@ -1115,7 +1133,7 @@ exports.FullScreenEditorModule = ) { this.setHeaderText(MciViewIds.header.from, this.message.fromUserName); } - this.setHeaderText(MciViewIds.header.to, this.message.toUserName); + this.setHeaderText(MciViewIds.header.to, this._viewModeToField()); this.setHeaderText(MciViewIds.header.subject, this.message.subject); this.setHeaderText( @@ -1199,7 +1217,7 @@ exports.FullScreenEditorModule = const outputFileName = paths.join( sysTempDownloadDir, - sanatizeFilename( + sanitizeFilename( `(${msgInfo.messageId}) ${ msgInfo.subject }_(${this.message.modTimestamp.format('YYYY-MM-DD')}).txt` diff --git a/core/message.js b/core/message.js index 31b5621b..c35a08f3 100644 --- a/core/message.js +++ b/core/message.js @@ -91,6 +91,10 @@ module.exports = class Message { return Message.isPrivateAreaTag(this.areaTag); } + isPublic() { + return !this.isPrivate(); + } + isFromRemoteUser() { return null !== this.getRemoteFromUser(); } diff --git a/core/servers/content/web_handlers/activitypub.js b/core/servers/content/web_handlers/activitypub.js index ce8af721..c153a47b 100644 --- a/core/servers/content/web_handlers/activitypub.js +++ b/core/servers/content/web_handlers/activitypub.js @@ -3,6 +3,7 @@ const { userFromActorId, getUserProfileTemplatedBody, DefaultProfileTemplate, + getActorId, } = require('../../../activitypub/util'); const Endpoints = require('../../../activitypub/endpoint'); const { @@ -257,7 +258,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule { } // Fetch and validate the signature of the remote Actor - Actor.fromId(activity.actor, (err, remoteActor) => { + Actor.fromId(getActorId(activity), (err, remoteActor) => { if (err) { return this.webServer.internalServerError(resp, err); } @@ -318,7 +319,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule { activity ); } else { - this.log.warn(`Unsupported Undo for type "${type}`); + this.log.warn(`Unsupported Undo for type "${type}"`); } } break; @@ -920,7 +921,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule { const accept = Activity.makeAccept( this.webServer, - localActor, + localActor.id, requestActivity );