diff --git a/src/activitypub/helpers.js b/src/activitypub/helpers.js index 959c8a5419..5e86939878 100644 --- a/src/activitypub/helpers.js +++ b/src/activitypub/helpers.js @@ -4,6 +4,7 @@ const request = require('request-promise-native'); const { generateKeyPairSync } = require('crypto'); const winston = require('winston'); const nconf = require('nconf'); +const validator = require('validator'); const db = require('../database'); const ttl = require('../cache/ttl'); @@ -68,10 +69,26 @@ Helpers.generateKeys = async (uid) => { return { publicKey, privateKey }; }; -Helpers.resolveLocalUid = async (id) => { - const [slug, host] = id.split('@'); +Helpers.resolveLocalUid = async (input) => { + let slug; - if (id.indexOf('@') === -1 || host !== nconf.get('url_parsed').host) { + if (validator.isURL(input, { + require_protocol: true, + require_host: true, + require_tld: false, + protocols: ['https'], + require_valid_protocol: true, + })) { + const { host, pathname } = new URL(input); + + if (host === nconf.get('url_parsed').host) { + slug = pathname.split('/').filter(Boolean)[1]; + } else { + throw new Error('[[activitypub:invalid-id]]'); + } + } else if (input.indexOf('@') !== -1) { // Webfinger + ([slug] = input.replace(/^acct:/, '').split('@')); + } else { throw new Error('[[activitypub:invalid-id]]'); } diff --git a/test/activitypub.js b/test/activitypub.js index d59fe1cbc1..7b6748bea2 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -100,6 +100,53 @@ describe('ActivityPub integration', () => { }); }); + describe.only('Helpers', () => { + describe('.query()', () => { + + }); + + describe('.generateKeys()', () => { + + }); + + describe('.resolveLocalUid()', () => { + let uid; + let slug; + + beforeEach(async () => { + slug = slugify(utils.generateUUID().slice(0, 8)); + uid = await user.create({ username: slug }); + }); + + it('should throw when an invalid input is passed in', async () => { + await assert.rejects( + activitypub.helpers.resolveLocalUid('ncl28h3qwhoiclwnevoinw3u'), + { message: '[[activitypub:invalid-id]]' } + ); + }); + + it('should return null when valid input is passed but does not resolve', async () => { + const uid = await activitypub.helpers.resolveLocalUid(`acct:foobar@${nconf.get('url_parsed').host}`); + assert.strictEqual(uid, null); + }); + + it('should resolve to a local uid when given a webfinger-style string', async () => { + const found = await activitypub.helpers.resolveLocalUid(`acct:${slug}@${nconf.get('url_parsed').host}`); + assert.strictEqual(found, uid); + }); + + it('should resolve even without the "acct:" prefix', async () => { + const found = await activitypub.helpers.resolveLocalUid(`${slug}@${nconf.get('url_parsed').host}`); + assert.strictEqual(found, uid); + }); + + it('should resolve when passed a full URL', async () => { + const found = await activitypub.helpers.resolveLocalUid(`${nconf.get('url')}/user/${slug}`); + assert.strictEqual(found, uid); + }); + }); + }); + describe('ActivityPub screener middleware', () => { let uid; let slug;