changed env
All checks were successful
Build Frontend / Build Frontend (push) Successful in 23s

This commit is contained in:
2026-01-11 01:57:51 +00:00
parent 1189d49905
commit 0bd3f60627
2 changed files with 120 additions and 79 deletions

View File

@@ -74,6 +74,7 @@ export const config = {
// WebSocket // WebSocket
websocket: { websocket: {
url: process.env.WS_URL || "ws://localhost:3000/ws",
pingInterval: parseInt(process.env.WS_PING_INTERVAL, 10) || 30000, pingInterval: parseInt(process.env.WS_PING_INTERVAL, 10) || 30000,
maxPayload: parseInt(process.env.WS_MAX_PAYLOAD, 10) || 1048576, maxPayload: parseInt(process.env.WS_MAX_PAYLOAD, 10) || 1048576,
}, },

View File

@@ -5,23 +5,23 @@
* Checks your .env file for production deployment without exposing secrets * Checks your .env file for production deployment without exposing secrets
*/ */
import dotenv from 'dotenv'; import dotenv from "dotenv";
import { fileURLToPath } from 'url'; import { fileURLToPath } from "url";
import { dirname, join } from 'path'; import { dirname, join } from "path";
import { existsSync } from 'fs'; import { existsSync } from "fs";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
// Colors for terminal output // Colors for terminal output
const colors = { const colors = {
reset: '\x1b[0m', reset: "\x1b[0m",
red: '\x1b[31m', red: "\x1b[31m",
green: '\x1b[32m', green: "\x1b[32m",
yellow: '\x1b[33m', yellow: "\x1b[33m",
blue: '\x1b[34m', blue: "\x1b[34m",
magenta: '\x1b[35m', magenta: "\x1b[35m",
cyan: '\x1b[36m', cyan: "\x1b[36m",
}; };
const log = { const log = {
@@ -29,30 +29,31 @@ const log = {
success: (msg) => console.log(`${colors.green}${msg}${colors.reset}`), success: (msg) => console.log(`${colors.green}${msg}${colors.reset}`),
warning: (msg) => console.log(`${colors.yellow}⚠️ ${msg}${colors.reset}`), warning: (msg) => console.log(`${colors.yellow}⚠️ ${msg}${colors.reset}`),
info: (msg) => console.log(`${colors.blue} ${msg}${colors.reset}`), info: (msg) => console.log(`${colors.blue} ${msg}${colors.reset}`),
header: (msg) => console.log(`\n${colors.cyan}${'='.repeat(60)}${colors.reset}`), header: (msg) =>
console.log(`\n${colors.cyan}${"=".repeat(60)}${colors.reset}`),
title: (msg) => console.log(`${colors.magenta}${msg}${colors.reset}`), title: (msg) => console.log(`${colors.magenta}${msg}${colors.reset}`),
}; };
// Load environment variables // Load environment variables
const envPath = join(__dirname, '..', '.env'); const envPath = join(__dirname, "..", ".env");
const envLocalPath = join(__dirname, '..', '.env.local'); const envLocalPath = join(__dirname, "..", ".env.local");
console.clear(); console.clear();
log.header(); log.header();
log.title('🔍 Environment Configuration Validator'); log.title("🔍 Environment Configuration Validator");
log.header(); log.header();
// Check if .env files exist // Check if .env files exist
console.log('\n📁 Checking .env files...\n'); console.log("\n📁 Checking .env files...\n");
if (!existsSync(envPath)) { if (!existsSync(envPath)) {
log.error('.env file not found!'); log.error(".env file not found!");
process.exit(1); process.exit(1);
} }
log.success('.env file exists'); log.success(".env file exists");
if (existsSync(envLocalPath)) { if (existsSync(envLocalPath)) {
log.info('.env.local file exists (will override .env values)'); log.info(".env.local file exists (will override .env values)");
dotenv.config({ path: envLocalPath }); dotenv.config({ path: envLocalPath });
} }
@@ -64,7 +65,7 @@ const warnings = [];
let passedChecks = 0; let passedChecks = 0;
const totalChecks = 15; const totalChecks = 15;
console.log('\n🔍 Validating configuration...\n'); console.log("\n🔍 Validating configuration...\n");
// Helper functions // Helper functions
const checkRequired = (key, name) => { const checkRequired = (key, name) => {
@@ -83,8 +84,10 @@ const checkUrl = (key, expectedProtocol, expectedDomain) => {
return false; return false;
} }
if (value.includes('localhost') || value.includes('127.0.0.1')) { if (value.includes("localhost") || value.includes("127.0.0.1")) {
issues.push(`${key} contains localhost/127.0.0.1 - should be production domain`); issues.push(
`${key} contains localhost/127.0.0.1 - should be production domain`
);
log.error(`${key}: Uses localhost (should be ${expectedDomain})`); log.error(`${key}: Uses localhost (should be ${expectedDomain})`);
return false; return false;
} }
@@ -142,76 +145,108 @@ const checkBoolean = (key, expectedValue) => {
}; };
const maskSecret = (value) => { const maskSecret = (value) => {
if (!value || value.length < 8) return '***'; if (!value || value.length < 8) return "***";
return value.substring(0, 4) + '...' + value.substring(value.length - 4); return value.substring(0, 4) + "..." + value.substring(value.length - 4);
}; };
// Run validations // Run validations
console.log('🌐 Network Configuration:'); console.log("🌐 Network Configuration:");
checkUrl('STEAM_REALM', 'https://', 'api.turbotrades.dev'); checkUrl("STEAM_REALM", "https://", "api.turbotrades.dev");
checkUrl('STEAM_RETURN_URL', 'https://', 'api.turbotrades.dev'); checkUrl("STEAM_RETURN_URL", "https://", "api.turbotrades.dev");
checkUrl('CORS_ORIGIN', 'https://', 'turbotrades.dev'); checkUrl("CORS_ORIGIN", "https://", "turbotrades.dev");
// Check WebSocket URL (optional but recommended)
if (process.env.WS_URL) {
checkUrl("WS_URL", "wss://", "api.turbotrades.dev");
} else {
log.info("WS_URL: Not set (will use default)");
}
// Check CORS_ORIGIN is NOT the API domain // Check CORS_ORIGIN is NOT the API domain
if (process.env.CORS_ORIGIN && process.env.CORS_ORIGIN.includes('api.turbotrades.dev')) { if (
issues.push('CORS_ORIGIN should be the FRONTEND domain (turbotrades.dev), not the API domain'); process.env.CORS_ORIGIN &&
log.error('CORS_ORIGIN: Should be https://turbotrades.dev (frontend domain)'); process.env.CORS_ORIGIN.includes("api.turbotrades.dev")
log.info(' CORS_ORIGIN = where requests COME FROM (frontend)'); ) {
log.info(' STEAM_REALM = where requests GO TO (backend)'); issues.push(
} else if (process.env.CORS_ORIGIN && !process.env.CORS_ORIGIN.includes('localhost')) { "CORS_ORIGIN should be the FRONTEND domain (turbotrades.dev), not the API domain"
);
log.error("CORS_ORIGIN: Should be https://turbotrades.dev (frontend domain)");
log.info(" CORS_ORIGIN = where requests COME FROM (frontend)");
log.info(" STEAM_REALM = where requests GO TO (backend)");
} else if (
process.env.CORS_ORIGIN &&
!process.env.CORS_ORIGIN.includes("localhost")
) {
passedChecks++; passedChecks++;
} }
console.log('\n🔒 Security Configuration:'); console.log("\n🔒 Security Configuration:");
checkBoolean('COOKIE_SECURE', 'true'); checkBoolean("COOKIE_SECURE", "true");
checkValue('COOKIE_SAME_SITE', 'none', 'for cross-domain cookies'); checkValue("COOKIE_SAME_SITE", "none", "for cross-domain cookies");
checkValue('NODE_ENV', 'production', 'production environment'); checkValue("NODE_ENV", "production", "production environment");
// Check cookie domain // Check cookie domain
if (process.env.COOKIE_DOMAIN) { if (process.env.COOKIE_DOMAIN) {
if (process.env.COOKIE_DOMAIN.includes('localhost')) { if (process.env.COOKIE_DOMAIN.includes("localhost")) {
issues.push('COOKIE_DOMAIN contains localhost - should be .turbotrades.dev'); issues.push(
log.error('COOKIE_DOMAIN: Contains localhost'); "COOKIE_DOMAIN contains localhost - should be .turbotrades.dev"
} else if (process.env.COOKIE_DOMAIN === '.turbotrades.dev' || process.env.COOKIE_DOMAIN === 'turbotrades.dev') { );
log.success('COOKIE_DOMAIN: Correctly set'); log.error("COOKIE_DOMAIN: Contains localhost");
} else if (
process.env.COOKIE_DOMAIN === ".turbotrades.dev" ||
process.env.COOKIE_DOMAIN === "turbotrades.dev"
) {
log.success("COOKIE_DOMAIN: Correctly set");
passedChecks++; passedChecks++;
} else { } else {
warnings.push('COOKIE_DOMAIN might be incorrect'); warnings.push("COOKIE_DOMAIN might be incorrect");
log.warning(`COOKIE_DOMAIN: Set to "${process.env.COOKIE_DOMAIN}" (should be .turbotrades.dev)`); log.warning(
`COOKIE_DOMAIN: Set to "${process.env.COOKIE_DOMAIN}" (should be .turbotrades.dev)`
);
} }
} }
console.log('\n🔑 Required Secrets:'); console.log("\n🔑 Required Secrets:");
// Check Steam API Key // Check Steam API Key
if (checkRequired('STEAM_API_KEY', 'Steam API Key')) { if (checkRequired("STEAM_API_KEY", "Steam API Key")) {
const key = process.env.STEAM_API_KEY; const key = process.env.STEAM_API_KEY;
if (key.length === 32 && /^[A-F0-9]{32}$/i.test(key)) { if (key.length === 32 && /^[A-F0-9]{32}$/i.test(key)) {
log.success(`STEAM_API_KEY: Valid format (${maskSecret(key)})`); log.success(`STEAM_API_KEY: Valid format (${maskSecret(key)})`);
} else { } else {
warnings.push('STEAM_API_KEY format looks unusual (should be 32 hex characters)'); warnings.push(
"STEAM_API_KEY format looks unusual (should be 32 hex characters)"
);
log.warning(`STEAM_API_KEY: Unusual format (${maskSecret(key)})`); log.warning(`STEAM_API_KEY: Unusual format (${maskSecret(key)})`);
} }
} }
// Check MongoDB URI // Check MongoDB URI
if (checkRequired('MONGODB_URI', 'MongoDB connection string')) { if (checkRequired("MONGODB_URI", "MongoDB connection string")) {
const uri = process.env.MONGODB_URI; const uri = process.env.MONGODB_URI;
if (uri.includes('localhost') || uri.includes('127.0.0.1')) { if (uri.includes("localhost") || uri.includes("127.0.0.1")) {
issues.push('MONGODB_URI contains localhost - should be production database'); issues.push(
log.error('MONGODB_URI: Uses localhost (should be production database)'); "MONGODB_URI contains localhost - should be production database"
);
log.error("MONGODB_URI: Uses localhost (should be production database)");
} else { } else {
log.success('MONGODB_URI: Points to remote database'); log.success("MONGODB_URI: Points to remote database");
} }
} }
// Check JWT secrets // Check JWT secrets
console.log('\n🎫 JWT Configuration:'); console.log("\n🎫 JWT Configuration:");
['JWT_ACCESS_SECRET', 'JWT_REFRESH_SECRET', 'SESSION_SECRET'].forEach((key) => { ["JWT_ACCESS_SECRET", "JWT_REFRESH_SECRET", "SESSION_SECRET"].forEach((key) => {
if (process.env[key]) { if (process.env[key]) {
const value = process.env[key]; const value = process.env[key];
if (value.includes('your-') || value.includes('change-this') || value.length < 16) { if (
warnings.push(`${key} appears to be a default/weak value - generate a secure one!`); value.includes("your-") ||
value.includes("change-this") ||
value.length < 16
) {
warnings.push(
`${key} appears to be a default/weak value - generate a secure one!`
);
log.warning(`${key}: Using default/weak value (${maskSecret(value)})`); log.warning(`${key}: Using default/weak value (${maskSecret(value)})`);
} else { } else {
log.success(`${key}: Set (${maskSecret(value)})`); log.success(`${key}: Set (${maskSecret(value)})`);
@@ -225,13 +260,13 @@ console.log('\n🎫 JWT Configuration:');
// Summary // Summary
log.header(); log.header();
console.log('\n📊 Validation Summary:\n'); console.log("\n📊 Validation Summary:\n");
const score = Math.round((passedChecks / totalChecks) * 100); const score = Math.round((passedChecks / totalChecks) * 100);
if (issues.length === 0 && warnings.length === 0) { if (issues.length === 0 && warnings.length === 0) {
log.success(`Perfect! All checks passed (${passedChecks}/${totalChecks})`); log.success(`Perfect! All checks passed (${passedChecks}/${totalChecks})`);
log.success('Your .env file is correctly configured for production! 🎉'); log.success("Your .env file is correctly configured for production! 🎉");
process.exit(0); process.exit(0);
} }
@@ -256,40 +291,45 @@ if (warnings.length > 0) {
// Recommendations // Recommendations
if (issues.length > 0) { if (issues.length > 0) {
log.header(); log.header();
log.title('🔧 Recommended Fixes:'); log.title("🔧 Recommended Fixes:");
log.header(); log.header();
console.log('\n1. Edit your .env file:'); console.log("\n1. Edit your .env file:");
console.log(' nano .env # or vim .env\n'); console.log(" nano .env # or vim .env\n");
console.log('2. Update the following values:\n'); console.log("2. Update the following values:\n");
if (issues.some(i => i.includes('CORS_ORIGIN'))) { if (issues.some((i) => i.includes("CORS_ORIGIN"))) {
console.log(' CORS_ORIGIN=https://turbotrades.dev'); console.log(" CORS_ORIGIN=https://turbotrades.dev");
} }
if (issues.some(i => i.includes('STEAM_REALM'))) { if (issues.some((i) => i.includes("STEAM_REALM"))) {
console.log(' STEAM_REALM=https://api.turbotrades.dev'); console.log(" STEAM_REALM=https://api.turbotrades.dev");
} }
if (issues.some(i => i.includes('STEAM_RETURN_URL'))) { if (issues.some((i) => i.includes("STEAM_RETURN_URL"))) {
console.log(' STEAM_RETURN_URL=https://api.turbotrades.dev/auth/steam/return'); console.log(
" STEAM_RETURN_URL=https://api.turbotrades.dev/auth/steam/return"
);
} }
if (issues.some(i => i.includes('COOKIE_DOMAIN'))) { if (issues.some((i) => i.includes("COOKIE_DOMAIN"))) {
console.log(' COOKIE_DOMAIN=.turbotrades.dev'); console.log(" COOKIE_DOMAIN=.turbotrades.dev");
} }
if (issues.some(i => i.includes('COOKIE_SECURE'))) { if (issues.some((i) => i.includes("COOKIE_SECURE"))) {
console.log(' COOKIE_SECURE=true'); console.log(" COOKIE_SECURE=true");
} }
if (issues.some(i => i.includes('MONGODB_URI'))) { if (issues.some((i) => i.includes("MONGODB_URI"))) {
console.log(' MONGODB_URI=mongodb+srv://...(your production database)'); console.log(" MONGODB_URI=mongodb+srv://...(your production database)");
}
if (issues.some((i) => i.includes("WS_URL"))) {
console.log(" WS_URL=wss://api.turbotrades.dev/ws");
} }
console.log('\n3. Restart PM2:'); console.log("\n3. Restart PM2:");
console.log(' pm2 restart turbotrades-backend --update-env\n'); console.log(" pm2 restart turbotrades-backend --update-env\n");
log.header(); log.header();
process.exit(1); process.exit(1);
} }
if (warnings.length > 0) { if (warnings.length > 0) {
log.info('Configuration is functional but has some warnings.'); log.info("Configuration is functional but has some warnings.");
log.info('Consider addressing the warnings above for better security.'); log.info("Consider addressing the warnings above for better security.");
process.exit(0); process.exit(0);
} }