import { Router, Request, Response } from "express"; import uuidv4 from "uuid/v4"; import { fetchActor, signAndSend } from "./federate"; import { Activity, Follow, Accept, Undo, Create, Note } from "./activity"; import { Database } from "sqlite3"; import { URL } from "url"; const domain = process.env.DOMAIN; export default function inbox(router: Router) { router.post("/ap/inbox", handleInbox); router.post("/inbox", handleInbox); } async function handleInbox(req: Request, res: Response) { console.log(req.body); const activity = req.body as Activity; if (activity.type === "Follow") { handleFollow(activity, req, res); } else if (activity.type === "Create") { handleCreate(activity, req, res); } else if (activity.type === "Undo") { handleUndo(activity, req, res); } else { res.end(); // TODO: handle this better } } async function handleFollow(activity: Activity, req: Request, res: Response) { if (typeof req.body.object !== "string") { res.end(); // TODO: handle this better return; } const follow = activity as Follow; if (follow.object !== `https://${domain}/ap/actor`) { res.end(); return; } const actor = await fetchActor(follow.actor); const acceptObject = { "@context": [ "https://www.w3.org/ns/activitystreams", // "https://w3id.org/security/v1" ], "id": `https://${domain}/ap/${uuidv4()}`, "type": "Accept", "actor": `https://${domain}/ap/actor`, "object": follow }; signAndSend(acceptObject, actor.inbox); const db = req.app.get("db") as Database; const serverInbox = new URL("/inbox", actor.inbox).toString(); db.run("INSERT OR IGNORE INTO followers(id, inbox) VALUES($id, $inbox)", { $id: actor.id, $inbox: serverInbox }, (err) => { if (err) console.error(`Encountered error adding follower ${follow.actor}`, err); }); res.end(); } async function handleCreate(activity: Activity, req: Request, res: Response) { const create = activity as Create; if (create.object.type == "Note") { handleCreateNote(create, req, res); } else { res.end(); } } async function handleCreateNote(create: Create, req: Request, res: Response) { const note = create.object as Note; console.log(note); } async function handleUndo(activity: Activity, req: Request, res: Response) { const undo = activity as Undo; if (undo.object.type === "Follow") { handleUndoFollow(undo, req, res); } else { res.end(); } } async function handleUndoFollow(undo: Undo, req: Request, res: Response) { const follow = undo.object as Follow; if (follow.object !== `https://${domain}/ap/actor`) { res.end(); return; } const db = req.app.get("db") as Database; db.run("DELETE FROM followers WHERE id = $id", { $id: follow.actor }, (err) => { if (err) console.error(`Error unfollowing ${follow.actor}`, err); }); res.end(); }