89 lines
2.7 KiB
JavaScript
89 lines
2.7 KiB
JavaScript
'use strict'
|
|
|
|
const { queryOne } = require('../database/postgres')
|
|
|
|
// Cache simples em memória — evita query por request (TTL 60s)
|
|
const cache = new Map()
|
|
const CACHE_TTL = 60_000
|
|
|
|
async function resolveTenant(identifier) {
|
|
const now = Date.now()
|
|
if (cache.has(identifier)) {
|
|
const hit = cache.get(identifier)
|
|
if (now - hit.ts < CACHE_TTL) return hit.tenant
|
|
cache.delete(identifier)
|
|
}
|
|
|
|
const tenant = await queryOne(
|
|
`SELECT t.*, tc.primary_color, tc.secondary_color, tc.logo_url,
|
|
tc.favicon_url, tc.contact_email, tc.contact_phone, tc.app_url, tc.asaas_key
|
|
FROM tenants t
|
|
LEFT JOIN tenant_config tc ON tc.tenant_id = t.id
|
|
WHERE (t.domain = $1 OR t.slug = $1) AND t.active = true
|
|
LIMIT 1`,
|
|
[identifier]
|
|
).catch(() => null)
|
|
|
|
if (tenant) cache.set(identifier, { tenant, ts: now })
|
|
return tenant
|
|
}
|
|
|
|
// Middleware principal — anexa req.tenant
|
|
async function tenantMiddleware(req, res, next) {
|
|
try {
|
|
// 1. Tenta pelo subdomínio (hostname sem porta)
|
|
const hostname = (req.hostname || '').split(':')[0]
|
|
const subdomain = hostname.split('.')[0]
|
|
|
|
let tenant = null
|
|
|
|
// Tenta pelo hostname completo primeiro (para domínios customizados)
|
|
if (hostname && hostname !== 'localhost') {
|
|
tenant = await resolveTenant(hostname)
|
|
}
|
|
|
|
// Tenta pelo subdomínio
|
|
if (!tenant && subdomain && subdomain !== 'localhost' && subdomain !== 'www') {
|
|
tenant = await resolveTenant(subdomain)
|
|
}
|
|
|
|
// Tenta pelo header X-Tenant-Slug (útil para dev e APIs internas)
|
|
if (!tenant && req.headers['x-tenant-slug']) {
|
|
tenant = await resolveTenant(req.headers['x-tenant-slug'])
|
|
}
|
|
|
|
// Fallback: tenant padrão (id=1, slug=alemao) — garante funcionamento local
|
|
if (!tenant) {
|
|
tenant = await resolveTenant('alemao')
|
|
}
|
|
|
|
if (!tenant) {
|
|
return res.status(503).json({ error: 'Tenant não encontrado ou inativo.' })
|
|
}
|
|
|
|
req.tenant = tenant
|
|
next()
|
|
} catch (err) {
|
|
console.error('[tenant middleware]', err.message)
|
|
return res.status(503).json({ error: 'Serviço temporariamente indisponível' })
|
|
}
|
|
}
|
|
|
|
// Middleware para rotas de admin — verifica que admin pertence ao tenant
|
|
function tenantAdminMiddleware(req, res, next) {
|
|
if (!req.admin || !req.tenant) return next()
|
|
// Se admin tem tenant_id definido, deve bater com o tenant da request
|
|
if (req.admin.tenant_id && req.admin.tenant_id !== req.tenant.id) {
|
|
return res.status(403).json({ error: 'Acesso negado a este tenant.' })
|
|
}
|
|
next()
|
|
}
|
|
|
|
// Limpar cache (útil após update de tenant_config)
|
|
function invalidateTenantCache(identifier) {
|
|
if (identifier) cache.delete(identifier)
|
|
else cache.clear()
|
|
}
|
|
|
|
module.exports = { tenantMiddleware, tenantAdminMiddleware, invalidateTenantCache }
|