93 lines · 4.1 KB
import { fileURLToPath, URL as NodeURL } from "node:url";
import { SMTPServer, type SMTPServerDataStream, type SMTPServerSession } from "smtp-server";
import { printFlame } from "../banner.ts";
import { loadEnvFile } from "../env-file.ts";
import { createDiscordAdapter } from "../adapters/discord/index.ts";
import { buildCommandConfig } from "../adapters/discord/config.ts";
import { createAddress, deleteExpiredAndRevoked, deleteStaleRateLimits } from "../core/db.ts";
import { createDispatcher } from "../core/dispatch.ts";
import { handleInboundEmail } from "../core/email.ts";
import type { SqlExecutor } from "../core/storage.ts";
import type { MailAdapter, OwnerRef } from "../core/types.ts";
import { createSqliteExecutor, openSqliteDatabase } from "../storage/sqlite.ts";
import { scheduleCleanup } from "./cleanup-schedule.ts";
import { loadNodeHostConfig } from "./config.ts";
import { startHttpServer } from "./http-server.ts";

const CLEANUP_GRACE_SECONDS = 24 * 60 * 60;
const STALE_RATE_LIMIT_SECONDS = 30 * 24 * 60 * 60;

function buildAdapters(adapters: string[], discordToken: string): MailAdapter[] {
  const list: MailAdapter[] = [];
  if (adapters.includes("discord")) {
    list.push(createDiscordAdapter(discordToken));
  }
  return list;
}

function startSmtpServer(config: ReturnType<typeof loadNodeHostConfig>, db: SqlExecutor, dispatcher: ReturnType<typeof createDispatcher>) {
  const server = new SMTPServer({
    disabledCommands: ["AUTH", "STARTTLS"],
    onRcptTo(address, _session, callback) {
      const domain = address.address.split("@")[1]?.toLowerCase();
      if (domain !== config.disposableDomain.toLowerCase()) {
        return callback(new Error("550 No such mailbox here"));
      }
      callback();
    },
    onData(stream: SMTPServerDataStream, session: SMTPServerSession, callback) {
      const chunks: Buffer[] = [];
      stream.on("data", (chunk: Buffer) => chunks.push(chunk));