31 lines
1.6 KiB
SQL
31 lines
1.6 KiB
SQL
-- 0003_hardening — надёжность и безопасность.
|
||
--
|
||
-- 1) email сравнивается и хранится без учёта регистра: раньше
|
||
-- Admin@x.ru и admin@x.ru считались разными пользователями.
|
||
-- Перед созданием индекса дубликатов быть не должно
|
||
-- (проверено: 0), иначе миграция откатится транзакцией.
|
||
-- 2) refresh-токены: в БД хранится только sha256-хеш, сам секрет
|
||
-- известен клиенту один раз. Выдача — с ротацией при каждом обновлении.
|
||
--
|
||
-- Применённый файл не редактировать (checksum в schema_migrations).
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS profiles_email_lower_key ON profiles (lower(email));
|
||
|
||
CREATE TABLE IF NOT EXISTS refresh_tokens (
|
||
id uuid PRIMARY KEY,
|
||
user_id uuid NOT NULL REFERENCES profiles (id) ON DELETE CASCADE,
|
||
token_hash text NOT NULL UNIQUE,
|
||
expires_at timestamptz NOT NULL,
|
||
revoked_at timestamptz,
|
||
created_at timestamptz NOT NULL DEFAULT now(),
|
||
user_agent text,
|
||
ip text
|
||
);
|
||
|
||
-- Сессии пользователя (для logout-all и отзыва при деактивации).
|
||
CREATE INDEX IF NOT EXISTS refresh_tokens_user_idx ON refresh_tokens (user_id);
|
||
|
||
-- Активные токены — для очистки протухших.
|
||
CREATE INDEX IF NOT EXISTS refresh_tokens_live_idx
|
||
ON refresh_tokens (expires_at) WHERE revoked_at IS NULL;
|