Remove webfinger from activitypub

This commit is contained in:
Yarmo Mackenbach 2022-10-03 22:32:46 +02:00
parent 1710195211
commit 2a29832110
No known key found for this signature in database
GPG key ID: 37367F4AF4087AD1
5 changed files with 44 additions and 44 deletions

View file

@ -220,7 +220,7 @@ class Claim {
// For each match // For each match
for (let index = 0; index < this._matches.length; index++) { for (let index = 0; index < this._matches.length; index++) {
const claimData = this._matches[index] let claimData = this._matches[index]
let verificationResult = null let verificationResult = null
let proofData = null let proofData = null
@ -243,6 +243,11 @@ class Claim {
fetcher: proofData.fetcher, fetcher: proofData.fetcher,
viaProxy: proofData.viaProxy viaProxy: proofData.viaProxy
} }
// Post process the data
if (claimData.functions && claimData.functions.postprocess) {
({ claimData, proofData } = claimData.functions.postprocess(claimData, proofData))
}
} else { } else {
// Consider the proof completed but with a negative result // Consider the proof completed but with a negative result
verificationResult = verificationResult || { verificationResult = verificationResult || {

View file

@ -15,11 +15,9 @@ limitations under the License.
*/ */
const E = require('../enums') const E = require('../enums')
const reURI = /^acct:(.*)@(.*)\/?/ const reURI = /^https:\/\/(.*)\/?/
const processURI = (uri) => { const processURI = (uri) => {
const match = uri.match(reURI)
return { return {
serviceprovider: { serviceprovider: {
type: 'web', type: 'web',
@ -30,7 +28,7 @@ const processURI = (uri) => {
isAmbiguous: false isAmbiguous: false
}, },
profile: { profile: {
display: `${match[1]}@${match[2]}`, display: uri,
uri: uri, uri: uri,
qr: null qr: null
}, },
@ -41,8 +39,7 @@ const processURI = (uri) => {
access: E.ProofAccess.GENERIC, access: E.ProofAccess.GENERIC,
format: E.ProofFormat.JSON, format: E.ProofFormat.JSON,
data: { data: {
username: match[1], url: uri
domain: match[2]
} }
} }
}, },
@ -57,25 +54,39 @@ const processURI = (uri) => {
relation: E.ClaimRelation.CONTAINS, relation: E.ClaimRelation.CONTAINS,
path: ['attachment', 'value'] path: ['attachment', 'value']
} }
] ],
functions: {
postprocess: (claimData, proofData) => {
claimData.profile.display = `${proofData.result.preferredUsername}@${new URL(proofData.result.url).hostname}`
return { claimData, proofData }
}
}
} }
} }
const tests = [ const tests = [
{ {
uri: 'acct:alice@domain.org', uri: 'https://domain.org',
shouldMatch: true shouldMatch: true
}, },
{ {
uri: 'acct:alice', uri: 'https://domain.org/@/alice/',
shouldMatch: false shouldMatch: true
}, },
{ {
uri: 'https://domain.org/@alice/', uri: 'https://domain.org/@alice',
shouldMatch: false 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 shouldMatch: false
} }
] ]

View file

@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios') const axios = require('axios')
const validator = require('validator')
const jsEnv = require('browser-or-node') const jsEnv = require('browser-or-node')
/** /**
@ -31,10 +32,9 @@ module.exports.timeout = 5000
* @function * @function
* @async * @async
* @param {object} data - Data used in the request * @param {object} data - Data used in the request
* @param {string} data.username - The username of the account to verify * @param {string} data.url - The URL of the account to verify
* @param {string} data.domain - The domain of the ActivityPub instance
* @param {object} opts - Options used to enable the request * @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 * @param {string} opts.claims.activitypub.privateKey - The private key to sign the request
* @returns {object} * @returns {object}
*/ */
@ -54,33 +54,15 @@ module.exports.fn = async (data, opts) => {
const fetchPromise = new Promise((resolve, reject) => { const fetchPromise = new Promise((resolve, reject) => {
(async () => { (async () => {
if (!opts.claims.activitypub.acct.match(/acct:(.*)@(.*)/)) { try {
reject(new Error('ActivityPub fetcher was not set up properly')) 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 // Prepare the signature
const matchAcct = opts.claims.activitypub.acct.match(/acct:(.*)@(.*)/)
const now = new Date() 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 signedString = `(request-target): get ${pathname}${search}\nhost: ${host}\ndate: ${now.toUTCString()}`
const headers = { const headers = {
@ -95,10 +77,10 @@ module.exports.fn = async (data, opts) => {
sign.write(signedString) sign.write(signedString)
sign.end() sign.end()
const signatureSig = sign.sign(opts.claims.activitypub.privateKey, 'base64') 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 headers
}) })

View file

@ -249,8 +249,7 @@ router.get(
// ActivityPub route // ActivityPub route
router.get( router.get(
'/get/activitypub', '/get/activitypub',
query('username').isString(), query('url').isURL(),
query('domain').isFQDN(),
async (req, res) => { async (req, res) => {
const errors = validationResult(req) const errors = validationResult(req)
if (!errors.isEmpty()) { if (!errors.isEmpty()) {

View file

@ -52,6 +52,9 @@ const pattern = {
claim: (x) => { claim: (x) => {
return _.isObject(x) || _.isArray(x) return _.isObject(x) || _.isArray(x)
}, },
functions: (x) => {
return _.isObject(x) || _.isUndefined(x)
},
} }
doipjs.claimDefinitions.list.forEach((claimDefName, i) => { doipjs.claimDefinitions.list.forEach((claimDefName, i) => {