docfast/dist/services/verification.js
OpenClaw Subagent 70eb6908e3
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Document rate limit headers in OpenAPI spec
- Add reusable header components (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After)
- Reference headers in 200 responses on all conversion and demo endpoints
- Add Retry-After header to 429 responses
- Update Rate Limits section in API description to mention response headers
- Add comprehensive tests for header documentation (21 new tests)
- All 809 tests passing
2026-03-18 11:06:22 +01:00

41 lines
1.9 KiB
JavaScript

import { randomInt, timingSafeEqual } from "crypto";
import { queryWithRetry } from "./db.js";
const CODE_EXPIRY_MS = 15 * 60 * 1000;
const MAX_ATTEMPTS = 3;
export async function createPendingVerification(email) {
await queryWithRetry("DELETE FROM pending_verifications WHERE email = $1", [email]);
const now = new Date();
const pending = {
email,
code: String(randomInt(100000, 999999)),
createdAt: now.toISOString(),
expiresAt: new Date(now.getTime() + CODE_EXPIRY_MS).toISOString(),
attempts: 0,
};
await queryWithRetry("INSERT INTO pending_verifications (email, code, created_at, expires_at, attempts) VALUES ($1, $2, $3, $4, $5)", [pending.email, pending.code, pending.createdAt, pending.expiresAt, pending.attempts]);
return pending;
}
export async function verifyCode(email, code) {
const cleanEmail = email.trim().toLowerCase();
const result = await queryWithRetry("SELECT * FROM pending_verifications WHERE email = $1", [cleanEmail]);
const pending = result.rows[0];
if (!pending)
return { status: "invalid" };
if (new Date() > new Date(pending.expires_at)) {
await queryWithRetry("DELETE FROM pending_verifications WHERE email = $1", [cleanEmail]);
return { status: "expired" };
}
if (pending.attempts >= MAX_ATTEMPTS) {
await queryWithRetry("DELETE FROM pending_verifications WHERE email = $1", [cleanEmail]);
return { status: "max_attempts" };
}
await queryWithRetry("UPDATE pending_verifications SET attempts = attempts + 1 WHERE email = $1", [cleanEmail]);
const a = Buffer.from(pending.code, "utf8");
const b = Buffer.from(code, "utf8");
const codeMatch = a.length === b.length && timingSafeEqual(a, b);
if (!codeMatch) {
return { status: "invalid" };
}
await queryWithRetry("DELETE FROM pending_verifications WHERE email = $1", [cleanEmail]);
return { status: "ok" };
}