fix(permisos): compara la ruta completa y avisa de los menús que dan 404
Auditoría del sistema de permisos a partir del 404 en /app/doc/paginas. 1. La comparación de permisos usaba solo el último segmento de la URL (lo que va después del último '/'). Rompía en las dos direcciones: con permiso sobre /app/doc/categorias se entraba a cualquier otra ruta terminada en "categorias", y a la vez el permiso parecía no aplicarse donde sí correspondía porque el segmento coincidía por casualidad. Ahora se compara la ruta completa, cortando en el separador para que /app/doc/paginas no habilite /app/doc/paginas-privadas. 2. El submódulo de Documentación nunca se sembró, aunque las rutas y las vistas existen desde mayo. Había que crear el ítem del menú a mano, y una URL mal tipeada ahí se ve exactamente igual que un permiso mal asignado: un 404. Ahora se siembra con la URL correcta. 3. El submódulo "Statuspage" apuntaba a /app/statuspage, que no existe en ninguna parte — la página real es la pública /status. Se corrige el seed y también el registro ya creado en la base. 4. Chequeo en el arranque que recorre los submódulos de la base y avisa cuáles apuntan a una URL sin ruta. Cubre los creados a mano, que es justo donde el compilador y los tests no llegan. 5. Test que cruza las URLs sembradas contra las rutas registradas: fue el que encontró lo de statuspage. Queda pendiente y es más grande: de 454 rutas protegidas solo 54 pasan por MenuMiddleware. El permiso gatea la página HTML pero no los endpoints de datos — cualquier usuario autenticado puede llamar a GET /app/doc/loadpaginas o DELETE /app/doc/paginas/:id sin tener el submódulo asignado. Se reporta antes de tocarlo porque cerrarlo de golpe puede dejar gente afuera. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ad3458bb71
commit
105ab44759
+90
-1
@@ -3,6 +3,7 @@ package migrations
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
@@ -239,9 +240,15 @@ func SeedStatuspage() {
|
||||
}
|
||||
|
||||
entries := []struct{ title, desc, url string }{
|
||||
{"Statuspage", "Monitoreo de estado de servicios vía Atlassian Statuspage", "/app/statuspage"},
|
||||
// La página real es la pública /status (rest/routes/publicas.go):
|
||||
// /app/statuspage nunca existió y el ítem daba 404 al entrar.
|
||||
{"Statuspage", "Monitoreo de estado de servicios vía Atlassian Statuspage", "/status"},
|
||||
}
|
||||
|
||||
// La URL vieja apuntaba a /app/statuspage, que no existe: se corrige el
|
||||
// registro ya creado en vez de dejar un ítem de menú que da 404.
|
||||
db.Model(&models.Submodules{}).Where("url = ?", "/app/statuspage").Update("url", "/status")
|
||||
|
||||
var insertados []models.Submodules
|
||||
for _, e := range entries {
|
||||
var sub models.Submodules
|
||||
@@ -1533,3 +1540,85 @@ func LiberarColumnasHuerfanasUmind() {
|
||||
log.Printf("[MIGRACION] %s.%s ya no es NOT NULL (columna huérfana del refactor multi-agente)", h.Tabla, h.Columna)
|
||||
}
|
||||
}
|
||||
|
||||
// VerificarUrlsDeSubmodulos avisa en el arranque de los ítems del menú cuya
|
||||
// URL no corresponde a ninguna ruta registrada.
|
||||
//
|
||||
// Un submódulo es una URL escrita a mano (en un seed o desde /app/submodules).
|
||||
// Si no coincide con una ruta real, el ítem igual aparece en el menú y se le
|
||||
// puede asignar permiso a un rol — y recién al hacer clic aparece un 404, sin
|
||||
// nada que explique por qué. Esto lo convierte en una línea de log al
|
||||
// arrancar, en vez de un misterio en producción.
|
||||
//
|
||||
// Solo informa: no borra ni modifica nada, porque una URL "rota" puede ser una
|
||||
// ruta servida por otro lado.
|
||||
func VerificarUrlsDeSubmodulos(rutasGET map[string]bool) {
|
||||
var subs []models.Submodules
|
||||
if err := app.Http.Database.DB.Find(&subs).Error; err != nil {
|
||||
log.Printf("[MENU] no se pudieron revisar las URLs de los submódulos: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
rotos := 0
|
||||
for _, s := range subs {
|
||||
url := strings.TrimSpace(s.Url)
|
||||
if url == "" {
|
||||
log.Printf("[MENU] el submódulo %q (ID %d) no tiene URL", s.Title, s.ID)
|
||||
rotos++
|
||||
continue
|
||||
}
|
||||
if !rutasGET[url] {
|
||||
log.Printf("[MENU] el submódulo %q (ID %d) apunta a %q, que no es ninguna ruta: va a dar 404", s.Title, s.ID, url)
|
||||
rotos++
|
||||
}
|
||||
}
|
||||
if rotos == 0 {
|
||||
log.Printf("[MENU] %d submódulos revisados, todas las URLs resuelven", len(subs))
|
||||
} else {
|
||||
log.Printf("[MENU] %d de %d submódulos apuntan a una URL inexistente (ver líneas anteriores)", rotos, len(subs))
|
||||
}
|
||||
}
|
||||
|
||||
// SeedDocumentacion registra los submódulos de Documentación.
|
||||
//
|
||||
// Existían las rutas y las vistas pero nunca el seed, así que había que crear
|
||||
// el ítem del menú a mano desde /app/submodules — y una URL mal tipeada ahí es
|
||||
// indistinguible de un permiso mal asignado: en los dos casos se ve un 404.
|
||||
func SeedDocumentacion() {
|
||||
db := app.Http.Database.DB
|
||||
|
||||
var modulo models.Modules
|
||||
if err := db.Where("title = ?", "Documentación").First(&modulo).Error; err != nil {
|
||||
modulo = models.Modules{
|
||||
Title: "Documentación",
|
||||
Description: "Páginas y categorías de documentación interna",
|
||||
ModifiedAt: time.Now(),
|
||||
}
|
||||
if err := db.Create(&modulo).Error; err != nil {
|
||||
log.Printf("[SEED] Error creando módulo Documentación: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
entries := []struct{ title, desc, url string }{
|
||||
{"Doc: Páginas", "Páginas de documentación", "/app/doc/paginas"},
|
||||
{"Doc: Categorías", "Categorías de documentación", "/app/doc/categorias"},
|
||||
}
|
||||
for _, e := range entries {
|
||||
var sub models.Submodules
|
||||
if err := db.Where("url = ?", e.url).First(&sub).Error; err != nil {
|
||||
sub = models.Submodules{
|
||||
Title: e.title,
|
||||
Description: e.desc,
|
||||
Url: e.url,
|
||||
ModuleId: modulo.ID,
|
||||
ModifiedAt: time.Now(),
|
||||
}
|
||||
if err := db.Create(&sub).Error; err != nil {
|
||||
log.Printf("[SEED] Error creando submódulo '%s': %v", e.title, err)
|
||||
continue
|
||||
}
|
||||
log.Printf("[SEED] Submódulo '%s' creado (ID %d)", e.title, sub.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user