SPA nueva en /orchestrator (Vue 3 + Vite, servida por el mismo binario Go bajo /orchestrator para que la cookie de sesión funcione sin tocar CORS), reemplaza al panel Alpine.js como punto de entrada del menú. Backend, todo aditivo sobre el motor de uMind ya existente: - UmindHerramienta: tools custom por tenant que llaman un webhook HTTP, integradas al loop de function-calling existente. Cliente HTTP con guardas SSRF (bloqueo de IPs privadas/loopback/link-local resuelto en el momento de conectar, no antes, para cerrar la ventana de DNS rebinding) que no existían en el proyecto. - UmindCanal: Telegram y WhatsApp Business Cloud API como canales adicionales del mismo agente que ya atiende el widget web, ambos reusando ProcessWidgetMessage. WhatsApp valida X-Hub-Signature-256. Credenciales cifradas en reposo con el mismo AES-GCM+APP_KEY que ya usa el proyecto para la contraseña SMTP (primer uso para secretos de uMind). - Se conecta middlewares.Limit() (rate limiter que existía pero no se usaba en ningún lado) al widget público y a los webhooks nuevos. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
123 lines
7.3 KiB
Go
Executable File
123 lines
7.3 KiB
Go
Executable File
package routes
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/sujit-baniya/fiber-boilerplate/rest/controllers"
|
|
apiControllers "github.com/sujit-baniya/fiber-boilerplate/rest/controllers/api"
|
|
"github.com/sujit-baniya/fiber-boilerplate/rest/middlewares"
|
|
)
|
|
|
|
func RutasPublicas(web fiber.Router) {
|
|
web.Get("/", controllers.Landing)
|
|
web.Get("/index", controllers.Index)
|
|
//web.Get("/login", controllers.Login)
|
|
web.Get("/ping", Pong)
|
|
web.Get("/all-routes", AllRoutes)
|
|
web.Get("/do/verify-email", middlewares.ValidateConfirmToken, controllers.VerifyRegisteredEmail)
|
|
|
|
// ─── Webhooks públicos (sin autenticación) ────────────────────────────
|
|
// Bold requiere respuesta HTTP 200 rápida, sin middleware de sesión.
|
|
web.Post("/webhooks/bold", apiControllers.BoldWebhook)
|
|
// dLocal requiere respuesta HTTP 200 inmediata.
|
|
web.Post("/webhooks/dlocal", apiControllers.DlocalWebhook)
|
|
// PayPal: configurar en el panel de PayPal → Webhooks, con los eventos
|
|
// CHECKOUT.ORDER.APPROVED y PAYMENT.CAPTURE.COMPLETED.
|
|
web.Post("/webhooks/paypal", apiControllers.PaypalWebhook)
|
|
// Webhook entrante por integración SaaS (token único por config)
|
|
web.Post("/webhooks/saas-in/:token", controllers.SaasWebhookInHandler)
|
|
web.Get("/webhooks/saas-in/:token", controllers.SaasWebhookInHandler) // algunos SaaS verifican con GET
|
|
// Coolify notifica eventos de deployment/restart aquí (configurar en Coolify → Settings → Notifications → Webhook)
|
|
// Ruta genérica
|
|
web.Post("/webhooks/coolify", controllers.CoolifyWebhook)
|
|
// Ruta por instancia: incluye el config_id para identificar de qué Coolify viene
|
|
web.Post("/webhooks/coolify/:config_id", controllers.CoolifyWebhook)
|
|
|
|
// ─── Página de confirmación de pago ───────────────────────────────────
|
|
web.Get("/pago-exitoso", apiControllers.PagoExitosoPage)
|
|
// Ruta fuera del prefijo /api para evitar que AuthApi() la intercepte
|
|
web.Get("/pago/estado", apiControllers.PagoEstadoAPI)
|
|
// ─── Documentación pública ────────────────────────────────────────────────
|
|
web.Get("/docs/:saas", controllers.DocsPublicoIndex)
|
|
web.Get("/docs/:saas/:slug", controllers.DocsPublicaPagina)
|
|
// ─── Webhook de Telegram para vinculación del portal ──────────────────────
|
|
// Configurar en el bot: POST https://api.telegram.org/bot{TOKEN}/setWebhook?url={HOST}/webhooks/telegram-portal
|
|
web.Post("/webhooks/telegram-portal", controllers.TelegramPortalWebhook)
|
|
|
|
// ─── Webhook del agente administrador (bot con IA) ──────────────────────
|
|
// Configurar en el bot: POST https://api.telegram.org/bot{TOKEN}/setWebhook?url={HOST}/webhooks/telegram-agent/{BOT_TOKEN}
|
|
web.Post("/webhooks/telegram-agent/:bot_token", controllers.TelegramAgentWebhook)
|
|
|
|
// ─── WebSMS (LabsMobile) — API de envío + webhooks ──────────────────
|
|
web.Post("/api/sms/send", controllers.ApiSendSms)
|
|
web.Post("/webhooks/websms/delivery", controllers.WebSmsDeliveryWebhook)
|
|
web.Post("/webhooks/websms/click", controllers.WebSmsClickWebhook)
|
|
web.Post("/webhooks/websms/incoming", controllers.WebSmsIncomingWebhook)
|
|
|
|
// ─── Agente de monitoreo de servidores ────────────────────────────────────
|
|
// El agente instalado en cada servidor reporta métricas aquí (sin sesión, auth por token).
|
|
web.Post("/agent/heartbeat", controllers.AgentHeartbeat)
|
|
// Servir el script de instalación del agente
|
|
web.Get("/agent/install.sh", func(c *fiber.Ctx) error {
|
|
c.Set("Content-Type", "text/plain; charset=utf-8")
|
|
return c.SendFile("./agent/install.sh")
|
|
})
|
|
// Descargar binario pre-compilado del agente
|
|
// Ejemplo: GET /agent/download/usite-agent-linux-amd64
|
|
web.Get("/agent/download/:filename", func(c *fiber.Ctx) error {
|
|
filename := c.Params("filename")
|
|
// Validar que sea un nombre de binario válido (sin path traversal)
|
|
for _, ch := range filename {
|
|
if ch == '/' || ch == '.' || ch == '\\' {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "nombre inválido"})
|
|
}
|
|
}
|
|
path := "./agent/dist/" + filename
|
|
c.Set("Content-Disposition", "attachment; filename=\""+filename+"\"")
|
|
c.Set("Content-Type", "application/octet-stream")
|
|
return c.SendFile(path)
|
|
})
|
|
// ─── Página de estado del sistema (Atlassian Statuspage) ────────────────
|
|
web.Get("/status", controllers.StatusPage)
|
|
|
|
// ─── Webhook de soporte (correo entrante) ────────────────────────────────
|
|
// Configurar en SendGrid/Mailgun: POST {HOST}/webhooks/soporte/{provider}
|
|
web.Post("/webhooks/soporte/:provider", controllers.SoporteWebhook)
|
|
|
|
// ─── Landing Generator (acceso con X-Landing-Secret) ─────────────────────
|
|
// Rutas públicas (sin secret) para lectura de preview y polling
|
|
web.Get("/landing/preview/:token", apiControllers.LandingGetSession)
|
|
web.Get("/landing/poll/:token", apiControllers.LandingPollPayment)
|
|
// Rutas internas (requieren X-Landing-Secret del Next.js)
|
|
web.Post("/landing/session", apiControllers.LandingCreateSession)
|
|
web.Post("/landing/chat", apiControllers.LandingChat)
|
|
web.Post("/landing/generate", apiControllers.LandingGenerate)
|
|
web.Post("/landing/payment", apiControllers.LandingCreatePayment)
|
|
web.Get("/landing/answers/:token", apiControllers.LandingGetAnswers)
|
|
web.Get("/landing/download/:token", apiControllers.LandingDownload)
|
|
// Config de IA activa (para Landing Generator)
|
|
web.Get("/landing/ai-config", apiControllers.LandingGetAiConfig)
|
|
|
|
// ─── uMind: widget de chat embebible por tenant ───────────────────────────
|
|
// Público por diseño (lo llama el navegador del visitante de un sitio de
|
|
// terceros) — la protección es site_key + validación de dominio, no
|
|
// sesión. Excluido de AuthApi() por vivir fuera del grupo /api.
|
|
// middlewares.Limit por IP: cada mensaje dispara una llamada al LLM del
|
|
// tenant, sin límite era gasto libre para cualquiera con la site_key.
|
|
umindMsgLimit := middlewares.Limit(20, 1*time.Minute)
|
|
web.Get("/widget/umind.js", apiControllers.UmindWidgetScript)
|
|
widget := web.Group("/widget/:site_key")
|
|
widget.Options("*", middlewares.UmindWidgetCORS)
|
|
widget.Get("/init", middlewares.AuthUmindWidget, apiControllers.UmindWidgetInit)
|
|
widget.Post("/mensaje", umindMsgLimit, middlewares.AuthUmindWidget, apiControllers.UmindWidgetMensaje)
|
|
|
|
// ─── uMind: canales adicionales (Telegram, WhatsApp) ──────────────────────
|
|
// Igual que el widget: público por diseño, la autenticación real es
|
|
// específica de cada proveedor (firma de WhatsApp; Telegram no firma, el
|
|
// webhook_secret en la URL es lo único que lo protege).
|
|
web.Post("/webhooks/umind-telegram/:webhook_secret", umindMsgLimit, apiControllers.UmindTelegramWebhook)
|
|
web.Get("/webhooks/umind-whatsapp/:webhook_secret", apiControllers.UmindWhatsAppVerify)
|
|
web.Post("/webhooks/umind-whatsapp/:webhook_secret", umindMsgLimit, apiControllers.UmindWhatsAppWebhook)
|
|
}
|