From 4ddf66ce54a1bd674e571f95d91cd31d7efff342 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 13 Jan 2022 14:27:26 +0100 Subject: initial commit - read-only DiscDag integration --- main.ts | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 main.ts (limited to 'main.ts') diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..d8767b0 --- /dev/null +++ b/main.ts @@ -0,0 +1,159 @@ +import { URLSearchParams } from "url"; +import express from "express"; +import cors from "cors"; +import fetch from "node-fetch"; +import cookieParser from "cookie-parser"; +import * as cheerio from "cheerio"; + +import { wrap } from "./async"; + +const PORT = 3000; +const DISCDAG_URL = 'http://solipsys.co.uk/cgi-bin/DiscDAG.py'; +const PUBLIC_URL = 'http://localhost:3000'; + +const app = express(); + +app.use(cors({ origin: 'http://localhost:8080' })); +app.use(express.json()); +app.use(cookieParser()); + +const discdag = express() + .post('/login', wrap(async ($req, $res) => { + const { username, password } = $req.body; + + const res = await fetch(DISCDAG_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + Action: 'Login', + Username: username, + Password: password, + }).toString(), + }); + + if (res.status !== 200) + throw new Error("bad response"); + + const cookies = (res.headers.get('set-cookie') ?? '').split(' '); + let digest: string | null = null; + for (const cookiestr of cookies) { + if (!cookiestr.startsWith('digest=')) continue; + + digest = cookiestr.split('=')[1]; + break; + } + + if (!digest) + throw new Error("no digest cookie"); + + const body = await res.text(); + const discussions = [...body.matchAll(/"\/cgi-bin\/DiscDAG.py\?DiscussionID=(.+?)"/g)].map(m => m[1]); + + return $res + .cookie('digest', digest) + .json({ discussions }); + })) + + .get('/user/:name', wrap(async ($req, $res) => { + const { name } = $req.params; + + return $res.json({ + '@context': 'https://www.w3.org/ns/activitystreams', + id: `${PUBLIC_URL}/discdag/user/${name}`, + type: 'User', + name, + }); + })) + + .get('/:discussion', wrap(async ($req, $res) => { + const { discussion } = $req.params; + const { digest } = $req.cookies; + + const res = await fetch(DISCDAG_URL, { + headers: { + 'Cookie': `DiscussionID=${discussion}; digest=${digest}`, + } + }); + + if (res.status !== 200) + throw new Error("bad response"); + + const doc = cheerio.load(await res.text()); + + type Note = { + type: 'Note'; + published: string; + attributedTo: string | { + id: string; + type: 'Person', + name: string; + }; + inReplyTo: string[]; + replies: string[]; + content: string; + }; + + let first = null; + const items: Record = {}; + for (const node of doc('g.node', 'svg')) { + const nodeId = doc('title', node).text(); + const [_, time, author] = nodeId.split('_'); + + const id = `${PUBLIC_URL}/discdag/${discussion}/${nodeId}`; + first = first ?? id; + + const content = doc('g:first text', node) + .slice(3) + .map(function(this: any) { return doc(this).text(); }) + .toArray() + .join(' ').trim(); + + items[id] = { + type: 'Note', + published: time.replace(/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)[a-z]+/, '$1-$2-$3T$4:$5:$6Z'), + attributedTo: `${PUBLIC_URL}/discdag/user/${author}`, + inReplyTo: [], + replies: [], + content, + }; + } + + for (const node of doc('g.edge', 'svg')) { + let [frm, to] = doc('title', node).text().split('->'); + frm = `${PUBLIC_URL}/discdag/${discussion}/${frm}`; + to = `${PUBLIC_URL}/discdag/${discussion}/${to}`; + + items[frm].replies.push(to); + items[to].inReplyTo.push(frm); + } + + return $res.json({ + '@context': [ + 'https://www.w3.org/ns/activitystreams', + { + items: { + '@id': 'as:items', + '@type': '@id', + '@container': '@id' + }, + }, + ], + id: `${PUBLIC_URL}/discdag/${discussion}`, + type: 'Document', + name: discussion, + first, + items, + }); + })); + +app.use('/discdag', discdag) + +try { + app.listen(PORT, (): void => { + console.log(`Connected successfully on port ${PORT}`); + }); +} catch (error) { + console.error(`Error occured: ${error}`); +} -- cgit v1.2.3