| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| const KNOWN_WEAK_SECRETS = [
|
| "omniroute-default-secret-change-me",
|
| "change-me-to-a-long-random-secret",
|
| "endpoint-proxy-api-key-secret",
|
| "change-me-storage-encryption-key",
|
| "your-secret-here",
|
| "secret",
|
| "password",
|
| "changeme",
|
| ];
|
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
|
|
| const SECRET_RULES = [
|
| {
|
| name: "JWT_SECRET",
|
| minLength: 32,
|
| required: false,
|
| description: "JWT signing secret for dashboard authentication (auto-generated if not set)",
|
| generateHint: "openssl rand -base64 48",
|
| },
|
| {
|
| name: "API_KEY_SECRET",
|
| minLength: 16,
|
| required: true,
|
| description: "HMAC secret for API key CRC generation",
|
| generateHint: "openssl rand -hex 32",
|
| },
|
| ];
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
| |
| |
| |
| |
|
|
| export function validateSecrets(env = process.env) {
|
| const errors = [];
|
| const warnings = [];
|
|
|
| for (const rule of SECRET_RULES) {
|
| const value = env[rule.name];
|
|
|
|
|
| if (!value || value.trim() === "") {
|
| if (rule.required) {
|
| errors.push({
|
| name: rule.name,
|
| issue: `Required environment variable "${rule.name}" is not set.`,
|
| hint: `Generate with: ${rule.generateHint}`,
|
| });
|
| }
|
| continue;
|
| }
|
|
|
|
|
| if (value.length < rule.minLength) {
|
| errors.push({
|
| name: rule.name,
|
| issue: `"${rule.name}" is too short (${value.length} chars, minimum ${rule.minLength}).`,
|
| hint: `Generate with: ${rule.generateHint}`,
|
| });
|
| continue;
|
| }
|
|
|
|
|
| if (KNOWN_WEAK_SECRETS.includes(value.toLowerCase())) {
|
| warnings.push({
|
| name: rule.name,
|
| issue: `"${rule.name}" appears to use a default/weak value. Please generate a strong secret.`,
|
| });
|
| }
|
| }
|
|
|
| return {
|
| valid: errors.length === 0,
|
| errors,
|
| warnings,
|
| };
|
| }
|
|
|
| |
| |
| |
| |
|
|
| export function enforceSecrets(logger = console, env = process.env) {
|
| const result = validateSecrets(env);
|
|
|
|
|
| for (const w of result.warnings) {
|
| logger.warn(`β οΈ [SECURITY] ${w.issue}`);
|
| }
|
|
|
|
|
| if (!result.valid) {
|
| logger.error("");
|
| logger.error("βββββββββββββββββββββββββββββββββββββββββββββββββββ");
|
| logger.error(" β SECURITY: Missing required secrets");
|
| logger.error("βββββββββββββββββββββββββββββββββββββββββββββββββββ");
|
| for (const e of result.errors) {
|
| logger.error(` β’ ${e.issue}`);
|
| logger.error(` β ${e.hint}`);
|
| }
|
| logger.error("");
|
| logger.error(" Set these in your .env file or environment.");
|
| logger.error(" See .env.example for reference.");
|
| logger.error("βββββββββββββββββββββββββββββββββββββββββββββββββββ");
|
| logger.error("");
|
| process.exit(1);
|
| }
|
| }
|
|
|