diff --git a/index.html b/index.html index e387012..25dd4bd 100644 --- a/index.html +++ b/index.html @@ -157,6 +157,7 @@ + \ No newline at end of file diff --git a/src/app.jsx b/src/app.jsx index 207e8a3..b436c45 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -1421,7 +1421,6 @@ // PAKE password states removed - using SAS verification instead // Session state - all security features enabled by default - const [sessionTimeLeft, setSessionTimeLeft] = React.useState(0); const [pendingSession, setPendingSession] = React.useState(null); // All security features are enabled by default - no payment required @@ -1730,8 +1729,6 @@ setVerificationCode(''); setSecurityLevel(null); - // Reset session and timer - setSessionTimeLeft(0); // Return to main page after a short delay setTimeout(() => { @@ -3471,7 +3468,6 @@ isConnected: isConnectedAndVerified, securityLevel: securityLevel, // sessionManager removed - all features enabled by default - sessionTimeLeft: sessionTimeLeft, webrtcManager: webrtcManagerRef.current }), diff --git a/src/components/ui/Header.jsx b/src/components/ui/Header.jsx index 96ed2c2..6221840 100644 --- a/src/components/ui/Header.jsx +++ b/src/components/ui/Header.jsx @@ -5,13 +5,8 @@ const EnhancedMinimalHeader = ({ onDisconnect, isConnected, securityLevel, - sessionManager, - sessionTimeLeft, webrtcManager }) => { - const [currentTimeLeft, setCurrentTimeLeft] = React.useState(sessionTimeLeft || 0); - const [hasActiveSession, setHasActiveSession] = React.useState(false); - const [sessionType, setSessionType] = React.useState('unknown'); const [realSecurityLevel, setRealSecurityLevel] = React.useState(null); const [lastSecurityUpdate, setLastSecurityUpdate] = React.useState(0); @@ -268,8 +263,7 @@ const EnhancedMinimalHeader = ({ details: 'Security verification not available', isRealData: false, passedChecks: 0, - totalChecks: 0, - sessionType: 'unknown' + totalChecks: 0 }; console.log('Using fallback security data:', securityData); } @@ -277,7 +271,6 @@ const EnhancedMinimalHeader = ({ // Detailed information about the REAL security check let message = `REAL-TIME SECURITY VERIFICATION\n\n`; message += `Security Level: ${securityData.level} (${securityData.score}%)\n`; - message += `Session Type: ${securityData.sessionType || 'premium'}\n`; message += `Verification Time: ${new Date(securityData.timestamp).toLocaleTimeString()}\n`; message += `Data Source: ${securityData.isRealData ? 'Real Cryptographic Tests' : 'Simulated Data'}\n\n`; @@ -465,7 +458,6 @@ const EnhancedMinimalHeader = ({ const config = getStatusConfig(); const displaySecurityLevel = isConnected ? (realSecurityLevel || securityLevel) : null; - const shouldShowTimer = hasActiveSession && currentTimeLeft > 0 && window.SessionTimer; // ============================================ // DATA RELIABILITY INDICATOR @@ -570,13 +562,6 @@ const EnhancedMinimalHeader = ({ key: 'status-section', className: 'flex items-center space-x-2 sm:space-x-3' }, [ - // Session Timer - all features enabled by default - shouldShowTimer && React.createElement(window.SessionTimer, { - key: 'session-timer', - timeLeft: currentTimeLeft, - sessionType: sessionType, - onDisconnect: onDisconnect - }), displaySecurityLevel && React.createElement('div', { key: 'security-level', diff --git a/src/components/ui/SessionTimer.jsx b/src/components/ui/SessionTimer.jsx deleted file mode 100644 index a84862c..0000000 --- a/src/components/ui/SessionTimer.jsx +++ /dev/null @@ -1,334 +0,0 @@ -// SessionTimer Component - v4.3.120 - ECDH + DTLS + SAS -const SessionTimer = ({ timeLeft, sessionType, sessionManager, onDisconnect }) => { - const [currentTime, setCurrentTime] = React.useState(timeLeft || 0); - const [showExpiredMessage, setShowExpiredMessage] = React.useState(false); - const [initialized, setInitialized] = React.useState(false); - const [connectionBroken, setConnectionBroken] = React.useState(false); - - - const [loggedHidden, setLoggedHidden] = React.useState(false); - - React.useEffect(() => { - if (connectionBroken) { - if (!loggedHidden) { - console.log('⏱️ SessionTimer initialization skipped - connection broken'); - setLoggedHidden(true); - } - return; - } - - let initialTime = 0; - - if (sessionManager?.hasActiveSession()) { - initialTime = sessionManager.getTimeLeft(); - } else if (timeLeft && timeLeft > 0) { - initialTime = timeLeft; - } - - if (initialTime <= 0) { - setCurrentTime(0); - setInitialized(false); - setLoggedHidden(true); - return; - } - - if (connectionBroken) { - setCurrentTime(0); - setInitialized(false); - setLoggedHidden(true); - return; - } - setCurrentTime(initialTime); - setInitialized(true); - setLoggedHidden(false); - }, [sessionManager, connectionBroken]); - - React.useEffect(() => { - if (connectionBroken) { - if (!loggedHidden) { - setLoggedHidden(true); - } - return; - } - - if (timeLeft && timeLeft > 0) { - setCurrentTime(timeLeft); - } - setLoggedHidden(false); - }, [timeLeft, connectionBroken]); - - React.useEffect(() => { - if (!initialized) { - return; - } - - if (connectionBroken) { - if (!loggedHidden) { - setLoggedHidden(true); - } - return; - } - - if (!currentTime || currentTime <= 0 || !sessionManager) { - return; - } - - const interval = setInterval(() => { - if (connectionBroken) { - setCurrentTime(0); - clearInterval(interval); - return; - } - - if (sessionManager?.hasActiveSession()) { - const newTime = sessionManager.getTimeLeft(); - setCurrentTime(newTime); - - if (window.DEBUG_MODE && Math.floor(Date.now() / 30000) !== Math.floor((Date.now() - 1000) / 30000)) { - console.log('⏱️ Timer tick:', Math.floor(newTime / 1000) + 's'); - } - - if (newTime <= 0) { - setShowExpiredMessage(true); - setTimeout(() => setShowExpiredMessage(false), 5000); - clearInterval(interval); - } - } else { - setCurrentTime(0); - clearInterval(interval); - } - }, 1000); - - return () => { - clearInterval(interval); - }; - }, [initialized, currentTime, sessionManager, connectionBroken]); - - React.useEffect(() => { - const handleSessionTimerUpdate = (event) => { - if (connectionBroken) { - return; - } - - if (event.detail.timeLeft && event.detail.timeLeft > 0) { - setCurrentTime(event.detail.timeLeft); - } - }; - - const handleForceHeaderUpdate = (event) => { - if (connectionBroken) { - return; - } - - if (sessionManager && sessionManager.hasActiveSession()) { - const newTime = sessionManager.getTimeLeft(); - setCurrentTime(newTime); - } else { - setCurrentTime(event.detail.timeLeft); - } - }; - - const handlePeerDisconnect = (event) => { - setConnectionBroken(true); - setCurrentTime(0); - setShowExpiredMessage(false); - setLoggedHidden(false); - }; - - const handleNewConnection = (event) => { - setConnectionBroken(false); - setLoggedHidden(false); - }; - - const handleConnectionCleaned = (event) => { - setConnectionBroken(true); - setCurrentTime(0); - setShowExpiredMessage(false); - setInitialized(false); - setLoggedHidden(false); - }; - - const handleSessionReset = (event) => { - setConnectionBroken(true); - setCurrentTime(0); - setShowExpiredMessage(false); - setInitialized(false); - setLoggedHidden(false); - }; - - const handleSessionCleanup = (event) => { - setConnectionBroken(true); - setCurrentTime(0); - setShowExpiredMessage(false); - setInitialized(false); - setLoggedHidden(false); - }; - - const handleDisconnected = (event) => { - setConnectionBroken(true); - setCurrentTime(0); - setShowExpiredMessage(false); - setInitialized(false); - setLoggedHidden(false); - }; - - document.addEventListener('session-timer-update', handleSessionTimerUpdate); - document.addEventListener('force-header-update', handleForceHeaderUpdate); - document.addEventListener('peer-disconnect', handlePeerDisconnect); - document.addEventListener('new-connection', handleNewConnection); - document.addEventListener('connection-cleaned', handleConnectionCleaned); - document.addEventListener('session-reset', handleSessionReset); - document.addEventListener('session-cleanup', handleSessionCleanup); - document.addEventListener('disconnected', handleDisconnected); - - return () => { - document.removeEventListener('session-timer-update', handleSessionTimerUpdate); - document.removeEventListener('force-header-update', handleForceHeaderUpdate); - document.removeEventListener('peer-disconnect', handlePeerDisconnect); - document.removeEventListener('new-connection', handleNewConnection); - document.removeEventListener('connection-cleaned', handleConnectionCleaned); - document.removeEventListener('session-reset', handleSessionReset); - document.removeEventListener('session-cleanup', handleSessionCleanup); - document.removeEventListener('disconnected', handleDisconnected); - }; - }, [sessionManager]); - - if (showExpiredMessage) { - return React.createElement('div', { - className: 'session-timer expired flex items-center space-x-2 px-3 py-1.5 rounded-lg animate-pulse', - style: { background: 'linear-gradient(135deg, rgba(239, 68, 68, 0.2) 0%, rgba(220, 38, 38, 0.2) 100%)' } - }, [ - React.createElement('i', { - key: 'icon', - className: 'fas fa-exclamation-triangle text-red-400' - }), - React.createElement('span', { - key: 'message', - className: 'text-red-400 text-sm font-medium' - }, 'Session Expired!') - ]); - } - - if (!sessionManager) { - if (!loggedHidden) { - console.log('⏱️ SessionTimer hidden - no sessionManager'); - setLoggedHidden(true); - } - return null; - } - - if (connectionBroken) { - if (!loggedHidden) { - console.log('⏱️ SessionTimer hidden - connection broken'); - setLoggedHidden(true); - } - return null; - } - - if (!currentTime || currentTime <= 0) { - if (!loggedHidden) { - console.log('⏱️ SessionTimer hidden - no time left, currentTime:', currentTime); - setLoggedHidden(true); - } - return null; - } - - if (loggedHidden) { - setLoggedHidden(false); - } - - const totalMinutes = Math.floor(currentTime / (60 * 1000)); - const totalSeconds = Math.floor(currentTime / 1000); - - const isDemo = sessionType === 'demo'; - const isWarning = isDemo ? totalMinutes <= 2 : totalMinutes <= 10; - const isCritical = isDemo ? totalSeconds <= 60 : totalMinutes <= 5; - - const formatTime = (ms) => { - const hours = Math.floor(ms / (60 * 60 * 1000)); - const minutes = Math.floor((ms % (60 * 60 * 1000)) / (60 * 1000)); - const seconds = Math.floor((ms % (60 * 1000)) / 1000); - - if (hours > 0) { - return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; - } else { - return `${minutes}:${seconds.toString().padStart(2, '0')}`; - } - }; - - const getTimerStyle = () => { - const totalDuration = sessionType === 'demo' ? 6 * 60 * 1000 : 60 * 60 * 1000; - const timeProgress = (totalDuration - currentTime) / totalDuration; - - let backgroundColor, textColor, iconColor, iconClass, shouldPulse; - - if (timeProgress <= 0.33) { - backgroundColor = 'linear-gradient(135deg, rgba(34, 197, 94, 0.15) 0%, rgba(22, 163, 74, 0.15) 100%)'; - textColor = 'text-green-400'; - iconColor = 'text-green-400'; - iconClass = 'fas fa-clock'; - shouldPulse = false; - } else if (timeProgress <= 0.66) { - backgroundColor = 'linear-gradient(135deg, rgba(234, 179, 8, 0.15) 0%, rgba(202, 138, 4, 0.15) 100%)'; - textColor = 'text-yellow-400'; - iconColor = 'text-yellow-400'; - iconClass = 'fas fa-clock'; - shouldPulse = false; - } else { - backgroundColor = 'linear-gradient(135deg, rgba(239, 68, 68, 0.15) 0%, rgba(220, 38, 38, 0.15) 100%)'; - textColor = 'text-red-400'; - iconColor = 'text-red-400'; - iconClass = 'fas fa-exclamation-triangle'; - shouldPulse = true; - } - - return { backgroundColor, textColor, iconColor, iconClass, shouldPulse }; - }; - - const timerStyle = getTimerStyle(); - - const handleTimerClick = () => { - if (onDisconnect && typeof onDisconnect === 'function') { - onDisconnect(); - } - }; - - return React.createElement('div', { - className: `session-timer flex items-center space-x-2 px-3 py-1.5 rounded-lg transition-all duration-500 cursor-pointer hover:opacity-80 ${ - isDemo ? 'demo-session' : '' - } ${timerStyle.shouldPulse ? 'animate-pulse' : ''}`, - style: { background: timerStyle.backgroundColor }, - onClick: handleTimerClick, - title: 'Click to disconnect and clear session' - }, [ - React.createElement('i', { - key: 'icon', - className: `${timerStyle.iconClass} ${timerStyle.iconColor}` - }), - React.createElement('span', { - key: 'time', - className: `text-sm font-mono font-semibold ${timerStyle.textColor}` - }, formatTime(currentTime)), - React.createElement('div', { - key: 'progress', - className: 'ml-2 w-16 h-1 bg-gray-700 rounded-full overflow-hidden' - }, [ - React.createElement('div', { - key: 'progress-bar', - className: `${timerStyle.textColor.replace('text-', 'bg-')} h-full rounded-full transition-all duration-500`, - style: { - width: `${Math.max(0, Math.min(100, (currentTime / (sessionType === 'demo' ? 6 * 60 * 1000 : 60 * 60 * 1000)) * 100))}%` - } - }) - ]) - ]); -}; - -window.SessionTimer = SessionTimer; - -window.updateSessionTimer = (newTimeLeft, newSessionType) => { - document.dispatchEvent(new CustomEvent('session-timer-update', { - detail: { timeLeft: newTimeLeft, sessionType: newSessionType } - })); -}; - diff --git a/src/network/EnhancedSecureWebRTCManager.js b/src/network/EnhancedSecureWebRTCManager.js index dbede3e..0c20ea2 100644 --- a/src/network/EnhancedSecureWebRTCManager.js +++ b/src/network/EnhancedSecureWebRTCManager.js @@ -167,8 +167,6 @@ class EnhancedSecureWebRTCManager { } : null; }; this._secureLog('info', '🔒 Enhanced WebRTC Manager initialized with secure API'); - this.currentSessionType = null; - this.currentSecurityLevel = 'basic'; this.sessionConstraints = null; this.peerConnection = null; this.dataChannel = null; @@ -2311,7 +2309,7 @@ this._secureLog('info', '🔒 Enhanced Mutex system fully initialized and valida // Create simple getSecurityStatus method secureAPI.getSecurityStatus = () => ({ - securityLevel: this.currentSecurityLevel || 'basic', + securityLevel: 'maximum', stage: 'initialized', activeFeaturesCount: Object.values(this.securityFeatures || {}).filter(Boolean).length }); @@ -4484,11 +4482,8 @@ this._secureLog('info', '🔒 Enhanced Mutex system fully initialized and valida } // Security configuration - all features enabled by default - configureSecurityForSession(sessionType, securityLevel) { - this._secureLog('info', `🔧 Configuring security for ${sessionType} session (${securityLevel} level)`); - - this.currentSessionType = sessionType; - this.currentSecurityLevel = securityLevel; + configureSecurityForSession() { + this._secureLog('info', '🔧 Configuring security - all features enabled by default'); // All security features are enabled by default - no payment required this.sessionConstraints = {}; @@ -4499,7 +4494,7 @@ this._secureLog('info', '🔒 Enhanced Mutex system fully initialized and valida this.applySessionConstraints(); - this._secureLog('info', `✅ Security configured for ${sessionType} - all features enabled`, { constraints: this.sessionConstraints }); + this._secureLog('info', '✅ Security configured - all features enabled', { constraints: this.sessionConstraints }); if (!this._validateCryptographicSecurity()) { this._secureLog('error', '🚨 CRITICAL: Cryptographic security validation failed after session configuration'); @@ -4507,7 +4502,6 @@ this._secureLog('info', '🔒 Enhanced Mutex system fully initialized and valida if (this.onStatusChange) { this.onStatusChange('security_breach', { type: 'crypto_security_failure', - sessionType: sessionType, message: 'Cryptographic security validation failed after session configuration' }); } @@ -4644,27 +4638,21 @@ this._secureLog('info', '🔒 Enhanced Mutex system fully initialized and valida // Security Level Notification notifySecurityLevel() { - // Avoid duplicate notifications for the same security level - if (this.lastSecurityLevelNotification === this.currentSecurityLevel) { + // Avoid duplicate notifications + if (this.lastSecurityLevelNotification === 'maximum') { return; // prevent duplication } - this.lastSecurityLevelNotification = this.currentSecurityLevel; + this.lastSecurityLevelNotification = 'maximum'; - const levelMessages = { - 'basic': '🔒 Basic Security Active - Demo session with essential protection', - 'enhanced': '🔐 Enhanced Security Active - Paid session with advanced protection', - 'maximum': '🛡️ Maximum Security Active - Premium session with complete protection' - }; - - const message = levelMessages[this.currentSecurityLevel] || levelMessages['basic']; + const message = '🛡️ Maximum Security Active - All features enabled'; if (this.onMessage) { this.deliverMessageToUI(message, 'system'); } - // Showing details of functions for paid sessions - if (this.currentSecurityLevel !== 'basic' && this.onMessage) { + // Showing details of active features + if (this.onMessage) { const activeFeatures = Object.entries(this.securityFeatures) .filter(([key, value]) => value === true) .map(([key]) => key.replace('has', '').replace(/([A-Z])/g, ' $1').trim().toLowerCase()) @@ -6520,11 +6508,10 @@ async processMessage(data) { if (this.sessionConstraints?.hasAntiFingerprinting) { this.securityFeatures.hasAntiFingerprinting = true; this.antiFingerprintingConfig.enabled = true; - if (this.currentSecurityLevel === 'enhanced') { - this.antiFingerprintingConfig.randomizeSizes = false; - this.antiFingerprintingConfig.maskPatterns = false; - this.antiFingerprintingConfig.useRandomHeaders = false; - } + // Enable full anti-fingerprinting features + this.antiFingerprintingConfig.randomizeSizes = true; + this.antiFingerprintingConfig.maskPatterns = true; + this.antiFingerprintingConfig.useRandomHeaders = true; } this.notifySecurityUpgrade(2); @@ -6535,10 +6522,7 @@ async processMessage(data) { // Method to enable Stage 3 features (traffic obfuscation) enableStage3Security() { - if (this.currentSecurityLevel !== 'maximum') { - this._secureLog('info', '🔒 Stage 3 features only available for premium sessions'); - return; - } + this._secureLog('info', '🔒 Enabling Stage 3 features (traffic obfuscation)'); if (this.sessionConstraints?.hasMessageChunking) { this.securityFeatures.hasMessageChunking = true; @@ -6559,10 +6543,7 @@ async processMessage(data) { // Method for enabling Stage 4 functions (maximum safety) enableStage4Security() { - if (this.currentSecurityLevel !== 'maximum') { - this._secureLog('info', '🔒 Stage 4 features only available for premium sessions'); - return; - } + this._secureLog('info', '🔒 Enabling Stage 4 features (maximum safety)'); if (this.sessionConstraints?.hasDecoyChannels && this.isConnected() && this.isVerified) { this.securityFeatures.hasDecoyChannels = true; @@ -6603,14 +6584,11 @@ async processMessage(data) { .filter(([key, value]) => value === true) .map(([key]) => key); - const stage = this.currentSecurityLevel === 'basic' ? 1 : - this.currentSecurityLevel === 'enhanced' ? 2 : - this.currentSecurityLevel === 'maximum' ? 4 : 1; + const stage = 4; // Maximum security stage return { stage: stage, - sessionType: this.currentSessionType, - securityLevel: this.currentSecurityLevel, + securityLevel: 'maximum', activeFeatures: activeFeatures, totalFeatures: Object.keys(this.securityFeatures).length, activeFeaturesCount: activeFeatures.length, @@ -6730,52 +6708,42 @@ async processMessage(data) { // Method for automatic feature enablement with stability check async autoEnableSecurityFeatures() { - if (this.currentSessionType === 'demo') { - this._secureLog('info', 'Demo session - keeping basic security only'); + this._secureLog('info', 'Starting graduated security activation - all features enabled'); + + const checkStability = () => { + const isStable = this.isConnected() && + this.isVerified && + this.connectionAttempts === 0 && + this.messageQueue.length === 0 && + this.peerConnection?.connectionState === 'connected'; + return isStable; + }; + await this.calculateAndReportSecurityLevel(); this.notifySecurityUpgrade(1); - return; - } - - const checkStability = () => { - const isStable = this.isConnected() && - this.isVerified && - this.connectionAttempts === 0 && - this.messageQueue.length === 0 && - this.peerConnection?.connectionState === 'connected'; - return isStable; - }; - - this._secureLog('info', ` ${this.currentSessionType} session - starting graduated security activation`); - await this.calculateAndReportSecurityLevel(); - this.notifySecurityUpgrade(1); - - if (this.currentSecurityLevel === 'enhanced' || this.currentSecurityLevel === 'maximum') { + + // Enable all security stages progressively setTimeout(async () => { if (checkStability()) { this.enableStage2Security(); await this.calculateAndReportSecurityLevel(); - // For maximum sessions, turn on Stage 3 and 4 - if (this.currentSecurityLevel === 'maximum') { - setTimeout(async () => { - if (checkStability()) { - this.enableStage3Security(); - await this.calculateAndReportSecurityLevel(); - - setTimeout(async () => { - if (checkStability()) { - this.enableStage4Security(); - await this.calculateAndReportSecurityLevel(); - } - }, 20000); - } - }, 15000); - } + setTimeout(async () => { + if (checkStability()) { + this.enableStage3Security(); + await this.calculateAndReportSecurityLevel(); + + setTimeout(async () => { + if (checkStability()) { + this.enableStage4Security(); + await this.calculateAndReportSecurityLevel(); + } + }, 20000); + } + }, 15000); } }, 10000); } - } // ============================================ // CONNECTION MANAGEMENT WITH ENHANCED SECURITY @@ -11644,11 +11612,10 @@ async processMessage(data) { // Update session state this.currentSession = sessionData; - this.sessionManager = sessionData.sessionManager; // FIX: More lenient checks for activation const hasKeys = !!(this.encryptionKey && this.macKey); - const hasSession = !!(this.sessionManager && (this.sessionManager.hasActiveSession?.() || sessionData.sessionId)); + const hasSession = !!(sessionData.sessionId); // Force connection status if there is an active session if (hasSession) { @@ -12508,7 +12475,7 @@ class SecureKeyStorage { // Additional info connectionId: this.connectionId, keyFingerprint: this.keyFingerprint, - currentSecurityLevel: this.currentSecurityLevel, + currentSecurityLevel: 'maximum', timestamp: Date.now() }; diff --git a/src/scripts/app-boot.js b/src/scripts/app-boot.js index ac3bd38..e98c931 100644 --- a/src/scripts/app-boot.js +++ b/src/scripts/app-boot.js @@ -3,7 +3,6 @@ import { EnhancedSecureWebRTCManager } from '../network/EnhancedSecureWebRTCMana import { EnhancedSecureFileTransfer } from '../transfer/EnhancedSecureFileTransfer.js'; // Import UI components (side-effect: they attach themselves to window.*) -import '../components/ui/SessionTimer.jsx'; import '../components/ui/Header.jsx'; import '../components/ui/DownloadApps.jsx'; import '../components/ui/UniqueFeatureSlider.jsx'; diff --git a/src/scripts/bootstrap-modules.js b/src/scripts/bootstrap-modules.js index 574ea09..d05bb35 100644 --- a/src/scripts/bootstrap-modules.js +++ b/src/scripts/bootstrap-modules.js @@ -3,10 +3,9 @@ (async () => { try { const timestamp = Date.now(); - const [cryptoModule, webrtcModule, paymentModule, fileTransferModule] = await Promise.all([ + const [cryptoModule, webrtcModule, fileTransferModule] = await Promise.all([ import(`../crypto/EnhancedSecureCryptoUtils.js?v=${timestamp}`), import(`../network/EnhancedSecureWebRTCManager.js?v=${timestamp}`), - import(`../session/PayPerSessionManager.js?v=${timestamp}`), import(`../transfer/EnhancedSecureFileTransfer.js?v=${timestamp}`), ]); @@ -14,8 +13,6 @@ window.EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils; const { EnhancedSecureWebRTCManager } = webrtcModule; window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager; - const { PayPerSessionManager } = paymentModule; - window.PayPerSessionManager = PayPerSessionManager; const { EnhancedSecureFileTransfer } = fileTransferModule; window.EnhancedSecureFileTransfer = EnhancedSecureFileTransfer; @@ -28,11 +25,7 @@ } await Promise.all([ - loadReactComponent('../components/ui/SessionTimer.jsx'), loadReactComponent('../components/ui/Header.jsx'), - loadReactComponent('../components/ui/SessionTypeSelector.jsx'), - loadReactComponent('../components/ui/LightningPayment.jsx'), - loadReactComponent('../components/ui/PaymentModal.jsx'), loadReactComponent('../components/ui/DownloadApps.jsx'), loadReactComponent('../components/ui/ComparisonTable.jsx'), loadReactComponent('../components/ui/UniqueFeatureSlider.jsx'), diff --git a/src/scripts/pwa-globals.js b/src/scripts/pwa-globals.js index a18ba95..ae44d5a 100644 --- a/src/scripts/pwa-globals.js +++ b/src/scripts/pwa-globals.js @@ -1,27 +1,13 @@ -window.forceUpdateHeader = (timeLeft, sessionType) => { +window.forceUpdateHeader = () => { const event = new CustomEvent('force-header-update', { - detail: { timeLeft, sessionType, timestamp: Date.now() }, + detail: { timestamp: Date.now() }, }); document.dispatchEvent(event); - if (window.sessionManager && window.sessionManager.forceUpdateTimer) { - window.sessionManager.forceUpdateTimer(); - } -}; - -window.updateSessionTimer = (timeLeft, sessionType) => { - document.dispatchEvent( - new CustomEvent('session-timer-update', { - detail: { timeLeft, sessionType }, - }), - ); }; document.addEventListener('session-activated', (event) => { - if (window.updateSessionTimer) { - window.updateSessionTimer(event.detail.timeLeft, event.detail.sessionType); - } if (window.forceUpdateHeader) { - window.forceUpdateHeader(event.detail.timeLeft, event.detail.sessionType); + window.forceUpdateHeader(); } if (window.webrtcManager && window.webrtcManager.handleSessionActivation) { if (window.DEBUG_MODE) { @@ -29,9 +15,6 @@ document.addEventListener('session-activated', (event) => { } window.webrtcManager.handleSessionActivation({ sessionId: event.detail.sessionId, - sessionType: event.detail.sessionType, - timeLeft: event.detail.timeLeft, - isDemo: event.detail.isDemo, sessionManager: window.sessionManager, }); } diff --git a/src/scripts/pwa-offline-test.js b/src/scripts/pwa-offline-test.js new file mode 100644 index 0000000..96ada6a --- /dev/null +++ b/src/scripts/pwa-offline-test.js @@ -0,0 +1,270 @@ +// PWA Offline Test Script for SecureBit.chat +// Enhanced Security Edition v4.3.120 +// Tests offline functionality and cache status + +class PWAOfflineTester { + constructor() { + this.testResults = []; + this.isRunning = false; + } + + async runTests() { + if (this.isRunning) { + console.warn('⚠️ Tests already running'); + return; + } + + this.isRunning = true; + this.testResults = []; + + console.log('🧪 Starting PWA Offline Tests...'); + + try { + await this.testServiceWorkerRegistration(); + await this.testCacheStatus(); + await this.testOfflineResources(); + await this.testOnlineResources(); + + this.showTestResults(); + } catch (error) { + console.error('❌ Test failed:', error); + this.addTestResult('Test Suite', false, `Test suite failed: ${error.message}`); + } finally { + this.isRunning = false; + } + } + + async testServiceWorkerRegistration() { + try { + if ('serviceWorker' in navigator) { + const registration = await navigator.serviceWorker.getRegistration(); + if (registration) { + this.addTestResult('Service Worker Registration', true, 'Service worker is registered'); + } else { + this.addTestResult('Service Worker Registration', false, 'No service worker found'); + } + } else { + this.addTestResult('Service Worker Support', false, 'Service worker not supported'); + } + } catch (error) { + this.addTestResult('Service Worker Registration', false, `Error: ${error.message}`); + } + } + + async testCacheStatus() { + try { + if ('caches' in window) { + const cacheNames = await caches.keys(); + const totalCached = 0; + + for (const cacheName of cacheNames) { + const cache = await caches.open(cacheName); + const keys = await cache.keys(); + totalCached += keys.length; + } + + if (totalCached > 0) { + this.addTestResult('Cache Status', true, `${totalCached} resources cached`); + } else { + this.addTestResult('Cache Status', false, 'No resources cached'); + } + } else { + this.addTestResult('Cache API Support', false, 'Cache API not supported'); + } + } catch (error) { + this.addTestResult('Cache Status', false, `Error: ${error.message}`); + } + } + + async testOfflineResources() { + const criticalResources = [ + '/', + '/index.html', + '/manifest.json', + '/dist/app.js', + '/dist/app-boot.js', + '/libs/react/react.production.min.js', + '/libs/react-dom/react-dom.production.min.js', + '/assets/tailwind.css' + ]; + + let cachedCount = 0; + + for (const resource of criticalResources) { + try { + const cached = await caches.match(resource); + if (cached) { + cachedCount++; + } + } catch (error) { + console.warn(`⚠️ Failed to check cache for ${resource}:`, error); + } + } + + const success = cachedCount >= criticalResources.length * 0.8; // 80% success rate + this.addTestResult('Critical Resources Cached', success, + `${cachedCount}/${criticalResources.length} critical resources cached`); + } + + async testOnlineResources() { + try { + // Test if we can fetch a simple resource + const response = await fetch('/favicon.ico', { + method: 'HEAD', + cache: 'no-cache' + }); + + if (response.ok) { + this.addTestResult('Network Connectivity', true, 'Network is accessible'); + } else { + this.addTestResult('Network Connectivity', false, `Network error: ${response.status}`); + } + } catch (error) { + this.addTestResult('Network Connectivity', false, `Network error: ${error.message}`); + } + } + + addTestResult(testName, passed, message) { + this.testResults.push({ + name: testName, + passed, + message, + timestamp: new Date().toISOString() + }); + + console.log(`${passed ? '✅' : '❌'} ${testName}: ${message}`); + } + + showTestResults() { + const passedTests = this.testResults.filter(test => test.passed).length; + const totalTests = this.testResults.length; + const successRate = Math.round((passedTests / totalTests) * 100); + + const modal = document.createElement('div'); + modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 backdrop-blur-sm'; + modal.innerHTML = ` +
+
+
+ +
+

PWA Offline Test Results

+
+ +
+
+
+
Overall Score
+
${passedTests}/${totalTests} tests passed
+
+
+ ${successRate}% +
+
+
+ +
+ ${this.testResults.map(test => ` +
+
+ +
+
${test.name}
+
${test.message}
+
+
+
+ `).join('')} +
+ +
+
+

Recommendations:

+
    + ${this.getRecommendations().map(rec => `
  • • ${rec}
  • `).join('')} +
+
+ +
+ + +
+
+
+ `; + + document.body.appendChild(modal); + } + + getRecommendations() { + const recommendations = []; + + const failedTests = this.testResults.filter(test => !test.passed); + + if (failedTests.some(test => test.name.includes('Service Worker'))) { + recommendations.push('Ensure service worker is properly registered and active'); + } + + if (failedTests.some(test => test.name.includes('Cache'))) { + recommendations.push('Check cache configuration and ensure resources are being cached'); + } + + if (failedTests.some(test => test.name.includes('Network'))) { + recommendations.push('Verify network connectivity and server availability'); + } + + if (recommendations.length === 0) { + recommendations.push('All tests passed! Your PWA offline functionality is working correctly.'); + } + + return recommendations; + } + + // Public API + getTestResults() { + return this.testResults; + } + + clearResults() { + this.testResults = []; + } +} + +// Singleton pattern +let instance = null; + +const PWAOfflineTesterAPI = { + getInstance() { + if (!instance) { + instance = new PWAOfflineTester(); + } + return instance; + }, + + runTests() { + return this.getInstance().runTests(); + } +}; + +// Export for module use +if (typeof module !== 'undefined' && module.exports) { + module.exports = PWAOfflineTesterAPI; +} else if (typeof window !== 'undefined' && !window.PWAOfflineTester) { + window.PWAOfflineTester = PWAOfflineTesterAPI; +} + +// Auto-initialize +if (typeof window !== 'undefined' && !window.pwaOfflineTester) { + window.pwaOfflineTester = PWAOfflineTesterAPI.getInstance(); + + // Add global function for easy access + window.testPWAOffline = () => { + window.pwaOfflineTester.runTests(); + }; +} diff --git a/src/styles/components.css b/src/styles/components.css index fb0bd61..0a97947 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -349,35 +349,6 @@ button i { margin-right: 0.5rem; } -/* Pay-per-session UI - Обновленный трехцветный таймер */ -.session-timer { - padding: 8px 16px; - border-radius: 8px; - font-weight: 600; - font-size: 14px; - display: flex; - align-items: center; - gap: 8px; - border: 1px solid rgba(255, 255, 255, 0.1); - backdrop-filter: blur(10px); - transition: all 0.5s ease; -} - -.session-timer:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); -} - -/* Анимация пульсации для красной зоны */ -@keyframes timer-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.7; } -} - -.session-timer.animate-pulse { - animation: timer-pulse 2s ease-in-out infinite; -} - /* Lightning button */ .lightning-button { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); diff --git a/sw.js b/sw.js index 6f2dfe3..ffc87f8 100644 --- a/sw.js +++ b/sw.js @@ -1,34 +1,33 @@ // SecureBit.chat Service Worker -// Enhanced Security Edition v4.3.120 - ECDH + DTLS + SAS +// Conservative PWA Edition v4.3.120 - Minimal Caching Strategy -const CACHE_NAME = 'securebit-v4.3.120'; -const STATIC_CACHE = 'securebit-static-v4.3.120'; -const DYNAMIC_CACHE = 'securebit-dynamic-v4.3.120'; +const CACHE_NAME = 'securebit-pwa-v4.3.120'; +const STATIC_CACHE = 'securebit-pwa-static-v4.3.120'; +const DYNAMIC_CACHE = 'securebit-pwa-dynamic-v4.3.120'; -// Files to cache for offline functionality (excluding external CDNs that may have CORS issues) +// Essential files for PWA offline functionality const STATIC_ASSETS = [ '/', '/index.html', '/manifest.json', - '/src/crypto/EnhancedSecureCryptoUtils.js', - '/src/network/EnhancedSecureWebRTCManager.js', - '/src/session/PayPerSessionManager.js', - '/src/components/ui/SessionTimer.jsx', - '/src/components/ui/Header.jsx', - '/src/components/ui/PasswordModal.jsx', - '/src/components/ui/SessionTypeSelector.jsx', - '/src/components/ui/PaymentModal.jsx', - '/src/components/ui/DownloadApps.jsx', - '/src/components/ui/ComparisonTable.jsx', - '/src/components/ui/UniqueFeatureSlider.jsx', - '/src/components/ui/SecurityFeatures.jsx', - '/src/components/ui/Testimonials.jsx', - '/src/components/ui/Roadmap.jsx', - '/src/styles/main.css', - '/src/styles/animations.css', - '/src/styles/components.css', + + // Core PWA files only + '/dist/app.js', + '/dist/app-boot.js', + + // Essential styles for PWA '/src/styles/pwa.css', - '/logo/favicon.ico' + + // PWA icons (required for install) + '/logo/icon-192x192.png', + '/logo/icon-512x512.png', + '/logo/favicon.ico', + + // PWA components only + '/src/pwa/pwa-manager.js', + '/src/pwa/install-prompt.js', + '/src/scripts/pwa-register.js', + '/src/scripts/pwa-offline-test.js' ]; // Sensitive files that should never be cached @@ -43,21 +42,22 @@ const SENSITIVE_PATTERNS = [ // Network first patterns (always try network first) const NETWORK_FIRST_PATTERNS = [ - /\.js$/, - /\.jsx$/, - /\/src\//, - /api/ + /\/api\//, + /\/session\//, + /\/payment\//, + /\/verification\//, + /preimage/, + /auth/ ]; -// Cache first patterns (static assets) +// Cache first patterns (only essential PWA assets) const CACHE_FIRST_PATTERNS = [ - /\.css$/, - /\.png$/, - /\.jpg$/, - /\.svg$/, - /\.ico$/, - /fonts/, - /logo/ + /manifest\.json$/, + /logo\/icon-.*\.png$/, + /logo\/favicon\.ico$/, + /src\/styles\/pwa\.css$/, + /src\/pwa\/.*\.js$/, + /src\/scripts\/pwa-.*\.js$/ ]; self.addEventListener('message', (event) => { @@ -160,23 +160,23 @@ self.addEventListener('fetch', (event) => { event.respondWith(handleRequest(event.request)); }); -// Smart request handling with security considerations +// Conservative request handling - only cache PWA essentials async function handleRequest(request) { const url = new URL(request.url); try { - // Strategy 1: Cache First (for static assets) + // Strategy 1: Cache First (only for essential PWA assets) if (CACHE_FIRST_PATTERNS.some(pattern => pattern.test(url.pathname))) { return await cacheFirst(request); } - // Strategy 2: Network First (for dynamic content and security-critical files) + // Strategy 2: Network First (for all other requests) if (NETWORK_FIRST_PATTERNS.some(pattern => pattern.test(url.pathname))) { return await networkFirst(request); } - // Strategy 3: Stale While Revalidate (for main pages) - return await staleWhileRevalidate(request); + // Strategy 3: Network First for everything else (no aggressive caching) + return await networkFirst(request); } catch (error) { console.error('❌ Request handling failed:', error); @@ -254,29 +254,39 @@ async function staleWhileRevalidate(request) { return cachedResponse || networkResponsePromise || handleOffline(request); } -// Offline fallback +// Offline fallback - minimal caching for PWA only async function handleOffline(request) { const url = new URL(request.url); // For navigation requests, return cached index.html - if (request.destination === 'document') { - const cachedIndex = await caches.match('/'); + if (request.destination === 'document' || request.mode === 'navigate') { + const cachedIndex = await caches.match('/index.html'); if (cachedIndex) { return cachedIndex; } + + // Fallback to root if index.html not found + const cachedRoot = await caches.match('/'); + if (cachedRoot) { + return cachedRoot; + } } - // For images, return a placeholder or cached version - if (request.destination === 'image') { - return new Response( - 'Offline', - { headers: { 'Content-Type': 'image/svg+xml' } } - ); + // For PWA assets, try to return cached version + if (CACHE_FIRST_PATTERNS.some(pattern => pattern.test(url.pathname))) { + const cachedAsset = await caches.match(request); + if (cachedAsset) { + return cachedAsset; + } } - // Return a generic offline response + // Return a generic offline response for everything else return new Response( - JSON.stringify({ error: 'Offline', message: 'Network unavailable' }), + JSON.stringify({ + error: 'Offline', + message: 'Network unavailable - PWA offline mode', + url: url.pathname + }), { status: 503, statusText: 'Service Unavailable', @@ -293,6 +303,29 @@ self.addEventListener('sync', (event) => { } }); +async function retryFailedRequests() { + try { + // Get all cached requests that failed + const cache = await caches.open(DYNAMIC_CACHE); + const requests = await cache.keys(); + + for (const request of requests) { + try { + // Try to fetch the request again + const response = await fetch(request); + if (response.ok) { + // Update cache with successful response + await cache.put(request, response); + } + } catch (error) { + console.warn('⚠️ Retry failed for:', request.url, error.message); + } + } + } catch (error) { + console.error('❌ Failed to retry requests:', error); + } +} + // Notification click handler