const WebSocket = require('ws'); const http = require('http'); const fs = require('fs'); const path = require('path'); // Create HTTP server const server = http.createServer((req, res) => { // CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } // Serve files let urlPath = req.url; // Remove query string if present urlPath = urlPath.split('?')[0]; // Handle root path if (urlPath === '/' || urlPath === '/index.html') { urlPath = '/html/signature.html'; } // Map URL paths to file system paths based on file type let cleanPath = urlPath.startsWith('/') ? urlPath.substring(1) : urlPath; // Route requests to appropriate directories // Only add directory prefix if path doesn't already have it if (cleanPath.endsWith('.html')) { // HTML files from html/ directory const fileName = path.basename(cleanPath); if (!cleanPath.startsWith('html/')) { cleanPath = 'html/' + fileName; } } else if (cleanPath.endsWith('.css')) { // CSS files from css/ directory const fileName = path.basename(cleanPath); if (!cleanPath.startsWith('css/')) { cleanPath = 'css/' + fileName; } } else if (cleanPath.endsWith('.js')) { // JS files from js/ directory const fileName = path.basename(cleanPath); if (!cleanPath.startsWith('js/')) { cleanPath = 'js/' + fileName; } } // Security: Prevent directory traversal attacks if (cleanPath.includes('..')) { res.writeHead(403, { 'Content-Type': 'text/html' }); res.end('
Gesuchte Datei: ${filePath}
`, 'utf-8'); } else { console.error(`β Server Fehler bei ${filePath}:`, error); res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(`${error.code}
`, 'utf-8'); } } else { res.writeHead(200, { 'Content-Type': contentType }); res.end(content, 'utf-8'); } }); }); // Create WebSocket server const wss = new WebSocket.Server({ server }); // Store connections let masterConnection = null; let signatureConnection = null; wss.on('connection', (ws) => { console.log('Neue WebSocket Verbindung'); ws.on('message', (message) => { try { const data = JSON.parse(message); console.log('π¨ Nachricht empfangen:', data.type); console.log(' Von:', ws === masterConnection ? 'Master' : ws === signatureConnection ? 'Signatur-Station' : 'Unbekannt'); switch (data.type) { case 'register_master': handleMasterRegister(ws); break; case 'register_signature': handleSignatureRegister(ws); break; case 'pdf': handlePdfUpload(data); break; case 'signature': handleSignature(data); break; case 'page_change': handlePageChange(data); break; case 'signature_placed': console.log('π signature_placed Nachricht empfangen, leite weiter...'); handleSignaturePlaced(); break; case 'discard': console.log('π discard Nachricht empfangen, leite weiter...'); handleDiscard(); break; default: console.log('β οΈ Unbekannter Nachrichtentyp:', data.type); } } catch (error) { console.error('β Fehler beim Verarbeiten der Nachricht:', error); } }); ws.on('close', () => { console.log('WebSocket Verbindung geschlossen'); if (ws === masterConnection) { masterConnection = null; console.log('Master getrennt'); } if (ws === signatureConnection) { signatureConnection = null; console.log('Signatur-Station getrennt'); // Notify master that signature station disconnected if (masterConnection && masterConnection.readyState === WebSocket.OPEN) { masterConnection.send(JSON.stringify({ type: 'signature_station_disconnected' })); console.log('Master ΓΌber Signatur-Station Trennung informiert'); } } }); }); function handleMasterRegister(ws) { masterConnection = ws; console.log('Master registriert'); // Notify master about current signature station connection status if (signatureConnection && signatureConnection.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'signature_station_connected' })); console.log('Master ΓΌber Signatur-Station Verbindung informiert'); } else { ws.send(JSON.stringify({ type: 'signature_station_disconnected' })); console.log('Master ΓΌber fehlende Signatur-Station informiert'); } } function handleSignatureRegister(ws) { // Check if another signature station is already connected if (signatureConnection && signatureConnection.readyState === WebSocket.OPEN) { // Inform the new station that another station is already connected ws.send(JSON.stringify({ type: 'already_connected' })); console.log('β οΈ Neue Signatur-Station versucht sich zu verbinden, aber bereits eine Station verbunden'); console.log('β οΈ Neue Station wurde informiert, alte Station bleibt aktiv'); // Keep the old connection, don't replace it // Don't register the new connection as signatureConnection return; // Exit without registering the new connection } // No existing connection, register this new one signatureConnection = ws; console.log('Signatur-Station registriert'); // Notify master that signature station is now connected if (masterConnection && masterConnection.readyState === WebSocket.OPEN) { masterConnection.send(JSON.stringify({ type: 'signature_station_connected' })); console.log('Master ΓΌber Signatur-Station Verbindung informiert'); } } function handlePdfUpload(data) { const { pdf } = data; if (!signatureConnection || signatureConnection.readyState !== WebSocket.OPEN) { console.log('Keine Signatur-Station verbunden'); return; } // Forward PDF to signature station signatureConnection.send(JSON.stringify({ type: 'pdf', pdf: pdf })); console.log('PDF an Signatur-Station weitergeleitet'); } function handleSignature(data) { const { signature } = data; if (!masterConnection || masterConnection.readyState !== WebSocket.OPEN) { console.log('Keine Master-Verbindung'); return; } // Send signature to master masterConnection.send(JSON.stringify({ type: 'signature', signature: signature })); console.log('Unterschrift an Master gesendet'); } function handlePageChange(data) { const { pageNum, totalPages } = data; if (!signatureConnection || signatureConnection.readyState !== WebSocket.OPEN) { console.log('Keine Signatur-Station verbunden'); return; } // Forward page change to signature station signatureConnection.send(JSON.stringify({ type: 'page_change', pageNum: pageNum, totalPages: totalPages })); console.log('Seitenwechsel an Signatur-Station weitergeleitet: Seite', pageNum, 'von', totalPages); } function handleSignaturePlaced() { console.log('handleSignaturePlaced() aufgerufen'); console.log('signatureConnection vorhanden:', signatureConnection ? 'Ja' : 'Nein'); console.log('signatureConnection.readyState:', signatureConnection ? signatureConnection.readyState : 'N/A'); if (!signatureConnection || signatureConnection.readyState !== WebSocket.OPEN) { console.log('β οΈ Keine Signatur-Station verbunden - BestΓ€tigung kann nicht gesendet werden'); return; } try { // Forward signature placed confirmation to signature station const message = JSON.stringify({ type: 'signature_placed' }); signatureConnection.send(message); console.log('β Unterschrift-Platzierung-BestΓ€tigung an Signatur-Station gesendet'); } catch (error) { console.error('β Fehler beim Senden der BestΓ€tigung:', error); } } function handleDiscard() { console.log('handleDiscard() aufgerufen'); console.log('signatureConnection vorhanden:', signatureConnection ? 'Ja' : 'Nein'); console.log('signatureConnection.readyState:', signatureConnection ? signatureConnection.readyState : 'N/A'); if (!signatureConnection || signatureConnection.readyState !== WebSocket.OPEN) { console.log('β οΈ Keine Signatur-Station verbunden - Verwerfen-Nachricht kann nicht gesendet werden'); return; } try { // Forward discard message to signature station const message = JSON.stringify({ type: 'discard' }); signatureConnection.send(message); console.log('β Verwerfen-Nachricht an Signatur-Station gesendet'); } catch (error) { console.error('β Fehler beim Senden der Verwerfen-Nachricht:', error); } } const PORT = 8080; const HOST = '0.0.0.0'; // Listen on all network interfaces server.listen(PORT, HOST, () => { const os = require('os'); const networkInterfaces = os.networkInterfaces(); let ipAddresses = []; // Get all IPv4 addresses Object.keys(networkInterfaces).forEach((interfaceName) => { networkInterfaces[interfaceName].forEach((iface) => { if (iface.family === 'IPv4' && !iface.internal) { ipAddresses.push(iface.address); } }); }); console.log(` ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β PDF Unterschrift System gestartet! β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β Lokaler Zugriff: β Master-Seite: http://localhost:${PORT}/master.html β Signatur-Seite: http://localhost:${PORT}/signature.html β `); if (ipAddresses.length > 0) { console.log(`β β Netzwerk-Zugriff (fΓΌr iPhone/Tablet): `); ipAddresses.forEach(ip => { console.log(`β Master-Seite: http://${ip}:${PORT}/master.html `); console.log(`β Signatur-Seite: http://${ip}:${PORT}/signature.html `); }); } console.log(`β β WICHTIG: Γffne die Signatur-Seite einmal und lasse β sie offen. Jede neue PDF wird dort automatisch β angezeigt! β β WebSocket Server lΓ€uft auf Port ${PORT} β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ `); });