- Rol «externas» para la asamblea de externas: pide sin cupo, siempre con el colectivo de fuera y su contacto, y sus solicitudes salen en naranja hasta que la asamblea de la Enre las confirma. - /pedir/ explica en una línea que los colectivos externos piden fecha en la asamblea de externas, los lunes de 19:00 a 20:00. - Seguridad: argon2 limitado a dos cálculos a la vez y el intento se cuenta antes de calcular (60 accesos simultáneos llevaban el proceso a 3,8 GB); bloqueo por cuenta a 20 fallos para que no se pueda dejar fuera a la asamblea; avisos por sesión en vez de por URL; sig sin «..»; eventos de 31 días como mucho; parámetros de argon2 acotados. - Títulos pegados arriba en todas las páginas; la franja de la enredadera recupera ese alto para seguir llenando la pantalla. - despliegue/: instalar.sh, cuenta.sh, servicio de systemd con el proceso encerrado, fragmento de nginx que además deja de servir .git y las notas internas, y configuración de ejemplo. Ninguna contraseña en el repositorio.
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDestinoSeguro(t *testing.T) {
|
|
casos := map[string]string{
|
|
"/pedir/nueva?fecha=2026-10-09": "/pedir/nueva?fecha=2026-10-09",
|
|
"/pedir/mis-fechas": "/pedir/mis-fechas",
|
|
"": "",
|
|
"/": "",
|
|
"/index.html": "",
|
|
"//evil.example/pedir/": "",
|
|
"https://evil.example/pedir/": "",
|
|
"/\\evil.example/pedir/": "",
|
|
"/pedir/\r\nSet-Cookie: x=1": "",
|
|
"javascript:alert(1)": "",
|
|
}
|
|
for entrada, quiero := range casos {
|
|
if got := destinoSeguro(entrada); got != quiero {
|
|
t.Errorf("destinoSeguro(%q) = %q, quiero %q", entrada, got, quiero)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDestinoSeguroSinPuntos(t *testing.T) {
|
|
for _, sig := range []string{"/pedir/../index.html", "/pedir/./nueva", "/pedir//nueva", "/pedir/x/../../evil"} {
|
|
if got := destinoSeguro(sig); got != "" {
|
|
t.Errorf("destinoSeguro(%q) = %q, quiero vacío", sig, got)
|
|
}
|
|
}
|
|
if got := destinoSeguro("/pedir/"); got != "/pedir/" {
|
|
t.Errorf("destinoSeguro(/pedir/) = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestCerrojoApuntaAntesDeCalcular(t *testing.T) {
|
|
c := NuevoCerrojo(5, time.Minute, time.Minute)
|
|
pasan := 0
|
|
for i := 0; i < 50; i++ {
|
|
if ok, _ := c.Intentar("ip:1.2.3.4"); ok {
|
|
pasan++
|
|
}
|
|
}
|
|
if pasan != 5 {
|
|
t.Fatalf("pasaron %d intentos, quiero 5", pasan)
|
|
}
|
|
}
|
|
|
|
func TestArgonParametrosAcotados(t *testing.T) {
|
|
// Un hash manipulado que pide 4 GiB de memoria no se calcula.
|
|
malo := "$argon2id$v=19$m=4194304,t=3,p=4$c2FsdHNhbHRzYWx0$aGFzaGhhc2hoYXNoaGFzaGhhc2hoYXNoaGFzaGhhc2g"
|
|
if VerificarClave(malo, "loquesea") {
|
|
t.Fatal("no deberia verificar")
|
|
}
|
|
}
|
|
|
|
func TestConfigEjemploValida(t *testing.T) {
|
|
c, err := CargarConfig("../despliegue/config.ejemplo.json")
|
|
if err != nil {
|
|
t.Fatalf("despliegue/config.ejemplo.json no carga: %v", err)
|
|
}
|
|
if !c.CookieSegura || c.Local {
|
|
t.Fatal("el ejemplo de producción tiene que llevar cookie_segura y no local")
|
|
}
|
|
}
|