From 2a298321104999475f640d3d6a3d14a3593580f4 Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Mon, 3 Oct 2022 22:32:46 +0200 Subject: [PATCH] Remove webfinger from activitypub --- src/claim.js | 7 +++++- src/claimDefinitions/activitypub.js | 37 ++++++++++++++++++---------- src/fetcher/activitypub.js | 38 ++++++++--------------------- src/proxy/api/v2/index.js | 3 +-- test/claimDefinitions.test.js | 3 +++ 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/claim.js b/src/claim.js index f8298e2..3580123 100644 --- a/src/claim.js +++ b/src/claim.js @@ -220,7 +220,7 @@ class Claim { // For each match for (let index = 0; index < this._matches.length; index++) { - const claimData = this._matches[index] + let claimData = this._matches[index] let verificationResult = null let proofData = null @@ -243,6 +243,11 @@ class Claim { fetcher: proofData.fetcher, viaProxy: proofData.viaProxy } + + // Post process the data + if (claimData.functions && claimData.functions.postprocess) { + ({ claimData, proofData } = claimData.functions.postprocess(claimData, proofData)) + } } else { // Consider the proof completed but with a negative result verificationResult = verificationResult || { diff --git a/src/claimDefinitions/activitypub.js b/src/claimDefinitions/activitypub.js index 8fc7d0d..c0e34f7 100644 --- a/src/claimDefinitions/activitypub.js +++ b/src/claimDefinitions/activitypub.js @@ -15,11 +15,9 @@ limitations under the License. */ const E = require('../enums') -const reURI = /^acct:(.*)@(.*)\/?/ +const reURI = /^https:\/\/(.*)\/?/ const processURI = (uri) => { - const match = uri.match(reURI) - return { serviceprovider: { type: 'web', @@ -30,7 +28,7 @@ const processURI = (uri) => { isAmbiguous: false }, profile: { - display: `${match[1]}@${match[2]}`, + display: uri, uri: uri, qr: null }, @@ -41,8 +39,7 @@ const processURI = (uri) => { access: E.ProofAccess.GENERIC, format: E.ProofFormat.JSON, data: { - username: match[1], - domain: match[2] + url: uri } } }, @@ -57,25 +54,39 @@ const processURI = (uri) => { relation: E.ClaimRelation.CONTAINS, path: ['attachment', 'value'] } - ] + ], + functions: { + postprocess: (claimData, proofData) => { + claimData.profile.display = `${proofData.result.preferredUsername}@${new URL(proofData.result.url).hostname}` + return { claimData, proofData } + } + } } } const tests = [ { - uri: 'acct:alice@domain.org', + uri: 'https://domain.org', shouldMatch: true }, { - uri: 'acct:alice', - shouldMatch: false + uri: 'https://domain.org/@/alice/', + shouldMatch: true }, { - uri: 'https://domain.org/@alice/', - shouldMatch: false + uri: 'https://domain.org/@alice', + shouldMatch: true }, { - uri: 'https://domain.org/alice', + uri: 'https://domain.org/u/alice/', + shouldMatch: true + }, + { + uri: 'https://domain.org/users/alice/', + shouldMatch: true + }, + { + uri: 'http://domain.org/alice', shouldMatch: false } ] diff --git a/src/fetcher/activitypub.js b/src/fetcher/activitypub.js index 8325e3a..a9c1719 100644 --- a/src/fetcher/activitypub.js +++ b/src/fetcher/activitypub.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ const axios = require('axios') +const validator = require('validator') const jsEnv = require('browser-or-node') /** @@ -31,10 +32,9 @@ module.exports.timeout = 5000 * @function * @async * @param {object} data - Data used in the request - * @param {string} data.username - The username of the account to verify - * @param {string} data.domain - The domain of the ActivityPub instance + * @param {string} data.url - The URL of the account to verify * @param {object} opts - Options used to enable the request - * @param {string} opts.claims.activitypub.acct - The identifier of the verifier account + * @param {string} opts.claims.activitypub.url - The URL of the verifier account * @param {string} opts.claims.activitypub.privateKey - The private key to sign the request * @returns {object} */ @@ -54,33 +54,15 @@ module.exports.fn = async (data, opts) => { const fetchPromise = new Promise((resolve, reject) => { (async () => { - if (!opts.claims.activitypub.acct.match(/acct:(.*)@(.*)/)) { - reject(new Error('ActivityPub fetcher was not set up properly')) + try { + validator.isURL(opts.claims.activitypub.url) + } catch (err) { + throw new Error(`ActivityPub fetcher was not set up properly (${err.message})`) } - const urlWebfinger = `https://${data.domain}/.well-known/webfinger?resource=acct:${data.username}@${data.domain}` - const webfinger = await axios.get(urlWebfinger, - { - headers: { Accept: 'application/json' } - }) - .then(res => { - return res.data - }) - .catch(error => { - reject(error) - }) - - let urlActivitypub = null - webfinger.links.forEach(element => { - if (element.type === 'application/activity+json') { - urlActivitypub = element.href - } - }) - // Prepare the signature - const matchAcct = opts.claims.activitypub.acct.match(/acct:(.*)@(.*)/) const now = new Date() - const { host, pathname, search } = new URL(urlActivitypub) + const { host, pathname, search } = new URL(data.url) const signedString = `(request-target): get ${pathname}${search}\nhost: ${host}\ndate: ${now.toUTCString()}` const headers = { @@ -95,10 +77,10 @@ module.exports.fn = async (data, opts) => { sign.write(signedString) sign.end() const signatureSig = sign.sign(opts.claims.activitypub.privateKey, 'base64') - headers.signature = `keyId="https://${matchAcct[2]}/${matchAcct[1]}#main-key",headers="(request-target) host date",signature="${signatureSig}",algorithm="rsa-sha256"` + headers.signature = `keyId="${opts.claims.activitypub.url}#main-key",headers="(request-target) host date",signature="${signatureSig}",algorithm="rsa-sha256"` } - axios.get(urlActivitypub, + axios.get(data.url, { headers }) diff --git a/src/proxy/api/v2/index.js b/src/proxy/api/v2/index.js index 674150f..715d27c 100644 --- a/src/proxy/api/v2/index.js +++ b/src/proxy/api/v2/index.js @@ -249,8 +249,7 @@ router.get( // ActivityPub route router.get( '/get/activitypub', - query('username').isString(), - query('domain').isFQDN(), + query('url').isURL(), async (req, res) => { const errors = validationResult(req) if (!errors.isEmpty()) { diff --git a/test/claimDefinitions.test.js b/test/claimDefinitions.test.js index e580ff0..66b78b8 100644 --- a/test/claimDefinitions.test.js +++ b/test/claimDefinitions.test.js @@ -52,6 +52,9 @@ const pattern = { claim: (x) => { return _.isObject(x) || _.isArray(x) }, + functions: (x) => { + return _.isObject(x) || _.isUndefined(x) + }, } doipjs.claimDefinitions.list.forEach((claimDefName, i) => {