diff --git a/assets/pasted-20260415-121622-e57fee84.png b/assets/pasted-20260415-121622-e57fee84.png new file mode 100644 index 0000000..994d2f8 Binary files /dev/null and b/assets/pasted-20260415-121622-e57fee84.png differ diff --git a/css/styles.css b/css/styles.css index c04f1fb..c0e0c36 100644 --- a/css/styles.css +++ b/css/styles.css @@ -161,8 +161,7 @@ a:hover { background-size: auto; background-color: rgb(0 0 0 / 50%); z-index: 100; - width: min(300px, calc(100vw - 50px)); - max-width: calc(100vw - 50px); + width: 300px; display: flex; /* Active le mode Flexbox */ flex-direction: column; /* Aligne les liens les uns sous les autres */ align-items: center; /* Centre verticalement */ @@ -170,7 +169,7 @@ a:hover { justify-content: center; border: solid 3px rgb(155 145 60 / 25%); border-radius: 10px; - padding: 5px 12px; + padding: 5px 0px 5px 0px; text-align: center; } @@ -184,16 +183,13 @@ a:hover { background-size: auto; background-color: rgb(0 0 0 / 50%); z-index: 100; - width: min(300px, calc(100vw - 50px)); - max-width: calc(100vw - 50px); - min-height: 35px; - height: auto; + width: 300px; + height: 35px; display: flex; /* Active le mode Flexbox */ align-items: center; /* Centre verticalement */ justify-content: center; border: solid 3px rgb(155 145 60 / 25%); border-radius: 10px; - padding: 5px 12px; text-align: center; } @@ -206,9 +202,8 @@ a:hover { background-position: center center; background-size: auto; z-index: 3; - width: min(1050px, calc(100vw - 40px)); - min-height: 80px; - height: auto; + width: 1050px; + height: 80px; text-align: center; } @@ -217,7 +212,6 @@ a:hover { justify-content: center; /* Centre les items horizontalement */ align-items: center; /* Centre verticalement */ gap: 10px; /* Espace entre les divs (modifiable) */ - flex-wrap: wrap; } .center-div-menu .menu-item { @@ -380,7 +374,7 @@ a:hover { } .center-div-menu { - width: min(900px, calc(100vw - 48px)); + width: min(1050px, calc(100vw - 40px)); } } diff --git a/database/full.sql b/database/full.sql index 8b61be4..6dc7972 100644 --- a/database/full.sql +++ b/database/full.sql @@ -18714,3 +18714,14 @@ INSERT INTO `tbl_scitemcustomstat` (`cl_scitemcustomstat_id`,`cl_scitemcustomsta ('6','3','6','','0.50','2026-04-08 22:01:49'); SET FOREIGN_KEY_CHECKS = 1; + + +CREATE TABLE IF NOT EXISTS tbl_page_access ( + cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + cl_page_key VARCHAR(190) NOT NULL UNIQUE, + cl_page_file VARCHAR(190) NOT NULL UNIQUE, + cl_page_label VARCHAR(190) NOT NULL, + cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1, + cl_allow_member TINYINT(1) NOT NULL DEFAULT 0, + cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/database/schema.sql b/database/schema.sql index a15637a..fb60b89 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -193,3 +193,14 @@ CREATE TABLE `tbl_scwebhooks` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +CREATE TABLE IF NOT EXISTS tbl_page_access ( + cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + cl_page_key VARCHAR(190) NOT NULL UNIQUE, + cl_page_file VARCHAR(190) NOT NULL UNIQUE, + cl_page_label VARCHAR(190) NOT NULL, + cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1, + cl_allow_member TINYINT(1) NOT NULL DEFAULT 0, + cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/db/auth.php b/db/auth.php index b8ebf01..ab1d5bd 100644 --- a/db/auth.php +++ b/db/auth.php @@ -51,6 +51,18 @@ function auth_bootstrap(): void ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" ); + $pdo->exec( + "CREATE TABLE IF NOT EXISTS tbl_page_access ( + cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + cl_page_key VARCHAR(190) NOT NULL UNIQUE, + cl_page_file VARCHAR(190) NOT NULL UNIQUE, + cl_page_label VARCHAR(190) NOT NULL, + cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1, + cl_allow_member TINYINT(1) NOT NULL DEFAULT 0, + cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" + ); + $sql_count_admin = "SELECT COUNT(*) FROM tbl_auth WHERE cl_auth_right = 'admin'"; $stmt_count_admin = $pdo->query($sql_count_admin); $cl_auth_admin_total = (int) $stmt_count_admin->fetchColumn(); @@ -139,6 +151,20 @@ function auth_is_admin(): bool return isset($_SESSION['role']) && $_SESSION['role'] === 'admin'; } +function auth_current_user(): string +{ + auth_start_session(); + + return isset($_SESSION['user']) ? (string) $_SESSION['user'] : ''; +} + +function auth_current_role(): string +{ + auth_start_session(); + + return isset($_SESSION['role']) ? (string) $_SESSION['role'] : ''; +} + function auth_flash_set(string $flash_type, string $flash_message): void { auth_start_session(); @@ -160,4 +186,264 @@ function auth_flash_get(): ?array unset($_SESSION['flash']); return $flash; -} \ No newline at end of file +} + +function auth_page_basename(string $page_file): string +{ + $basename = basename(trim($page_file)); + + if ($basename === '' || preg_match('/^[a-zA-Z0-9._-]+$/', $basename) !== 1) { + throw new InvalidArgumentException('Nom de page invalide.'); + } + + return $basename; +} + +function auth_page_default_member_access(string $page_file): int +{ + static $member_defaults = [ + 'scnotification.php' => 1, + 'scpreset.php' => 1, + ]; + + $page_file = auth_page_basename($page_file); + + return $member_defaults[$page_file] ?? 0; +} + +function auth_page_access_defaults(string $page_file, string $page_label = ''): array +{ + $normalized_page_file = auth_page_basename($page_file); + $normalized_page_label = trim($page_label) !== '' ? trim($page_label) : $normalized_page_file; + + return [ + 'cl_page_key' => pathinfo($normalized_page_file, PATHINFO_FILENAME), + 'cl_page_file' => $normalized_page_file, + 'cl_page_label' => $normalized_page_label, + 'cl_allow_admin' => 1, + 'cl_allow_member' => auth_page_default_member_access($normalized_page_file), + ]; +} + +function auth_page_access_ensure(string $page_file, string $page_label = ''): array +{ + auth_bootstrap(); + + $defaults = auth_page_access_defaults($page_file, $page_label); + $pdo = db(); + + $stmt = $pdo->prepare( + 'SELECT cl_page_access_id, cl_page_key, cl_page_file, cl_page_label, cl_allow_admin, cl_allow_member + FROM tbl_page_access + WHERE cl_page_file = :cl_page_file + LIMIT 1' + ); + $stmt->execute([ + 'cl_page_file' => $defaults['cl_page_file'], + ]); + $row = $stmt->fetch(); + + if (!$row) { + $stmt_insert = $pdo->prepare( + 'INSERT INTO tbl_page_access (cl_page_key, cl_page_file, cl_page_label, cl_allow_admin, cl_allow_member) + VALUES (:cl_page_key, :cl_page_file, :cl_page_label, :cl_allow_admin, :cl_allow_member)' + ); + $stmt_insert->execute($defaults); + + $stmt->execute([ + 'cl_page_file' => $defaults['cl_page_file'], + ]); + $row = $stmt->fetch(); + } elseif ($defaults['cl_page_label'] !== '' && (string) $row['cl_page_label'] !== $defaults['cl_page_label']) { + $stmt_update_label = $pdo->prepare( + 'UPDATE tbl_page_access SET cl_page_label = :cl_page_label WHERE cl_page_file = :cl_page_file' + ); + $stmt_update_label->execute([ + 'cl_page_label' => $defaults['cl_page_label'], + 'cl_page_file' => $defaults['cl_page_file'], + ]); + $row['cl_page_label'] = $defaults['cl_page_label']; + } + + if (!$row) { + throw new RuntimeException('Impossible d\'initialiser la configuration d\'accès de la page.'); + } + + $row['cl_allow_admin'] = (int) ($row['cl_allow_admin'] ?? 1); + $row['cl_allow_member'] = (int) ($row['cl_allow_member'] ?? 0); + + return $row; +} + +function auth_user_can_access_page(string $page_file, string $page_label = ''): bool +{ + auth_start_session(); + auth_bootstrap(); + + if (!auth_is_logged_in()) { + return false; + } + + if (auth_is_admin()) { + return true; + } + + if (auth_current_role() !== 'member') { + return false; + } + + $row = auth_page_access_ensure($page_file, $page_label); + + return (int) $row['cl_allow_member'] === 1; +} + +function auth_require_page_access(string $page_file, string $page_label = ''): void +{ + if (!auth_is_logged_in()) { + header('Location: index.php'); + exit; + } + + if (auth_is_admin()) { + auth_page_access_ensure($page_file, $page_label); + return; + } + + if (auth_user_can_access_page($page_file, $page_label)) { + return; + } + + auth_flash_set('error', 'Accès refusé : cette page n\'est pas ouverte aux membres.'); + header('Location: index.php'); + exit; +} + +function auth_handle_page_access_post(string $page_file, string $page_label = ''): void +{ + auth_start_session(); + auth_bootstrap(); + + if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { + return; + } + + if (!isset($_POST['page_access_action'])) { + return; + } + + $redirect_target = auth_page_basename($page_file); + + if (!auth_is_admin()) { + auth_flash_set('error', 'Seul un administrateur peut modifier les accès de page.'); + header('Location: index.php'); + exit; + } + + $csrf_token = isset($_POST['csrf_token']) ? (string) $_POST['csrf_token'] : null; + if (!auth_validate_csrf($csrf_token)) { + auth_flash_set('error', 'Jeton CSRF invalide.'); + header('Location: ' . $redirect_target); + exit; + } + + $row = auth_page_access_ensure($page_file, $page_label); + $cl_allow_member = isset($_POST['cl_allow_member']) ? 1 : 0; + + $stmt = db()->prepare( + 'UPDATE tbl_page_access + SET cl_page_label = :cl_page_label, + cl_allow_admin = 1, + cl_allow_member = :cl_allow_member + WHERE cl_page_file = :cl_page_file' + ); + $stmt->execute([ + 'cl_page_label' => $row['cl_page_label'], + 'cl_allow_member' => $cl_allow_member, + 'cl_page_file' => $row['cl_page_file'], + ]); + + auth_flash_set('success', 'Accès mis à jour pour ' . $row['cl_page_label'] . '.'); + header('Location: ' . $redirect_target); + exit; +} + +function auth_render_page_access_widget(string $page_file, string $page_label = ''): string +{ + if (!auth_is_admin()) { + return ''; + } + + $row = auth_page_access_ensure($page_file, $page_label); + $csrf_token = auth_csrf_token(); + $action = htmlspecialchars($row['cl_page_file'], ENT_QUOTES, 'UTF-8'); + $label = htmlspecialchars((string) $row['cl_page_label'], ENT_QUOTES, 'UTF-8'); + $csrf = htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); + $member_checked = (int) $row['cl_allow_member'] === 1 ? 'checked' : ''; + + return << +
+ + +
Accès page
+
{$label}
+ + + +
+ +HTML; +} + +function auth_navigation_items(): array +{ + return [ + ['file' => 'admin.php', 'label' => 'Utilisateurs', 'admin_only' => true], + ['file' => 'scwebhook.php', 'label' => 'WEBHOOK'], + ['file' => 'scnotification.php', 'label' => 'NOTIF DISCORD'], + ['file' => 'scitems.php', 'label' => 'Base d\'Objets'], + ['file' => 'scstatsitem.php', 'label' => 'Stats Item'], + ['file' => 'scitemcustom.php', 'label' => 'Item Custom'], + ['file' => 'scmining.php', 'label' => 'Scanner Minage'], + ['file' => 'scmanufactures.php', 'label' => 'Manufactures'], + ['file' => 'scvaisseaux.php', 'label' => 'Vaisseaux'], + ['file' => 'scpreset.php', 'label' => 'Presets Vaisseau'], + ]; +} + +function auth_render_app_nav(string $current_page): string +{ + if (!auth_is_logged_in()) { + return ''; + } + + $current_page = auth_page_basename($current_page); + $html = ''; + + return $html; +} diff --git a/index-en.php b/index-en.php index c0efc58..45f9587 100644 --- a/index-en.php +++ b/index-en.php @@ -38,7 +38,7 @@ $has_member_access = $is_authenticated && in_array($session_cl_auth_right, ['mem
id="accountPanel"> > - >Admin + >Admin Déconnexion
diff --git a/index.php b/index.php index 9ca0aad..6256ab3 100644 --- a/index.php +++ b/index.php @@ -1005,7 +1005,7 @@ if ($has_member_access) {
id="accountPanel"> > - >Admin + >Admin Déconnexion
diff --git a/scitemcustom.php b/scitemcustom.php index ac032ce..3e3ed06 100644 --- a/scitemcustom.php +++ b/scitemcustom.php @@ -6,14 +6,11 @@ require_once __DIR__ . '/db/scitemcustom.php'; auth_start_session(); auth_bootstrap(); +auth_handle_page_access_post('scitemcustom.php', 'Item Custom'); +auth_require_page_access('scitemcustom.php', 'Item Custom'); scstatsitem_bootstrap(); scitemcustom_bootstrap(); -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} - function scitemcustom_normalize_sign(?string $sign): string { if ($sign === '-') { @@ -755,6 +752,7 @@ $current_session_user = $_SESSION['user'] ?? ''; +
@@ -768,18 +766,7 @@ $current_session_user = $_SESSION['user'] ?? '';
- +
diff --git a/scitems.php b/scitems.php index 82f4926..8dff132 100644 --- a/scitems.php +++ b/scitems.php @@ -4,11 +4,8 @@ require_once __DIR__ . '/db/auth.php'; auth_start_session(); auth_bootstrap(); - -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} +auth_handle_page_access_post('scitems.php', "Base d'Objets"); +auth_require_page_access('scitems.php', "Base d'Objets"); $flash = auth_flash_get(); $flash_type = $flash['type'] ?? ''; @@ -387,6 +384,7 @@ if ($edit_id > 0) { +
@@ -399,18 +397,7 @@ if ($edit_id > 0) {
- +
diff --git a/scmanufactures.php b/scmanufactures.php index 3eb154b..3fbc19c 100644 --- a/scmanufactures.php +++ b/scmanufactures.php @@ -4,11 +4,8 @@ require_once __DIR__ . '/db/auth.php'; auth_start_session(); auth_bootstrap(); - -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} +auth_handle_page_access_post('scmanufactures.php', 'Manufactures'); +auth_require_page_access('scmanufactures.php', 'Manufactures'); $flash = auth_flash_get(); $flash_type = $flash['type'] ?? ''; @@ -259,6 +256,7 @@ $current_session_user = $_SESSION['user'] ?? ''; +
@@ -271,18 +269,7 @@ $current_session_user = $_SESSION['user'] ?? '';
- +
diff --git a/scmining.php b/scmining.php index db0e718..c139b54 100644 --- a/scmining.php +++ b/scmining.php @@ -4,11 +4,8 @@ require_once __DIR__ . '/db/auth.php'; auth_start_session(); auth_bootstrap(); - -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} +auth_handle_page_access_post('scmining.php', 'Scanner Minage'); +auth_require_page_access('scmining.php', 'Scanner Minage'); $flash = auth_flash_get(); $flash_type = $flash['type'] ?? ''; @@ -445,6 +442,7 @@ $current_session_user = $_SESSION['user'] ?? ''; +
@@ -457,18 +455,7 @@ $current_session_user = $_SESSION['user'] ?? '';
- +
diff --git a/scnotification.php b/scnotification.php index 850292f..f312c91 100644 --- a/scnotification.php +++ b/scnotification.php @@ -5,13 +5,10 @@ require_once __DIR__ . '/db/scdiscord.php'; auth_start_session(); auth_bootstrap(); +auth_handle_page_access_post('scnotification.php', 'NOTIF DISCORD'); +auth_require_page_access('scnotification.php', 'NOTIF DISCORD'); scdiscord_bootstrap(); -if (!auth_is_logged_in()) { - header('Location: index.php'); - exit; -} - $db = db(); $csrf_token = auth_csrf_token(); $flash = auth_flash_get(); @@ -661,6 +658,7 @@ function scnotification_old_checked(array $old, string $key, bool $default = fal +
@@ -673,20 +671,7 @@ function scnotification_old_checked(array $old, string $key, bool $default = fal
- +
diff --git a/scpreset.php b/scpreset.php index 7451b19..411f7fc 100644 --- a/scpreset.php +++ b/scpreset.php @@ -4,11 +4,8 @@ require_once __DIR__ . '/db/auth.php'; auth_start_session(); auth_bootstrap(); - -if (!auth_is_logged_in()) { - header('Location: index.php'); - exit; -} +auth_handle_page_access_post('scpreset.php', 'Presets Vaisseau'); +auth_require_page_access('scpreset.php', 'Presets Vaisseau'); $flash = auth_flash_get(); $flash_type = $flash['type'] ?? ''; @@ -461,6 +458,7 @@ unset($preset); +
@@ -473,20 +471,7 @@ unset($preset);
- +
diff --git a/scstatsitem.php b/scstatsitem.php index 0c04dad..f5e7ccb 100644 --- a/scstatsitem.php +++ b/scstatsitem.php @@ -5,13 +5,10 @@ require_once __DIR__ . '/db/scstatsitem.php'; auth_start_session(); auth_bootstrap(); +auth_handle_page_access_post('scstatsitem.php', 'Stats Item'); +auth_require_page_access('scstatsitem.php', 'Stats Item'); scstatsitem_bootstrap(); -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} - $flash = auth_flash_get(); $flash_type = $flash['type'] ?? ''; $flash_message = $flash['message'] ?? ''; @@ -349,6 +346,7 @@ $current_session_user = $_SESSION['user'] ?? ''; +
@@ -362,18 +360,7 @@ $current_session_user = $_SESSION['user'] ?? '';
- +
diff --git a/scvaisseaux.php b/scvaisseaux.php index 5fba0b4..20b7306 100644 --- a/scvaisseaux.php +++ b/scvaisseaux.php @@ -4,11 +4,8 @@ require_once __DIR__ . '/db/auth.php'; auth_start_session(); auth_bootstrap(); - -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} +auth_handle_page_access_post('scvaisseaux.php', 'Vaisseaux'); +auth_require_page_access('scvaisseaux.php', 'Vaisseaux'); $flash = auth_flash_get(); $flash_type = $flash['type'] ?? ''; @@ -270,6 +267,7 @@ $current_session_user = $_SESSION['user'] ?? ''; +
@@ -282,18 +280,7 @@ $current_session_user = $_SESSION['user'] ?? '';
- +
diff --git a/scwebhook.php b/scwebhook.php index 3115711..7627e78 100644 --- a/scwebhook.php +++ b/scwebhook.php @@ -5,13 +5,10 @@ require_once __DIR__ . '/db/scdiscord.php'; auth_start_session(); auth_bootstrap(); +auth_handle_page_access_post('scwebhook.php', 'WEBHOOK'); +auth_require_page_access('scwebhook.php', 'WEBHOOK'); scdiscord_bootstrap(); -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} - $db = db(); $csrf_token = auth_csrf_token(); $flash = auth_flash_get(); @@ -535,6 +532,7 @@ $banners = $stmt_banners->fetchAll(); +
@@ -547,18 +545,7 @@ $banners = $stmt_banners->fetchAll();
- +