Backend: - UmindConexion: cuenta de correo conectada por tenant vía OAuth2 (golang.org/x/oauth2, promovida de indirecta a directa), tokens cifrados en reposo con el mismo AES-GCM+APP_KEY que ya usan tools/canales. - Flujo completo: /app/umind/conexiones/conectar redirige a Google/Microsoft, /callback/:proveedor intercambia el code (state autoverificable por HMAC, sin tabla de estados pendientes), refresh on-demand antes de cada uso. - Dos tools nuevas para el agente (enviar_correo/leer_bandeja) que aparecen solo si el tenant tiene una conexión activa, vía Gmail API / Microsoft Graph directo (sin el SDK pesado de Google). - Requiere que el dueño del proyecto cree las apps OAuth en Google Cloud Console / Azure y cargue GOOGLE_OAUTH_CLIENT_ID/SECRET y MS_OAUTH_CLIENT_ID/SECRET — sin eso los botones de conectar fallan con un mensaje claro, no en silencio. Frontend: rediseño del orquestador — layout de sidebar fijo (reemplaza el navbar + lista de página completa), modo oscuro vía prefers-color-scheme, tabs en pill, y la nueva tab "Conexiones". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
35 lines
925 B
Go
35 lines
925 B
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/sujit-baniya/fiber-boilerplate/app"
|
|
"github.com/sujit-baniya/fiber-boilerplate/config"
|
|
)
|
|
|
|
func TestFirmarYVerificarState(t *testing.T) {
|
|
app.Http = &config.AppConfig{Server: config.ServerConfig{Key: "clave-de-prueba-no-real"}}
|
|
|
|
state, err := firmarState(42)
|
|
if err != nil {
|
|
t.Fatalf("firmarState: %v", err)
|
|
}
|
|
tenantID, err := verificarState(state)
|
|
if err != nil {
|
|
t.Fatalf("verificarState de un state válido falló: %v", err)
|
|
}
|
|
if tenantID != 42 {
|
|
t.Errorf("tenantID = %d, esperaba 42", tenantID)
|
|
}
|
|
|
|
if _, err := verificarState(state + "x"); err == nil {
|
|
t.Error("un state alterado fue aceptado")
|
|
}
|
|
if _, err := verificarState("formato.invalido"); err == nil {
|
|
t.Error("un state con formato inválido fue aceptado")
|
|
}
|
|
if _, err := verificarState("noesnumero.aabbcc.deadbeef"); err == nil {
|
|
t.Error("un tenant_id no numérico fue aceptado")
|
|
}
|
|
}
|