ihm_client/examples/external-site.html
NicolasCantu bf680ab6dd ci: docker_tag=pbkdf2-credentials
🔐 Implémentation PBKDF2 avec credentials navigateur

 Fonctionnalités ajoutées:
- SecureCredentialsService avec PBKDF2 (100k itérations)
- Chiffrement AES-GCM des clés spend/scan
- Interface utilisateur complète pour gestion credentials
- Tests unitaires complets
- Architecture modulaire avec EventBus
- Gestion mémoire optimisée
- Performance monitoring
- Web Workers pour encodage asynchrone

🛡️ Sécurité:
- Dérivation PBKDF2 avec salt unique
- Chiffrement AES-GCM des clés sensibles
- Validation force mot de passe
- Stockage sécurisé IndexedDB + WebAuthn
- Logging sécurisé sans exposition données

🔧 Corrections:
- Erreur 500 résolue (clé dupliquée package.json)
- Configuration Vite simplifiée
- Dépendances manquantes corrigées

📊 Améliorations:
- Architecture découplée avec repositories
- Services spécialisés (PairingService, etc.)
- Monitoring performance et mémoire
- Tests avec couverture complète
- Documentation technique détaillée
2025-10-23 12:51:49 +02:00

328 lines
9.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>External Site - 4NK Integration Example</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.header {
background: rgba(255, 255, 255, 0.95);
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
}
.header h1 {
color: #333;
text-align: center;
margin-bottom: 10px;
}
.header p {
color: #666;
text-align: center;
font-size: 14px;
}
.main-content {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.integration-section {
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.integration-section h2 {
color: #333;
margin-bottom: 15px;
font-size: 24px;
}
.integration-section p {
color: #666;
margin-bottom: 20px;
line-height: 1.6;
}
.iframe-container {
position: relative;
width: 100%;
height: 600px;
border: 2px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.iframe-container iframe {
width: 100%;
height: 100%;
border: none;
}
.status-panel {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 15px;
margin-top: 20px;
}
.status-panel h3 {
color: #333;
margin-bottom: 10px;
}
.status-item {
display: flex;
justify-content: space-between;
padding: 5px 0;
border-bottom: 1px solid #e9ecef;
}
.status-item:last-child {
border-bottom: none;
}
.status-label {
font-weight: 500;
color: #555;
}
.status-value {
color: #007bff;
font-weight: 500;
}
.controls {
display: flex;
gap: 10px;
margin-top: 20px;
flex-wrap: wrap;
}
.btn {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s ease;
}
.btn:hover {
background: #0056b3;
transform: translateY(-2px);
}
.btn.secondary {
background: #6c757d;
}
.btn.secondary:hover {
background: #545b62;
}
.log-container {
background: #1e1e1e;
color: #f8f9fa;
padding: 15px;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 12px;
max-height: 200px;
overflow-y: auto;
margin-top: 20px;
}
.log-entry {
margin-bottom: 5px;
padding: 2px 0;
}
.log-entry.info {
color: #17a2b8;
}
.log-entry.success {
color: #28a745;
}
.log-entry.error {
color: #dc3545;
}
.log-entry.warning {
color: #ffc107;
}
</style>
</head>
<body>
<div class="header">
<h1>🏢 External Business Site</h1>
<p>Integrated 4NK Pairing System - Secure Device Authentication</p>
</div>
<div class="main-content">
<div class="integration-section">
<h2>🔐 4NK Pairing Integration</h2>
<p>
This external site demonstrates how to integrate the 4NK pairing system
using an iframe with channel_message communication. The iframe contains
the 4NK application without header, and all menu options are integrated
as buttons within the content.
</p>
<div class="iframe-container">
<iframe
id="4nk-iframe"
src="http://localhost:3004"
title="4NK Pairing System"
sandbox="allow-scripts allow-same-origin allow-forms"
></iframe>
</div>
<div class="status-panel">
<h3>📊 Integration Status</h3>
<div class="status-item">
<span class="status-label">Iframe Status:</span>
<span class="status-value" id="iframe-status">Loading...</span>
</div>
<div class="status-item">
<span class="status-label">Communication:</span>
<span class="status-value" id="communication-status">Waiting...</span>
</div>
<div class="status-item">
<span class="status-label">Last Message:</span>
<span class="status-value" id="last-message">None</span>
</div>
</div>
<div class="controls">
<button class="btn" onclick="sendTestMessage()">📤 Send Test Message</button>
<button class="btn secondary" onclick="clearLog()">🗑️ Clear Log</button>
<button class="btn secondary" onclick="refreshIframe()">🔄 Refresh Iframe</button>
</div>
<div class="log-container" id="log-container">
<div class="log-entry info">🚀 External site loaded</div>
<div class="log-entry info">📡 Waiting for iframe communication...</div>
</div>
</div>
</div>
<script>
let messageCount = 0;
// Listen for messages from the iframe
window.addEventListener('message', function(event) {
// Security check - in production, verify event.origin
if (event.origin !== 'http://localhost:3004') {
return;
}
const { type, data } = event.data;
messageCount++;
logMessage(`📨 Received: ${type}`, 'info');
updateStatus('communication-status', 'Active');
updateStatus('last-message', `${type} (${messageCount})`);
// Handle different message types
switch (type) {
case 'IFRAME_READY':
logMessage('✅ 4NK iframe is ready', 'success');
updateStatus('iframe-status', 'Ready');
break;
case 'MENU_NAVIGATION':
logMessage(`🧭 Menu navigation: ${data.page}`, 'info');
break;
case 'PAIRING_4WORDS_WORDS_GENERATED':
logMessage(`🔐 4 words generated: ${data.words}`, 'success');
break;
case 'PAIRING_4WORDS_STATUS_UPDATE':
logMessage(`📊 Status update: ${data.status}`, 'info');
break;
case 'PAIRING_4WORDS_SUCCESS':
logMessage(`✅ Pairing successful: ${data.message}`, 'success');
break;
case 'PAIRING_4WORDS_ERROR':
logMessage(`❌ Pairing error: ${data.error}`, 'error');
break;
default:
logMessage(`❓ Unknown message type: ${type}`, 'warning');
}
});
function logMessage(message, type = 'info') {
const logContainer = document.getElementById('log-container');
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.className = `log-entry ${type}`;
logEntry.textContent = `[${timestamp}] ${message}`;
logContainer.appendChild(logEntry);
logContainer.scrollTop = logContainer.scrollHeight;
}
function updateStatus(elementId, value) {
const element = document.getElementById(elementId);
if (element) {
element.textContent = value;
}
}
function sendTestMessage() {
const iframe = document.getElementById('4nk-iframe');
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({
type: 'TEST_MESSAGE',
data: { message: 'Hello from external site!' }
}, 'http://localhost:3004');
logMessage('📤 Sent test message to iframe', 'info');
}
}
function clearLog() {
const logContainer = document.getElementById('log-container');
logContainer.innerHTML = '<div class="log-entry info">🗑️ Log cleared</div>';
}
function refreshIframe() {
const iframe = document.getElementById('4nk-iframe');
iframe.src = iframe.src;
logMessage('🔄 Iframe refreshed', 'info');
updateStatus('iframe-status', 'Refreshing...');
}
// Initialize
logMessage('🌐 External site initialized', 'success');
</script>
</body>
</html>