ENRE_WEB/gestor/config.go
SITO ce3127baff Sección «Pedir evento» con gestor de reservas y calendario legible en móvil
- /pedir/: calendario de fechas pedidas (negro) y confirmadas (verde),
  findes tranqui y con ruido, solo findes por defecto con opción de ver la
  semana entera. Se pincha un día libre y, sin sesión, se pide entrar y se
  vuelve al formulario con la fecha puesta.
- Gestor en Go (gestor/): cuentas por colectivo con argon2id, sesiones y
  CSRF, cupo y ventana de la asamblea, caducidades, registro append-only.
- La cuenta de la asamblea confirma, rechaza, cambia turnos de finde y en
  «Todas las fechas» quita o modifica cualquier evento.
- Orden «cuenta» y «clave» con -clave y -definitiva para fijar contraseñas
  desde el servidor; ninguna contraseña va en el repositorio.
- Botón «Pedir evento» arriba de la barra lateral en todas las páginas.
- Calendario semanal en móvil: lista de días con nombre y hora de cada cita.
- Fuentes servidas desde fuentes/: fuera Google Fonts en todas las páginas.
2026-09-23 11:32:25 +02:00

94 lines
2.6 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"os"
"time"
)
type Config struct {
// Red
Escucha string `json:"escucha"` // siempre local: nginx hace de puerta
BaseURL string `json:"base_url"` // https://www.laenre.net, para comprobar el Origen
// Rutas
DirDatos string `json:"dir_datos"` // registro.jsonl
DirPlantillas string `json:"dir_plantillas"` // plantillas de /pedir/
DirEstatico string `json:"dir_estatico"` // raiz de la web, solo en modo local
LogAuth string `json:"log_auth"` // el registro que lee fail2ban
// Comportamiento
CookieSegura bool `json:"cookie_segura"` // false solo para probar sin TLS
Local bool `json:"local"` // sirve tambien la web estatica
MesesVista int `json:"meses_vista"` // meses que pinta /pedir/
Reglas Reglas `json:"reglas"`
}
func ConfigPorDefecto() Config {
return Config{
Escucha: "127.0.0.1:8090",
BaseURL: "https://www.laenre.net",
DirDatos: "/var/lib/enrecal",
DirPlantillas: "/var/www/laenre/gestor/plantillas",
DirEstatico: "/var/www/laenre",
LogAuth: "/var/log/enrecal/auth.log",
CookieSegura: true,
MesesVista: 4,
Reglas: ReglasPorDefecto(),
}
}
func CargarConfig(ruta string) (Config, error) {
c := ConfigPorDefecto()
if ruta == "" {
return c, nil
}
b, err := os.ReadFile(ruta)
if err != nil {
return c, err
}
dec := json.NewDecoder(bytes.NewReader(b))
dec.DisallowUnknownFields()
if err := dec.Decode(&c); err != nil {
return c, fmt.Errorf("%s: %w", ruta, err)
}
return c, c.Validar()
}
func (c Config) Validar() error {
if c.Reglas.CupoDias < 1 {
return fmt.Errorf("cupo_dias tiene que ser 1 o mas")
}
if c.Reglas.MesesVentana < 1 {
return fmt.Errorf("meses_ventana tiene que ser 1 o mas")
}
if c.Reglas.DiasMinimoConfirmar < 0 {
return fmt.Errorf("dias_minimo_confirmar no puede ser negativo")
}
if c.Reglas.DiasMaximoPendiente < 1 {
return fmt.Errorf("dias_maximo_pendiente tiene que ser 1 o mas")
}
if len(c.Reglas.DiasReservables) == 0 {
return fmt.Errorf("dias_reservables no puede estar vacio")
}
if _, err := c.Reglas.AnclaFinde.Time(); err != nil {
return fmt.Errorf("ancla_finde: %w", err)
}
if c.Reglas.TurnoAncla != Tranqui && c.Reglas.TurnoAncla != Ruido {
return fmt.Errorf("turno_ancla solo puede ser %q o %q", Tranqui, Ruido)
}
if c.MesesVista < 1 {
return fmt.Errorf("meses_vista tiene que ser 1 o mas")
}
return nil
}
const (
inactividadSesion = 8 * time.Hour
maxIntentos = 5
ventanaIntentos = 10 * time.Minute
esperaBloqueo = 15 * time.Minute
)