diff --git a/core/activitypub/user_config.js b/core/activitypub/user_config.js index 882f18eb..3e207827 100644 --- a/core/activitypub/user_config.js +++ b/core/activitypub/user_config.js @@ -275,16 +275,11 @@ exports.getModule = class ActivityPubUserConfig extends MenuModule { _updateCustomViews() { const enabledToggleView = this.getView('main', MciViewIds.main.enabledToggle); - const ws = this._webServer(); const enabled = enabledToggleView.isTrue(); const formatObj = { enabled, status: enabled ? 'enabled' : 'disabled', - subject: enabled - ? ws - ? userNameToSubject(this.client.user.username, ws) - : 'N/A' - : '', + subject: enabled ? userNameToSubject(this.client.user.username) : 'N/A', }; this.updateCustomViewTextsWithFilter( diff --git a/core/activitypub/util.js b/core/activitypub/util.js index 8adfd6f0..d66d657e 100644 --- a/core/activitypub/util.js +++ b/core/activitypub/util.js @@ -5,6 +5,7 @@ const ActivityPubSettings = require('./settings'); const { stripAnsiControlCodes } = require('../string_util'); const { WellKnownRecipientFields } = require('./const'); const Log = require('../logger').log; +const { getWebDomain } = require('../web_util'); // deps const _ = require('lodash'); @@ -226,8 +227,8 @@ function userNameFromSubject(subject) { return subject.replace(/^acct:(.+)$/, '$1'); } -function userNameToSubject(userName, webServer) { - return `@${userName}@${webServer.getDomain()}`; +function userNameToSubject(userName) { + return `@${userName}@${getWebDomain()}`; } function extractMessageMetadata(body) { diff --git a/core/oputil/activitypub.js b/core/oputil/activitypub.js new file mode 100644 index 00000000..11858d5d --- /dev/null +++ b/core/oputil/activitypub.js @@ -0,0 +1,152 @@ +const { + printUsageAndSetExitCode, + ExitCodes, + argv, + initConfigAndDatabases, +} = require('./oputil_common'); +const getHelpFor = require('./oputil_help.js').getHelpFor; +const UserProps = require('../user_property'); +const { Errors } = require('../enig_error'); + +// deps +const async = require('async'); +const { get } = require('lodash'); + +exports.handleUserCommand = handleUserCommand; + +function applyAction(username, actionFunc, cb) { + initConfigAndDatabases(err => { + if (err) { + return cb(err); + } + + if (!validateActivityPub()) { + return cb(Errors.General('Activity Pub is not enabled')); + } + + if ('*' === username) { + return actionFunc(null, cb); + } else { + const User = require('../../core/user.js'); + User.getUserIdAndName(username, (err, userId) => { + if (err) { + // try user ID if number was supplied + userId = parseInt(userId); + if (isNaN(userId)) { + return cb(err); + } + } + + User.getUser(userId, (err, user) => { + if (err) { + return cb(err); + } + return actionFunc(user, cb); + }); + }); + } + }); +} + +function conditionSingleUser(User, username, userId, settings, cb) { + const { userNameToSubject } = require('../activitypub/util'); + const subject = userNameToSubject(username); + if (!subject) { + return cb(Errors.General(`Failed to get subject for ${username}`)); + } + + console.info(`Conditioning ${username} (${userId}) -> ${subject}...`); + + User.persistPropertyByUserId(userId, UserProps.ActivityPubSettings, settings, err => { + return cb(err); + }); +} + +function actionConditionAllUsers(_, cb) { + const User = require('../../core/user.js'); + const ActivityPubSettings = require('../activitypub/settings'); + const defaultSettings = JSON.stringify(new ActivityPubSettings()); + + User.getUserList({}, (err, userList) => { + if (err) { + return cb(err); + } + + async.each( + userList, + (entry, next) => { + conditionSingleUser( + User, + entry.userName, + entry.userId, + defaultSettings, + next + ); + }, + err => { + return cb(err); + } + ); + }); +} + +function actionConditionUser(user, cb) { + const User = require('../../core/user.js'); + const ActivityPubSettings = require('../activitypub/settings'); + const defaultSettings = JSON.stringify(new ActivityPubSettings()); + return conditionSingleUser(User, user.username, user.userId, defaultSettings, cb); +} + +function validateActivityPub() { + // + // Web Server, and ActivityPub both must be enabled + // + const sysConfig = require('../config').get; + const config = sysConfig(); + if ( + true !== get(config, 'contentServers.web.http.enabled') && + true !== get(config, 'contentServers.web.https.enabled') + ) { + return false; + } + + return true === get(config, 'contentServers.web.handlers.activityPub.enabled'); +} + +function conditionUser(action, username) { + return applyAction( + username, + '*' === username ? actionConditionAllUsers : actionConditionUser, + err => { + if (err) { + console.error(err.message); + } + } + ); +} + +function handleUserCommand() { + const errUsage = () => { + return printUsageAndSetExitCode(getHelpFor('ActivityPub'), ExitCodes.ERROR); + }; + + if (true === argv.help) { + return errUsage(); + } + + const action = argv._[1]; + const usernameIdx = ['condition'].includes(action) + ? argv._.length - 1 + : argv._.length; + const username = argv._[usernameIdx]; + + if (!username) { + return errUsage(); + } + + return ( + { + condition: conditionUser, + }[action] || errUsage + )(action, username); +} diff --git a/core/oputil/oputil_help.js b/core/oputil/oputil_help.js index 22ed520a..c7a17d09 100644 --- a/core/oputil/oputil_help.js +++ b/core/oputil/oputil_help.js @@ -20,6 +20,7 @@ Commands: config Configuration management fb File base management mb Message base management + ap ActivityPub management `, User: `usage: oputil.js user [] @@ -208,6 +209,12 @@ qwk-export arguments: TIMESTAMP. --no-qwke Disable QWKE extensions. --no-synchronet Disable Synchronet style extensions. +`, + ActivityPub: `usage: oputil.js ap [] +Actions: + condition USERNAME Condition user with system ActivityPub defaults + + Instead of an actual USERNAME, the '*' character may be substituted. `, }); diff --git a/core/oputil/oputil_main.js b/core/oputil/oputil_main.js index 9dcbc510..985ff837 100644 --- a/core/oputil/oputil_main.js +++ b/core/oputil/oputil_main.js @@ -10,6 +10,7 @@ const handleFileBaseCommand = require('./oputil_file_base.js').handleFileBaseCom const handleMessageBaseCommand = require('./oputil_message_base.js').handleMessageBaseCommand; const handleConfigCommand = require('./oputil_config.js').handleConfigCommand; +const handleApCommand = require('./activitypub').handleUserCommand; const getHelpFor = require('./oputil_help.js').getHelpFor; module.exports = function () { @@ -32,6 +33,8 @@ module.exports = function () { return handleFileBaseCommand(); case 'mb': return handleMessageBaseCommand(); + case 'ap': + return handleApCommand(); default: return printUsageAndSetExitCode(getHelpFor('General'), ExitCodes.BAD_COMMAND); } diff --git a/core/predefined_mci.js b/core/predefined_mci.js index 321daec3..bd4d05c2 100644 --- a/core/predefined_mci.js +++ b/core/predefined_mci.js @@ -154,7 +154,7 @@ const PREDEFINED_MCI_GENERATORS = { if (!webServer) { return 'N/A'; } - return userNameToSubject(client.user.username, webServer); + return userNameToSubject(client.user.username); }, LO: function location(client) { return userStatAsString(client, UserProps.Location, ''); diff --git a/core/servers/content/web.js b/core/servers/content/web.js index 3062689c..cf9331a6 100644 --- a/core/servers/content/web.js +++ b/core/servers/content/web.js @@ -5,6 +5,7 @@ const Config = require('../../config.js').get; const { Errors } = require('../../enig_error.js'); const { loadModulesForCategory, moduleCategories } = require('../../module_util'); const WebHandlerModule = require('../../web_handler_module'); +const { getWebDomain } = require('../../web_util'); // deps const http = require('http'); @@ -90,14 +91,7 @@ exports.getModule = class WebServerModule extends ServerModule { } getDomain() { - const config = Config(); - const overridePrefix = _.get(config, 'contentServers.web.overrideUrlPrefix'); - if (_.isString(overridePrefix)) { - const url = new URL(overridePrefix); - return url.hostname; - } - - return config.contentServers.web.domain; + return getWebDomain(); } baseUrl() { diff --git a/core/servers/content/web_handlers/nodeinfo2.js b/core/servers/content/web_handlers/nodeinfo2.js index 9adab0ef..52bdf5f1 100644 --- a/core/servers/content/web_handlers/nodeinfo2.js +++ b/core/servers/content/web_handlers/nodeinfo2.js @@ -18,7 +18,7 @@ exports.moduleInfo = { packageName: 'codes.l33t.enigma.web.handler.nodeinfo2', }; -exports.getModule = class NodeInfo2WebHadnler extends WebHandlerModule { +exports.getModule = class NodeInfo2WebHandler extends WebHandlerModule { constructor() { super(); } diff --git a/core/web_util.js b/core/web_util.js new file mode 100644 index 00000000..eb13a8eb --- /dev/null +++ b/core/web_util.js @@ -0,0 +1,17 @@ +const Config = require('./config').get; + +// deps +const { get, isString } = require('lodash'); + +exports.getWebDomain = getWebDomain; + +function getWebDomain() { + const config = Config(); + const overridePrefix = get(config, 'contentServers.web.overrideUrlPrefix'); + if (isString(overridePrefix)) { + const url = new URL(overridePrefix); + return url.hostname; + } + + return config.contentServers.web.domain; +}