a414f03a59
- Configure tailscale serve automatically for each instance on Windows userspace networking. - Add local UI buttons: start/stop/reset/delete instances (stop/start preserve volumes). - Clean shutdown: stop tailscaled and instances, notify server with instance_stopped. - Restart tailscaled on agent boot using persisted state when pre-auth key is absent. - Sync instance stopped/deleted status to dashboard (server/lib/websocket.ts). - Security: include prior authz/scoping changes across API routes, ephemeral pre-auth keys, ACL policy, internal API key. - Update SUIVI_VPN_ONDEMAND.md and docs/ONBOARDING_CLIENT.md. - Bump agent version to 0.3.5.
26 lines
950 B
TypeScript
26 lines
950 B
TypeScript
import { randomBytes } from "crypto";
|
|
import { prisma } from "./prisma";
|
|
|
|
const CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
const CODE_LENGTH = 6;
|
|
const CODE_TTL_MINUTES = 60;
|
|
|
|
export function generateActivationCode(): { code: string; expiresAt: Date } {
|
|
let code = "";
|
|
const bytes = randomBytes(CODE_LENGTH);
|
|
for (let i = 0; i < CODE_LENGTH; i++) {
|
|
code += CODE_ALPHABET[bytes[i] % CODE_ALPHABET.length];
|
|
}
|
|
const expiresAt = new Date(Date.now() + CODE_TTL_MINUTES * 60 * 1000);
|
|
return { code, expiresAt };
|
|
}
|
|
|
|
export async function generateUniqueActivationCode(retries = 5): Promise<{ code: string; expiresAt: Date }> {
|
|
for (let i = 0; i < retries; i++) {
|
|
const { code, expiresAt } = generateActivationCode();
|
|
const existing = await prisma.student.findUnique({ where: { activationCode: code } });
|
|
if (!existing) return { code, expiresAt };
|
|
}
|
|
throw new Error("Failed to generate a unique activation code");
|
|
}
|