test: close remaining quality verification gaps

This commit is contained in:
hectorzhao
2026-08-28 16:27:00 +08:00
parent 3834d67a30
commit 9ac41e9308
8 changed files with 602 additions and 1 deletions
@@ -0,0 +1,122 @@
import assert from 'node:assert/strict';
import { createHash, randomUUID } from 'node:crypto';
import { createRequire } from 'node:module';
const redisUrl = process.env.AUTH_REDIS_INTEGRATION_URL;
if (!redisUrl) {
throw new Error('AUTH_REDIS_INTEGRATION_URL is required; use an isolated Redis database');
}
process.env.REDIS_URL = redisUrl;
const require = createRequire(import.meta.url);
const { SessionService } = require('../../api/dist/auth/session.service.js');
const IORedis = require('../../api/node_modules/ioredis');
const redis = new IORedis(redisUrl, { enableReadyCheck: true, maxRetriesPerRequest: 1 });
const first = new SessionService();
const second = new SessionService();
const runId = randomUUID();
const digest = (value) => createHash('sha256').update(value.trim()).digest('hex');
const keys = new Set();
function remember(...values) {
for (const value of values) keys.add(value);
}
async function ttlInRange(key, minimum, maximum) {
const ttl = await redis.ttl(key);
assert.ok(ttl >= minimum && ttl <= maximum, `${key} TTL ${ttl} is outside ${minimum}..${maximum}`);
}
try {
assert.equal(await redis.ping(), 'PONG');
const { token } = await first.create(`integration-user-${runId}`, 'client', 1);
const sessionKey = `cmpp:auth:session:${digest(token)}`;
remember(sessionKey);
const crossInstanceSession = await second.validate(token, false);
assert.equal(crossInstanceSession.status, 'active');
assert.equal(crossInstanceSession.record.userId, `integration-user-${runId}`);
const captchaId = `integration-captcha-${runId}`;
const captchaKey = `cmpp:auth:captcha:${captchaId}`;
remember(captchaKey);
await first.storeCaptcha(captchaId, '8291', 120);
assert.equal(await second.consumeCaptcha(captchaId), '8291');
assert.equal(await first.consumeCaptcha(captchaId), null);
const captchaIp = `198.51.100.${(Number.parseInt(runId.slice(0, 2), 16) % 200) + 1}`;
const captchaRateKey = `cmpp:auth:captcha-rate:ip:${digest(captchaIp)}`;
remember(captchaRateKey);
for (let index = 0; index < 30; index += 1) {
assert.equal(await (index % 2 === 0 ? first : second).assertCaptchaRequestAllowed(captchaIp), true);
}
assert.equal(await second.assertCaptchaRequestAllowed(captchaIp), false);
await ttlInRange(captchaRateKey, 1, 300);
const pairLogin = `pair-${runId}@integration.invalid`;
const pairIp = '198.51.100.210';
const accountDigest = digest(pairLogin.toLowerCase());
const ipDigest = digest(pairIp);
const pairDigest = digest(`${accountDigest}:${ipDigest}`);
const pairKeys = [
`cmpp:auth:failure:${accountDigest}`,
`cmpp:auth:failure:ip:${ipDigest}`,
`cmpp:auth:failure:pair:${pairDigest}`,
`cmpp:auth:lock:${accountDigest}`,
`cmpp:auth:lock:ip:${ipDigest}`,
`cmpp:auth:lock:pair:${pairDigest}`,
];
remember(...pairKeys);
for (let index = 0; index < 5; index += 1) {
await (index % 2 === 0 ? first : second).recordAnonymousLoginFailure(pairLogin, pairIp);
}
assert.equal(await second.anonymousLoginLockScope(pairLogin, pairIp), 'account');
await ttlInRange(pairKeys[0], 86_000, 86_400);
await ttlInRange(pairKeys[3], 86_000, 86_400);
await ttlInRange(pairKeys[2], 86_000, 86_400);
await ttlInRange(pairKeys[5], 86_000, 86_400);
const scanIp = '198.51.100.211';
const scanIpDigest = digest(scanIp);
const scanFailureKey = `cmpp:auth:failure:ip:${scanIpDigest}`;
const scanLockKey = `cmpp:auth:lock:ip:${scanIpDigest}`;
remember(scanFailureKey, scanLockKey);
for (let index = 0; index < 30; index += 1) {
const login = `scan-${runId}-${index}@integration.invalid`;
const loginDigest = digest(login.toLowerCase());
const loginPairDigest = digest(`${loginDigest}:${scanIpDigest}`);
remember(
`cmpp:auth:failure:${loginDigest}`,
`cmpp:auth:failure:pair:${loginPairDigest}`,
`cmpp:auth:lock:${loginDigest}`,
`cmpp:auth:lock:pair:${loginPairDigest}`,
);
await (index % 2 === 0 ? first : second).recordAnonymousLoginFailure(login, scanIp);
}
assert.equal(await first.anonymousLoginLockScope(`fresh-${runId}@integration.invalid`, scanIp), 'ip');
await ttlInRange(scanFailureKey, 600, 900);
await ttlInRange(scanLockKey, 600, 900);
const listedKeys = await redis.keys(`cmpp:auth:*${runId}*`);
assert.equal(listedKeys.length, 0, 'raw login/run identifiers must not appear in Redis keys');
console.log(
JSON.stringify({
status: 'passed',
sharedSession: true,
oneTimeCaptcha: true,
captchaRateLimit: true,
accountAndPairLock: true,
randomAccountIpLock: true,
ttlVerified: true,
hashedKeysOnly: true,
}),
);
} finally {
if (keys.size > 0) await redis.del(...keys);
await first.onModuleDestroy();
await second.onModuleDestroy();
redis.disconnect();
}