Import
This commit is contained in:
1 parent
6ae10c6f64
commit
3b754994a1
4 files changed
+462
No files matched your search
@@ -0,0 +1,261 @@
|
|||||||
|
-- =====================================================================
|
||||||
|
-- NetMonster Admin — Schema COMPLET pour INSTALLATION NEUVE
|
||||||
|
-- Fichier unique : contient tout ce qu'il faut executer une seule fois
|
||||||
|
-- sur une base vide pour obtenir un environnement pret a l'emploi.
|
||||||
|
--
|
||||||
|
-- Regroupe et remplace, dans l'ordre :
|
||||||
|
-- 1. schema_v3_with_radio_params.sql (tables de base + donnees Luxembourg)
|
||||||
|
-- 2. migration_fix_uniq_cell.sql (deja integre : uniq_cell inclut sub_id2 des la creation)
|
||||||
|
-- 3. migration_security_hardening.sql / schema_v3_addendum_login_attempts.sql
|
||||||
|
-- (table login_attempts pour le rate limiting de connexion)
|
||||||
|
--
|
||||||
|
-- Usage (installation neuve uniquement) :
|
||||||
|
-- mysql -u netmonster_user -p netmonster < install_full_schema.sql
|
||||||
|
--
|
||||||
|
-- Si vous avez DEJA une base existante avec un schema anterieur,
|
||||||
|
-- N'UTILISEZ PAS ce fichier : utilisez plutot, selon votre situation :
|
||||||
|
-- - migration_fix_uniq_cell.sql (si votre contrainte uniq_cell
|
||||||
|
-- ne contient pas encore sub_id2)
|
||||||
|
-- - migration_security_hardening.sql (si vous n'avez pas encore la
|
||||||
|
-- table login_attempts)
|
||||||
|
-- Ces deux fichiers de migration restent disponibles independamment
|
||||||
|
-- dans ce dossier pour les mises a jour d'une base deja en production,
|
||||||
|
-- sans risque de perte de donnees.
|
||||||
|
--
|
||||||
|
-- Toutes les instructions CREATE TABLE utilisent IF NOT EXISTS et les
|
||||||
|
-- INSERT de reference utilisent ON DUPLICATE KEY UPDATE : ce fichier
|
||||||
|
-- est idempotent, l'executer une seconde fois par erreur ne casse rien
|
||||||
|
-- et ne duplique aucune donnee.
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 1. PAYS
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS countries (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
mcc VARCHAR(3) NOT NULL UNIQUE,
|
||||||
|
iso2 VARCHAR(2) NOT NULL,
|
||||||
|
name VARCHAR(100) NOT NULL,
|
||||||
|
default_lat DOUBLE NULL,
|
||||||
|
default_lon DOUBLE NULL,
|
||||||
|
default_zoom TINYINT NULL DEFAULT 9,
|
||||||
|
cadastre_wms_url VARCHAR(255) NULL,
|
||||||
|
cadastre_wms_layer VARCHAR(100) NULL,
|
||||||
|
cadastre_attribution_html VARCHAR(500) NULL,
|
||||||
|
cadastre_srs VARCHAR(20) NULL DEFAULT 'EPSG:3857'
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
INSERT INTO countries (mcc, iso2, name, default_lat, default_lon, default_zoom,
|
||||||
|
cadastre_wms_url, cadastre_wms_layer, cadastre_attribution_html, cadastre_srs)
|
||||||
|
VALUES (
|
||||||
|
'270','LU','Luxembourg', 49.8153, 6.1296, 9,
|
||||||
|
'https://wms.geoportail.lu/public_map_layers/service',
|
||||||
|
'359',
|
||||||
|
'Cadastre : © Administration du Cadastre et de la Topographie (ACT)',
|
||||||
|
'EPSG:3857'
|
||||||
|
)
|
||||||
|
ON DUPLICATE KEY UPDATE name = VALUES(name);
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 2. OPERATEURS
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS operators (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
country_id INT NOT NULL,
|
||||||
|
mcc VARCHAR(3) NOT NULL,
|
||||||
|
mnc VARCHAR(2) NOT NULL,
|
||||||
|
brand VARCHAR(50) NOT NULL,
|
||||||
|
full_name VARCHAR(100),
|
||||||
|
UNIQUE KEY plmn (mcc, mnc),
|
||||||
|
FOREIGN KEY (country_id) REFERENCES countries(id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
INSERT INTO operators (country_id, mcc, mnc, brand, full_name)
|
||||||
|
SELECT c.id, '270','01','POST', 'POST Luxembourg' FROM countries c WHERE c.mcc='270'
|
||||||
|
UNION ALL SELECT c.id, '270','05','LoL', 'Luxembourg Online S.A.' FROM countries c WHERE c.mcc='270'
|
||||||
|
UNION ALL SELECT c.id, '270','77','Tango', 'Tango SA' FROM countries c WHERE c.mcc='270'
|
||||||
|
UNION ALL SELECT c.id, '270','99','Orange', 'Orange Communications Luxembourg S.A.' FROM countries c WHERE c.mcc='270'
|
||||||
|
ON DUPLICATE KEY UPDATE brand = VALUES(brand);
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 3. SITES = lieu physique (pylone, toit...). Regroupe plusieurs cellules.
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS sites (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
country_id INT NOT NULL,
|
||||||
|
operator_id INT NOT NULL,
|
||||||
|
lat DOUBLE NOT NULL,
|
||||||
|
lon DOUBLE NOT NULL,
|
||||||
|
location_desc VARCHAR(255),
|
||||||
|
address_desc VARCHAR(255),
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
created_by VARCHAR(100),
|
||||||
|
FOREIGN KEY (country_id) REFERENCES countries(id),
|
||||||
|
FOREIGN KEY (operator_id) REFERENCES operators(id),
|
||||||
|
INDEX idx_geo (lat, lon)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 4. CELLS = table finale VALIDEE. Une ligne = une cellule/secteur radio.
|
||||||
|
-- Inclut les parametres radio detailles (bande, frequence, azimut,
|
||||||
|
-- largeur de bande), stockes de facon structuree plutot que noyes
|
||||||
|
-- dans un texte libre.
|
||||||
|
--
|
||||||
|
-- uniq_cell inclut DEJA sub_id2 (eNB/RNC) des la creation : deux eNB
|
||||||
|
-- distincts peuvent legitimement partager le meme cell_id + area_code
|
||||||
|
-- (le CID local est souvent un petit compteur par eNB), ce n'est donc
|
||||||
|
-- pas un doublon. Le vrai doublon est : meme eNB + meme Cell ID + meme
|
||||||
|
-- area_code. (Correctif anciennement livre a part dans
|
||||||
|
-- migration_fix_uniq_cell.sql, integre ici directement.)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS cells (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
site_id BIGINT NOT NULL,
|
||||||
|
tech ENUM('2G','3G','4G','5G','CDMA') NOT NULL,
|
||||||
|
mcc VARCHAR(3) NOT NULL,
|
||||||
|
mnc VARCHAR(2) NOT NULL,
|
||||||
|
cell_id BIGINT NOT NULL,
|
||||||
|
area_code INT NOT NULL,
|
||||||
|
sub_id INT, -- BSIC / PSC / PCI
|
||||||
|
sub_id2 INT, -- RNC / eNB
|
||||||
|
band VARCHAR(20), -- ex: "B7", "N78"
|
||||||
|
frequency VARCHAR(20), -- ex: "700MHz"
|
||||||
|
azimuth SMALLINT, -- 0-359 degres
|
||||||
|
bandwidth VARCHAR(20), -- ex: "10MHz"
|
||||||
|
arfcn BIGINT,
|
||||||
|
validated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
validated_by VARCHAR(100),
|
||||||
|
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE,
|
||||||
|
UNIQUE KEY uniq_cell (tech, mcc, mnc, sub_id2, cell_id, area_code),
|
||||||
|
INDEX idx_operator_tech (mcc, mnc, tech),
|
||||||
|
INDEX idx_band (band)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 5. STAGING = zone de quarantaine. Rien n'entre dans sites/cells sans
|
||||||
|
-- passer par ici et etre valide manuellement dans l'admin.
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS staging_batches (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
label VARCHAR(255),
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
created_by VARCHAR(100)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS staging_cells (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
import_id INT,
|
||||||
|
batch_id INT NULL,
|
||||||
|
tech ENUM('2G','3G','4G','5G','CDMA') NOT NULL,
|
||||||
|
mcc VARCHAR(3) NOT NULL,
|
||||||
|
mnc VARCHAR(2) NOT NULL,
|
||||||
|
operator_guess INT,
|
||||||
|
cell_id BIGINT NOT NULL,
|
||||||
|
area_code INT NOT NULL,
|
||||||
|
sub_id INT,
|
||||||
|
sub_id2 INT,
|
||||||
|
band VARCHAR(20),
|
||||||
|
frequency VARCHAR(20),
|
||||||
|
azimuth SMALLINT,
|
||||||
|
bandwidth VARCHAR(20),
|
||||||
|
address_desc VARCHAR(255),
|
||||||
|
lat DOUBLE,
|
||||||
|
lon DOUBLE,
|
||||||
|
location_desc VARCHAR(255),
|
||||||
|
arfcn BIGINT,
|
||||||
|
raw_line TEXT,
|
||||||
|
source ENUM('ntm_import','manual_form','cellmapper_import') NOT NULL DEFAULT 'ntm_import',
|
||||||
|
possible_dup_of BIGINT NULL,
|
||||||
|
status ENUM('pending','validated','rejected','edited') DEFAULT 'pending',
|
||||||
|
submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
reviewed_at DATETIME NULL,
|
||||||
|
reviewed_by VARCHAR(100) NULL,
|
||||||
|
reject_reason VARCHAR(255) NULL,
|
||||||
|
FOREIGN KEY (operator_guess) REFERENCES operators(id),
|
||||||
|
FOREIGN KEY (possible_dup_of) REFERENCES cells(id),
|
||||||
|
FOREIGN KEY (batch_id) REFERENCES staging_batches(id),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_source (source)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
-- Note : la valeur 'cellmapper_import' a ete ajoutee a l'ENUM `source`
|
||||||
|
-- pour tracer les cellules completees/creees via admin/cellmapper_import.php
|
||||||
|
-- (voir aussi lib none dedie : la logique vit directement dans la page).
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 6. IMPORTS = historique des depots de fichiers .ntm
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS imports (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
filename VARCHAR(255) NOT NULL,
|
||||||
|
country_id INT,
|
||||||
|
uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
processed_at DATETIME NULL,
|
||||||
|
total_lines INT DEFAULT 0,
|
||||||
|
staged_count INT DEFAULT 0,
|
||||||
|
error_count INT DEFAULT 0,
|
||||||
|
status ENUM('uploaded','processing','done','error') DEFAULT 'uploaded',
|
||||||
|
FOREIGN KEY (country_id) REFERENCES countries(id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 7. COMPTES ADMIN (separation stricte admin / public)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS admin_users (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
username VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
password_hash VARCHAR(255) NOT NULL,
|
||||||
|
role ENUM('admin','reviewer') DEFAULT 'reviewer',
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 8. RATE LIMITING DE CONNEXION (durcissement securite du 20/09/2026)
|
||||||
|
--
|
||||||
|
-- Compteur d'echecs de connexion stocke en base (et non en session
|
||||||
|
-- PHP), afin qu'un attaquant ne puisse pas remettre son compteur a
|
||||||
|
-- zero en vidant ses cookies ou en ouvrant une navigation privee.
|
||||||
|
-- Utilise par admin/admin_auth.php (is_login_locked_out,
|
||||||
|
-- record_login_attempt) et admin/login.php.
|
||||||
|
--
|
||||||
|
-- Deux seuils appliques cote PHP a partir de cette meme table :
|
||||||
|
-- - 5 echecs sur le couple (identifiant, IP) en 15 min -> verrouillage cible
|
||||||
|
-- - 30 echecs sur l'IP seule (tous identifiants confondus) en 15 min
|
||||||
|
-- -> verrouillage large, plus permissif pour ne pas bloquer tout
|
||||||
|
-- le monde depuis une IP partagee (ex: sortie Tailscale commune)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS login_attempts (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
username_normalized VARCHAR(190) NOT NULL,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
attempted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
success TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
turnstile_verified TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
KEY idx_username_ip_time (username_normalized, ip_address, attempted_at),
|
||||||
|
KEY idx_ip_time (ip_address, attempted_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- Purge recommandee via cron (pas dans ce fichier), pour eviter que
|
||||||
|
-- la table ne grossisse indefiniment :
|
||||||
|
-- DELETE FROM login_attempts WHERE attempted_at < NOW() - INTERVAL 30 DAY;
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- Fin du schema. A ce stade, la base contient :
|
||||||
|
-- - Luxembourg (MCC 270) + POST/LoL/Tango/Orange pre-configures
|
||||||
|
-- - Toutes les tables necessaires au fonctionnement complet de
|
||||||
|
-- l'admin (import .ntm, import CellMapper, validation staging,
|
||||||
|
-- edition de sites, export, rate limiting login)
|
||||||
|
-- - AUCUN compte administrateur : creez-en un manuellement, voir
|
||||||
|
-- INSTALL.md ou INSTALL_TEST_VM.md, section "Creation du compte
|
||||||
|
-- administrateur".
|
||||||
|
-- =====================================================================
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
-- admin/sql/migration_add_missing_tables.sql
|
||||||
|
--
|
||||||
|
-- Corrige un oubli de livraison : plusieurs pages admin referencent
|
||||||
|
-- des tables qui n'ont jamais ete creees dans install_full_schema.sql
|
||||||
|
-- ni dans aucune migration precedente, causant des erreurs 500
|
||||||
|
-- (SQLSTATE 42S02 "Base table or view not found") des l'ouverture :
|
||||||
|
-- - admin/backup.php -> backup_log
|
||||||
|
-- - admin/map_layers.php -> map_layers
|
||||||
|
-- - admin/audit_log.php -> audit_log
|
||||||
|
-- - admin/import_history.php -> import_batches, import_errors
|
||||||
|
--
|
||||||
|
-- A executer sur TOUTE base existante (prod ou test) :
|
||||||
|
-- mysql -u netmonster_user -p netmonster < migration_add_missing_tables.sql
|
||||||
|
--
|
||||||
|
-- Idempotent (IF NOT EXISTS) : sans risque a rejouer.
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- Utilisee par admin/backup.php (journal des sauvegardes effectuees
|
||||||
|
-- manuellement ou par cron, aucun contenu de sauvegarde n'est stocke
|
||||||
|
-- ici, uniquement des metadonnees).
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS backup_log (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
admin_username VARCHAR(100) NOT NULL,
|
||||||
|
label VARCHAR(255) NOT NULL,
|
||||||
|
note TEXT NULL,
|
||||||
|
size_bytes_reported BIGINT UNSIGNED NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
KEY idx_created_at (created_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- Utilisee par admin/map_layers.php (configuration des couches
|
||||||
|
-- cartographiques affichees sur la carte : nom, couleur, visibilite,
|
||||||
|
-- ordre d'affichage).
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS map_layers (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(100) NOT NULL,
|
||||||
|
layer_key VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
color CHAR(7) NOT NULL DEFAULT '#3388ff',
|
||||||
|
is_visible TINYINT(1) NOT NULL DEFAULT 1,
|
||||||
|
sort_order INT NOT NULL DEFAULT 0,
|
||||||
|
description VARCHAR(255) NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- Utilisee par admin/audit_log.php (historique en lecture seule des
|
||||||
|
-- actions administratives). Cette table n'est actuellement remplie par
|
||||||
|
-- AUCUNE page : voir la note importante en bas de fichier.
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS audit_log (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
admin_username VARCHAR(100) NOT NULL,
|
||||||
|
action VARCHAR(50) NOT NULL,
|
||||||
|
entity_type VARCHAR(50) NOT NULL,
|
||||||
|
entity_id BIGINT NULL,
|
||||||
|
details TEXT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
KEY idx_created_at (created_at),
|
||||||
|
KEY idx_entity (entity_type, entity_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- Utilisees par admin/import_history.php. Distinctes de la table
|
||||||
|
-- `imports` (deja existante, alimentee par lib/ntm_import_to_staging.php
|
||||||
|
-- et utilisee par admin/import_ntm.php) : import_batches/import_errors
|
||||||
|
-- ne sont actuellement alimentees par AUCUNE page non plus, meme
|
||||||
|
-- probleme que audit_log (voir note importante ci-dessous).
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS import_batches (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
filename VARCHAR(255) NOT NULL,
|
||||||
|
country_id INT NULL,
|
||||||
|
imported_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
imported_by VARCHAR(100) NOT NULL,
|
||||||
|
status ENUM('success','partial','failed') NOT NULL DEFAULT 'success',
|
||||||
|
rows_total INT NOT NULL DEFAULT 0,
|
||||||
|
rows_imported INT NOT NULL DEFAULT 0,
|
||||||
|
rows_rejected INT NOT NULL DEFAULT 0,
|
||||||
|
FOREIGN KEY (country_id) REFERENCES countries(id),
|
||||||
|
KEY idx_imported_at (imported_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS import_errors (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
batch_id INT NOT NULL,
|
||||||
|
line_number INT NOT NULL,
|
||||||
|
message VARCHAR(500) NOT NULL,
|
||||||
|
raw_line TEXT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (batch_id) REFERENCES import_batches(id) ON DELETE CASCADE,
|
||||||
|
KEY idx_batch (batch_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- NOTE IMPORTANTE : ces 4 tables (backup_log, map_layers, audit_log,
|
||||||
|
-- import_batches/import_errors) resoudront les erreurs 500 (les pages
|
||||||
|
-- pourront s'afficher), mais audit_log, import_batches et import_errors
|
||||||
|
-- resteront VIDES tant qu'aucune page n'insere explicitement dedans a
|
||||||
|
-- chaque action concernee. Cette instrumentation n'a jamais ete ecrite :
|
||||||
|
-- ces pages de consultation ont ete livrees en supposant a tort que
|
||||||
|
-- d'autres pages les alimentaient deja. Une correction complementaire
|
||||||
|
-- sera necessaire si vous voulez que ces journaux soient utiles au
|
||||||
|
-- quotidien (par exemple: brancher import_history.php sur la table
|
||||||
|
-- `imports` deja existante et alimentee par import_ntm.php, plutot que
|
||||||
|
-- sur import_batches qui fait doublon et n'est jamais rempli).
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
-- migration_fix_uniq_cell.sql
|
||||||
|
-- Corrige la contrainte unique de la table `cells` pour inclure l'eNB/RNC
|
||||||
|
-- (sub_id2), evitant les faux positifs de duplication quand deux eNB
|
||||||
|
-- differents partagent par coincidence le meme Cell ID + area_code.
|
||||||
|
--
|
||||||
|
-- Erreur corrigee :
|
||||||
|
-- SQLSTATE[23000]: Integrity constraint violation: 1062
|
||||||
|
-- Duplicate entry 'xxx' for key 'uniq_cell'
|
||||||
|
--
|
||||||
|
-- A executer sur la base de production avant de redeployer edit_site.php
|
||||||
|
-- si celui-ci permet desormais d'ajouter des cellules a un eNB different
|
||||||
|
-- partageant un Cell ID deja utilise ailleurs.
|
||||||
|
|
||||||
|
-- 1) Verification prealable : recherche de vrais doublons (meme eNB, meme
|
||||||
|
-- Cell ID, meme area_code) qui bloqueraient la creation du nouvel index.
|
||||||
|
-- Si cette requete renvoie des lignes, il faut les corriger/supprimer
|
||||||
|
-- manuellement AVANT d'executer l'ALTER TABLE ci-dessous.
|
||||||
|
SELECT tech, mcc, mnc, sub_id2, cell_id, area_code, COUNT(*) AS doublons
|
||||||
|
FROM cells
|
||||||
|
GROUP BY tech, mcc, mnc, sub_id2, cell_id, area_code
|
||||||
|
HAVING COUNT(*) > 1;
|
||||||
|
|
||||||
|
-- 2) Si la requete ci-dessus ne renvoie aucune ligne, appliquer la migration :
|
||||||
|
ALTER TABLE cells DROP INDEX uniq_cell;
|
||||||
|
ALTER TABLE cells ADD UNIQUE KEY uniq_cell (tech, mcc, mnc, sub_id2, cell_id, area_code);
|
||||||
|
|
||||||
|
-- 3) Meme correction sur staging_cells si une contrainte equivalente y existe,
|
||||||
|
-- pour eviter le meme blocage lors de l'import initial (avant validation).
|
||||||
|
-- Decommentez si applicable a votre schema :
|
||||||
|
-- ALTER TABLE staging_cells DROP INDEX uniq_cell;
|
||||||
|
-- ALTER TABLE staging_cells ADD UNIQUE KEY uniq_cell (tech, mcc, mnc, sub_id2, cell_id, area_code);
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
-- migration_security_hardening.sql
|
||||||
|
--
|
||||||
|
-- Migration de durcissement securite suite a l'audit du 20/09/2026,
|
||||||
|
-- POUR UNE BASE DEJA EN PRODUCTION (schema anterieur a la fusion en
|
||||||
|
-- install_full_schema.sql). Si vous demarrez une installation NEUVE,
|
||||||
|
-- n'utilisez PAS ce fichier : utilisez install_full_schema.sql qui
|
||||||
|
-- inclut deja tout ce qui suit.
|
||||||
|
--
|
||||||
|
-- Contenu :
|
||||||
|
-- 1. Table login_attempts pour un rate limiting stocke en base,
|
||||||
|
-- independant de la session PHP du visiteur (donc non
|
||||||
|
-- contournable en vidant les cookies ou en ouvrant une navigation
|
||||||
|
-- privee). Utilisee par admin/admin_auth.php et admin/login.php.
|
||||||
|
-- 2. Ajout de la valeur 'cellmapper_import' a l'ENUM `source` de
|
||||||
|
-- staging_cells : admin/cellmapper_import.php insere des lignes
|
||||||
|
-- avec source = "cellmapper_import", ce qui echoue (ou tronque
|
||||||
|
-- silencieusement selon le mode strict SQL) si l'ENUM d'origine ne
|
||||||
|
-- contient que ('ntm_import','manual_form'). Sans ce correctif,
|
||||||
|
-- tout import CellMapper sur une base anterieure a la fusion du
|
||||||
|
-- schema echoue en base malgre un code PHP fonctionnel.
|
||||||
|
--
|
||||||
|
-- Les roles admin_users (admin/reviewer) sont volontairement REPORTES
|
||||||
|
-- a une migration future : tant qu'un seul compte administrateur est
|
||||||
|
-- utilise, ajouter une colonne role non appliquee partout donnerait
|
||||||
|
-- une fausse impression de securite sans reel controle d'acces.
|
||||||
|
--
|
||||||
|
-- A executer une seule fois sur la base existante :
|
||||||
|
-- mysql --defaults-extra-file=/etc/netmonster/.my.cnf netmonster < migration_security_hardening.sql
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 1. Rate limiting de connexion
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS login_attempts (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
username_normalized VARCHAR(190) NOT NULL,
|
||||||
|
ip_address VARCHAR(45) NOT NULL,
|
||||||
|
attempted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
success TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
turnstile_verified TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
KEY idx_username_ip_time (username_normalized, ip_address, attempted_at),
|
||||||
|
KEY idx_ip_time (ip_address, attempted_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- Purge recommandee via cron (pas dans cette migration), pour eviter
|
||||||
|
-- que la table ne grossisse indefiniment :
|
||||||
|
-- DELETE FROM login_attempts WHERE attempted_at < NOW() - INTERVAL 30 DAY;
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- 2. Ajout de 'cellmapper_import' a l'ENUM source de staging_cells
|
||||||
|
--
|
||||||
|
-- MODIFY COLUMN reconstruit l'ENUM avec la valeur supplementaire, sans
|
||||||
|
-- toucher aux lignes existantes (leurs valeurs actuelles 'ntm_import'
|
||||||
|
-- et 'manual_form' restent valides et inchangees dans le nouvel ENUM).
|
||||||
|
-- Operation instantanee ou quasi-instantanee selon la version
|
||||||
|
-- MySQL/MariaDB (pas de reecriture de table necessaire pour un ajout
|
||||||
|
-- de valeur en fin d'ENUM sur les versions recentes).
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
ALTER TABLE staging_cells
|
||||||
|
MODIFY COLUMN source ENUM('ntm_import','manual_form','cellmapper_import')
|
||||||
|
NOT NULL DEFAULT 'ntm_import';
|
||||||
Reference in new issue
Block a user