zektyc/public/z-panel/index.html
riricdev 8e7ec41f18 chore: checkpoint initial — Zektyc dataset, avant humanisation
- site vitrine + fingerprint test + zmap + z-panel
- remplacement duckdns -> riricdev.tail5ea5cd.ts.net (canonical/og/alternates/docs)
- suppression du token DuckDNS (plus utilisé)
2026-09-06 13:03:25 +02:00

406 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<title>Console · Zektyc</title>
<link rel="stylesheet" href="/z-panel/admin.css?v=2" />
</head>
<body>
<div id="login" class="login-view" hidden>
<div class="login-card">
<div class="brand brand-login">
<span class="brand-mark" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 16" role="presentation" focusable="false">
<path d="M5 4h22L5 12h22" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
<span class="brand-name">Zektyc</span>
</div>
<h1>Console d'administration</h1>
<p class="login-sub">Accès restreint · réservé à l'éditeur</p>
<form id="auth-form">
<label for="password">Mot de passe</label>
<div class="pw-wrap">
<input type="password" id="password" autocomplete="current-password" required spellcheck="false" />
<button type="button" id="toggle-pw" class="pw-eye" aria-label="Afficher ou masquer le mot de passe">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
<circle cx="12" cy="12" r="3" />
</svg>
</button>
</div>
<button type="submit" id="auth-btn" class="btn-primary btn-block">Connexion</button>
<p id="auth-msg" class="msg" role="status"></p>
</form>
</div>
</div>
<div id="app" class="app" hidden>
<aside class="sidebar">
<div class="brand">
<span class="brand-mark" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 16" role="presentation" focusable="false">
<path d="M5 4h22L5 12h22" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
<span class="brand-name">Zektyc</span>
</div>
<nav class="side-nav" aria-label="Sections du panneau">
<button class="nav-item active" data-tab="dash" type="button" aria-label="Tableau de bord" title="Tableau de bord">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v18h18"/><path d="M7 14l4-4 4 3 5-6"/></svg>
<span>Tableau de bord</span>
</button>
<button class="nav-item" data-tab="logs" type="button" aria-label="Logs" title="Logs">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
<span>Logs</span>
</button>
<button class="nav-item" data-tab="system" type="button" aria-label="Système" title="Système">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
<span>Système</span>
</button>
<button class="nav-item" data-tab="zmap" type="button" aria-label="ZMap" title="ZMap">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
<span>ZMap</span>
</button>
<button class="nav-item" data-tab="articles" type="button" aria-label="Articles" title="Articles">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h8l6 6v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/><path d="M14 3v6h6"/><path d="M8 13h8M8 17h5"/></svg>
<span>Articles</span>
</button>
<button class="nav-item" data-tab="trans" type="button" aria-label="Traductions" title="Traductions">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
<span>Traductions</span>
</button>
<button class="nav-item" data-tab="rules" type="button" aria-label="Règles Discord" title="Règles Discord">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M12 8v4M12 16h.01"/></svg>
<span>Règles Discord</span>
</button>
<button class="nav-item" data-tab="honeypot" type="button" aria-label="Honeypot" title="Honeypot">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4v5c0 5-3.5 8-8 9-4.5-1-8-4-8-9V7z"/><circle cx="12" cy="11" r="3"/></svg>
<span>Honeypot</span>
</button>
<button class="nav-item" data-tab="restart" type="button" aria-label="Redémarrage" title="Redémarrage">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M23 4v6h-6"/><path d="M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10"/><path d="M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
<span>Redémarrage</span>
</button>
</nav>
<div class="side-foot">
<button id="logout" class="btn-ghost" type="button" aria-label="Se déconnecter" title="Se déconnecter">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="M16 17l5-5-5-5"/><path d="M21 12H9"/></svg>
<span>Se déconnecter</span>
</button>
</div>
</aside>
<main class="main">
<header class="topbar">
<h1 id="page-title">Tableau de bord</h1>
<div class="topbar-actions">
<span id="updated" class="updated" role="status"></span>
<label class="switch" title="Actualisation automatique toutes les 15 s">
<input type="checkbox" id="autorefresh" checked />
<span class="switch-track" aria-hidden="true"></span>
Auto
</label>
<button id="refresh" class="btn-ghost" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M23 4v6h-6"/><path d="M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10"/><path d="M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
Actualiser
</button>
</div>
</header>
<section id="tab-dash" class="tab" aria-label="Tableau de bord">
<div id="stat-cards" class="stat-grid">
<div class="stat-card"><div class="stat-icon ic-total"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v18h18"/><path d="M7 14l4-4 4 3 5-6"/></svg></div><div class="stat-body"><b class="stat-value">—</b><span class="stat-label">requêtes</span></div></div>
<div class="stat-card"><div class="stat-icon ic-ok"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="M22 4L12 14l-3-3"/></svg></div><div class="stat-body"><b class="stat-value">—</b><span class="stat-label">200 OK</span></div></div>
<div class="stat-card"><div class="stat-icon ic-err"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg></div><div class="stat-body"><b class="stat-value">—</b><span class="stat-label">404 bloqués</span></div></div>
<div class="stat-card"><div class="stat-icon ic-warn"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01"/><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg></div><div class="stat-body"><b class="stat-value">—</b><span class="stat-label">429 rate-limit</span></div></div>
<div class="stat-card"><div class="stat-icon ic-err"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg></div><div class="stat-body"><b class="stat-value">—</b><span class="stat-label">405 refusés</span></div></div>
<div class="stat-card"><div class="stat-icon ic-info"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v18h18"/><path d="M7 9h4M7 13h8M7 17h6"/></svg></div><div class="stat-body"><b class="stat-value">—</b><span class="stat-label">statuts distincts</span></div></div>
</div>
<div class="card">
<div class="card-head">
<h2>Activité par heure</h2>
<span id="chart-meta" class="meta"></span>
</div>
<div id="chart" class="chart"><p class="meta">Chargement…</p></div>
<div class="legend">
<span class="lg lg-ok">200–299</span>
<span class="lg lg-redir">300–399</span>
<span class="lg lg-err4">400–499</span>
<span class="lg lg-err5">500+</span>
</div>
</div>
<div class="grid-2">
<div class="card">
<div class="card-head"><h2>Chemins bloqués</h2><span id="blocked-count" class="meta"></span></div>
<div id="blocked-table" class="table-scroll"><p class="meta">Chargement…</p></div>
</div>
<div class="card">
<div class="card-head"><h2>Rate-limit par IP</h2><span id="ratelimit-count" class="meta"></span></div>
<div id="ratelimit-table" class="table-scroll"><p class="meta">Chargement…</p></div>
</div>
</div>
</section>
<section id="tab-logs" class="tab" hidden aria-label="Logs">
<div class="card">
<div class="card-head">
<h2>Logs d'accès</h2>
<div class="head-actions">
<span id="log-meta" class="meta"></span>
<button id="log-exclude" class="btn-ghost btn-sm" type="button" aria-pressed="true" title="Masquer/afficher les requêtes de base (CSS, JS, images, favicon, robots.txt, API du panneau)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/>
</svg>
<span id="log-exclude-label">Masquer le bruit</span>
</button>
</div>
</div>
<div class="filters">
<input type="text" id="log-filter" placeholder="Filtre (IP, URI, méthode)…" spellcheck="false" />
<select id="log-status">
<option value="">Tous les statuts</option>
<option value="200">200</option>
<option value="404">404</option>
<option value="405">405</option>
<option value="429">429</option>
<option value="500">5xx</option>
</select>
</div>
<div class="table-scroll">
<table id="log-table">
<thead>
<tr>
<th>Date</th>
<th>IP</th>
<th>Méthode</th>
<th>URI</th>
<th>Statut</th>
<th>Durée</th>
<th>User-Agent</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</section>
<section id="tab-system" class="tab" hidden aria-label="Système">
<div id="sys-grid" class="stat-grid"></div>
<div class="card">
<div class="card-head"><h2>Processus</h2></div>
<div id="procs" class="table-scroll"><p class="meta">Chargement…</p></div>
</div>
<div class="card">
<div class="card-head"><h2>Disque</h2></div>
<div id="disk"><p class="meta">Chargement…</p></div>
</div>
</section>
<section id="tab-zmap" class="tab" hidden aria-label="ZMap">
<div id="zmap-grid" class="stat-grid"></div>
<div class="card">
<div class="card-head"><h2>Build Planet</h2><span id="zmap-build-meta" class="meta"></span></div>
<div id="zmap-build-info"><p class="meta">Chargement…</p></div>
</div>
<div class="card">
<div class="card-head"><h2>Grilles</h2><span id="zmap-grids-meta" class="meta"></span></div>
<div id="zmap-grids-info"><p class="meta">Chargement…</p></div>
</div>
<div class="card">
<div class="card-head"><h2>Log du build</h2></div>
<pre id="zmap-build-log" class="build-log"></pre>
</div>
</section>
<section id="tab-articles" class="tab" hidden aria-label="Articles">
<div class="card">
<div class="card-head">
<h2>Articles</h2>
<span id="articles-meta" class="meta"></span>
<button id="article-new" class="btn-primary" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
Nouvel article
</button>
</div>
<div id="articles-list" class="table-scroll"><p class="meta">Chargement…</p></div>
</div>
<div id="article-editor" class="card" hidden>
<div class="card-head">
<h2 id="article-editor-title">Nouvel article</h2>
<span id="article-editor-meta" class="meta"></span>
</div>
<form id="article-form">
<div class="form-grid">
<label class="field">
<span>Slug (URL)</span>
<input type="text" id="art-slug" required pattern="[a-z0-9-]+" spellcheck="false" placeholder="ex : censure-reseaux-sociaux-mineurs" />
</label>
<label class="field">
<span>Date de publication</span>
<input type="date" id="art-published" required />
</label>
</div>
<fieldset class="lang-pane">
<legend>
Français
<button type="button" class="btn-ghost btn-sm" id="art-copy-from-en" title="Copie titre + description + contenu depuis l'anglais">← Copier depuis l'anglais</button>
</legend>
<div class="form-grid">
<label class="field">
<span>Titre</span>
<input type="text" id="art-fr-title" required />
</label>
<label class="field">
<span>Titre OG (partage)</span>
<input type="text" id="art-fr-og" spellcheck="false" />
</label>
</div>
<label class="field">
<span>Description (meta)</span>
<input type="text" id="art-fr-desc" spellcheck="false" />
</label>
<label class="field">
<span>Contenu (Markdown)</span>
<textarea id="art-fr-body" rows="10" spellcheck="false" required></textarea>
<span class="md-tools">
<button type="button" class="btn-ghost btn-sm" data-preview="fr">Aperçu</button>
</span>
</label>
<div id="art-fr-preview" class="md-preview" hidden></div>
</fieldset>
<fieldset class="lang-pane">
<legend>
English
<button type="button" class="btn-ghost btn-sm" id="art-copy-from-fr" title="Copies title + description + content from French">Copier depuis le français →</button>
</legend>
<div class="form-grid">
<label class="field">
<span>Title</span>
<input type="text" id="art-en-title" required />
</label>
<label class="field">
<span>OG title (share)</span>
<input type="text" id="art-en-og" spellcheck="false" />
</label>
</div>
<label class="field">
<span>Description (meta)</span>
<input type="text" id="art-en-desc" spellcheck="false" />
</label>
<label class="field">
<span>Body (Markdown)</span>
<textarea id="art-en-body" rows="10" spellcheck="false" required></textarea>
<span class="md-tools">
<button type="button" class="btn-ghost btn-sm" data-preview="en">Preview</button>
</span>
</label>
<div id="art-en-preview" class="md-preview" hidden></div>
</fieldset>
<div class="form-actions">
<button type="submit" id="art-save" class="btn-primary">Enregistrer</button>
<button type="button" id="art-cancel" class="btn-ghost">Annuler</button>
<button type="button" id="art-delete" class="btn-danger" hidden>Supprimer</button>
</div>
<p id="art-msg" class="msg" role="status"></p>
</form>
</div>
</section>
<section id="tab-trans" class="tab" hidden aria-label="Traductions">
<div class="card">
<div class="card-head">
<h2>Traductions</h2>
<span id="trans-meta" class="meta"></span>
<div class="head-actions">
<button id="trans-add" class="btn-ghost" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
Ajouter une clé
</button>
<button id="trans-save" class="btn-primary" type="button">Enregistrer</button>
</div>
</div>
<div class="filters">
<input type="text" id="trans-filter" placeholder="Filtrer les clés…" spellcheck="false" />
</div>
<div class="table-scroll">
<table id="trans-table">
<thead>
<tr>
<th>Clé</th>
<th>Français</th>
<th>English</th>
<th class="col-actions"></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<p id="trans-msg" class="msg" role="status"></p>
</div>
</section>
<section id="tab-rules" class="tab" hidden aria-label="Règles Discord">
<div class="card">
<div class="card-head">
<h2>Règles Discord</h2>
<span id="rules-meta" class="meta"></span>
<div class="head-actions">
<button id="rules-reload" class="btn-ghost" type="button">Recharger</button>
<button id="rules-save" class="btn-primary" type="button">Enregistrer</button>
</div>
</div>
<p class="muted">Markdown Discord. Le bot Zektyc publie ces règles chaque minute dans le salon des règles, avec le bouton « ✅ Accepter » qui attribue le rôle <b>Membre</b>. Si le contenu change, le message existant est mis à jour automatiquement. Limite : 2000 caractères.</p>
<div class="rules-editor">
<textarea id="rules-content" rows="18" spellcheck="false" placeholder="# Règles du serveur…"></textarea>
</div>
<p id="rules-msg" class="msg" role="status"></p>
</div>
</section>
<section id="tab-honeypot" class="tab" hidden aria-label="Honeypot">
<div class="card">
<div class="card-head">
<h2>Honeypot</h2>
<span id="honeypot-meta" class="meta"></span>
<div class="head-actions">
<button id="honeypot-clear" class="btn-danger" type="button">Vider la liste</button>
<button id="honeypot-refresh" class="btn-ghost" type="button">Actualiser</button>
</div>
</div>
<p class="muted">Les adresses qui demandent des chemins WordPress inexistants (wp-login.php, .env, xmlrpc.php, etc.) reçoivent une fausse réponse WordPress et sont enregistrées ici. Bannir une IP la bloque définitivement (HTTP 403).</p>
<div id="honeypot-list" class="table-scroll"><p class="meta">Chargement…</p></div>
</div>
</section>
<section id="tab-restart" class="tab" hidden aria-label="Redémarrage">
<div class="card">
<div class="card-head"><h2>Redémarrage des services</h2></div>
<p class="muted">Redémarrage automatique via pm2. L'application relance en ~1 s, Caddy entraîne une coupure TLS de quelques secondes.</p>
<div class="restart-actions">
<button id="restart-app" class="btn-danger" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
Redémarrer l'application
</button>
<button id="restart-caddy" class="btn-danger" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M23 4v6h-6"/><path d="M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10"/><path d="M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
Redémarrer Caddy
</button>
</div>
</div>
</section>
</main>
</div>
<script src="/vendor/marked.umd.js" defer></script>
<script src="/z-panel/admin.js" defer></script>
</body>
</html>