91 lines · 3.0 KB
import PostalMime from "postal-mime";
import {
  abuseForwardAddress,
  guessAbuseCategory,
  recordAbuseReport,
  siteIdForUrl,
} from "./abuse";

const MAX_RAW_BYTES = 2 * 1024 * 1024;
const MAX_TARGETS = 10;
const URL_PATTERN = /\bhttps?:\/\/[^\s<>"'()]+/gi;
const TRAILING_PUNCTUATION = /[.,;:!?\]]+$/;

/** URLs mentioned in the mail, hosted sites first so a long signature can't push the reported page out. */
export async function extractReportTargets(
  text: string,
): Promise<{ hosted: string[]; other: string[] }> {
  const seen = new Set<string>();
  const hosted: string[] = [];
  const other: string[] = [];
  for (const match of text.matchAll(URL_PATTERN)) {
    const url = match[0].replace(TRAILING_PUNCTUATION, "");
    if (seen.has(url) || seen.size >= MAX_TARGETS * 4) continue;
    seen.add(url);
    if (hosted.length < MAX_TARGETS && (await siteIdForUrl(url)))
      hosted.push(url);
    else if (other.length < MAX_TARGETS) other.push(url);
  }
  return { hosted, other };
}

async function readRaw(
  stream: ReadableStream<Uint8Array>,
): Promise<Uint8Array> {
  const reader = stream.getReader();
  const chunks: Uint8Array[] = [];
  let size = 0;
  while (size < MAX_RAW_BYTES) {
    const { done, value } = await reader.read();
    if (done) break;