aboutsummaryrefslogtreecommitdiffstats
path: root/main.ts
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2022-01-13 13:27:26 +0000
committers-ol <s+removethis@s-ol.nu>2022-01-13 13:32:06 +0000
commit4ddf66ce54a1bd674e571f95d91cd31d7efff342 (patch)
treeb8ed1b22aa6b4924d100581146dd4c6903e39151 /main.ts
downloadfedidag-4ddf66ce54a1bd674e571f95d91cd31d7efff342.tar.gz
fedidag-4ddf66ce54a1bd674e571f95d91cd31d7efff342.zip
initial commit - read-only DiscDag integration
Diffstat (limited to 'main.ts')
-rw-r--r--main.ts159
1 files changed, 159 insertions, 0 deletions
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<string, Note> = {};
+ 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}`);
+}