Een dating-app op basis van brieven, niet van gezichten!

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

2.7 kB Ruw bestand
import { LETTERS_PER_HOUR, LETTERS_PER_DAY, NEW_ACCOUNT_HOURS, NEW_ACCOUNT_LETTERS } from "../src/constants.js";
import { inWords } from "./ratelimit.js";

/*
 * Wat één account per tijdseenheid kan schrijven — de eerste tranche sybil-kosten.
 *
 * De grootste dreiging voor een briefapp is niet de vervelende gebruiker (daar is melden voor) maar
 * de verkoper die zich als dater voordoet, en het script dat hetzelfde doet zonder te typen. Beide
 * hebben massa nodig. Deze grenzen maken massa duur en vragen daarvoor geen enkel nieuw
 * persoonsgegeven: er wordt alleen geteld wat er al ligt.
 *
 * Drie grenzen, van streng naar ruim: de eerste dag maar een paar brieven (een nieuw account is het
 * goedkoopste dat er is, dus is het ook het minst waard), daarna LETTERS_PER_HOUR per uur en
 * LETTERS_PER_DAY per etmaal.
 *
 * Wat dit met opzet níet doet: straffen, of een melding aanmaken. Wie hiertegenaan loopt is meestal
 * gewoon ijverig; het antwoord is een wachttijd, geen dossier.
 */

/* Seconden tot `from` + `windowHours` — het moment waarop er echt weer een plek vrij is */
const untilSec = (from, windowHours) => (new Date(from).getTime() + windowHours * 3600_000 - Date.now()) / 1000;

/*
 * Mag deze gebruiker nu een brief versturen? `quota` komt van db.letterQuota():
 * { createdAt, hour: { count, oldest }, day: { count, oldest } }.
 * Geeft null als het mag, anders { error, retryAfterSec } — de wachttijd is telkens het echte
 * moment waarop het weer kan, zodat het antwoord klopt in plaats van alleen afhoudt.
 */
export function letterDenial({ createdAt, hour, day }) {
  /*
   * Startdrempel. Voor een account jonger dan een etmaal is day.count meteen het totaal aantal
   * verstuurde brieven — daarom moet NEW_ACCOUNT_HOURS 24 of minder blijven (zie src/constants.js).
   */
  const ageHours = (Date.now() - new Date(createdAt).getTime()) / 3600_000;
  if (ageHours < NEW_ACCOUNT_HOURS && day.count >= NEW_ACCOUNT_LETTERS) {
    const sec = untilSec(createdAt, NEW_ACCOUNT_HOURS);
    return {
      retryAfterSec: sec,
      error: `Een nieuw account kan de eerste dag ${NEW_ACCOUNT_LETTERS} brieven versturen. Je kunt ${inWords(sec)} weer verder, en daarna vervalt deze grens.`,
    };
  }
  if (hour.count >= LETTERS_PER_HOUR) {
    const sec = untilSec(hour.oldest, 1);
    return {
      retryAfterSec: sec,
      error: `Je hebt het afgelopen uur ${LETTERS_PER_HOUR} brieven verstuurd. Je kunt ${inWords(sec)} weer verder.`,
    };
  }
  if (day.count >= LETTERS_PER_DAY) {
    const sec = untilSec(day.oldest, 24);
    return {
      retryAfterSec: sec,
      error: `Je hebt in een dag ${LETTERS_PER_DAY} brieven verstuurd — dat is genoeg voor één dag schrijven. Je kunt ${inWords(sec)} weer verder.`,
    };
  }
  return null;
}