feat: session_create, session_validate, session_cleanup
Fase 3 del issue 0010 — sesiones SQLite como alternativa a JWT. - Tabla sessions creada con CREATE TABLE IF NOT EXISTS (autosetup) - Tokens de 32 bytes aleatorios (crypto/rand) codificados en hex (256 bits) - Indices en user_id y expires_at - Prepared statements para evitar SQL injection - SessionCleanup para eliminar expiradas periodicamente
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: session_create
|
||||
kind: function
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "func SessionCreate(db *sql.DB, userID string, ttl time.Duration, metadata map[string]any) (Session, error)"
|
||||
description: "Crea una sesion SQLite con token aleatorio de 32 bytes hex (256 bits de entropia). Crea la tabla sessions si no existe. Retorna la Session lista para devolver al cliente."
|
||||
tags: [session, auth, sqlite, token, infra]
|
||||
uses_functions: []
|
||||
uses_types: [Session_go_infra]
|
||||
returns: [Session_go_infra]
|
||||
returns_optional: false
|
||||
error_type: error_go_core
|
||||
imports: [crypto/rand, database/sql, encoding/hex, encoding/json, fmt, time]
|
||||
params:
|
||||
- name: db
|
||||
desc: "conexion SQL abierta a la BD de la app. No debe ser nil"
|
||||
- name: userID
|
||||
desc: "identificador del usuario al que pertenece la sesion. No vacio"
|
||||
- name: ttl
|
||||
desc: "tiempo de vida de la sesion (time.Duration). Debe ser positivo"
|
||||
- name: metadata
|
||||
desc: "datos libres a persistir junto a la sesion (role, email, ip, etc.). Puede ser nil"
|
||||
output: "Session con token opaco listo para devolver al cliente via header o cookie"
|
||||
tested: true
|
||||
tests: ["crea sesion y persiste en BD", "genera tokens distintos", "rechaza db nil", "rechaza user_id vacio"]
|
||||
test_file_path: "functions/infra/session_test.go"
|
||||
file_path: "functions/infra/session_create.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
db, _ := sql.Open("sqlite3", "app.db")
|
||||
session, err := SessionCreate(db, user.ID, 24*time.Hour, map[string]any{
|
||||
"email": user.Email,
|
||||
"role": "admin",
|
||||
"ip": r.RemoteAddr,
|
||||
})
|
||||
if err != nil {
|
||||
HTTPErrorResponse(w, HTTPError{Status: 500, Code: "session_error", Message: err.Error()})
|
||||
return
|
||||
}
|
||||
HTTPJSONResponse(w, 200, map[string]string{"token": session.Token})
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Impura — hace I/O en SQLite, usa entropia del OS con `crypto/rand`, y lee el tiempo con `time.Now()`. La tabla `sessions` se crea con `CREATE TABLE IF NOT EXISTS` (PK token, indices en user_id y expires_at) para que la primera llamada deje todo listo sin setup manual. Token es 32 bytes aleatorios codificados en hex = 64 chars, 256 bits de entropia. Session fixation mitigada: el token lo genera el servidor, no se acepta del cliente. Para invalidar una sesion: `DELETE FROM sessions WHERE token = ?`. Limpieza periodica de expiradas: SessionCleanup.
|
||||
Reference in New Issue
Block a user