130 lines
No EOL
4.6 KiB
PL/PgSQL
130 lines
No EOL
4.6 KiB
PL/PgSQL
-- Migration 003: Schéma amélioré - VERSION CORRIGÉE
|
|
|
|
BEGIN;
|
|
|
|
-- Supprimer les fonctions qui pourraient être en conflit
|
|
DROP FUNCTION IF EXISTS cleanup_expired_sessions();
|
|
DROP FUNCTION IF EXISTS cleanup_old_data();
|
|
|
|
-- Supprimer les vues qui pourraient être en conflit
|
|
DROP VIEW IF EXISTS server_stats CASCADE;
|
|
|
|
-- Extensions nécessaires
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
|
|
|
|
-- Table des sessions utilisateur sécurisées
|
|
CREATE TABLE IF NOT EXISTS user_sessions_secure (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
token_hash VARCHAR(255) NOT NULL UNIQUE,
|
|
refresh_token_hash VARCHAR(255) UNIQUE,
|
|
device_info JSONB DEFAULT '{}',
|
|
ip_address INET NOT NULL,
|
|
user_agent TEXT,
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
expires_at TIMESTAMPTZ NOT NULL DEFAULT (NOW() + INTERVAL '7 days'),
|
|
last_used TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
-- Table des événements de sécurité
|
|
CREATE TABLE IF NOT EXISTS security_events_secure (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
event_type VARCHAR(50) NOT NULL,
|
|
severity VARCHAR(20) DEFAULT 'info' CHECK (severity IN ('critical', 'high', 'medium', 'low', 'info')),
|
|
description TEXT NOT NULL,
|
|
ip_address INET,
|
|
user_agent TEXT,
|
|
additional_data JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
resolved_at TIMESTAMPTZ,
|
|
resolved_by INTEGER REFERENCES users(id) ON DELETE SET NULL
|
|
);
|
|
|
|
-- Table des mentions
|
|
CREATE TABLE IF NOT EXISTS message_mentions_secure (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
is_read BOOLEAN DEFAULT false,
|
|
read_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE (message_id, user_id)
|
|
);
|
|
|
|
-- Table des blocages utilisateur
|
|
CREATE TABLE IF NOT EXISTS user_blocks_secure (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
blocker_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
blocked_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
reason VARCHAR(500),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE (blocker_id, blocked_id),
|
|
CONSTRAINT no_self_block CHECK (blocker_id != blocked_id)
|
|
);
|
|
|
|
-- Index pour les performances
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_secure_user ON user_sessions_secure (user_id, is_active);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_secure_expires ON user_sessions_secure (expires_at);
|
|
CREATE INDEX IF NOT EXISTS idx_security_events_user ON security_events_secure (user_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_mentions_secure_user ON message_mentions_secure (user_id, is_read);
|
|
CREATE INDEX IF NOT EXISTS idx_blocks_secure_blocker ON user_blocks_secure (blocker_id);
|
|
|
|
-- Fonction de nettoyage des sessions expirées (nom unique)
|
|
CREATE OR REPLACE FUNCTION cleanup_expired_sessions_secure()
|
|
RETURNS INTEGER AS $$
|
|
DECLARE
|
|
deleted_count INTEGER;
|
|
BEGIN
|
|
DELETE FROM user_sessions_secure
|
|
WHERE expires_at < NOW() OR last_used < NOW() - INTERVAL '30 days';
|
|
|
|
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
RETURN deleted_count;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Fonction de nettoyage général (nom unique)
|
|
CREATE OR REPLACE FUNCTION cleanup_old_data_secure()
|
|
RETURNS void AS $$
|
|
BEGIN
|
|
-- Supprimer les sessions expirées
|
|
PERFORM cleanup_expired_sessions_secure();
|
|
|
|
-- Nettoyer les événements de sécurité anciens
|
|
DELETE FROM security_events_secure
|
|
WHERE created_at < NOW() - INTERVAL '6 months' AND severity = 'info';
|
|
|
|
RAISE NOTICE 'Nettoyage terminé';
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Trigger pour les mentions automatiques
|
|
CREATE OR REPLACE FUNCTION handle_mentions_secure()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
-- Extraire les mentions @username du contenu
|
|
INSERT INTO message_mentions_secure (message_id, user_id)
|
|
SELECT NEW.id, u.id
|
|
FROM users u
|
|
WHERE NEW.content ~* ('@' || u.username || '\M')
|
|
AND u.id != NEW.from_user
|
|
ON CONFLICT (message_id, user_id) DO NOTHING;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS trigger_handle_mentions_secure ON messages;
|
|
CREATE TRIGGER trigger_handle_mentions_secure
|
|
AFTER INSERT ON messages
|
|
FOR EACH ROW EXECUTE FUNCTION handle_mentions_secure();
|
|
|
|
-- Permissions
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO veza;
|
|
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO veza;
|
|
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO veza;
|
|
|
|
COMMIT; |