ML-KEM-1024 | FIPS 203 | CSPN ANSSI Chiffrement souverain post-quantique
/* chat-widget.js — Cryptops AI assistant widget */ (function(){ 'use strict'; var API = 'https://contact.cryptops.fr/api/chat'; var sid = null; var isOpen = false; function create(){ // Chat button var btn = document.createElement('button'); btn.id = 'cw-btn'; btn.setAttribute('aria-label','Assistant Cryptops'); btn.innerHTML = ''; document.body.appendChild(btn); // Chat panel var panel = document.createElement('div'); panel.id = 'cw-panel'; panel.innerHTML = '
Assistant PQC
' + '
' + '
'; document.body.appendChild(panel); // Style var s = document.createElement('style'); s.textContent = '#cw-btn{position:fixed;bottom:1.5rem;right:1.5rem;z-index:900;width:56px;height:56px;border-radius:50%;background:var(--accent,#6366f1);color:#fff;border:none;cursor:pointer;box-shadow:0 4px 16px rgba(99,102,241,.4);transition:transform .2s,box-shadow .2s;display:flex;align-items:center;justify-content:center}' + '#cw-btn:hover{transform:scale(1.08);box-shadow:0 6px 24px rgba(99,102,241,.5)}' + '#cw-btn svg{width:24px;height:24px}' + '#cw-panel{position:fixed;bottom:5.5rem;right:1.5rem;z-index:901;width:380px;max-width:calc(100vw - 2rem);max-height:500px;background:var(--bg2,#0f172a);border:1px solid var(--border,#334155);border-radius:16px;box-shadow:0 8px 32px rgba(0,0,0,.3);display:none;flex-direction:column;overflow:hidden}' + '#cw-panel.open{display:flex}' + '#cw-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--border,#334155);font-weight:600;font-size:.9rem;color:var(--text,#e2e8f0)}' + '#cw-close{background:none;border:none;color:var(--dim,#94a3b8);font-size:1.4rem;cursor:pointer;padding:4px 8px}' + '#cw-msgs{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem;min-height:200px;max-height:350px}' + '.cw-msg{padding:.6rem .9rem;border-radius:12px;font-size:.85rem;line-height:1.5;max-width:85%;word-wrap:break-word}' + '.cw-user{background:var(--accent,#6366f1);color:#fff;align-self:flex-end;border-bottom-right-radius:4px}' + '.cw-bot{background:var(--bg3,#1e293b);color:var(--text,#e2e8f0);align-self:flex-start;border-bottom-left-radius:4px}' + '.cw-typing{opacity:.6;font-style:italic}' + '#cw-form{display:flex;padding:.5rem;border-top:1px solid var(--border,#334155);gap:.5rem}' + '#cw-input{flex:1;background:var(--bg,#030712);color:var(--text,#e2e8f0);border:1px solid var(--border,#334155);border-radius:8px;padding:.5rem .75rem;font-size:.85rem;outline:none}' + '#cw-input:focus{border-color:var(--accent,#6366f1)}' + '#cw-form button[type=submit]{background:var(--accent,#6366f1);color:#fff;border:none;border-radius:8px;padding:.5rem;cursor:pointer;display:flex;align-items:center;justify-content:center;width:36px;min-width:36px}' + '#cw-form button[type=submit] svg{width:16px;height:16px}' + '@media(max-width:480px){#cw-panel{bottom:0;right:0;left:0;width:100%;max-width:100%;max-height:70vh;border-radius:16px 16px 0 0}#cw-btn{bottom:1rem;right:1rem}}'; document.head.appendChild(s); // Events btn.addEventListener('click', function(){ toggle(); }); document.getElementById('cw-close').addEventListener('click', function(){ toggle(); }); document.getElementById('cw-form').addEventListener('submit', function(e){ e.preventDefault(); send(); }); // Welcome addMsg('bot', 'Bonjour ! Je suis l\'assistant Cryptosphere. Comment puis-je vous aider concernant la cryptographie post-quantique ?'); } function toggle(){ isOpen = !isOpen; document.getElementById('cw-panel').classList.toggle('open', isOpen); if (isOpen) document.getElementById('cw-input').focus(); } function addMsg(role, text){ var msgs = document.getElementById('cw-msgs'); var d = document.createElement('div'); d.className = 'cw-msg cw-' + (role === 'user' ? 'user' : 'bot'); d.textContent = text; msgs.appendChild(d); msgs.scrollTop = msgs.scrollHeight; return d; } function send(){ var input = document.getElementById('cw-input'); var msg = input.value.trim(); if (!msg) return; input.value = ''; addMsg('user', msg); var typing = addMsg('bot', '...'); typing.classList.add('cw-typing'); fetch(API, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({message: msg, session_id: sid}) }) .then(function(r){ return r.json(); }) .then(function(d){ typing.remove(); addMsg('bot', d.response || 'Erreur.'); if (d.session_id) sid = d.session_id; }) .catch(function(){ typing.remove(); addMsg('bot', 'Connexion impossible. Réessayez.'); }); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', create); else create(); })();