From 36e21fcf7d3a40d6a232e489316545f3aae82c0a Mon Sep 17 00:00:00 2001 From: garrettmills Date: Mon, 20 Jan 2025 21:12:47 -0500 Subject: [PATCH] Implement support for mailbox filtering + start http server --- README.md | 39 ++++++++++++++++++++++++++++++--------- src/config.ts | 6 ++++++ src/http/server.ts | 11 +++++++++++ src/mail/read.ts | 6 ++++++ src/types.ts | 6 ++++++ 5 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 src/http/server.ts diff --git a/README.md b/README.md index 48e84a7..24a6707 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,36 @@ # `chorus`: Email-based comments -To install dependencies: +This is a system for adding comments to arbitrary sites like a blog. Rather than requiring users to have an account +with your blog or a 3rd-party comments platform, it uses email. -```bash -bun install -``` +## Features -To run: +- Works with any mail server that supports arbitrary mailbox aliases (e.g. `user+alias@example.com`) +- Writes out comments as static JSON files so they can be served by your webserver of choice +- Handles arbitrarily deep replies to comments +- Threads generate UUIDs and don't need to pre-register with Chorus +- **WIP** DKIM verification for incoming mail +- Optionally, only include comments that have been moderated/approved by the admin -```bash -bun run index.ts -``` +## Principles -This project was created using `bun init` in bun v1.1.42. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. +1. Email, as a federated and decentralized communication protocol, is good. +2. Independent blogs and websites that do not rely on a large 3rd-party platform are good. +3. Users should not have to create an account with every individual website to participate in a discussion thread. +4. Individual threads should not have to pre-register with the comment server. + +## How It Works + + + +## Configuration + +Configuration is handled via environment variables: + +- `CHORUS_IMAP_HOST` +- `CHORUS_IMAP_PORT` 993 +- `CHORUS_IMAP_USER` +- `CHORUS_IMAP_PASS` +- `CHORUS_THREAD_TEMPLATE` +- `CHORUS_DATA_DIR` chorus-data +- `CHORUS_MAILBOX` diff --git a/src/config.ts b/src/config.ts index a340483..3c02eea 100644 --- a/src/config.ts +++ b/src/config.ts @@ -10,6 +10,7 @@ const maybeConfig: any = { user: process.env.CHORUS_IMAP_USER, pass: process.env.CHORUS_IMAP_PASS, }, + mailbox: process.env.CHORUS_MAILBOX, }, threads: { type: 'alias', @@ -21,6 +22,11 @@ const maybeConfig: any = { dirs: { data: process.env.CHORUS_DATA_DIR || 'chorus-data', }, + http: { + enabled: process.env.CHORUS_HTTP_ENABLE === 'true', + address: process.env.CHORUS_HTTP_ADDRESS || '0.0.0.0', + port: process.env.CHORUS_HTTP_PORT || 8101, + }, } export const config: CommentsConfig = castCommentsConfig(maybeConfig) diff --git a/src/http/server.ts b/src/http/server.ts new file mode 100644 index 0000000..bbcd84f --- /dev/null +++ b/src/http/server.ts @@ -0,0 +1,11 @@ +import {config} from "../config.ts"; + +export async function runHttpServer() { + Bun.serve({ + hostname: config.http.address, + port: config.http.port, + fetch: async request => { + + }, + }) +} diff --git a/src/mail/read.ts b/src/mail/read.ts index 361b81c..7cd8169 100644 --- a/src/mail/read.ts +++ b/src/mail/read.ts @@ -13,6 +13,12 @@ import {htmlReplyPipeline} from "./sanitize.ts"; import {blake2bHex, blake2sHex} from "blakejs"; export async function getMailboxesToSearch(thread?: string, client?: ImapFlow): Promise> { + // If the config indicates a specific mailbox to search, use that: + if ( config.mail.imap.mailbox ) { + return collect([config.mail.imap.mailbox]) + } + + // Otherwise, search all plausible mailboxes automatically. // There are 2 possibilities for where mail might end up. // Either the mail-server is configured to forward the + extensions // to their own folders automatically (e.g. the "c.1234" folder), or diff --git a/src/types.ts b/src/types.ts index 3dc28f4..4bfabd7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,7 @@ const commentsConfigSchema = z.object({ user: z.string(), pass: z.string(), }), + mailbox: z.string().optional(), }), threads: z.object({ type: z.string(), // fixme : in validation @@ -20,6 +21,11 @@ const commentsConfigSchema = z.object({ dirs: z.object({ data: z.string(), }), + http: z.object({ + enabled: z.boolean().optional(), + address: z.string(), + port: z.number(), + }), }) export type CommentsConfig = z.infer