Extract backend runtime configuration

This commit is contained in:
Cauê Faleiros
2026-05-29 10:22:41 -03:00
parent aa59e642af
commit c512809a38
7 changed files with 95 additions and 153 deletions

13
backend/config/cors.js Normal file
View File

@@ -0,0 +1,13 @@
const cors = require('cors');
const createCorsMiddleware = ({ allowedOrigins, isProduction }) => cors({
origin: (origin, callback) => {
if (!origin || !isProduction || allowedOrigins.includes(origin)) {
return callback(null, true);
}
return callback(new Error('Origem não permitida pelo CORS.'));
},
credentials: true
});
module.exports = { createCorsMiddleware };

50
backend/config/runtime.js Normal file
View File

@@ -0,0 +1,50 @@
const { stripEnvQuotes } = require('../utils/security');
const isProduction = process.env.NODE_ENV === 'production';
const port = process.env.PORT || 3001;
const jwtSecret = process.env.JWT_SECRET || (isProduction ? null : 'fasto_dev_secret_change_me');
if (!jwtSecret) {
throw new Error('JWT_SECRET is required in production.');
}
const allowedOrigins = (process.env.CORS_ORIGIN || '')
.split(',')
.map(origin => origin.trim())
.filter(Boolean);
const smtp = {
host: process.env.SMTP_HOST || 'mail.blyzer.com.br',
port: parseInt(process.env.SMTP_PORT, 10) || 587,
user: stripEnvQuotes(process.env.SMTP_USER || 'nao-responda@blyzer.com.br'),
pass: stripEnvQuotes(process.env.SMTP_PASS || ''),
debug: process.env.SMTP_DEBUG === 'true',
};
const getBaseUrl = (req) => {
if (process.env.APP_URL) return process.env.APP_URL;
const host = req ? (req.get('host') || 'localhost:3001') : 'localhost:3001';
const protocol = (req && (req.protocol === 'https' || req.get('x-forwarded-proto') === 'https')) ? 'https' : 'http';
if (isProduction && !host.includes('localhost')) {
return `https://${host}`;
}
return `${protocol}://${host}`;
};
const getStartupBaseUrl = () => {
if (process.env.APP_URL) return process.env.APP_URL;
if (isProduction) return 'https://fasto.blyzer.com.br';
return 'http://localhost:3001';
};
module.exports = {
allowedOrigins,
getBaseUrl,
getStartupBaseUrl,
isProduction,
jwtSecret,
port,
smtp,
};

View File

@@ -1,16 +1,17 @@
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const path = require('path');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const nodemailer = require('nodemailer');
const multer = require('multer');
const { v4: uuidv4 } = require('uuid');
const fs = require('fs');
const pool = require('./db');
const { stripEnvQuotes, hashSecret, maskSecret } = require('./utils/security');
const { hashSecret, maskSecret } = require('./utils/security');
const transporter = require('./services/mailer');
const { createCorsMiddleware } = require('./config/cors');
const { allowedOrigins, getBaseUrl, getStartupBaseUrl, isProduction, jwtSecret: JWT_SECRET, port: PORT } = require('./config/runtime');
const {
canReadUser,
canUpdateUser,
@@ -21,69 +22,9 @@ const {
} = require('./policies/accessPolicy');
const app = express();
const PORT = process.env.PORT || 3001;
const isProduction = process.env.NODE_ENV === 'production';
const JWT_SECRET = process.env.JWT_SECRET || (isProduction ? null : 'fasto_dev_secret_change_me');
if (!JWT_SECRET) {
throw new Error('JWT_SECRET is required in production.');
}
const USER_PUBLIC_FIELDS = 'id, tenant_id, team_id, name, email, slug, role, status, bio, avatar_url, sound_enabled, created_at';
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST || 'mail.blyzer.com.br',
port: parseInt(process.env.SMTP_PORT) || 587,
secure: false, // false para 587 (STARTTLS)
auth: {
user: stripEnvQuotes(process.env.SMTP_USER || 'nao-responda@blyzer.com.br'),
pass: stripEnvQuotes(process.env.SMTP_PASS || ''),
},
tls: {
ciphers: 'SSLv3',
rejectUnauthorized: false
},
debug: process.env.SMTP_DEBUG === 'true',
logger: process.env.SMTP_DEBUG === 'true'
});
// Helper para obter a URL base
const getBaseUrl = (req) => {
// Use explicit environment variable if set
if (process.env.APP_URL) return process.env.APP_URL;
// Otherwise, attempt to construct it from the request object dynamically
const host = req ? (req.get('host') || 'localhost:3001') : 'localhost:3001';
const protocol = (req && (req.protocol === 'https' || req.get('x-forwarded-proto') === 'https')) ? 'https' : 'http';
// Se estivermos em produção e o host não for localhost, force HTTPS
if (process.env.NODE_ENV === 'production' && !host.includes('localhost')) {
return `https://${host}`;
}
return `${protocol}://${host}`;
};
// Quando não temos a request (ex: startup), usamos uma versão simplificada
const getStartupBaseUrl = () => {
if (process.env.APP_URL) return process.env.APP_URL;
if (process.env.NODE_ENV === 'production') return 'https://fasto.blyzer.com.br';
return 'http://localhost:3001';
};
const allowedOrigins = (process.env.CORS_ORIGIN || '')
.split(',')
.map(origin => origin.trim())
.filter(Boolean);
app.use(cors({
origin: (origin, callback) => {
if (!origin || !isProduction || allowedOrigins.includes(origin)) {
return callback(null, true);
}
return callback(new Error('Origem não permitida pelo CORS.'));
},
credentials: true
}));
app.use(createCorsMiddleware({ allowedOrigins, isProduction }));
app.use(express.json());
// Logger de Requisições

View File

@@ -0,0 +1,20 @@
const nodemailer = require('nodemailer');
const { smtp } = require('../config/runtime');
const transporter = nodemailer.createTransport({
host: smtp.host,
port: smtp.port,
secure: false,
auth: {
user: smtp.user,
pass: smtp.pass,
},
tls: {
ciphers: 'SSLv3',
rejectUnauthorized: false
},
debug: smtp.debug,
logger: smtp.debug
});
module.exports = transporter;