Files
fitme3070.pt/database/migration_20260925_remember_me.sql
T
andreandClaude Sonnet 5 300655b92a feat(auth): «Manter sessão iniciada» (auditoria: item Médio)
config/functions_remember.php reimplementa o desenho selector/validator
do platform-tools (functions_remember.php) localmente, porque esta app
tem autenticação própria e não passa por functions_auth.php partilhado:
selector em claro e UNIQUE indexa a linha, só o SHA-256 do validator
fica na BD, hash_equals() na comparação, rotação a cada uso, e um
validator que não bate certo revoga TODOS os tokens da conta (sinal de
cookie em circulação).

- Checkbox no login; remember_issue() só quando marcada.
- require_login() tenta remember_resume() antes de mandar para o login.
- logout.php apaga só o token deste browser (não a conta toda).
- auth_set_password() revoga todos os tokens da conta — uma password
  nova não pode deixar um cookie antigo continuar a entrar.

Migração: database/migration_20260925_remember_me.sql (remember_tokens).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 13:01:18 +01:00

28 lines
1.5 KiB
SQL

-- ─── «Manter sessão iniciada» ────────────────────────────────────────────────
-- Auditoria 2026-09-24, "Sem «Manter sessão iniciada»" (Médio). A sessão do
-- PHP morre com o browser e o garbage collector apaga-a do servidor bem antes
-- disso — esticar o cookie da sessão não chega, é preciso estado próprio.
--
-- Selector/validator (o mesmo desenho do platform-tools functions_remember.php,
-- implementado localmente porque esta app tem a sua própria autenticação — ver
-- config/functions_remember.php): selector em claro e UNIQUE (é o índice da
-- consulta), só o hash SHA-256 do validator fica guardado. Quem levar um dump
-- desta tabela não consegue forjar um cookie a partir dela.
--
-- Safe to re-run.
CREATE TABLE IF NOT EXISTS `remember_tokens` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT UNSIGNED NOT NULL,
`selector` CHAR(32) NOT NULL,
`validator_hash` CHAR(64) NOT NULL,
`expires_at` DATETIME NOT NULL,
`last_ip` VARCHAR(45) NOT NULL DEFAULT '',
`user_agent` VARCHAR(255) NOT NULL DEFAULT '',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_remember_selector` (`selector`),
KEY `idx_remember_user` (`user_id`),
KEY `idx_remember_expires` (`expires_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;