diff --git a/src/activitypub/actors.js b/src/activitypub/actors.js index fab22475c3..b6288e4a11 100644 --- a/src/activitypub/actors.js +++ b/src/activitypub/actors.js @@ -88,7 +88,7 @@ Actors.assert = async (ids, options = {}) => { return true; } - // winston.verbose(`[activitypub/actors] Asserting ${ids.length} actor(s)`); + activitypub.helpers.log(`[activitypub/actors] Asserting ${ids.length} actor(s)`); // NOTE: MAKE SURE EVERY DB ADDITION HAS A CORRESPONDING REMOVAL IN ACTORS.REMOVE! @@ -97,7 +97,7 @@ Actors.assert = async (ids, options = {}) => { const pubKeysMap = new Map(); let actors = await Promise.all(ids.map(async (id) => { try { - // winston.verbose(`[activitypub/actors] Processing ${id}`); + activitypub.helpers.log(`[activitypub/actors] Processing ${id}`); const actor = (typeof id === 'object' && id.hasOwnProperty('id')) ? id : await activitypub.get('uid', 0, id, { cache: process.env.CI === 'true' }); if ( !activitypub._constants.acceptableActorTypes.has(actor.type) || @@ -116,7 +116,7 @@ Actors.assert = async (ids, options = {}) => { actor.followingCount = following.totalItems; } catch (e) { // no action required - // winston.verbose(`[activitypub/actor.assert] Unable to retrieve follower counts for ${actor.id}`); + activitypub.helpers.log(`[activitypub/actor.assert] Unable to retrieve follower counts for ${actor.id}`); } // Save url for backreference diff --git a/src/activitypub/helpers.js b/src/activitypub/helpers.js index b54366fa4c..d2539cfee4 100644 --- a/src/activitypub/helpers.js +++ b/src/activitypub/helpers.js @@ -1,7 +1,9 @@ 'use strict'; const { generateKeyPairSync } = require('crypto'); +const process = require('process'); const nconf = require('nconf'); +const winston = require('winston'); const validator = require('validator'); const cheerio = require('cheerio'); const crypto = require('crypto'); @@ -25,6 +27,12 @@ const sha256 = payload => crypto.createHash('sha256').update(payload).digest('he const Helpers = module.exports; +Helpers.log = (message) => { + if (process.env.NODE_ENV === 'development') { + winston.verbose(message); + } +}; + Helpers.isUri = (value) => { if (typeof value !== 'string') { value = String(value); @@ -106,7 +114,7 @@ Helpers.query = async (id) => { }; Helpers.generateKeys = async (type, id) => { - // winston.verbose(`[activitypub] Generating RSA key-pair for ${type} ${id}`); + activitypub.helpers.log(`[activitypub] Generating RSA key-pair for ${type} ${id}`); const { publicKey, privateKey, diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index da75f23627..708ed12ebc 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -182,7 +182,7 @@ inbox.delete = async (req) => { // } default: { - // winston.verbose(`[activitypub/inbox.delete] Object (${object}) does not exist locally. Doing nothing.`); + activitypub.helpers.log(`[activitypub/inbox.delete] Object (${object}) does not exist locally. Doing nothing.`); break; } } @@ -479,9 +479,7 @@ inbox.undo = async (req) => { id = id || object.object; // remote announces const exists = await posts.exists(id); if (!exists) { - // winston.verbose( - // `[activitypub/inbox/undo] Attempted to undo announce of ${id} but couldn't find it, so doing nothing. - // `); + activitypub.helpers.log(`[activitypub/inbox/undo] Attempted to undo announce of ${id} but couldn't find it, so doing nothing.`); break; } diff --git a/src/activitypub/index.js b/src/activitypub/index.js index c378a2d9f9..37fb50d3b6 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -48,7 +48,7 @@ ActivityPub.actors = require('./actors'); ActivityPub.instances = require('./instances'); ActivityPub.startJobs = () => { - // winston.verbose('[activitypub/jobs] Registering jobs.'); + ActivityPub.helpers.log('[activitypub/jobs] Registering jobs.'); new CronJob('0 0 * * *', async () => { try { await ActivityPub.notes.prune(); @@ -188,9 +188,9 @@ ActivityPub.sign = async ({ key, keyId }, url, payload) => { }; ActivityPub.verify = async (req) => { - // winston.verbose('[activitypub/verify] Starting signature verification...'); + ActivityPub.helpers.log('[activitypub/verify] Starting signature verification...'); if (!req.headers.hasOwnProperty('signature')) { - // winston.verbose('[activitypub/verify] Failed, no signature header.'); + ActivityPub.helpers.log('[activitypub/verify] Failed, no signature header.'); return false; } @@ -238,17 +238,17 @@ ActivityPub.verify = async (req) => { // Verify the signature string via public key try { // Retrieve public key from remote instance - // winston.verbose(`[activitypub/verify] Retrieving pubkey for ${keyId}`); + ActivityPub.helpers.log(`[activitypub/verify] Retrieving pubkey for ${keyId}`); const { publicKeyPem } = await ActivityPub.fetchPublicKey(keyId); const verify = createVerify('sha256'); verify.update(signed_string); verify.end(); - // winston.verbose('[activitypub/verify] Attempting signed string verification'); + ActivityPub.helpers.log('[activitypub/verify] Attempting signed string verification'); const verified = verify.verify(publicKeyPem, signature, 'base64'); return verified; } catch (e) { - // winston.verbose('[activitypub/verify] Failed, key retrieval or verification failure.'); + ActivityPub.helpers.log('[activitypub/verify] Failed, key retrieval or verification failure.'); return false; } }; @@ -266,7 +266,7 @@ ActivityPub.get = async (type, id, uri, options) => { const keyData = await ActivityPub.getPrivateKey(type, id); const headers = id >= 0 ? await ActivityPub.sign(keyData, uri) : {}; - // winston.verbose(`[activitypub/get] ${uri}`); + ActivityPub.helpers.log(`[activitypub/get] ${uri}`); try { const { response, body } = await request.get(uri, { headers: { @@ -313,7 +313,7 @@ pubsub.on(`activitypub-retry-queue:lruCache:del`, (keys) => { async function sendMessage(uri, id, type, payload, attempts = 1) { const keyData = await ActivityPub.getPrivateKey(type, id); const headers = await ActivityPub.sign(keyData, uri, payload); - // winston.verbose(`[activitypub/send] ${uri}`); + ActivityPub.helpers.log(`[activitypub/send] ${uri}`); try { const { response, body } = await request.post(uri, { headers: { @@ -324,7 +324,7 @@ async function sendMessage(uri, id, type, payload, attempts = 1) { }); if (String(response.statusCode).startsWith('2')) { - // winston.verbose(`[activitypub/send] Successfully sent ${payload.type} to ${uri}`); + ActivityPub.helpers.log(`[activitypub/send] Successfully sent ${payload.type} to ${uri}`); } else { throw new Error(String(body)); } @@ -337,7 +337,7 @@ async function sendMessage(uri, id, type, payload, attempts = 1) { const timeoutId = setTimeout(() => sendMessage(uri, id, type, payload, attempts + 1), timeout); ActivityPub.retryQueue.set(queueId, timeoutId); - // winston.verbose(`[activitypub/send] Added ${payload.type} to ${uri} to retry queue for ${timeout}ms`); + ActivityPub.helpers.log(`[activitypub/send] Added ${payload.type} to ${uri} to retry queue for ${timeout}ms`); } else { winston.warn(`[activitypub/send] Max attempts reached for ${payload.type} to ${uri}; giving up on sending`); } diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 5841d68d0f..7506c43f2e 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -80,7 +80,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { members.unshift(await posts.exists(mainPid)); if (tid && members.every(Boolean)) { // All cached, return early. - // winston.verbose('[notes/assert] No new notes to process.'); + activitypub.helpers.log('[notes/assert] No new notes to process.'); unlock(id); return { tid, count: 0 }; } @@ -138,7 +138,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { return post; }).filter((p, idx) => !members[idx]); const count = unprocessed.length; - // winston.verbose(`[notes/assert] ${count} new note(s) found.`); + activitypub.helpers.log(`[notes/assert] ${count} new note(s) found.`); let tags; if (!hasTid) { @@ -399,7 +399,7 @@ Notes.syncUserInboxes = async function (tid, uid) { .filter(uid => !uids.has(parseInt(uid, 10))) .map((uid => `uid:${uid}:inbox`)); - // winston.verbose(`[activitypub/syncUserInboxes] Syncing tid ${tid} with ${uids.size} inboxes`); + activitypub.helpers.log(`[activitypub/syncUserInboxes] Syncing tid ${tid} with ${uids.size} inboxes`); await Promise.all([ db.sortedSetsRemove(removeKeys, tid), db.sortedSetsAdd(keys, keys.map(() => score || Date.now()), tid), diff --git a/src/api/activitypub.js b/src/api/activitypub.js index a303a80e04..7443ba2653 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -177,7 +177,7 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => { const allowed = await privileges.posts.can('topics:read', pid, activitypub._constants.uid); if (!allowed) { - // winston.verbose(`[activitypub/api] Not federating creation of pid ${pid} to the fediverse due to privileges.`); + activitypub.helpers.log(`[activitypub/api] Not federating creation of pid ${pid} to the fediverse due to privileges.`); return; } @@ -272,9 +272,7 @@ activitypubApi.update.note = enabledCheck(async (caller, { post }) => { const allowed = await privileges.posts.can('topics:read', post.pid, activitypub._constants.uid); if (!allowed) { - // winston.verbose( - // `[activitypub/api] Not federating update of pid ${post.pid} to the fediverse due to privileges.` - // ); + activitypub.helpers.log(`[activitypub/api] Not federating update of pid ${post.pid} to the fediverse due to privileges.`); return; } @@ -321,7 +319,7 @@ activitypubApi.delete.note = enabledCheck(async (caller, { pid }) => { const allowed = await privileges.posts.can('topics:read', pid, activitypub._constants.uid); if (!allowed) { - // winston.verbose(`[activitypub/api] Not federating update of pid ${pid} to the fediverse due to privileges.`); + activitypub.helpers.log(`[activitypub/api] Not federating update of pid ${pid} to the fediverse due to privileges.`); return; } @@ -369,7 +367,7 @@ activitypubApi.announce.note = enabledCheck(async (caller, { tid }) => { const uid = await posts.getPostField(pid, 'uid'); // author const allowed = await privileges.posts.can('topics:read', pid, activitypub._constants.uid); if (!allowed) { - // winston.verbose(`[activitypub/api] Not federating announce of pid ${pid} to the fediverse due to privileges.`); + activitypub.helpers.log(`[activitypub/api] Not federating announce of pid ${pid} to the fediverse due to privileges.`); return; } diff --git a/src/middleware/activitypub.js b/src/middleware/activitypub.js index a8812ef06c..f7183f6f36 100644 --- a/src/middleware/activitypub.js +++ b/src/middleware/activitypub.js @@ -37,7 +37,7 @@ middleware.verify = async function (req, res, next) { const verified = await activitypub.verify(req); if (!verified && req.method === 'POST') { - // winston.verbose('[middleware/activitypub] HTTP signature verification failed.'); + activitypub.helpers.log('[middleware/activitypub] HTTP signature verification failed.'); return res.sendStatus(400); } @@ -49,26 +49,26 @@ middleware.verify = async function (req, res, next) { } } - // winston.verbose('[middleware/activitypub] HTTP signature verification passed.'); + activitypub.helpers.log('[middleware/activitypub] HTTP signature verification passed.'); next(); }; middleware.assertPayload = async function (req, res, next) { // Checks the validity of the incoming payload against the sender and rejects on failure - // winston.verbose('[middleware/activitypub] Validating incoming payload...'); + activitypub.helpers.log('[middleware/activitypub] Validating incoming payload...'); // Sanity-check payload schema const required = ['id', 'type', 'actor', 'object']; if (!required.every(prop => req.body.hasOwnProperty(prop))) { - // winston.verbose('[middleware/activitypub] Request body missing required properties.'); + activitypub.helpers.log('[middleware/activitypub] Request body missing required properties.'); return res.sendStatus(400); } - // winston.verbose('[middleware/activitypub] Request body check passed.'); + activitypub.helpers.log('[middleware/activitypub] Request body check passed.'); // History check const seen = await db.isSortedSetMember('activities:datetime', req.body.id); if (seen) { - // winston.verbose(`[middleware/activitypub] Activity already seen, ignoring (${req.body.id}).`); + activitypub.helpers.log(`[middleware/activitypub] Activity already seen, ignoring (${req.body.id}).`); return res.sendStatus(200); } @@ -88,7 +88,7 @@ middleware.assertPayload = async function (req, res, next) { const { hostname } = new URL(actor); const allowed = await activitypub.instances.isAllowed(hostname); if (!allowed) { - // winston.verbose(`[middleware/activitypub] Blocked incoming activity from ${hostname}.`); + activitypub.helpers.log(`[middleware/activitypub] Blocked incoming activity from ${hostname}.`); return res.sendStatus(403); } await db.sortedSetAdd('instances:lastSeen', Date.now(), hostname); @@ -99,10 +99,10 @@ middleware.assertPayload = async function (req, res, next) { const objectHostname = new URL(object.id).hostname; // require that all actors have the same hostname as the object for now if (!actorHostnames.every(actorHostname => actorHostname === objectHostname)) { - // winston.verbose('[middleware/activitypub] Origin check failed, stripping object down to id.'); + activitypub.helpers.log('[middleware/activitypub] Origin check failed, stripping object down to id.'); req.body.object = [object.id]; } - // winston.verbose('[middleware/activitypub] Origin check passed.'); + activitypub.helpers.log('[middleware/activitypub] Origin check passed.'); } // Cross-check key ownership against received actor @@ -114,10 +114,10 @@ middleware.assertPayload = async function (req, res, next) { return [v.substring(0, index), v.slice(index + 1)]; })).get('keyId'); if (`"${compare}"` !== keyId) { - // winston.verbose('[middleware/activitypub] Key ownership cross-check failed.'); + activitypub.helpers.log('[middleware/activitypub] Key ownership cross-check failed.'); return res.sendStatus(403); } - // winston.verbose('[middleware/activitypub] Key ownership cross-check passed.'); + activitypub.helpers.log('[middleware/activitypub] Key ownership cross-check passed.'); next(); }; @@ -125,12 +125,12 @@ middleware.assertPayload = async function (req, res, next) { middleware.resolveObjects = async function (req, res, next) { const { type, object } = req.body; if (type !== 'Delete' && (typeof object === 'string' || (Array.isArray(object) && object.every(o => typeof o === 'string')))) { - // winston.verbose('[middleware/activitypub] Resolving object(s)...'); + activitypub.helpers.log('[middleware/activitypub] Resolving object(s)...'); try { req.body.object = await activitypub.helpers.resolveObjects(object); - // winston.verbose('[middleware/activitypub] Object(s) successfully resolved.'); + activitypub.helpers.log('[middleware/activitypub] Object(s) successfully resolved.'); } catch (e) { - // winston.verbose('[middleware/activitypub] Failed to resolve object(s).'); + activitypub.helpers.log('[middleware/activitypub] Failed to resolve object(s).'); return res.sendStatus(424); } }