Pre-reordenación

This commit is contained in:
2025-09-05 04:02:39 +00:00
parent 8522d02170
commit 80778c0ed9
10 changed files with 1115 additions and 120 deletions
+85
View File
@@ -12,6 +12,14 @@ import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
//Redis
import session from 'express-session';
import { createClient } from 'redis';
import * as connectRedis from 'connect-redis';
const RedisStore = connectRedis.default || connectRedis.RedisStore;
const redis = createClient({ url: process.env.REDIS_URL || 'redis://authentik-redis:6379' });
await redis.connect();
// Variables de Entorno
import dotenv from 'dotenv';
@@ -36,6 +44,18 @@ app.use(express.json());
app.use(express.json({ limit: '1mb' }));
app.use(express.static(path.join(__dirname, 'pages')));
app.use(session({
name: 'sc.sid',
store: new RedisStore({ client: redis, prefix: 'sess:' }),
secret: process.env.SESSION_SECRET || 'change-me',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
},
}));
// ----------------------------------------------------------
// Motor de vistas EJS
@@ -72,6 +92,14 @@ const dbConfig = {
const pool = new Pool(dbConfig);
const tenantsPool = new Pool({
host: process.env.TENANTS_HOST || 'dev-tenants',
port: Number(process.env.TENANTS_PORT || 5432),
user: process.env.TENANTS_USER || 'postgres',
password: process.env.TENANTS_PASS || 'postgres',
database: process.env.TENANTS_DB || 'dev-postgres',
});
// ----------------------------------------------------------
// Seguridad: Tablas permitidas
// ----------------------------------------------------------
@@ -103,6 +131,63 @@ async function getClient() {
return client;
}
export async function withTenant(req, res, next) {
const client = await tenantsPool.connect();
try {
await client.query('BEGIN');
const uuid = getTenantUuid(req);
const schema = `schema_tenant_${uuid}`;
// Usa la función helper si la creaste en la DB (recomendado)
// await client.query('SELECT public.f_set_search_path($1)', [schema]);
// Alternativa directa si aún no tienes la función:
await client.query(`SET LOCAL search_path TO ${schema.replace(/"/g, '')}`);
req.pg = client;
req.pgSchema = schema;
next();
} catch (e) {
try { if (client) await client.query('ROLLBACK'); } catch {}
if (client) client.release();
return res.status(400).json({ error: e.message });
}
}
// Cierra la transacción y libera la conexión
export async function done(req, res, next) {
try {
if (req.pg) await req.pg.query('COMMIT');
} catch (e) {
try { if (req.pg) await req.pg.query('ROLLBACK'); } catch {}
} finally {
if (req.pg) req.pg.release();
}
next?.();
}
function requireAuth(req, res, next) {
if (!req.session?.user) return res.status(401).json({ error: 'no-auth' });
next();
}
function getTenantUuid(req) {
// 1) header enviado por el front (fetchWithTenant)
const h = req.get('x-tenant-uuid');
if (h) return String(h).replace(/-/g, '');
// 2) sesión del login OIDC
const s = req.session?.user?.tenant_uuid;
if (s) return String(s).replace(/-/g, '');
throw new Error('Tenant no especificado');
}
app.get('/api/productos', requireAuth, withTenant, async (req, res, next) => {
const { rows } = await req.pg.query('SELECT * FROM productos ORDER BY id');
res.json(rows);
}, done);
app.use((req,res,next)=>{ res.locals.user = req.session?.user || null; next(); });
// ----------------------------------------------------------
// Introspección de esquema
// ----------------------------------------------------------