diff --git a/package.json b/package.json index 12b8a6af..e714cce2 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "email-templates": "^6.0.0", "express": "^4.17.1", "express-jwt": "^5.3.1", - "fetch": "^1.1.0", + "http-signature": "^1.2.0", "ics": "^2.15.1", "inquirer": "^6.5.0", "jsonwebtoken": "^8.5.1", @@ -65,6 +65,7 @@ "mastodon-api": "lesion/mastodon-api", "morgan": "^1.9.1", "multer": "^1.4.2", + "node-fetch": "^2.6.0", "nuxt": "^2.8.1", "pg": "^7.11.0", "sass-loader": "^7.1.0", diff --git a/server/api/index.js b/server/api/index.js index a3f31aa3..74d5c630 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -103,12 +103,12 @@ api.get('/event/:month/:year', eventController.getAll) // Handle 404 api.use(function(req, res) { - res.send('404: Page not Found', 404) + res.status(404).send('404: Page not Found') }) // Handle 500 api.use(function(error, req, res, next) { - res.send('500: Internal Server Error', 500) + res.status(500).send('500: Internal Server Error') }) diff --git a/server/federation/helpers.js b/server/federation/helpers.js index 902727aa..e1ca6988 100644 --- a/server/federation/helpers.js +++ b/server/federation/helpers.js @@ -1,7 +1,10 @@ -const fetch = require('fetch') +const fetch = require('node-fetch') const request = require('request') const crypto = require('crypto') const config = require('config') +const httpSignature = require('http-signature') + +const actorCache = [] const Helpers = { async signAndSend(message, user, to) {//, domain, req, res, targetOrigin) { @@ -57,24 +60,38 @@ const Helpers = { } }, - // TODO: cache - // user: les@mastodon.cisti.org async getFederatedUser(address) { address = address.trim() - let [ user, host ] = address.split('@') - const url = `https://${host}/.well-known/webfinger?resource=acct:${user}@${host}` - console.error('get federated user at => ', address, url) + const [ username, host ] = address.split('@') + const url = `https://${host}/.well-known/webfinger?resource=acct:${username}@${host}` + return Helpers.getActor(url) + }, + + // TODO: cache + async getActor(url, force=false) { + // try with cache first if not forced + if (!force && actorCache[url]) return actorCache[url] const user = await fetch(url, { headers: {'Accept': 'application/jrd+json, application/json'} }) + .then(res => res.json()) + actorCache[url] = user return user }, - async verifySignature(req, res) { - console.error(req.headers['signature']) - // https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/ - const signature_header = req.headers['signature'].split(',') - .map(pair => pair.split('=')) - console.error(signature_header) - return true + // ref: https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/ + async verifySignature(req, res, next) { + let user = Helpers.getActor(req.body.actor) + + // little hack -> https://github.com/joyent/node-http-signature/pull/83 + req.headers.authorization = 'Signature ' + req.headers.signature + const parsed = httpSignature.parseRequest(req) + if (httpSignature.verifySignature(parsed, user.publicKey.publicKeyPem)) return next() + + // signature not valid, try without cache + user = Helpers.getActor(req.body.actor, true) + if (httpSignature.verifySignature(parsed, user.publicKey.publicKeyPem)) return next() + + // still not valid + res.send('Request signature could not be verified', 401) } } diff --git a/server/federation/index.js b/server/federation/index.js index 223ea6d5..f22bc64a 100644 --- a/server/federation/index.js +++ b/server/federation/index.js @@ -29,11 +29,7 @@ router.get('/m/:event_id', async (req, res) => { // get any message coming from federation // Federation is calling! -router.post('/u/:name/inbox', async (req, res) => { - - if (!Helpers.verifySignature(req, res)) { - res.send('Request signature could not be verified', 401) - } +router.post('/u/:name/inbox', Helpers.verifySignature, async (req, res) => { const b = req.body console.error('> INBOX ', b.type, b) @@ -55,28 +51,24 @@ router.post('/u/:name/inbox', async (req, res) => { } break case 'Announce': - console.error('This is a boost ?') Ego.boost(req, res) break case 'Note': console.error('This is a note ! I probably should not receive this') break case 'Like': - console.error('This is a like!') Ego.like(req, res) break case 'Delete': - console.error('Delete a comment ?!?!') + console.error('Delete ?!?!') break case 'Create': // this is a reply if (b.object.type === 'Note' && b.object.inReplyTo) { - console.error('this is a reply to an event') Comments.create(b) } else { console.error('Create what? ', b.object.type) } - break } }) diff --git a/yarn.lock b/yarn.lock index efbb9686..d8570907 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1953,13 +1953,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== -biskviit@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/biskviit/-/biskviit-1.0.1.tgz#037a0cd4b71b9e331fd90a1122de17dc49e420a7" - integrity sha1-A3oM1LcbnjMf2QoRIt4X3EnkIKc= - dependencies: - psl "^1.1.7" - bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -3688,13 +3681,6 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -encoding@0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= - dependencies: - iconv-lite "~0.4.13" - end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" @@ -4436,14 +4422,6 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fetch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fetch/-/fetch-1.1.0.tgz#0a8279f06be37f9f0ebb567560a30a480da59a2e" - integrity sha1-CoJ58Gvjf58Ou1Z1YKMKSA2lmi4= - dependencies: - biskviit "1.0.1" - encoding "0.1.12" - figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -5306,7 +5284,7 @@ http-proxy@^1.17.0: follow-redirects "^1.0.0" requires-port "^1.0.0" -http-signature@~1.2.0: +http-signature@^1.2.0, http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= @@ -5337,7 +5315,7 @@ i18n@^0.8.3: mustache "*" sprintf-js ">=1.0.3" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -8642,7 +8620,7 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.24, psl@^1.1.7: +psl@^1.1.24: version "1.2.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6" integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==