Pre-reordenación
This commit is contained in:
@@ -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
|
||||
// ----------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user