diff --git a/core/activitypub/activity.js b/core/activitypub/activity.js index 809e8dc8..c5b5dbcd 100644 --- a/core/activitypub/activity.js +++ b/core/activitypub/activity.js @@ -1,20 +1,8 @@ -const { - ActivityStreamMediaType, - WellKnownActivityTypes, - WellKnownActivity, - HttpSignatureSignHeaders, -} = require('./const'); +const { WellKnownActivityTypes, WellKnownActivity } = require('./const'); const { recipientIdsFromObject } = require('./util'); -const Endpoints = require('./endpoint'); const ActivityPubObject = require('./object'); -const { Errors } = require('../enig_error'); -const UserProps = require('../user_property'); -const { postJson } = require('../http_util'); const { getISOTimestampString } = require('../database'); -// deps -const _ = require('lodash'); - module.exports = class Activity extends ActivityPubObject { constructor(obj, withContext = ActivityPubObject.DefaultContext) { super(obj, withContext); @@ -84,32 +72,6 @@ module.exports = class Activity extends ActivityPubObject { }); } - sendTo(inboxEndpoint, fromUser, webServer, cb) { - const privateKey = fromUser.getProperty(UserProps.PrivateActivityPubSigningKey); - if (_.isEmpty(privateKey)) { - return cb( - Errors.MissingProperty( - `User "${fromUser.username}" is missing the '${UserProps.PrivateActivityPubSigningKey}' property` - ) - ); - } - - const reqOpts = { - headers: { - 'Content-Type': ActivityStreamMediaType, - }, - sign: { - key: privateKey, - keyId: Endpoints.actorId(webServer, fromUser) + '#main-key', - authorizationHeaderName: 'Signature', - headers: HttpSignatureSignHeaders, - }, - }; - - const activityJson = JSON.stringify(this); - return postJson(inboxEndpoint, activityJson, reqOpts, cb); - } - recipientIds() { return recipientIdsFromObject(this); } diff --git a/core/activitypub/actor.js b/core/activitypub/actor.js index 735dcbf6..c2d94caa 100644 --- a/core/activitypub/actor.js +++ b/core/activitypub/actor.js @@ -253,7 +253,7 @@ module.exports = class Actor extends ActivityPubObject { static _fromCache(actorIdOrSubject, cb) { apDb.get( - `SELECT rowid, actor_json, subject, timestamp, + `SELECT actor_json, subject, timestamp FROM actor_cache WHERE actor_id = ? OR subject = ? LIMIT 1;`, diff --git a/core/activitypub/object.js b/core/activitypub/object.js index 018dabca..21e4217b 100644 --- a/core/activitypub/object.js +++ b/core/activitypub/object.js @@ -1,8 +1,15 @@ -const { ActivityStreamsContext } = require('./util'); +const { + ActivityStreamsContext, + ActivityStreamMediaType, + HttpSignatureSignHeaders, +} = require('./const'); const Endpoints = require('./endpoint'); +const UserProps = require('../user_property'); +const { Errors } = require('../enig_error'); +const { postJson } = require('../http_util'); // deps -const { isString, isObject } = require('lodash'); +const { isString, isObject, isEmpty } = require('lodash'); const Context = '@context'; @@ -79,4 +86,30 @@ module.exports = class ActivityPubObject { static makeObjectId(webServer, objectType) { return Endpoints.objectId(webServer, objectType); } + + sendTo(inboxEndpoint, fromUser, webServer, cb) { + const privateKey = fromUser.getProperty(UserProps.PrivateActivityPubSigningKey); + if (isEmpty(privateKey)) { + return cb( + Errors.MissingProperty( + `User "${fromUser.username}" is missing the '${UserProps.PrivateActivityPubSigningKey}' property` + ) + ); + } + + const reqOpts = { + headers: { + 'Content-Type': ActivityStreamMediaType, + }, + sign: { + key: privateKey, + keyId: Endpoints.actorId(webServer, fromUser) + '#main-key', + authorizationHeaderName: 'Signature', + headers: HttpSignatureSignHeaders, + }, + }; + + const activityJson = JSON.stringify(this); + return postJson(inboxEndpoint, activityJson, reqOpts, cb); + } }; diff --git a/core/activitypub/util.js b/core/activitypub/util.js index 05002aa2..88e249ff 100644 --- a/core/activitypub/util.js +++ b/core/activitypub/util.js @@ -3,7 +3,9 @@ const { Errors, ErrorReasons } = require('../enig_error'); const UserProps = require('../user_property'); const ActivityPubSettings = require('./settings'); const { stripAnsiControlCodes } = require('../string_util'); -const { WellKnownRecipientFields } = require('./const'); +const { WellKnownRecipientFields, WellKnownActivity } = require('./const'); +const ActivityPubObject = require('./object'); +const Log = require('../logger').log; // deps const _ = require('lodash'); @@ -15,9 +17,6 @@ const moment = require('moment'); const { striptags } = require('striptags'); const { encode, decode } = require('html-entities'); const { isString } = require('lodash'); -const Log = require('../logger').log; - -exports.ActivityStreamsContext = 'https://www.w3.org/ns/activitystreams'; exports.parseTimestampOrNow = parseTimestampOrNow; exports.isValidLink = isValidLink; @@ -29,6 +28,7 @@ exports.htmlToMessageBody = htmlToMessageBody; exports.userNameFromSubject = userNameFromSubject; exports.extractMessageMetadata = extractMessageMetadata; exports.recipientIdsFromObject = recipientIdsFromObject; +exports.sendFollowRequest = sendFollowRequest; // :TODO: more info in default // this profile template is the *default* for both WebFinger @@ -259,3 +259,23 @@ function recipientIdsFromObject(obj) { return Array.from(new Set(ids)); } + +function sendFollowRequest(fromUser, toActor, webServer, cb) { + const fromActorId = fromUser.getProperty(UserProps.ActivityPubActorId); + if (!fromActorId) { + return cb( + Errors.MissingProperty( + `User missing "${UserProps.ActivityPubActorId}" property` + ) + ); + } + + 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); +} diff --git a/core/http_util.js b/core/http_util.js index 53654b32..d7bf57a8 100644 --- a/core/http_util.js +++ b/core/http_util.js @@ -57,7 +57,7 @@ function postJson(url, json, options, cb) { function _makeRequest(url, options, cb) { if (options.body) { - options.headers['Content-Length'] = Buffer(options.body).length; + options.headers['Content-Length'] = Buffer.from(options.body).length; if (options?.sign?.headers?.includes('digest')) { options.headers['Digest'] = diff --git a/core/scanner_tossers/activitypub.js b/core/scanner_tossers/activitypub.js index 62dee319..22d32d58 100644 --- a/core/scanner_tossers/activitypub.js +++ b/core/scanner_tossers/activitypub.js @@ -283,7 +283,7 @@ exports.getModule = class ActivityPubScannerTosser extends MessageScanTossModule } return cb(null, { - additionalTo: actor.id, + additionalTo: actor.inbox, sharedInboxes: endpoints, followers: followersEndpoint, });