mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 22:03:13 -06:00
The flap-limiter could 30-min quarantine a PAIRED, legitimate device on reconnect churn.
Behind Bold's single SNAT IP a repeated edge flush -> every device reconnects -> trips flap
-> quarantined -> a recoverable blip becomes a SUSTAINED FLEET-WIDE LOCKOUT we caused.
check(key, now, {paired}) now skips (and clears) the quarantine escalation for a paired
device — it still gets the brief soft cooldown if it truly hammers, but never the long
lockout. The register gate computes paired = device_id && validateDeviceToken(...) (a
matching STORED token, false for missing/mismatch) so a spoofed device_id can't claim the
exemption; unpaired/anon flapping (attacker / unprovisioned hammering) still quarantines.
Tests: unpaired flapper still quarantined; paired never quarantined (soft cooldown only);
paired creds RELEASE an in-flight quarantine; N paired devices from one SNAT IP all admitted
on reconnect and never quarantined across repeated flush cycles.
67 lines
3.4 KiB
JavaScript
67 lines
3.4 KiB
JavaScript
'use strict';
|
|
|
|
// #148 Item 1 — paired + authenticated devices are exempt from the flap-limiter's 30-min
|
|
// QUARANTINE (a self-inflicted fleet-wide lockout behind one SNAT IP), while unpaired/anon
|
|
// flapping is still quarantined. Fast, deterministic: env shrinks the thresholds and we
|
|
// drive `now` explicitly instead of waiting.
|
|
|
|
const os = require('node:os'); const path = require('node:path'); const crypto = require('node:crypto');
|
|
process.env.DATA_DIR = path.join(os.tmpdir(), 'st-flapx-' + crypto.randomBytes(4).toString('hex'));
|
|
process.env.CONNECT_RATE_MAX = '2';
|
|
process.env.CONNECT_RATE_COOLDOWN_MS = '10';
|
|
process.env.CONNECT_RATE_QUARANTINE_TRIPS = '2';
|
|
process.env.CONNECT_RATE_WINDOW_MS = '100000';
|
|
|
|
const { test, beforeEach } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const flap = require('../lib/flap-limiter');
|
|
|
|
beforeEach(() => flap.reset());
|
|
|
|
// Drive one "trip": exceed max within the window at time `now` (max=2 → 3 checks trips).
|
|
function tripAt(key, now, paired) { let v; for (let i = 0; i < 3; i++) v = flap.check(key, now, { paired }); return v; }
|
|
|
|
test('unpaired flapper IS quarantined after the trip threshold', () => {
|
|
const k = 'attacker';
|
|
assert.equal(tripAt(k, 0, false).tripped, true); // trip 1
|
|
const v = tripAt(k, 11, false); // trip 2 (past cooldown) → quarantine
|
|
assert.equal(v.quarantined, true, 'unpaired escalates to quarantine');
|
|
const q = flap.check(k, 12, { paired: false });
|
|
assert.equal(q.allow, false); assert.equal(q.reason, 'quarantined');
|
|
});
|
|
|
|
test('PAIRED device is NEVER quarantined — soft cooldown at most', () => {
|
|
const k = 'paired-device';
|
|
tripAt(k, 0, true);
|
|
const v = tripAt(k, 11, true); // would quarantine an unpaired
|
|
assert.notEqual(v.reason, 'quarantined');
|
|
assert.notEqual(v.quarantined, true, 'paired never escalates to the long lockout');
|
|
// hammer for a long time — still never quarantined
|
|
for (let t = 22; t < 5000; t += 11) {
|
|
const r = tripAt(k, t, true);
|
|
assert.notEqual(r.reason, 'quarantined', `t=${t} paired must not be quarantined`);
|
|
}
|
|
});
|
|
|
|
test('presenting paired creds RELEASES an in-flight quarantine', () => {
|
|
const k = 'dev-x';
|
|
tripAt(k, 0, false); tripAt(k, 11, false); // quarantine it as unpaired
|
|
assert.equal(flap.check(k, 12, { paired: false }).reason, 'quarantined');
|
|
const released = flap.check(k, 13, { paired: true }); // now authenticated/paired
|
|
assert.notEqual(released.reason, 'quarantined', 'quarantine released for a now-authenticated device (soft cooldown at most)');
|
|
assert.equal(flap.check(k, 100, { paired: true }).allow, true, 'admitted once the brief soft cooldown passes');
|
|
});
|
|
|
|
test('SNAT: N paired devices from one IP all admitted on reconnect; repeated cycles never quarantine', () => {
|
|
const N = 50;
|
|
// A single flush → each device reconnects once (its own device_id key) → all admitted.
|
|
for (let d = 0; d < N; d++) assert.equal(flap.check('device-' + d, 1000, { paired: true }).allow, true);
|
|
// Repeated flush cycles → a paired device may hit the soft cooldown but is NEVER quarantined.
|
|
for (let cycle = 0; cycle < 10; cycle++) {
|
|
for (let d = 0; d < N; d++) {
|
|
const v = flap.check('device-' + d, 2000 + cycle * 5, { paired: true });
|
|
assert.notEqual(v.reason, 'quarantined', `device ${d} cycle ${cycle} must not be quarantined`);
|
|
}
|
|
}
|
|
});
|