securisation d'acces à la page

This commit is contained in:
LIABEUF, Stephane (External) 2026-06-24 07:06:24 +02:00
parent 17d89c024d
commit 773cc71613
3 changed files with 286 additions and 96 deletions

View file

@ -702,8 +702,13 @@
<script> <script>
const cv = new URLSearchParams(window.location.search).get('cv'); const cv = new URLSearchParams(window.location.search).get('cv');
if (cv) document.getElementById('backBtn').href = `index.html?cv=${cv}`; const validCodes = ['f3b9c7a8d5e4b2d1c0a9b8d7', 'e2d1c0b9a8f7e6d5c4b3a2f1', 'a1b2c3d4e5f6a7b8c9d0e1f2'];
if (!cv || !validCodes.includes(cv)) {
window.location.href = 'index.html';
} else {
document.getElementById('backBtn').href = `index.html?cv=${cv}`;
if (typeof umami !== 'undefined') umami.track('ecosystem-view'); if (typeof umami !== 'undefined') umami.track('ecosystem-view');
}
</script> </script>
</body> </body>
</html> </html>

View file

@ -3485,8 +3485,187 @@
// Sélection du fichier JSON selon le paramètre ?cv= // Sélection du fichier JSON selon le paramètre ?cv=
const cvParam = new URLSearchParams(window.location.search).get('cv'); const cvParam = new URLSearchParams(window.location.search).get('cv');
const cvAllowed = ['ux', 'dsi'];
const cvFile = cvAllowed.includes(cvParam) ? `cv-data-${cvParam}.json` : 'cv-data.json'; // Mapping des codes de 24 caractères vers les fichiers de CV correspondants
const cvMap = {
'f3b9c7a8d5e4b2d1c0a9b8d7': 'cv-data.json', // Version Générale (Directeur Conseil Service)
'e2d1c0b9a8f7e6d5c4b3a2f1': 'cv-data-ux.json', // Version UX & Digital Manager
'a1b2c3d4e5f6a7b8c9d0e1f2': 'cv-data-dsi.json' // Version Directeur SI & Transformation
};
if (!cvParam || !cvMap[cvParam]) {
// Masquer l'écran de chargement
const ld = document.getElementById('loading');
if (ld) ld.remove();
// Masquer les contrôles globaux non pertinents pour l'écran de verrouillage
const burger = document.getElementById('burgerBtn');
if (burger) burger.style.display = 'none';
const readProgress = document.getElementById('read-progress');
if (readProgress) readProgress.style.display = 'none';
// Injecter le CSS pour la page privée
const style = document.createElement('style');
style.textContent = `
.private-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #02050a;
color: #f4f7fb;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
padding: 20px;
box-sizing: border-box;
position: fixed;
inset: 0;
z-index: 9999;
}
.private-card {
background: rgba(7, 18, 29, 0.75);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(0, 215, 255, 0.2);
border-radius: 16px;
padding: 40px 30px;
max-width: 440px;
width: 100%;
text-align: center;
box-shadow: 0 0 40px rgba(0, 215, 255, 0.08);
}
.lock-icon {
color: #00d8ff;
margin-bottom: 24px;
animation: pulse-glow 3s infinite ease-in-out;
display: inline-flex;
justify-content: center;
align-items: center;
}
@keyframes pulse-glow {
0%, 100% {
transform: scale(1);
filter: drop-shadow(0 0 8px rgba(0, 216, 255, 0.4));
}
50% {
transform: scale(1.05);
filter: drop-shadow(0 0 20px rgba(0, 216, 255, 0.8));
}
}
.private-card h1 {
font-family: 'Orbitron', 'Arial Black', sans-serif;
font-size: 22px;
letter-spacing: 0.15em;
margin-bottom: 16px;
color: #00d8ff;
text-shadow: 0 0 10px rgba(0, 216, 255, 0.3);
}
.private-card p {
color: #9aa8b8;
font-size: 14px;
line-height: 1.6;
margin-bottom: 30px;
}
.input-group {
position: relative;
margin-bottom: 20px;
}
.private-card input {
width: 100%;
padding: 14px 16px;
background: rgba(2, 5, 10, 0.8);
border: 1px solid rgba(0, 215, 255, 0.15);
border-radius: 8px;
color: #fff;
font-family: 'Share Tech Mono', 'Courier New', monospace;
font-size: 15px;
letter-spacing: 0.05em;
text-align: center;
transition: all 0.3s ease;
box-sizing: border-box;
}
.private-card input:focus {
outline: none;
border-color: #00d8ff;
box-shadow: 0 0 15px rgba(0, 216, 255, 0.25);
}
.private-card button {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #00d8ff 0%, #228cff 100%);
border: none;
border-radius: 8px;
color: #02050a;
font-family: 'Orbitron', sans-serif;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.1em;
cursor: pointer;
transition: all 0.3s ease;
}
.private-card button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(0, 216, 255, 0.4);
}
.private-card button:active {
transform: translateY(0);
}
.error-message {
color: #ff3c74;
font-size: 12px;
margin-top: 15px;
font-family: 'Share Tech Mono', monospace;
min-height: 18px;
}
`;
document.head.appendChild(style);
// Injecter le HTML de la page privée dans #app
const app = document.getElementById('app');
app.innerHTML = `
<div class="private-container">
<div class="private-card">
<div class="lock-icon">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
</div>
<h1>PAGE PRIVÉE</h1>
<p>Ce curriculum vitæ est confidentiel. Veuillez saisir votre code d'accès de 24 caractères pour y accéder.</p>
<form id="accessForm">
<div class="input-group">
<input type="text" id="accessCode" placeholder="Code d'accès (24 caractères)" maxlength="24" autocomplete="off" required>
</div>
<button type="submit">VALIDER</button>
</form>
<div id="errorMessage" class="error-message"></div>
</div>
</div>
`;
// Se focaliser sur le champ de saisie
const accessCodeInput = document.getElementById('accessCode');
if (accessCodeInput) accessCodeInput.focus();
// Écouter la soumission du formulaire
document.getElementById('accessForm').addEventListener('submit', (e) => {
e.preventDefault();
const code = accessCodeInput.value.trim();
if (cvMap[code]) {
// Rediriger avec le bon paramètre d'URL
window.location.search = `?cv=${code}`;
} else {
// Afficher le message d'erreur
const errEl = document.getElementById('errorMessage');
if (errEl) {
errEl.textContent = '❌ Code d\'accès invalide';
accessCodeInput.style.borderColor = '#ff3c74';
accessCodeInput.style.boxShadow = '0 0 15px rgba(255, 60, 116, 0.25)';
}
}
});
} else {
const cvFile = cvMap[cvParam];
fetch(cvFile) fetch(cvFile)
.then(r => { .then(r => {
@ -3586,6 +3765,7 @@
</span> </span>
</div>`; </div>`;
}); });
}
// ══════════════════════════════════════════════ // ══════════════════════════════════════════════
// TÉLÉCHARGEMENT PDF // TÉLÉCHARGEMENT PDF

View file

@ -980,7 +980,12 @@
</main> </main>
<script> <script>
const cv = new URLSearchParams(window.location.search).get('cv'); const cv = new URLSearchParams(window.location.search).get('cv');
if (cv) document.getElementById('backBtn').href = `index.html?cv=${cv}`; const validCodes = ['f3b9c7a8d5e4b2d1c0a9b8d7', 'e2d1c0b9a8f7e6d5c4b3a2f1', 'a1b2c3d4e5f6a7b8c9d0e1f2'];
if (!cv || !validCodes.includes(cv)) {
window.location.href = 'index.html';
} else {
document.getElementById('backBtn').href = `index.html?cv=${cv}`;
}
</script> </script>
</body> </body>