Sign-up deny list beside the allow list
fraud-allow.json says "never block this person". There was nothing for the opposite case. fraud-block.json: an address on it cannot open an account through /api/signup or the email-code door, and the admin fraud report carries the list with a matching /api/admin/fraud/block route. Existing accounts are untouched; Suspend covers those. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -1214,6 +1214,7 @@ const server = http.createServer(async (req, res) => {
|
||||
// out only at purchase / payout-activation time and gets linked then)
|
||||
if (p === '/api/signup' && req.method === 'POST') {
|
||||
const b = await readBody(req);
|
||||
if (fraud.isBlocked(b.email)) return json(res, 403, { error: 'This address cannot open an account.' });
|
||||
const ref = parseCookies(req)['iap.sponsor'] || ''; // last-touch attribution, locked at account creation
|
||||
const r = await accounts.signup(b.email, b.password, ref);
|
||||
if (r.error) return json(res, 400, r);
|
||||
@@ -1239,6 +1240,7 @@ const server = http.createServer(async (req, res) => {
|
||||
const e = String(b.email || '').trim().toLowerCase();
|
||||
const devHdr = fraud.deviceOf(req) ? undefined : { 'Set-Cookie': fraud.deviceCookie(fraud.newDeviceId(), IS_PROD) }; // browser id for one-account-per-person checks
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(e)) return json(res, 400, { error: 'That email address does not look right.' });
|
||||
if (fraud.isBlocked(e)) return json(res, 403, { error: 'This address cannot open an account.' });
|
||||
const prev = emailCodes.get(e);
|
||||
if (prev && Date.now() < prev.nextAt) { console.log('signup-guard cooldown', clientIp(req), e.replace(/^(.).*(@.*)$/, '$1***$2')); return json(res, 429, { error: 'Code already sent. Give it a minute, then try again.' }, devHdr); }
|
||||
const guard = codeGuard(req, b); // honeypot, form age, per-IP + global limits, icon check once limited
|
||||
@@ -2817,11 +2819,16 @@ const server = http.createServer(async (req, res) => {
|
||||
}
|
||||
if (p === '/api/admin/fraud' && req.method === 'GET') { // duplicate signals: shared browsers / IPs, flagged and suspended accounts
|
||||
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });
|
||||
return json(res, 200, Object.assign(await fraud.report(), { allow: fraud.allowList() }));
|
||||
return json(res, 200, Object.assign(await fraud.report(), { allow: fraud.allowList(), block: fraud.blockList() }));
|
||||
}
|
||||
// Approved exceptions: people Marty has okayed to hold more than one account. Adding an
|
||||
// address here stops the duplicate checks blocking or hard-flagging them, and stops them
|
||||
// being dropped from the leaderboard or barred from adopting.
|
||||
if (p === '/api/admin/fraud/block' && req.method === 'POST') {
|
||||
const b = await readBody(req);
|
||||
const r = b.remove ? fraud.blockRemove(b.email) : fraud.blockAdd(b.email, b.note, ADMIN_EMAIL || 'admin');
|
||||
return json(res, r.error ? 400 : 200, r);
|
||||
}
|
||||
if (p === '/api/admin/fraud/allow' && req.method === 'POST') {
|
||||
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });
|
||||
const b = await readBody(req);
|
||||
|
||||
Reference in New Issue
Block a user