Een dating-app op basis van brieven, niet van gezichten!
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
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;
}