diff --git a/src/config.js b/src/config.js index 7dbdefe..2c2c106 100644 --- a/src/config.js +++ b/src/config.js @@ -20,8 +20,9 @@ function setupDataDirs() { module.exports = { - port: 4000, + port: process.env.PORT || 4000, host: "localhost", + token: process.env.TOKEN || "miauwkes", utcOffset: 60, diff --git a/src/serve.js b/src/serve.js index 48ce633..4dfd78b 100644 --- a/src/serve.js +++ b/src/serve.js @@ -34,9 +34,7 @@ config.setupDataDirs(); app.use(router.routes()).use(router.allowedMethods()); -const port = process.env.PORT || config.port - -app.listen(port, config.host, () => { - console.log(`Started localhost at port ${port}`) +app.listen(config.port, config.host, () => { + console.log(`Started localhost at port ${config.port}`) }); diff --git a/src/webmention/loader.js b/src/webmention/loader.js new file mode 100644 index 0000000..7a63168 --- /dev/null +++ b/src/webmention/loader.js @@ -0,0 +1,25 @@ + +const config = require("../config") +const fsp = require('fs').promises + +function validate(params) { + return params.token === config.token && + config.allowedWebmentionSources.includes(params.domain) +} + +async function load(domain) { + const fileEntries = await fsp.readdir(`data/${domain}`, { withFileTypes: true }); + console.log(fileEntries) + + const files = await Promise.all(fileEntries.map(async (file) => { + const contents = await fsp.readFile(`data/${domain}/${file.name}`, 'utf-8') + return JSON.parse(contents) + })); + + return files +} + +module.exports = { + validate, + load +} diff --git a/src/webmention/receive.js b/src/webmention/receive.js index f5ffddf..cb2596a 100644 --- a/src/webmention/receive.js +++ b/src/webmention/receive.js @@ -110,6 +110,7 @@ async function processSourceBody(body, source, target) { return } + // fiddle: https://aimee-gm.github.io/microformats-parser/ const microformat = mf2(body, { // WHY? crashes on relative URL, should be injected using Jest. Don't care. baseUrl: source.startsWith("http") ? source : `http://localhost/${source}` diff --git a/src/webmention/route.js b/src/webmention/route.js index 0a0ad8c..e2a1d9e 100644 --- a/src/webmention/route.js +++ b/src/webmention/route.js @@ -1,19 +1,34 @@ -const { validate, receive } = require('./receive') +const webmentionReceiver = require('./receive') +const webmentionLoader = require('./loader') function route(router) { router.post("webmention receive endpoint", "/webmention", async (ctx) => { - if(!validate(ctx.request)) { + if(!webmentionReceiver.validate(ctx.request)) { ctx.throw(400, "malformed webmention request") } console.log(` OK: looks like a valid webmention: \n\tsource ${ctx.request.body.source}\n\ttarget ${ctx.request.body.target}`) // we do NOT await this on purpose. - receive(ctx.request.body) + webmentionReceiver.receive(ctx.request.body) ctx.body = "Thanks, bro. Will process this webmention soon, pinky swear!"; ctx.status = 202 }); + + router.get("webmention get endpoint", "/webmention/:domain/:token", async (ctx) => { + if(!webmentionLoader.validate(ctx.params)) { + ctx.throw(403, "access denied") + } + + console.log(` OK: someone wants a list of mentions at domain ${ctx.params.domain}`) + const result = await webmentionLoader.load(ctx.params.domain) + + ctx.body = { + status: 'success', + json: result + } + }) } module.exports = { diff --git a/test/webmention/loader-load.test.js b/test/webmention/loader-load.test.js new file mode 100644 index 0000000..05923ef --- /dev/null +++ b/test/webmention/loader-load.test.js @@ -0,0 +1,45 @@ + +const { load } = require('../../src/webmention/loader') +const fs = require('fs'); +const fsp = require('fs').promises; +const { rmdir } = require('./../utils') +const dumpdir = 'data/brainbaking.com' + +const exampleWebmention = { + author: { + name: "Wouter Groeneveld", + picture: "https://brainbaking.com//img/avatar.jpg" + }, + content: "This is cool, I just found out about valid indieweb target - so cool...", + source: "https://coolness.com", + target: "https://brainbaking.com/notes/2021/03/02h17m18s46/", + published: "2021-03-06T12:41:00" +} + +const exampleWebmention2 = { + author: { + name: "Jef Klakveld" + }, + content: "Give it to me baby uhuh-uhuh white flies girls etc", + source: "https://darkness.be", + target: "https://brainbaking.com/about", + published: "2021-03-06T12:41:00" +} + +describe("webmention loading of existing json files tests", () => { + beforeEach(() => { + if(fs.existsSync(dumpdir)) { + rmdir(dumpdir) + } + fs.mkdirSync(dumpdir) + }) + + test("return an array of webmentions from domain dir", async () => { + await fsp.writeFile(`${dumpdir}/test.json`, JSON.stringify(exampleWebmention), 'utf-8') + await fsp.writeFile(`${dumpdir}/test2.json`, JSON.stringify(exampleWebmention2), 'utf-8') + + const result = await load("brainbaking.com") + expect(result.length).toBe(2) + }) + +}) \ No newline at end of file diff --git a/test/webmention/loader-validate.test.js b/test/webmention/loader-validate.test.js new file mode 100644 index 0000000..2f8c8e6 --- /dev/null +++ b/test/webmention/loader-validate.test.js @@ -0,0 +1,33 @@ + +describe("webmention loader validate tests", () => { + + const { validate } = require('../../src/webmention/loader') + const config = require('../../src/config') + + test("is invalid if token not the same", () => { + const result = validate({ + token: "drie roze olifanten hopla in de lucht", + domain: config.allowedWebmentionSources[0] + }) + + expect(result).toBe(false) + }) + + test("is invalid if domain not the list of known domains", () => { + const result = validate({ + token: config.token, + domain: "woozaas.be" + }) + + expect(result).toBe(false) + }) + + test("is valid if domain and token matching", () => { + const result = validate({ + token: config.token, + domain: config.allowedWebmentionSources[0] + }) + + expect(result).toBe(true) + }) +}) diff --git a/test/webmention/receive-validate.test.js b/test/webmention/receive-validate.test.js index 4639a99..a6556ce 100644 --- a/test/webmention/receive-validate.test.js +++ b/test/webmention/receive-validate.test.js @@ -1,5 +1,5 @@ -describe("validate tests", () => { +describe("webmention receiver validate tests", () => { const validhttpurl = "http://brainbaking.com/bla" const validhttpsurl = "https://brainbaking.com/blie"