2025-08-11 20:52:14 -04:00
<!DOCTYPE html>
2025-08-13 23:02:04 -04:00
< html lang = "en" >
2025-08-11 20:52:14 -04:00
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta http-equiv = "Content-Security-Policy"
content = "default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://unpkg.com https://cdn.tailwindcss.com https://cdnjs.cloudflare.com https://static.cloudflareinsights.com;
style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://cdnjs.cloudflare.com https://fonts.googleapis.com;
font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com;
connect-src 'self' https: https://cloudflareinsights.com;
img-src 'self' data: https://api.qrserver.com;
media-src 'none';
object-src 'none';
frame-src 'none';" >
2025-08-17 16:04:45 -04:00
< meta http-equiv = "X-Content-Type-Options" content = "nosniff" >
2025-08-11 20:52:14 -04:00
< meta http-equiv = "X-XSS-Protection" content = "1; mode=block" >
< meta http-equiv = "Referrer-Policy" content = "strict-origin-when-cross-origin" >
2025-08-13 22:56:29 -04:00
2025-08-17 16:04:45 -04:00
<!-- PWA Manifest -->
2025-08-17 16:49:04 -04:00
< link rel = "manifest" href = "./manifest.json" >
< link rel = "icon" type = "image/x-icon" href = "./logo/favicon.ico" >
2025-08-17 16:04:45 -04:00
<!-- PWA Meta Tags -->
< meta name = "mobile-web-app-capable" content = "yes" >
< meta name = "apple-mobile-web-app-capable" content = "yes" >
2025-08-19 21:54:17 -04:00
< meta name = "format-detection" content = "telephone=no" >
2025-08-17 16:04:45 -04:00
< meta name = "apple-mobile-web-app-status-bar-style" content = "black-translucent" >
< meta name = "apple-mobile-web-app-title" content = "SecureBit" >
< meta name = "application-name" content = "SecureBit" >
< meta name = "msapplication-TileColor" content = "#ff6b35" >
< meta name = "msapplication-config" content = "/browserconfig.xml" >
2025-08-24 15:22:53 -04:00
<!-- iOS Splash Screens -->
< link rel = "apple-touch-startup-image" href = "./logo/splash/launch-640x1136.png"
2025-08-19 21:54:17 -04:00
media = "(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" >
2025-08-24 15:22:53 -04:00
< link rel = "apple-touch-startup-image" href = "./logo/splash/launch-750x1334.png"
2025-08-19 21:54:17 -04:00
media = "(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" >
2025-08-24 15:22:53 -04:00
< link rel = "apple-touch-startup-image" href = "./logo/splash/launch-1125x2436.png"
2025-08-19 21:54:17 -04:00
media = "(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" >
2025-08-24 15:22:53 -04:00
< link rel = "apple-touch-startup-image" href = "./logo/splash/launch-1242x2688.png"
2025-08-19 21:54:17 -04:00
media = "(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" >
2025-08-17 16:04:45 -04:00
<!-- Apple Touch Icons -->
2025-08-19 21:54:17 -04:00
< link rel = "apple-touch-icon" href = "./logo/icon-180x180.png" >
< link rel = "apple-touch-icon" sizes = "57x57" href = "./logo/icon-57x57.png" >
< link rel = "apple-touch-icon" sizes = "60x60" href = "./logo/icon-60x60.png" >
< link rel = "apple-touch-icon" sizes = "72x72" href = "./logo/icon-72x72.png" >
< link rel = "apple-touch-icon" sizes = "76x76" href = "./logo/icon-76x76.png" >
< link rel = "apple-touch-icon" sizes = "114x114" href = "./logo/icon-114x114.png" >
< link rel = "apple-touch-icon" sizes = "120x120" href = "./logo/icon-120x120.png" >
< link rel = "apple-touch-icon" sizes = "144x144" href = "./logo/icon-144x144.png" >
< link rel = "apple-touch-icon" sizes = "152x152" href = "./logo/icon-152x152.png" >
< link rel = "apple-touch-icon" sizes = "180x180" href = "./logo/icon-180x180.png" >
2025-08-17 16:04:45 -04:00
<!-- Microsoft Tiles -->
2025-08-19 21:54:17 -04:00
< meta name = "msapplication-TileColor" content = "#ff6b35" >
< meta name = "msapplication-TileImage" content = "./logo/icon-144x144.png" >
< meta name = "msapplication-config" content = "./browserconfig.xml" >
<!-- Theme colors -->
2025-08-17 16:04:45 -04:00
< meta name = "theme-color" content = "#ff6b35" >
2025-08-19 21:54:17 -04:00
< meta name = "msapplication-navbutton-color" content = "#ff6b35" >
2025-08-17 16:04:45 -04:00
<!-- Security Headers for PWA -->
< meta http-equiv = "Content-Security-Policy" content = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://unpkg.com https://cdn.tailwindcss.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://cdnjs.cloudflare.com https://fonts.googleapis.com; font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com; connect-src 'self' https: wss: ws:; img-src 'self' data: https:; media-src 'none'; object-src 'none'; frame-src 'none'; worker-src 'self';" >
2025-08-11 20:52:14 -04:00
<!-- GitHub Pages SEO -->
2025-08-14 15:54:11 -04:00
< meta name = "description" content = "SecureBit.chat — P2P messenger with military-grade cryptography and Lightning Network payments" >
2025-08-11 20:52:14 -04:00
< meta name = "keywords" content = "P2P messenger, encryption, Lightning Network, WebRTC, privacy" >
< meta name = "author" content = "Volodymyr" >
2025-08-16 19:17:32 -04:00
< link rel = "canonical" href = "https://github.com/SecureBitChat/securebit-chat/" >
2025-08-11 20:52:14 -04:00
<!-- Open Graph -->
2025-08-14 15:54:11 -04:00
< meta property = "og:title" content = "SecureBit.chat - Enhanced Security Edition" >
2025-08-12 13:55:07 -04:00
< meta property = "og:description" content = "The first P2P messenger with Lightning Network payments" >
2025-08-16 19:17:32 -04:00
< meta property = "og:url" content = "https://github.com/SecureBitChat/securebit-chat/" >
2025-08-11 20:52:14 -04:00
< meta property = "og:type" content = "website" >
2025-08-17 00:33:12 -04:00
< meta property = "og:image" content = "https://github.com/SecureBitChat/securebit-chat/favicon.ico" >
2025-08-11 20:52:14 -04:00
<!-- Twitter Card -->
< meta name = "twitter:card" content = "summary_large_image" >
2025-08-14 15:54:11 -04:00
< meta name = "twitter:title" content = "SecureBit.chat - Enhanced Security Edition" >
2025-08-12 13:55:07 -04:00
< meta name = "twitter:description" content = "P2P messenger with military-grade cryptography" >
2025-08-11 20:52:14 -04:00
2025-08-14 15:54:11 -04:00
< title > SecureBit.chat - Enhanced Security Edition</ title >
2025-08-11 20:52:14 -04:00
< script src = "https://unpkg.com/react@18/umd/react.production.min.js" ></ script >
< script src = "https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" ></ script >
< script src = "https://unpkg.com/@babel/standalone/babel.min.js" ></ script >
< script src = "https://cdn.tailwindcss.com" ></ script >
2025-08-13 22:56:29 -04:00
< link rel = "icon" type = "image/x-icon" href = "/logo/favicon.ico" >
2025-08-11 20:52:14 -04:00
< link href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" rel = "stylesheet" integrity = "sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin = "anonymous" referrerpolicy = "no-referrer" >
< link rel = "preload" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/webfonts/fa-solid-900.woff2" as = "font" type = "font/woff2" crossorigin >
< link rel = "preload" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/webfonts/fa-regular-400.woff2" as = "font" type = "font/woff2" crossorigin >
< link href = "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel = "stylesheet" >
< link rel = "stylesheet" href = "src/styles/main.css" >
< link rel = "stylesheet" href = "src/styles/animations.css" >
< link rel = "stylesheet" href = "src/styles/components.css" >
< script >
2025-08-14 23:34:54 -04:00
// Global logging and function settings
window . DEBUG_MODE = true ;
// Fake function settings (for stability)
window . DISABLE_FAKE_TRAFFIC = false ; // Set true to disable fake messages
window . DISABLE_DECOY_CHANNELS = false ; // Set true to disable decoy channels
2025-08-11 20:52:14 -04:00
// Enhanced icon loading fallback
document . addEventListener ( 'DOMContentLoaded' , function () {
// Check if Font Awesome loaded properly
function checkFontAwesome () {
const testIcon = document . createElement ( 'i' );
testIcon . className = 'fas fa-shield-halved' ;
testIcon . style . position = 'absolute' ;
testIcon . style . left = '-9999px' ;
testIcon . style . visibility = 'hidden' ;
document . body . appendChild ( testIcon );
const computedStyle = window . getComputedStyle ( testIcon , '::before' );
const content = computedStyle . content ;
const fontFamily = computedStyle . fontFamily ;
document . body . removeChild ( testIcon );
// Check if Font Awesome is properly loaded
if ( ! content || content === 'none' || content === 'normal' ||
! fontFamily . includes ( 'Font Awesome' ) && ! fontFamily . includes ( 'fa-solid' )) {
console . warn ( 'Font Awesome not loaded properly, using fallback icons' );
document . body . classList . add ( 'fa-fallback' );
return false ;
}
console . log ( 'Font Awesome loaded successfully' );
return true ;
}
// Check immediately and after a delay
if ( ! checkFontAwesome ()) {
// Try alternative CDN if first one failed
setTimeout ( function () {
if ( ! checkFontAwesome ()) {
console . warn ( 'Font Awesome still not loaded, using fallback icons' );
document . body . classList . add ( 'fa-fallback' );
}
}, 2000 );
}
});
</ script >
</ head >
< body >
< div id = "root" ></ div >
< script type = "text/babel" >
// Slider Component
const UniqueFeatureSlider = () => {
2025-08-14 04:45:39 -04:00
const [ currentSlide , setCurrentSlide ] = React . useState ( 0 );
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
const slides = [
{
icon : "fas fa-shield-halved" ,
color : "orange" ,
title : "12-Layer Military Security" ,
2025-08-24 16:30:06 -04:00
description : "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA. Enhanced Security Edition v4.01.441 provides military-grade protection exceeding government standards."
2025-08-14 04:45:39 -04:00
},
{
icon : "fas fa-bolt" ,
color : "yellow" ,
title : "Lightning Network Payments" ,
description : "First messenger with Lightning Network integration. Pay-per-session with satoshis via WebLN. Sustainable economic model without ads or data harvesting."
},
{
icon : "fas fa-network-wired" ,
color : "purple" ,
title : "Pure P2P WebRTC Architecture" ,
description : "Direct peer-to-peer connections without any servers. Impossible to censor, block, or monitor. Complete decentralization with zero infrastructure."
},
{
icon : "fas fa-sync-alt" ,
color : "green" ,
title : "Perfect Forward Secrecy" ,
description : "Automatic key rotation every 5 minutes or 100 messages. Non-extractable keys with hardware protection ensure past messages remain secure."
},
{
icon : "fas fa-user-secret" ,
color : "cyan" ,
title : "Advanced Traffic Obfuscation" ,
description : "Fake traffic generation, packet padding, and pattern masking make communication indistinguishable from random noise. Defeats traffic analysis."
},
{
icon : "fas fa-eye-slash" ,
color : "blue" ,
title : "Zero Data Collection" ,
description : "No registration, no servers, no logs. Messages exist only in browser memory. Complete anonymity with instant anonymous channels."
},
{
icon : "fas fa-code" ,
color : "emerald" ,
title : "100% Open Source Security" ,
description : "All code is open for audit under MIT license. Uses only standard WebCrypto APIs. Cryptography runs directly in browser without server dependencies."
}
];
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
const nextSlide = () => setCurrentSlide (( prev ) => ( prev + 1 ) % slides . length );
const prevSlide = () => setCurrentSlide (( prev ) => ( prev - 1 + slides . length ) % slides . length );
const goToSlide = ( index ) => setCurrentSlide ( index );
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
React . useEffect (() => {
const timer = setInterval (() => {
nextSlide ();
}, 15000 );
return () => clearInterval ( timer );
}, []);
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
return React . createElement ( 'div' , {
className : "mt-12"
}, [
React . createElement ( 'div' , {
key : 'header' ,
className : "text-center mb-8"
}, [
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-2xl font-semibold text-primary mb-3"
2025-08-14 15:54:11 -04:00
}, 'Why SecureBit.chat is unique' ),
2025-08-14 04:45:39 -04:00
React . createElement ( 'p' , {
key : 'subtitle' ,
className : "text-secondary max-w-2xl mx-auto"
}, 'The only messenger with military-grade cryptography and Lightning payments' )
]),
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
React . createElement ( 'div' , {
key : 'slider-container' ,
className : "relative max-w-4xl mx-auto"
}, [
React . createElement ( 'div' , {
key : 'slider-wrapper' ,
className : "overflow-hidden rounded-xl"
}, [
React . createElement ( 'div' , {
key : 'slides' ,
className : "flex transition-transform duration-500 ease-in-out" ,
style : { transform : `translateX(- ${ currentSlide * 100 } %)` }
}, slides . map (( slide , index ) =>
React . createElement ( 'div' , {
key : index ,
className : "w-full flex-shrink-0 px-4"
}, [
React . createElement ( 'div' , {
key : 'slide-content' ,
className : "card-minimal rounded-xl p-8 text-center min-h-[300px] flex flex-col justify-center relative overflow-hidden"
}, [
// Background icon
React . createElement ( 'i' , {
key : 'bg-icon' ,
className : ` ${ slide . icon } absolute right-[-100px] top-1/2 -translate-y-1/2 opacity-10 text-[300px] pointer-events-none ${
slide . color === 'orange' ? 'text-orange-500' :
slide . color === 'yellow' ? 'text-yellow-500' :
slide . color === 'purple' ? 'text-purple-500' :
slide . color === 'green' ? 'text-green-500' :
slide . color === 'cyan' ? 'text-cyan-500' :
slide . color === 'blue' ? 'text-blue-500' :
'text-emerald-500'
} `
}),
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
// Content
React . createElement ( 'h4' , {
key : 'slide-title' ,
className : "text-xl font-semibold text-primary mb-4 relative z-10"
}, slide . title ),
React . createElement ( 'p' , {
key : 'slide-description' ,
className : "text-secondary leading-relaxed max-w-2xl mx-auto relative z-10"
}, slide . description )
])
])
))
]),
// Navigation
React . createElement ( 'button' , {
key : 'prev-btn' ,
onClick : prevSlide ,
className : "absolute left-2 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-gray-600/80 hover:bg-gray-500/80 text-white rounded-full flex items-center justify-center transition-all duration-200 z-10"
}, [
React . createElement ( 'i' , {
key : 'prev-icon' ,
className : "fas fa-chevron-left"
})
]),
React . createElement ( 'button' , {
key : 'next-btn' ,
onClick : nextSlide ,
className : "absolute right-2 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-gray-600/80 hover:bg-gray-500/80 text-white rounded-full flex items-center justify-center transition-all duration-200 z-10"
}, [
React . createElement ( 'i' , {
key : 'next-icon' ,
className : "fas fa-chevron-right"
})
])
]),
// Enhanced dots navigation (оставляем улучшенные точки)
React . createElement ( 'div' , {
key : 'dots-container' ,
className : "flex justify-center space-x-3 mt-6"
}, slides . map (( slide , index ) =>
React . createElement ( 'button' , {
key : index ,
onClick : () => goToSlide ( index ),
className : `relative group transition-all duration-300 ${
index === currentSlide
? 'w-12 h-4 bg-orange-500 rounded-full'
: 'w-4 h-4 bg-gray-600 hover:bg-gray-500 rounded-full hover:scale-125'
} `
}, [
// Tooltip on hover
React . createElement ( 'div' , {
key : 'tooltip' ,
className : "absolute -top-10 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200 whitespace-nowrap pointer-events-none"
}, slide . title )
])
))
]);
};
2025-08-11 20:52:14 -04:00
const ComparisonTable = () => {
const [ selectedFeature , setSelectedFeature ] = React . useState ( null );
const messengers = [
{
2025-08-14 15:54:11 -04:00
name : "SecureBit.chat" ,
2025-08-14 04:45:39 -04:00
logo : < div className = "w-8 h-8 bg-orange-500/10 border border-orange-500/20 rounded-lg flex items-center justify-center" >
< i className = "fas fa-shield-halved text-orange-400" />
< /div>,
type : "P2P WebRTC" ,
version : "v4.0 Enhanced" ,
color : "orange" ,
2025-08-11 20:52:14 -04:00
},
{
2025-08-14 04:45:39 -04:00
name : "Signal" ,
logo : (
< svg className = "w-8 h-8" viewBox = "0 0 122.88 122.31" xmlns = "http://www.w3.org/2000/svg" >
< path className = "fill-blue-500" d = "M27.75,0H95.13a27.83,27.83,0,0,1,27.75,27.75V94.57a27.83,27.83,0,0,1-27.75,27.74H27.75A27.83,27.83,0,0,1,0,94.57V27.75A27.83,27.83,0,0,1,27.75,0Z" />
< path className = "fill-white" d = "M61.44,25.39A35.76,35.76,0,0,0,31.18,80.18L27.74,94.86l14.67-3.44a35.77,35.77,0,1,0,19-66Z" />
< /svg>
),
type : "Centralized" ,
version : "Latest" ,
color : "blue" ,
2025-08-11 20:52:14 -04:00
},
{
2025-08-14 04:45:39 -04:00
name : "Threema" ,
logo : (
< svg className = "w-8 h-8" viewBox = "0 0 122.88 122.88" xmlns = "http://www.w3.org/2000/svg" >
< rect width = "122.88" height = "122.88" rx = "18.43" fill = "#474747" />
< path fill = "#FFFFFF" d = "M44.26,78.48l-19.44,4.8l4.08-16.56c-4.08-5.28-6.48-12-6.48-18.96c0-18.96,17.52-34.32,39.12-34.32c21.6,0,39.12,15.36,39.12,34.32c0,18.96-17.52,34.32-39.12,34.32c-6,0-12-1.2-17.04-3.36L44.26,78.48z M50.26,44.64h-0.48c-0.96,0-1.68,0.72-1.44,1.68v15.6c0,0.96,0.72,1.68,1.68,1.68l23.04,0c0.96,0,1.68-0.72,1.68-1.68v-15.6c0-0.96-0.72-1.68-1.68-1.68h-0.48v-4.32c0-6-5.04-11.04-11.04-11.04S50.5,34.32,50.5,40.32v4.32H50.26z M68.02,44.64h-13.2v-4.32c0-3.6,2.88-6.72,6.72-6.72c3.6,0,6.72,2.88,6.72,6.72v4.32H68.02z" />
< circle cx = "37.44" cy = "97.44" r = "6.72" fill = "#3fe669" />
< circle cx = "61.44" cy = "97.44" r = "6.72" fill = "#3fe669" />
< circle cx = "85.44" cy = "97.44" r = "6.72" fill = "#3fe669" />
< /svg>
),
type : "Centralized" ,
version : "Latest" ,
color : "green" ,
2025-08-11 20:52:14 -04:00
},
{
2025-08-14 04:45:39 -04:00
name : "Session" ,
logo : (
< svg className = "w-8 h-8" viewBox = "0 0 1024 1024" xmlns = "http://www.w3.org/2000/svg" >
< rect width = "1024" height = "1024" fill = "#333132" />
< path fill = "#00f782" d = "M431 574.8c-.8-7.4-6.7-8.2-10.8-10.6-13.6-7.9-27.5-15.4-41.3-23l-22.5-12.3c-8.5-4.7-17.1-9.2-25.6-14.1-10.5-6-21-11.9-31.1-18.6-18.9-12.5-33.8-29.1-46.3-48.1-8.3-12.6-14.8-26.1-19.2-40.4-6.7-21.7-10.8-44.1-7.8-66.8 1.8-14 4.6-28 9.7-41.6 7.8-20.8 19.3-38.8 34.2-54.8 9.8-10.6 21.2-19.1 33.4-26.8 14.7-9.3 30.7-15.4 47.4-19 13.8-3 28.1-4.3 42.2-4.4 89.9-.4 179.7-.3 269.6 0 12.6 0 25.5 1 37.7 4.1 24.3 6.2 45.7 18.2 63 37 11.2 12.2 20.4 25.8 25.8 41.2 7.3 20.7 12.3 42.1 6.7 64.4-2.1 8.5-2.7 17.5-6.1 25.4-4.7 10.9-10.8 21.2-17.2 31.2-8.7 13.5-20.5 24.3-34.4 32.2-10.1 5.7-21 10.2-32 14.3-18.1 6.7-37.2 5-56.1 5.2-17.2.2-34.5 0-51.7.1-1.7 0-3.4 1.2-5.1 1.9 1.3 1.8 2.1 4.3 3.9 5.3 13.5 7.8 27.2 15.4 40.8 22.9 11 6 22.3 11.7 33.2 17.9 15.2 8.5 30.2 17.4 45.3 26.1 19.3 11.1 34.8 26.4 47.8 44.3 9.7 13.3 17.2 27.9 23 43.5 6.1 16.6 9.2 33.8 10.4 51.3.6 9.1-.7 18.5-1.9 27.6-1.2 9.1-2.7 18.4-5.6 27.1-3.3 10.2-7.4 20.2-12.4 29.6-8.4 15.7-19.6 29.4-32.8 41.4-12.7 11.5-26.8 20.6-42.4 27.6-22.9 10.3-46.9 14.4-71.6 14.5-89.7.3-179.4.2-269.1-.1-12.6 0-25.5-1-37.7-3.9-24.5-5.7-45.8-18-63.3-36.4-11.6-12.3-20.2-26.5-26.6-41.9-2.7-6.4-4.1-13.5-5.4-20.4-1.5-8.1-2.8-16.3-3.1-24.5-.6-15.7 2.8-30.9 8.2-45.4 8.2-22 21.7-40.6 40.2-55.2 10-7.9 21.3-13.7 33.1-18.8 16.6-7.2 34-8.1 51.4-8.5 21.9-.5 43.9-.1 65.9-.1 1.9-.1 3.9-.3 6.2-.4zm96.3-342.4c0 .1 0 .1 0 0-48.3.1-96.6-.6-144.9.5-13.5.3-27.4 3.9-40.1 8.7-14.9 5.6-28.1 14.6-39.9 25.8-20.2 19-32.2 42.2-37.2 68.9-3.6 19-1.4 38.1 4.1 56.5 4.1 13.7 10.5 26.4 18.5 38.4 14.8 22.2 35.7 36.7 58.4 49.2 11 6.1 22.2 11.9 33.2 18 13.5 7.5 26.9 15.1 40.4 22.6 13.1 7.3 26.2 14.5 39.2 21.7 9.7 5.3 19.4 10.7 29.1 16.1 2.9 1.6 4.1.2 4.5-2.4.3-2 .3-4 .3-6.1v-58.8c0-19.9.1-39.9 0-59.8 0-6.6 1.7-12.8 7.6-16.1 3.5-2 8.2-2.8 12.4-2.8 50.3-.2 100.7-.2 151-.1 19.8 0 38.3-4.4 55.1-15.1 23.1-14.8 36.3-36.3 40.6-62.9 3.4-20.8-1-40.9-12.4-58.5-17.8-27.5-43.6-43-76.5-43.6-47.8-.8-95.6-.2-143.4-.2zm-30.6 559.7c45.1 0 90.2-.2 135.3.1 18.9.1 36.6-3.9 53.9-11.1 18.4-7.7 33.6-19.8 46.3-34.9 9.1-10.8 16.2-22.9 20.8-36.5 4.2-12.4 7.4-24.7 7.3-37.9-.1-10.3.2-20.5-3.4-30.5-2.6-7.2-3.4-15.2-6.4-22.1-3.9-8.9-8.9-17.3-14-25.5-12.9-20.8-31.9-34.7-52.8-46.4-10.6-5.9-21.2-11.6-31.8-17.5-10.3-5.7-20.4-11.7-30.7-17.4-11.2-6.1-22.5-11.9-33.7-18-16.6-9.1-33.1-18.4-49.8-27.5-4.9-2.7-6.1-1.9-6.4 3.9-.1 2-.1 4.1-.1 6.1v114.5c0 14.8-5.6 20.4-20.4 20.4-47.6.1-95.3-.1-142.9.2-10.5.1-21.1 1.4-31.6 2.8-16.5 2.2-30.5 9.9-42.8 21-17 15.5-27 34.7-29.4 57.5-1.1 10.9-.4 21.7 2.9 32.5 3.7 12.3 9.2 23.4 17.5 33 19.2 22.1 43.4 33.3 72.7 33.3 46.6.1 93 0 139.5 0z" />
< /svg>
),
type : "Onion Network" ,
version : "Latest" ,
color : "cyan" ,
},
2025-08-11 20:52:14 -04:00
];
const features = [
2025-08-14 04:45:39 -04:00
{
name : "Security Architecture" ,
lockbit : { status : "🏆" , detail : "12-layer military-grade defense system" },
signal : { status : "✅" , detail : "Signal Protocol with double ratchet" },
threema : { status : "✅" , detail : "Standard security implementation" },
session : { status : "✅" , detail : "Modified Signal Protocol + Onion routing" },
},
2025-08-11 20:52:14 -04:00
{
2025-08-12 13:55:07 -04:00
name : "Cryptography" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "ECDH P-384 + AES-GCM 256 + ECDSA P-384" },
2025-08-12 13:55:07 -04:00
signal : { status : "✅" , detail : "Signal Protocol + Double Ratchet" },
threema : { status : "✅" , detail : "NaCl + XSalsa20 + Poly1305" },
2025-08-14 04:45:39 -04:00
session : { status : "✅" , detail : "Modified Signal Protocol" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Perfect Forward Secrecy" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "Auto rotation every 5 minutes or 100 messages" },
2025-08-12 13:55:07 -04:00
signal : { status : "✅" , detail : "Double Ratchet algorithm" },
threema : { status : "⚠️" , detail : "Partial (group chats)" },
2025-08-14 04:45:39 -04:00
session : { status : "✅" , detail : "Session Ratchet algorithm" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Architecture" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "Pure P2P WebRTC without servers" },
2025-08-12 13:55:07 -04:00
signal : { status : "❌" , detail : "Centralized Signal servers" },
threema : { status : "❌" , detail : "Threema servers in Switzerland" },
2025-08-14 04:45:39 -04:00
session : { status : "⚠️" , detail : "Onion routing via network nodes" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Registration Anonymity" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "No registration required, instant anonymous channels" },
2025-08-12 13:55:07 -04:00
signal : { status : "❌" , detail : "Phone number required" },
threema : { status : "✅" , detail : "ID generated locally" },
2025-08-14 04:45:39 -04:00
session : { status : "✅" , detail : "Random session ID" },
},
{
name : "Payment Integration" ,
lockbit : { status : "🏆" , detail : "Lightning Network satoshis per session + WebLN" },
signal : { status : "❌" , detail : "No payment system" },
threema : { status : "❌" , detail : "No payment system" },
session : { status : "❌" , detail : "No payment system" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Metadata Protection" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "Full metadata encryption + traffic obfuscation" },
2025-08-12 13:55:07 -04:00
signal : { status : "⚠️" , detail : "Sealed Sender (partial)" },
threema : { status : "⚠️" , detail : "Minimal metadata" },
2025-08-14 04:45:39 -04:00
session : { status : "✅" , detail : "Onion routing hides metadata" },
},
{
name : "Traffic Obfuscation" ,
lockbit : { status : "🏆" , detail : "Fake traffic + pattern masking + packet padding" },
signal : { status : "❌" , detail : "No traffic obfuscation" },
threema : { status : "❌" , detail : "No traffic obfuscation" },
session : { status : "✅" , detail : "Onion routing provides obfuscation" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Open Source" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "100% open + auditable + MIT license" },
2025-08-12 13:55:07 -04:00
signal : { status : "✅" , detail : "Fully open" },
threema : { status : "⚠️" , detail : "Only clients open" },
2025-08-14 04:45:39 -04:00
session : { status : "✅" , detail : "Fully open" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-14 04:45:39 -04:00
name : "MITM Protection" ,
lockbit : { status : "🏆" , detail : "Out-of-band verification + mutual auth + ECDSA" },
signal : { status : "✅" , detail : "Safety numbers verification" },
threema : { status : "✅" , detail : "QR code scanning" },
session : { status : "⚠️" , detail : "Basic key verification" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Economic Model" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "Sustainable pay-per-session model" },
signal : { status : "⚠️" , detail : "Donations and grants dependency" },
2025-08-12 13:55:07 -04:00
threema : { status : "✅" , detail : "One-time app purchase" },
2025-08-14 04:45:39 -04:00
session : { status : "⚠️" , detail : "Donations dependency" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Censorship Resistance" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "Impossible to block P2P + no servers to target" },
2025-08-12 13:55:07 -04:00
signal : { status : "⚠️" , detail : "Blocked in authoritarian countries" },
threema : { status : "⚠️" , detail : "May be blocked" },
2025-08-14 04:45:39 -04:00
session : { status : "✅" , detail : "Onion routing bypasses blocks" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
name : "Data Storage" ,
2025-08-14 04:45:39 -04:00
lockbit : { status : "🏆" , detail : "Zero data storage - only in browser memory" },
signal : { status : "⚠️" , detail : "Local database storage" },
2025-08-12 13:55:07 -04:00
threema : { status : "⚠️" , detail : "Local + optional backup" },
2025-08-14 04:45:39 -04:00
session : { status : "⚠️" , detail : "Local database storage" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-14 04:45:39 -04:00
name : "Key Security" ,
lockbit : { status : "🏆" , detail : "Non-extractable keys + hardware protection" },
signal : { status : "✅" , detail : "Secure key storage" },
threema : { status : "✅" , detail : "Local key storage" },
session : { status : "✅" , detail : "Secure key storage" },
2025-08-11 20:52:14 -04:00
},
{
2025-08-14 04:45:39 -04:00
name : "Post-Quantum Roadmap" ,
lockbit : { status : "✅" , detail : "Planned v5.0 - CRYSTALS-Kyber/Dilithium" },
signal : { status : "⚠️" , detail : "PQXDH in development" },
threema : { status : "❌" , detail : "Not announced" },
session : { status : "❌" , detail : "Not announced" },
},
2025-08-11 20:52:14 -04:00
];
const getStatusIcon = ( status ) => {
2025-08-14 04:45:39 -04:00
const statusMap = {
"🏆" : { icon : "🏆" , color : "text-yellow-400" },
"✅" : { icon : "✅" , color : "text-green-400" },
"⚠️" : { icon : "⚠️" , color : "text-yellow-400" },
"❌" : { icon : "❌" , color : "text-red-400" },
};
return statusMap [ status ] || { icon : status , color : "text-gray-400" };
2025-08-11 20:52:14 -04:00
};
const toggleFeatureDetail = ( index ) => {
setSelectedFeature ( selectedFeature === index ? null : index );
};
2025-08-14 04:45:39 -04:00
return (
< div className = "mt-16" >
{ /* Title */ }
< div className = "text-center mb-8" >
< h3 className = "text-3xl font-bold text-primary mb-3" >
Enhanced Security Edition Comparison
< /h3>
< p className = "text-secondary max-w-2xl mx-auto mb-4" >
2025-08-24 16:30:06 -04:00
SecureBit . chat v4 . 01.441 Enhanced Security Edition vs leading secure messengers
2025-08-14 04:45:39 -04:00
< /p>
< div className = "inline-flex items-center px-4 py-2 bg-yellow-500/10 border border-yellow-500/20 rounded-lg" >
< span className = "text-yellow-400 mr-2" > 🏆 < /span>
< span className = "text-yellow-300 text-sm font-medium" >
Category Leader - Military - Grade Security
< /span>
< /div>
< /div>
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
{ /* Table container */ }
< div className = "max-w-7xl mx-auto" >
{ /* Mobile Alert */ }
< div className = "md:hidden p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-lg mb-4" >
< p className = "text-yellow-400 text-sm text-center" >
💡 Rotate your device horizontally for better viewing
< /p>
< /div>
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
{ /* Table */ }
< div className = "overflow-x-auto custom-scrollbar" >
< table
className = "w-full border-collapse rounded-xl overflow-hidden shadow-2xl"
style = {{ backgroundColor : "rgba(42, 43, 42, 0.9)" }}
>
{ /* Table Header */ }
< thead >
< tr className = "bg-my" >
< th className = "text-left p-4 border-b border-gray-600 text-primary font-bold min-w-[240px]" >
Security Criterion
< /th>
{ messengers . map (( messenger , index ) => (
< th key = { `messenger- ${ index } ` } className = "text-center p-4 border-b border-gray-600 min-w-[160px]" >
< div className = "flex flex-col items-center" >
< div className = "mb-2" > { messenger . logo } < /div>
< div className = { `text-sm font-bold ${
messenger . color === 'orange' ? 'text-orange-400' :
messenger . color === 'blue' ? 'text-blue-400' :
messenger . color === 'green' ? 'text-green-400' :
'text-cyan-400'
} ` } >
{ messenger . name }
< /div>
< div className = "text-xs text-gray-400" > { messenger . type } < /div>
< div className = "text-xs text-gray-500 mt-1" > { messenger . version } < /div>
< /div>
< /th>
))}
< /tr>
< /thead>
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
{ /* Table body*/ }
< tbody >
{ features . map (( feature , featureIndex ) => (
< React . Fragment key = { `feature- ${ featureIndex } ` } >
< tr
className = { `border-b border-gray-700/30 hover:bg-gray-800/30 transition-all duration-200 cursor-pointer ${
selectedFeature === featureIndex ? 'bg-gray-800/50' : ''
} ` }
onClick = {() => toggleFeatureDetail ( featureIndex )}
>
< td className = "p-4 text-primary font-semibold" >
< div className = "flex items-center justify-between" >
< span > { feature . name } < /span>
< i className = { `fas fa-chevron- ${ selectedFeature === featureIndex ? 'up' : 'down' } text-xs text-gray-400 opacity-60 transition-all duration-200` } />
< /div>
< /td>
< td className = "p-4 text-center" >
< span className = { ` ${ getStatusIcon ( feature . lockbit . status ). color } text-2xl` } >
{ getStatusIcon ( feature . lockbit . status ). icon }
< /span>
< /td>
< td className = "p-4 text-center" >
< span className = { ` ${ getStatusIcon ( feature . signal . status ). color } text-2xl` } >
{ getStatusIcon ( feature . signal . status ). icon }
< /span>
< /td>
< td className = "p-4 text-center" >
< span className = { ` ${ getStatusIcon ( feature . threema . status ). color } text-2xl` } >
{ getStatusIcon ( feature . threema . status ). icon }
< /span>
< /td>
< td className = "p-4 text-center" >
< span className = { ` ${ getStatusIcon ( feature . session . status ). color } text-2xl` } >
{ getStatusIcon ( feature . session . status ). icon }
< /span>
< /td>
< /tr>
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
{ /* Details */ }
{ selectedFeature === featureIndex && (
< tr className = "border-b border-gray-700/30 bg-gradient-to-r from-gray-800/20 to-gray-900/20" >
< td className = "p-4 text-xs text-gray-400 font-medium" > Technical Details :< /td>
< td className = "p-4 text-center" >
< div className = "text-xs text-orange-300 font-medium leading-relaxed max-w-32" >
{ feature . lockbit . detail }
< /div>
< /td>
< td className = "p-4 text-center" >
< div className = "text-xs text-blue-300 leading-relaxed max-w-32" >
{ feature . signal . detail }
< /div>
< /td>
< td className = "p-4 text-center" >
< div className = "text-xs text-green-300 leading-relaxed max-w-32" >
{ feature . threema . detail }
< /div>
< /td>
< td className = "p-4 text-center" >
< div className = "text-xs text-cyan-300 leading-relaxed max-w-32" >
{ feature . session . detail }
< /div>
< /td>
< /tr>
)}
< /React.Fragment>
))}
< /tbody>
< /table>
< /div>
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
{ /* Legend */ }
< div className = "mt-8 grid grid-cols-2 md:grid-cols-4 gap-4 max-w-5xl mx-auto" >
< div className = "flex items-center justify-center p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-xl hover:bg-yellow-500/20 transition-colors" >
< span className = "text-yellow-400 mr-2 text-xl" > 🏆 < /span>
< span className = "text-yellow-300 text-sm font-bold" > Category Leader < /span>
< /div>
< div className = "flex items-center justify-center p-4 bg-green-500/10 border border-green-500/20 rounded-xl hover:bg-green-500/20 transition-colors" >
< span className = "text-green-400 mr-2 text-xl" > ✅ < /span>
< span className = "text-green-300 text-sm font-bold" > Excellent < /span>
< /div>
< div className = "flex items-center justify-center p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-xl hover:bg-yellow-500/20 transition-colors" >
< span className = "text-yellow-400 mr-2 text-xl" > ⚠️ < /span>
< span className = "text-yellow-300 text-sm font-bold" > Partial / Limited < /span>
< /div>
< div className = "flex items-center justify-center p-4 bg-red-500/10 border border-red-500/20 rounded-xl hover:bg-red-500/20 transition-colors" >
< span className = "text-red-400 mr-2 text-xl" > ❌ < /span>
< span className = "text-red-300 text-sm font-bold" > Not Available < /span>
< /div>
< /div>
2025-08-11 20:52:14 -04:00
2025-08-14 04:45:39 -04:00
{ /* Legend */ }
< div className = "mt-10 space-y-6 max-w-6xl mx-auto" >
< div className = "p-6 bg-gradient-to-r from-orange-500/10 to-yellow-500/10 border border-orange-500/20 rounded-xl" >
< h4 className = "text-xl font-bold text-orange-400 mb-4 flex items-center" >
< i className = "fas fa-trophy mr-3" />
2025-08-24 16:30:06 -04:00
SecureBit . chat v4 . 01.441 Enhanced Security Edition Summary
2025-08-14 04:45:39 -04:00
< /h4>
< p className = "text-secondary leading-relaxed text-lg mb-4" >
2025-08-14 15:54:11 -04:00
SecureBit . chat dominates in 11 out of 15 security categories , establishing itself as the most secure P2P messenger available .
2025-08-14 04:45:39 -04:00
The Enhanced Security Edition introduces revolutionary 12 - layer defense architecture , Lightning Network integration , and military - grade cryptography that exceeds government and enterprise standards .
< /p>
< div className = "grid md:grid-cols-2 gap-4 mt-6" >
< div className = "p-4 bg-orange-500/5 border border-orange-500/10 rounded-lg" >
< h5 className = "text-orange-400 font-semibold mb-2" > 🔐 Cryptographic Superiority < /h5>
< p className = "text-sm text-gray-300" >
ECDH P - 384 + AES - GCM 256 + ECDSA P - 384 with non - extractable keys and 12 - layer defense system
< /p>
< /div>
< div className = "p-4 bg-orange-500/5 border border-orange-500/10 rounded-lg" >
< h5 className = "text-orange-400 font-semibold mb-2" > ⚡ Lightning Integration < /h5>
< p className = "text-sm text-gray-300" >
First messenger with Lightning Network payments - sustainable economic model with instant satoshi transactions
< /p>
< /div>
< div className = "p-4 bg-orange-500/5 border border-orange-500/10 rounded-lg" >
< h5 className = "text-orange-400 font-semibold mb-2" > 🌐 True P2P Architecture < /h5>
< p className = "text-sm text-gray-300" >
Pure WebRTC connections with zero servers , impossible to censor or shutdown , complete anonymity
< /p>
< /div>
< div className = "p-4 bg-orange-500/5 border border-orange-500/10 rounded-lg" >
< h5 className = "text-orange-400 font-semibold mb-2" > 🎭 Traffic Obfuscation < /h5>
< p className = "text-sm text-gray-300" >
Advanced fake traffic generation , packet padding , and pattern masking defeat traffic analysis
< /p>
< /div>
< /div>
< /div>
< /div>
{ /* Version information */ }
< div className = "mt-8 text-center" >
< div className = "inline-flex items-center px-6 py-3 bg-gray-800/50 border border-gray-600/30 rounded-xl" >
< span className = "text-orange-400 mr-2" > 🚀 < /span>
< span className = "text-gray-300 text-sm" > Enhanced Security Edition v4 . 0 - < /span>
< span className = "text-orange-400 font-semibold text-sm" > Active Production Release < /span>
< span className = "text-gray-400 text-sm ml-2" > | Next : v5 . 0 Post - Quantum < /span>
< /div>
< /div>
< /div>
< /div>
);
};
2025-08-11 20:52:14 -04:00
function Roadmap () {
const [ selectedPhase , setSelectedPhase ] = React . useState ( null );
const phases = [
{
2025-08-12 13:55:07 -04:00
version : "v1.0" ,
title : "Start of Development" ,
status : "done" ,
date : "Early 2025" ,
description : "Idea, prototype, and infrastructure setup" ,
features : [
"Concept and requirements formation" ,
"Stack selection: WebRTC, P2P, cryptography" ,
"First messaging prototypes" ,
"Repository creation and CI" ,
"Basic encryption architecture" ,
"UX/UI design"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v1.5" ,
title : "Alpha Release" ,
status : "done" ,
date : "Spring 2025" ,
description : "First public alpha: basic chat and key exchange" ,
features : [
"Basic P2P messaging via WebRTC" ,
"Simple E2E encryption (demo scheme)" ,
"Stable signaling and reconnection" ,
"Minimal UX for testing" ,
"Feedback collection from early testers"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v2.0" ,
title : "Security Hardened" ,
status : "done" ,
date : "Summer 2025" ,
description : "Security strengthening and stable branch release" ,
features : [
"ECDH/ECDSA implementation in production" ,
"Perfect Forward Secrecy and key rotation" ,
"Improved authentication checks" ,
"File encryption and large payload transfers" ,
"Audit of basic cryptoprocesses"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v3.0" ,
title : "Scaling & Stability" ,
status : "done" ,
date : "Fall 2025" ,
description : "Network scaling and stability improvements" ,
features : [
"Optimization of P2P connections and NAT traversal" ,
"Reconnection mechanisms and message queues" ,
"Reduced battery consumption on mobile" ,
"Support for multi-device synchronization" ,
"Monitoring and logging tools for developers"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v3.5" ,
title : "Privacy-first Release" ,
status : "done" ,
date : "Winter 2025" ,
description : "Focus on privacy: minimizing metadata" ,
features : [
"Metadata protection and fingerprint reduction" ,
"Experiments with onion routing and DHT" ,
"Options for anonymous connections" ,
"Preparation for open code audit" ,
"Improved user verification processes"
]
2025-08-11 20:52:14 -04:00
},
2025-08-12 13:55:07 -04:00
// current and future phases
2025-08-11 20:52:14 -04:00
{
2025-08-12 13:55:07 -04:00
version : "v4.0" ,
title : "Enhanced Security Edition" ,
status : "current" ,
date : "Now" ,
description : "Current version with military-grade cryptography" ,
features : [
"ECDH P-384 + AES-GCM 256-bit encryption" ,
"ECDSA digital signatures" ,
"Perfect Forward Secrecy with key rotation" ,
"Out-of-band MITM verification" ,
"Lightning Network payments" ,
"P2P WebRTC architecture" ,
"Metadata protection" ,
"100% open source code"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v4.5" ,
title : "Mobile & Desktop Edition" ,
status : "development" ,
date : "Q2 2025" ,
description : "Native apps for all platforms" ,
features : [
"PWA app for mobile" ,
"Electron app for desktop" ,
"Real-time notifications" ,
"Automatic reconnection" ,
"Battery optimization" ,
"Cross-device synchronization" ,
"Improved UX/UI" ,
"Support for files up to 100MB"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v5.0" ,
title : "Quantum-Resistant Edition" ,
status : "planned" ,
date : "Q4 2025" ,
description : "Protection against quantum computers" ,
features : [
"Post-quantum cryptography CRYSTALS-Kyber" ,
"SPHINCS+ digital signatures" ,
"Hybrid scheme: classic + PQ" ,
2025-08-11 20:52:14 -04:00
"Quantum-safe key exchange" ,
2025-08-12 13:55:07 -04:00
"Updated hashing algorithms" ,
"Migration of existing sessions" ,
"Compatibility with v4.x" ,
"Quantum-resistant protocols"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v5.5" ,
title : "Group Communications" ,
status : "planned" ,
date : "Q2 2026" ,
description : "Group chats with preserved privacy" ,
features : [
"P2P group connections up to 8 participants" ,
"Mesh networking for groups" ,
"Signal Double Ratchet for groups" ,
"Anonymous groups without metadata" ,
"Ephemeral groups (disappear after session)" ,
"Group Lightning payments" ,
"Cryptographic group administration" ,
"Group member auditing"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v6.0" ,
title : "Decentralized Network" ,
status : "research" ,
date : "2027" ,
description : "Fully decentralized network" ,
features : [
"LockBit node mesh network" ,
"DHT for peer discovery" ,
"Built-in onion routing" ,
"Tokenomics and node incentives" ,
"Governance via DAO" ,
"Interoperability with other networks" ,
"Cross-platform compatibility" ,
"Self-healing network"
]
2025-08-11 20:52:14 -04:00
},
{
2025-08-12 13:55:07 -04:00
version : "v7.0" ,
title : "AI Privacy Assistant" ,
status : "research" ,
date : "2028+" ,
description : "AI for privacy and security" ,
features : [
"Local AI threat analysis" ,
"Automatic MITM detection" ,
"Adaptive cryptography" ,
2025-08-11 20:52:14 -04:00
"Personalized security recommendations" ,
"Zero-knowledge machine learning" ,
2025-08-12 13:55:07 -04:00
"Private AI assistant" ,
"Predictive security" ,
"Autonomous attack protection"
]
2025-08-11 20:52:14 -04:00
}
2025-08-12 13:55:07 -04:00
];
2025-08-11 20:52:14 -04:00
const getStatusConfig = ( status ) => {
switch ( status ) {
2025-08-12 13:55:07 -04:00
case 'current' :
2025-08-11 20:52:14 -04:00
return {
2025-08-12 13:55:07 -04:00
color : 'green' ,
bgClass : 'bg-green-500/10 border-green-500/20' ,
textClass : 'text-green-400' ,
icon : 'fas fa-check-circle' ,
label : 'Current Version'
2025-08-11 20:52:14 -04:00
};
2025-08-12 13:55:07 -04:00
case 'development' :
2025-08-11 20:52:14 -04:00
return {
2025-08-12 13:55:07 -04:00
color : 'orange' ,
bgClass : 'bg-orange-500/10 border-orange-500/20' ,
textClass : 'text-orange-400' ,
icon : 'fas fa-code' ,
label : 'In Development'
2025-08-11 20:52:14 -04:00
};
2025-08-12 13:55:07 -04:00
case 'planned' :
2025-08-11 20:52:14 -04:00
return {
2025-08-12 13:55:07 -04:00
color : 'blue' ,
bgClass : 'bg-blue-500/10 border-blue-500/20' ,
textClass : 'text-blue-400' ,
icon : 'fas fa-calendar-alt' ,
label : 'Planned'
2025-08-11 20:52:14 -04:00
};
2025-08-12 13:55:07 -04:00
case 'research' :
2025-08-11 20:52:14 -04:00
return {
2025-08-12 13:55:07 -04:00
color : 'purple' ,
bgClass : 'bg-purple-500/10 border-purple-500/20' ,
textClass : 'text-purple-400' ,
icon : 'fas fa-flask' ,
label : 'Research'
2025-08-11 20:52:14 -04:00
};
2025-08-12 13:55:07 -04:00
case 'done' :
2025-08-11 20:52:14 -04:00
return {
2025-08-12 13:55:07 -04:00
color : 'gray' ,
bgClass : 'bg-gray-500/10 border-gray-500/20' ,
textClass : 'text-gray-300' ,
icon : 'fas fa-flag-checkered' ,
label : 'Released'
2025-08-11 20:52:14 -04:00
};
2025-08-12 13:55:07 -04:00
default :
2025-08-11 20:52:14 -04:00
return {
2025-08-12 13:55:07 -04:00
color : 'gray' ,
bgClass : 'bg-gray-500/10 border-gray-500/20' ,
textClass : 'text-gray-400' ,
icon : 'fas fa-question' ,
label : 'Unknown'
2025-08-11 20:52:14 -04:00
};
}
2025-08-12 13:55:07 -04:00
};
2025-08-11 20:52:14 -04:00
const togglePhaseDetail = ( index ) => {
setSelectedPhase ( selectedPhase === index ? null : index );
};
return (
< div key = "roadmap-section" className = "mt-16 px-4 sm:px-0" >
< div key = "section-header" className = "text-center mb-12" >
< h3 key = "title" className = "text-2xl font-semibold text-primary mb-3" >
2025-08-12 13:55:07 -04:00
Development Roadmap
2025-08-11 20:52:14 -04:00
< /h3>
< p key = "subtitle" className = "text-secondary max-w-2xl mx-auto mb-6" >
2025-08-14 15:54:11 -04:00
Evolution of SecureBit . chat : from initial development to a quantum - resistant decentralized network
2025-08-11 20:52:14 -04:00
< /p>
< div
key = "roadmap-note"
className = "inline-flex items-center px-4 py-2 bg-blue-500/10 border border-blue-500/20 rounded-lg"
>
< i key = "icon" className = "fas fa-rocket text-blue-400 mr-2" />
< span key = "text" className = "text-blue-300 text-sm font-medium" >
2025-08-12 13:55:07 -04:00
Click on a version for details
2025-08-11 20:52:14 -04:00
< /span>
< /div>
< /div>
< div key = "roadmap-container" className = "max-w-6xl mx-auto" >
< div key = "timeline" className = "relative" >
2025-08-12 13:55:07 -04:00
{ /* The line has been removed */ }
2025-08-11 20:52:14 -04:00
< div key = "phases" className = "space-y-8" >
{ phases . map (( phase , index ) => {
const statusConfig = getStatusConfig ( phase . status );
const isExpanded = selectedPhase === index ;
return (
< div key = { `phase- ${ index } ` } className = "relative" >
2025-08-12 13:55:07 -04:00
{ /* The dots are visible only on sm and larger screens */ }
2025-08-11 20:52:14 -04:00
< button
type = "button"
aria - expanded = { isExpanded }
onClick = {() => togglePhaseDetail ( index )}
key = { `phase-button- ${ index } ` }
className = { `card-minimal rounded-xl p-4 text-left w-full transition-all duration-300 ${
isExpanded
? "ring-2 ring-" + statusConfig . color + "-500/30"
: ""
} ` }
>
< div
key = "phase-header"
className = "flex flex-col sm:flex-row sm:items-center sm:justify-between mb-4 space-y-2 sm:space-y-0"
>
< div
key = "phase-info"
className = "flex flex-col sm:flex-row sm:items-center sm:space-x-4"
>
< div
key = "version-badge"
className = { `px-3 py-1 ${ statusConfig . bgClass } border rounded-lg mb-2 sm:mb-0` }
>
< span
key = "version"
className = { ` ${ statusConfig . textClass } font-bold text-sm` }
>
{ phase . version }
< /span>
< /div>
< div key = "title-section" >
< h4
key = "title"
className = "text-lg font-semibold text-primary"
>
{ phase . title }
< /h4>
< p
key = "description"
className = "text-secondary text-sm"
>
{ phase . description }
< /p>
< /div>
< /div>
< div
key = "phase-meta"
className = "flex items-center space-x-3 text-sm text-gray-400 font-medium"
>
< div
key = "status-badge"
className = { `flex items-center px-3 py-1 ${ statusConfig . bgClass } border rounded-lg` }
>
< i
key = "status-icon"
className = { ` ${ statusConfig . icon } ${ statusConfig . textClass } mr-2 text-xs` }
/>
< span
key = "status-text"
className = { ` ${ statusConfig . textClass } text-xs font-medium` }
>
{ statusConfig . label }
< /span>
< /div>
< div key = "date" > { phase . date } < /div>
< i
key = "expand-icon"
className = { `fas fa-chevron- ${
isExpanded ? "up" : "down"
} text-gray-400 text-sm` }
/>
< /div>
< /div>
{ isExpanded && (
< div
key = "features-section"
className = "mt-6 pt-6 border-t border-gray-700/30"
>
< h5
key = "features-title"
className = "text-primary font-medium mb-4 flex items-center"
>
< i
key = "features-icon"
className = "fas fa-list-ul mr-2 text-sm"
/>
2025-08-12 13:55:07 -04:00
Key features :
2025-08-11 20:52:14 -04:00
< /h5>
< div
key = "features-grid"
className = "grid md:grid-cols-2 gap-3"
>
{ phase . features . map (( feature , featureIndex ) => (
< div
key = { `feature- ${ featureIndex } ` }
className = "flex items-center space-x-3 p-3 bg-custom-bg rounded-lg"
>
< div
className = { `w-2 h-2 rounded-full ${ statusConfig . textClass . replace (
"text-" ,
"bg-"
) } ` }
/>
< span className = "text-secondary text-sm" >
{ feature }
< /span>
< /div>
))}
< /div>
< /div>
)}
< /button>
< /div>
);
})}
< /div>
< /div>
< /div>
< div key = "cta-section" className = "mt-12 text-center" >
< div
key = "cta-card"
className = "card-minimal rounded-xl p-8 max-w-2xl mx-auto"
>
< h4
key = "cta-title"
className = "text-xl font-semibold text-primary mb-3"
>
2025-08-12 13:55:07 -04:00
Join the future of privacy
2025-08-11 20:52:14 -04:00
< /h4>
< p key = "cta-description" className = "text-secondary mb-6" >
2025-08-14 15:54:11 -04:00
SecureBit . chat grows thanks to the community . Your ideas and feedback help shape the future of secure communication .
2025-08-11 20:52:14 -04:00
< /p>
< div
key = "cta-buttons"
className = "flex flex-col sm:flex-row gap-4 justify-center"
>
< a
key = "github-link"
2025-08-16 19:17:32 -04:00
href = "https://github.com/SecureBitChat/securebit-chat/"
2025-08-11 20:52:14 -04:00
className = "btn-primary text-white py-3 px-6 rounded-lg font-medium transition-all duration-200 flex items-center justify-center"
>
< i key = "github-icon" className = "fab fa-github mr-2" />
GitHub Repository
< /a>
< a
key = "feedback-link"
href = "mailto:lockbitchat@tutanota.com"
className = "btn-secondary text-white py-3 px-6 rounded-lg font-medium transition-all duration-200 flex items-center justify-center"
>
< i key = "feedback-icon" className = "fas fa-comments mr-2" />
2025-08-12 13:55:07 -04:00
Feedback
2025-08-11 20:52:14 -04:00
< /a>
< /div>
< /div>
< /div>
< /div>
);
}
// Enhanced Copy Button with better UX
const EnhancedCopyButton = ({ text , className = "" , children }) => {
const [ copied , setCopied ] = React . useState ( false );
const handleCopy = async () => {
try {
await navigator . clipboard . writeText ( text );
setCopied ( true );
setTimeout (() => setCopied ( false ), 2000 );
} catch ( error ) {
console . error ( 'Copy failed:' , error );
// Fallback for older browsers
const textArea = document . createElement ( 'textarea' );
textArea . value = text ;
document . body . appendChild ( textArea );
textArea . select ();
document . execCommand ( 'copy' );
document . body . removeChild ( textArea );
setCopied ( true );
setTimeout (() => setCopied ( false ), 2000 );
}
};
return React . createElement ( 'button' , {
onClick : handleCopy ,
className : ` ${ className } transition-all duration-200`
}, [
React . createElement ( 'i' , {
key : 'icon' ,
className : ` ${ copied ? 'fas fa-check accent-green' : 'fas fa-copy text-secondary' } mr-2`
}),
2025-08-12 13:55:07 -04:00
copied ? 'Copied!' : children
2025-08-11 20:52:14 -04:00
]);
};
// Verification Component
const VerificationStep = ({ verificationCode , onConfirm , onReject }) => {
return React . createElement ( 'div' , {
className : "card-minimal rounded-xl p-6 border-purple-500/20"
}, [
React . createElement ( 'div' , {
key : 'header' ,
className : "flex items-center mb-4"
}, [
React . createElement ( 'div' , {
key : 'icon' ,
className : "w-10 h-10 bg-purple-500/10 border border-purple-500/20 rounded-lg flex items-center justify-center mr-3"
}, [
React . createElement ( 'i' , {
className : 'fas fa-shield-alt accent-purple'
})
]),
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-medium text-primary"
2025-08-12 13:55:07 -04:00
}, "Security verification" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'content' ,
className : "space-y-4"
}, [
React . createElement ( 'p' , {
key : 'description' ,
className : "text-secondary text-sm"
2025-08-12 13:55:07 -04:00
}, "Verify the security code with your contact via another communication channel (voice, SMS, etc.):" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'div' , {
key : 'code-display' ,
className : "text-center"
}, [
React . createElement ( 'div' , {
key : 'code' ,
className : "verification-code text-2xl py-4"
}, verificationCode )
]),
React . createElement ( 'div' , {
key : 'warning' ,
className : "p-3 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"
}, [
React . createElement ( 'p' , {
className : "text-yellow-400 text-sm flex items-center"
}, [
React . createElement ( 'i' , {
className : 'fas fa-exclamation-triangle mr-2'
}),
2025-08-12 13:55:07 -04:00
'Make sure the codes match exactly.!'
2025-08-11 20:52:14 -04:00
])
]),
React . createElement ( 'div' , {
key : 'buttons' ,
className : "flex space-x-3"
}, [
React . createElement ( 'button' , {
key : 'confirm' ,
onClick : onConfirm ,
className : "flex-1 btn-verify text-white py-3 px-4 rounded-lg font-medium transition-all duration-200"
}, [
React . createElement ( 'i' , {
className : 'fas fa-check mr-2'
}),
2025-08-12 13:55:07 -04:00
'The codes match'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'button' , {
key : 'reject' ,
onClick : onReject ,
className : "flex-1 bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 py-3 px-4 rounded-lg font-medium transition-all duration-200"
}, [
React . createElement ( 'i' , {
className : 'fas fa-times mr-2'
}),
2025-08-12 13:55:07 -04:00
'The codes do not match'
2025-08-11 20:52:14 -04:00
])
])
])
]);
};
// Enhanced Chat Message with better security indicators
const EnhancedChatMessage = ({ message , type , timestamp }) => {
const formatTime = ( ts ) => {
return new Date ( ts ). toLocaleTimeString ( 'ru-RU' , {
hour : '2-digit' ,
minute : '2-digit' ,
second : '2-digit'
});
};
const getMessageStyle = () => {
switch ( type ) {
case 'sent' :
return {
container : "ml-auto bg-orange-500/15 border-orange-500/20 text-primary" ,
icon : "fas fa-lock accent-orange" ,
2025-08-12 13:55:07 -04:00
label : "Encrypted"
2025-08-11 20:52:14 -04:00
};
case 'received' :
return {
container : "mr-auto card-minimal text-primary" ,
icon : "fas fa-unlock-alt accent-green" ,
2025-08-12 13:55:07 -04:00
label : "Decrypted"
2025-08-11 20:52:14 -04:00
};
case 'system' :
return {
container : "mx-auto bg-yellow-500/10 border border-yellow-500/20 text-yellow-400" ,
icon : "fas fa-info-circle accent-yellow" ,
2025-08-12 13:55:07 -04:00
label : "System"
2025-08-11 20:52:14 -04:00
};
default :
return {
container : "mx-auto card-minimal text-secondary" ,
icon : "fas fa-circle text-muted" ,
2025-08-12 13:55:07 -04:00
label : "Unknown"
2025-08-11 20:52:14 -04:00
};
}
};
const style = getMessageStyle ();
return React . createElement ( 'div' , {
className : `message-slide mb-3 p-3 rounded-lg max-w-md break-words ${ style . container } border`
}, [
React . createElement ( 'div' , {
key : 'content' ,
className : "flex items-start space-x-2"
}, [
React . createElement ( 'i' , {
key : 'icon' ,
className : ` ${ style . icon } text-sm mt-0.5 opacity-70`
}),
React . createElement ( 'div' , {
key : 'text' ,
className : "flex-1"
}, [
React . createElement ( 'div' , {
key : 'message' ,
className : "text-sm"
}, message ),
timestamp && React . createElement ( 'div' , {
key : 'meta' ,
className : "flex items-center justify-between mt-1 text-xs opacity-50"
}, [
React . createElement ( 'span' , {
key : 'time'
}, formatTime ( timestamp )),
React . createElement ( 'span' , {
key : 'status' ,
className : "text-xs"
}, style . label )
])
])
])
]);
};
// Enhanced Connection Setup with verification
const EnhancedConnectionSetup = ({
messages ,
onCreateOffer ,
onCreateAnswer ,
onConnect ,
onClearData ,
onVerifyConnection ,
connectionStatus ,
offerData ,
answerData ,
offerInput ,
setOfferInput ,
answerInput ,
setAnswerInput ,
showOfferStep ,
showAnswerStep ,
verificationCode ,
showVerification ,
offerPassword ,
answerPassword
}) => {
const [ mode , setMode ] = React . useState ( 'select' );
const resetToSelect = () => {
setMode ( 'select' );
onClearData ();
};
const handleVerificationConfirm = () => {
onVerifyConnection ( true );
};
const handleVerificationReject = () => {
onVerifyConnection ( false );
};
if ( showVerification ) {
return React . createElement ( 'div' , {
className : "min-h-[calc(100vh-104px)] flex items-center justify-center p-4"
}, [
React . createElement ( 'div' , {
key : 'verification' ,
className : "w-full max-w-md"
}, [
React . createElement ( VerificationStep , {
verificationCode : verificationCode ,
onConfirm : handleVerificationConfirm ,
onReject : handleVerificationReject
})
])
]);
}
if ( mode === 'select' ) {
return React . createElement ( 'div' , {
className : "min-h-[calc(100vh-104px)] flex items-center justify-center p-4"
}, [
React . createElement ( 'div' , {
key : 'selector' ,
className : "w-full max-w-4xl"
}, [
React . createElement ( 'div' , {
key : 'header' ,
className : "text-center mb-8"
}, [
React . createElement ( 'h2' , {
key : 'title' ,
className : "text-2xl font-semibold text-primary mb-3"
2025-08-12 13:55:07 -04:00
}, 'Start secure communication' ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'p' , {
key : 'subtitle' ,
className : "text-secondary max-w-2xl mx-auto"
2025-08-12 13:55:07 -04:00
}, "Choose a connection method for a secure channel with ECDH encryption and Perfect Forward Secrecy." )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'options' ,
className : "grid md:grid-cols-2 gap-6 max-w-3xl mx-auto"
}, [
// Create Connection
React . createElement ( 'div' , {
key : 'create' ,
onClick : () => setMode ( 'create' ),
className : "card-minimal rounded-xl p-6 cursor-pointer group"
}, [
React . createElement ( 'div' , {
key : 'icon' ,
className : "w-12 h-12 bg-blue-500/10 border border-blue-500/20 rounded-lg flex items-center justify-center mx-auto mb-4"
}, [
React . createElement ( 'i' , {
className : 'fas fa-plus text-xl text-blue-400'
})
]),
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-semibold text-primary text-center mb-3"
2025-08-12 13:55:07 -04:00
}, "Create channel" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'p' , {
key : 'description' ,
className : "text-secondary text-center text-sm mb-4"
2025-08-12 13:55:07 -04:00
}, "Initiate a new secure connection with encrypted exchange" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'div' , {
key : 'features' ,
className : "space-y-2"
}, [
React . createElement ( 'div' , {
key : 'f1' ,
className : "flex items-center text-sm text-muted"
}, [
React . createElement ( 'i' , {
className : 'fas fa-key accent-orange mr-2 text-xs'
}),
2025-08-12 13:55:07 -04:00
'Generating ECDH keys'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'f2' ,
className : "flex items-center text-sm text-muted"
}, [
React . createElement ( 'i' , {
className : 'fas fa-shield-alt accent-orange mr-2 text-xs'
}),
2025-08-12 13:55:07 -04:00
'Verification code'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'f3' ,
className : "flex items-center text-sm text-muted"
}, [
React . createElement ( 'i' , {
className : 'fas fa-sync-alt accent-purple mr-2 text-xs'
}),
2025-08-12 13:55:07 -04:00
'PFS key rotation'
2025-08-11 20:52:14 -04:00
])
])
]),
// Join Connection
React . createElement ( 'div' , {
key : 'join' ,
onClick : () => setMode ( 'join' ),
className : "card-minimal rounded-xl p-6 cursor-pointer group"
}, [
React . createElement ( 'div' , {
key : 'icon' ,
className : "w-12 h-12 bg-green-500/10 border border-green-500/20 rounded-lg flex items-center justify-center mx-auto mb-4"
}, [
React . createElement ( 'i' , {
className : 'fas fa-link text-xl accent-green'
})
]),
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-semibold text-primary text-center mb-3"
2025-08-12 13:55:07 -04:00
}, "Join" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'p' , {
key : 'description' ,
className : "text-secondary text-center text-sm mb-4"
2025-08-12 13:55:07 -04:00
}, "Connect to an existing secure channel" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'div' , {
key : 'features' ,
className : "space-y-2"
}, [
React . createElement ( 'div' , {
key : 'f1' ,
className : "flex items-center text-sm text-muted"
}, [
React . createElement ( 'i' , {
className : 'fas fa-paste accent-green mr-2 text-xs'
}),
2025-08-12 13:55:07 -04:00
'Paste Offer invitation'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'f2' ,
className : "flex items-center text-sm text-muted"
}, [
React . createElement ( 'i' , {
className : 'fas fa-check-circle accent-green mr-2 text-xs'
}),
2025-08-12 13:55:07 -04:00
'Automatic verification'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'f3' ,
className : "flex items-center text-sm text-muted"
}, [
React . createElement ( 'i' , {
className : 'fas fa-sync-alt accent-purple mr-2 text-xs'
}),
2025-08-12 13:55:07 -04:00
'PFS protection'
2025-08-11 20:52:14 -04:00
])
])
])
]),
React . createElement ( 'div' , {
key : 'security-features' ,
className : "grid grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4 max-w-6xl mx-auto mt-8"
}, [
React . createElement ( 'div' , { key : 'feature1' , className : "text-center p-3 sm:p-4" }, [
React . createElement ( 'div' , { key : 'icon' , className : "w-10 h-10 sm:w-12 sm:h-12 bg-green-500/10 border border-green-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
2025-08-14 04:45:39 -04:00
React . createElement ( 'i' , { className : 'fas fa-key accent-green' })
2025-08-11 20:52:14 -04:00
]),
2025-08-14 04:45:39 -04:00
React . createElement ( 'h4' , { key : 'title' , className : "text-xs sm:text-sm font-medium text-primary mb-1" }, "ECDH P-384 Key Exchange" ),
React . createElement ( 'p' , { key : 'desc' , className : "text-xs text-muted leading-tight" }, "Military-grade elliptic curve key exchange" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , { key : 'feature2' , className : "text-center p-3 sm:p-4" }, [
React . createElement ( 'div' , { key : 'icon' , className : "w-10 h-10 sm:w-12 sm:h-12 bg-purple-500/10 border border-purple-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
2025-08-14 04:45:39 -04:00
React . createElement ( 'i' , { className : 'fas fa-user-shield accent-purple' })
2025-08-11 20:52:14 -04:00
]),
2025-08-14 04:45:39 -04:00
React . createElement ( 'h4' , { key : 'title' , className : "text-xs sm:text-sm font-medium text-primary mb-1" }, "MITM Protection" ),
React . createElement ( 'p' , { key : 'desc' , className : "text-xs text-muted leading-tight" }, "Out-of-band verification against attacks" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , { key : 'feature3' , className : "text-center p-3 sm:p-4" }, [
React . createElement ( 'div' , { key : 'icon' , className : "w-10 h-10 sm:w-12 sm:h-12 bg-orange-500/10 border border-orange-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
React . createElement ( 'i' , { className : 'fas fa-lock accent-orange' })
]),
2025-08-14 04:45:39 -04:00
React . createElement ( 'h4' , { key : 'title' , className : "text-xs sm:text-sm font-medium text-primary mb-1" }, "AES-GCM 256 Encryption" ),
React . createElement ( 'p' , { key : 'desc' , className : "text-xs text-muted leading-tight" }, "Authenticated encryption standard" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , { key : 'feature4' , className : "text-center p-3 sm:p-4" }, [
React . createElement ( 'div' , { key : 'icon' , className : "w-10 h-10 sm:w-12 sm:h-12 bg-cyan-500/10 border border-cyan-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
React . createElement ( 'i' , { className : 'fas fa-sync-alt accent-cyan' })
]),
React . createElement ( 'h4' , { key : 'title' , className : "text-xs sm:text-sm font-medium text-primary mb-1" }, "Perfect Forward Secrecy" ),
2025-08-14 04:45:39 -04:00
React . createElement ( 'p' , { key : 'desc' , className : "text-xs text-muted leading-tight" }, "Automatic key rotation every 5 minutes" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , { key : 'feature5' , className : "text-center p-3 sm:p-4" }, [
React . createElement ( 'div' , { key : 'icon' , className : "w-10 h-10 sm:w-12 sm:h-12 bg-blue-500/10 border border-blue-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
2025-08-14 04:45:39 -04:00
React . createElement ( 'i' , { className : 'fas fa-signature accent-blue' })
2025-08-11 20:52:14 -04:00
]),
2025-08-14 04:45:39 -04:00
React . createElement ( 'h4' , { key : 'title' , className : "text-xs sm:text-sm font-medium text-primary mb-1" }, "ECDSA P-384 Signatures" ),
React . createElement ( 'p' , { key : 'desc' , className : "text-xs text-muted leading-tight" }, "Digital signatures for message integrity" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , { key : 'feature6' , className : "text-center p-3 sm:p-4" }, [
2025-08-14 04:45:39 -04:00
React . createElement ( 'div' , { key : 'icon' , className : "w-10 h-10 sm:w-12 sm:h-12 bg-yellow-500/10 border border-yellow-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
React . createElement ( 'i' , { className : 'fas fa-bolt accent-yellow' })
2025-08-11 20:52:14 -04:00
]),
2025-08-14 04:45:39 -04:00
React . createElement ( 'h4' , { key : 'title' , className : "text-xs sm:text-sm font-medium text-primary mb-1" }, "Lightning Payments" ),
React . createElement ( 'p' , { key : 'desc' , className : "text-xs text-muted leading-tight" }, "Pay-per-session via WebLN" )
2025-08-11 20:52:14 -04:00
])
]),
2025-08-17 00:10:33 -04:00
2025-08-11 20:52:14 -04:00
// Wallet Logos Section
React . createElement ( 'div' , {
key : 'wallet-logos-section' ,
className : "mt-8"
}, [
React . createElement ( 'div' , {
key : 'wallet-logos-header' ,
className : "text-center mb-4"
}, [
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-medium text-primary mb-2"
2025-08-12 13:55:07 -04:00
}, "Supported Lightning wallets" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'p' , {
key : 'subtitle' ,
className : "text-secondary text-sm"
2025-08-12 13:55:07 -04:00
}, "To pay for sessions, use any of the popular wallets." )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'wallet-logos-container' ,
className : "wallet-logos-container"
}, [
React . createElement ( 'div' , {
key : 'wallet-logos-track' ,
className : "wallet-logos-track"
}, [
// First set of logos
React . createElement ( 'a' , {
key : 'alby1-link' ,
href : "https://getalby.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo alby"
}, [
React . createElement ( 'img' , {
key : 'alby-img1' ,
src : "logo/alby.svg" ,
alt : "Alby Lightning Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'zeus1-link' ,
href : "https://zeusln.app" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo zeus"
}, [
React . createElement ( 'img' , {
key : 'zeus-img1' ,
src : "logo/zeus.svg" ,
alt : "Zeus Lightning Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'wos1-link' ,
href : "https://www.walletofsatoshi.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo wos"
}, [
React . createElement ( 'img' , {
key : 'wos-img1' ,
src : "logo/wos.svg" ,
alt : "Wallet of Satoshi" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'muun1-link' ,
href : "https://muun.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo muun"
}, [
React . createElement ( 'img' , {
key : 'muun-img1' ,
src : "logo/muun.svg" ,
alt : "Muun Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'atomic1-link' ,
href : "https://atomicwallet.io" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo atomic"
}, [
React . createElement ( 'img' , {
key : 'atomic-img1' ,
src : "logo/atomic.svg" ,
alt : "Atomic Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'breez1-link' ,
href : "https://breez.technology/mobile/" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo breez"
}, [
React . createElement ( 'img' , {
key : 'breez-img1' ,
src : "logo/breez.svg" ,
alt : "Breez Lightning Wallet" ,
})
]),
React . createElement ( 'a' , {
key : 'lightning-labs1-link' ,
href : "https://lightning.engineering" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo lightning-labs"
}, [
React . createElement ( 'img' , {
key : 'lightning-labs-img1' ,
src : "logo/lightning-labs.svg" ,
alt : "Lightning Labs" ,
})
]),
React . createElement ( 'a' , {
key : 'lnbits1-link' ,
href : "https://lnbits.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo lnbits"
}, [
React . createElement ( 'img' , {
key : 'lnbits-img1' ,
src : "logo/lnbits.svg" ,
alt : "LNbits" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'strike1-link' ,
href : "https://strike.me" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo strike"
}, [
React . createElement ( 'img' , {
key : 'strike-img1' ,
src : "logo/strike.svg" ,
alt : "Strike" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'impervious1-link' ,
href : "https://impervious.ai" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo impervious"
}, [
React . createElement ( 'img' , {
key : 'impervious-img1' ,
src : "logo/impervious.svg" ,
alt : "Impervious" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'bitcoin-lightning1-link' ,
href : "https://www.blink.sv/" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo bitcoin-lightning"
}, [
React . createElement ( 'img' , {
key : 'blink-img1' ,
src : "logo/blink.svg" ,
alt : "Blink Wallet" ,
className : "wallet-logo-img"
})
]),
// Second set of logos
React . createElement ( 'a' , {
key : 'alby2-link' ,
href : "https://getalby.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo alby"
}, [
React . createElement ( 'img' , {
key : 'alby-img2' ,
src : "logo/alby.svg" ,
alt : "Alby Lightning Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'zeus2-link' ,
href : "https://zeusln.app" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo zeus"
}, [
React . createElement ( 'img' , {
key : 'zeus-img2' ,
src : "logo/zeus.svg" ,
alt : "Zeus Lightning Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'wos2-link' ,
href : "https://www.walletofsatoshi.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo wos"
}, [
React . createElement ( 'img' , {
key : 'wos-img2' ,
src : "logo/wos.svg" ,
alt : "Wallet of Satoshi" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'muun2-link' ,
href : "https://muun.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo muun"
}, [
React . createElement ( 'img' , {
key : 'muun-img2' ,
src : "logo/muun.svg" ,
alt : "Muun Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'atomic2-link' ,
href : "https://atomicwallet.io" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo atomic"
}, [
React . createElement ( 'img' , {
key : 'atomic-img2' ,
src : "logo/atomic.svg" ,
alt : "Atomic Wallet" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'breez2-link' ,
href : "https://breez.technology/mobile/" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo breez"
}, [
React . createElement ( 'img' , {
key : 'breez-img2' ,
src : "logo/breez.svg" ,
alt : "Breez Lightning Wallet" ,
})
]),
React . createElement ( 'a' , {
key : 'lightning-labs2-link' ,
href : "https://lightning.engineering" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo lightning-labs"
}, [
React . createElement ( 'img' , {
key : 'lightning-labs-img2' ,
src : "logo/lightning-labs.svg" ,
alt : "Lightning Labs" ,
})
]),
React . createElement ( 'a' , {
key : 'lnbits2-link' ,
href : "https://lnbits.com" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo lnbits"
}, [
React . createElement ( 'img' , {
key : 'lnbits-img2' ,
src : "logo/lnbits.svg" ,
alt : "LNbits" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'strike2-link' ,
href : "https://strike.me" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo strike"
}, [
React . createElement ( 'img' , {
key : 'strike-img2' ,
src : "logo/strike.svg" ,
alt : "Strike" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'impervious2-link' ,
href : "https://impervious.ai" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo impervious"
}, [
React . createElement ( 'img' , {
key : 'impervious-img2' ,
src : "logo/impervious.svg" ,
alt : "Impervious" ,
className : "wallet-logo-img"
})
]),
React . createElement ( 'a' , {
key : 'bitcoin-lightning2-link' ,
href : "https://www.blink.sv/" ,
target : "_blank" ,
rel : "noindex nofollow" ,
className : "wallet-logo bitcoin-lightning"
}, [
React . createElement ( 'img' , {
key : 'blink-img2' ,
src : "logo/blink.svg" ,
alt : "Blink Wallet" ,
className : "wallet-logo-img"
})
])
])
])
]),
React . createElement ( UniqueFeatureSlider , { key : 'unique-features-slider' }),
2025-08-17 00:10:33 -04:00
React . createElement ( DownloadApps , { key : 'download-apps' }),
2025-08-11 20:52:14 -04:00
React . createElement ( ComparisonTable , { key : 'comparison-table' }),
React . createElement ( Roadmap , { key : 'roadmap' }),
])
]);
}
if ( mode === 'create' ) {
return React . createElement ( 'div' , {
className : "min-h-[calc(100vh-104px)] flex items-center justify-center p-4"
}, [
React . createElement ( 'div' , {
key : 'create-flow' ,
className : "w-full max-w-3xl space-y-6"
}, [
React . createElement ( 'div' , {
key : 'header' ,
className : "text-center"
}, [
React . createElement ( 'button' , {
key : 'back' ,
onClick : resetToSelect ,
className : "mb-4 text-secondary hover:text-primary transition-colors flex items-center mx-auto text-sm"
}, [
React . createElement ( 'i' , {
className : 'fas fa-arrow-left mr-2'
}),
2025-08-12 13:55:07 -04:00
'Back to selection'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'h2' , {
key : 'title' ,
className : "text-xl font-semibold text-primary mb-2"
2025-08-12 13:55:07 -04:00
}, 'Creating a secure channel' )
2025-08-11 20:52:14 -04:00
]),
// Step 1
React . createElement ( 'div' , {
key : 'step1' ,
className : "card-minimal rounded-xl p-6"
}, [
React . createElement ( 'div' , {
key : 'step-header' ,
className : "flex items-center mb-4"
}, [
React . createElement ( 'div' , {
key : 'number' ,
className : "step-number mr-3"
}, '1' ),
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-medium text-primary"
2025-08-12 13:55:07 -04:00
}, "Generating ECDH keys and verification code" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'p' , {
key : 'description' ,
className : "text-secondary text-sm mb-4"
2025-08-12 13:55:07 -04:00
}, "Creating cryptographically strong keys and codes to protect against attacks" ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'button' , {
key : 'create-btn' ,
onClick : onCreateOffer ,
disabled : connectionStatus === 'connecting' || showOfferStep ,
className : `w-full btn-primary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed`
}, [
React . createElement ( 'i' , {
className : 'fas fa-shield-alt mr-2'
}),
2025-08-12 13:55:07 -04:00
showOfferStep ? 'Keys created ✓' : 'Create secure keys'
2025-08-11 20:52:14 -04:00
]),
showOfferStep && React . createElement ( 'div' , {
key : 'offer-result' ,
className : "mt-6 space-y-4"
}, [
React . createElement ( 'div' , {
key : 'success' ,
className : "p-3 bg-green-500/10 border border-green-500/20 rounded-lg"
}, [
React . createElement ( 'p' , {
className : "text-green-400 text-sm font-medium flex items-center"
}, [
React . createElement ( 'i' , {
className : 'fas fa-check-circle mr-2'
}),
2025-08-19 21:54:17 -04:00
'Encrypted invitation created! Send the code and password to your contact:'
2025-08-11 20:52:14 -04:00
]),
offerPassword && React . createElement ( 'div' , {
key : 'password-display' ,
className : "mt-3 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg"
}, [
React . createElement ( 'p' , {
key : 'password-label' ,
className : "text-blue-400 text-sm font-medium mb-2"
2025-08-12 13:55:07 -04:00
}, '🔑 Decryption password:' ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'div' , {
key : 'password-container' ,
className : "flex items-center space-x-2"
}, [
React . createElement ( 'code' , {
key : 'password' ,
className : "flex-1 p-2 bg-gray-900/50 border border-gray-500/30 rounded font-mono text-sm text-blue-300 font-medium"
}, offerPassword ),
React . createElement ( EnhancedCopyButton , {
key : 'copy-password' ,
text : offerPassword ,
className : "px-3 py-2 bg-blue-500/20 hover:bg-blue-500/30 text-blue-400 border border-blue-500/30 rounded text-sm"
2025-08-12 13:55:07 -04:00
}, 'Copy' )
2025-08-11 20:52:14 -04:00
])
])
]),
React . createElement ( 'div' , {
key : 'offer-data' ,
className : "space-y-3"
}, [
React . createElement ( 'textarea' , {
key : 'textarea' ,
value : offerData ,
readOnly : true ,
rows : 8 ,
className : "w-full p-3 bg-custom-bg border border-gray-500/20 rounded-lg font-mono text-xs text-secondary resize-none custom-scrollbar"
}),
React . createElement ( EnhancedCopyButton , {
key : 'copy' ,
text : offerData ,
className : "w-full px-3 py-2 bg-orange-500/10 hover:bg-orange-500/20 text-orange-400 border border-orange-500/20 rounded text-sm font-medium"
2025-08-12 13:55:07 -04:00
}, 'Copy encrypted code' )
2025-08-11 20:52:14 -04:00
])
])
]),
2025-08-14 03:28:23 -04:00
// Step 2 - Session Type Selection
2025-08-19 21:54:17 -04:00
// showOfferStep && React.createElement('div', {
// key: 'step2',
// className: "card-minimal rounded-xl p-6"
// }, [
// React.createElement('div', {
// key: 'step-header',
// className: "flex items-center mb-4"
// }, [
// React.createElement('div', {
// key: 'number',
// className: "w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3"
// }, '2'),
// React.createElement('h3', {
// key: 'title',
// className: "text-lg font-medium text-primary"
// }, "Select session type")
// ]),
// React.createElement('p', {
// key: 'description',
// className: "text-secondary text-sm mb-4"
// }, "Choose a session plan or use limited demo mode for testing."),
// React.createElement(SessionTypeSelector, {
// key: 'session-selector',
// onSelectType: (sessionType) => {
// // Save the selected session type
// setSelectedSessionType(sessionType);
// console.log('🎯 Session type selected:', sessionType);
2025-08-14 23:34:54 -04:00
2025-08-19 21:54:17 -04:00
// // FIX: For demo sessions, we immediately call automatic activation
// if (sessionType === 'demo') {
// console.log('🎮 Demo session selected, scheduling automatic activation...');
// // Delay activation for 2 seconds to stabilize
// setTimeout(() => {
// if (sessionManager) {
// console.log('🚀 Triggering demo session activation from selection...');
// handleDemoVerification();
// }
// }, 2000);
// }
2025-08-14 23:34:54 -04:00
2025-08-19 21:54:17 -04:00
// // Open a modal payment window
// if (typeof window.showPaymentModal === 'function') {
// window.showPaymentModal(sessionType);
// } else {
// // Fallback - show session information
// console.log('Selected session type:', sessionType);
// }
// },
// onCancel: resetToSelect,
// sessionManager: window.sessionManager
// })
// ]),
2025-08-14 03:28:23 -04:00
// Step 3 - Waiting for response
showOfferStep && React . createElement ( 'div' , {
2025-08-19 21:54:17 -04:00
key : 'step2' ,
2025-08-14 03:28:23 -04:00
className : "card-minimal rounded-xl p-6"
}, [
React . createElement ( 'div' , {
key : 'step-header' ,
className : "flex items-center mb-4"
}, [
React . createElement ( 'div' , {
key : 'number' ,
className : "w-8 h-8 bg-blue-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3"
2025-08-19 21:54:17 -04:00
}, '2' ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-medium text-primary"
2025-08-12 13:55:07 -04:00
}, "Waiting for the peer's response" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'p' , {
key : 'description' ,
className : "text-secondary text-sm mb-4"
2025-08-12 13:55:07 -04:00
}, "Paste the encrypted invitation code from your contact." ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'textarea' , {
key : 'input' ,
value : answerInput ,
onChange : ( e ) => setAnswerInput ( e . target . value ),
rows : 6 ,
2025-08-12 13:55:07 -04:00
placeholder : "Paste the encrypted response code from your contact..." ,
2025-08-11 20:52:14 -04:00
className : "w-full p-3 bg-custom-bg border border-gray-500/20 rounded-lg resize-none mb-4 text-secondary placeholder-gray-500 focus:border-orange-500/40 focus:outline-none transition-all custom-scrollbar text-sm"
}),
React . createElement ( 'button' , {
key : 'connect-btn' ,
onClick : onConnect ,
disabled : ! answerInput . trim (),
className : "w-full btn-secondary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
}, [
React . createElement ( 'i' , {
className : 'fas fa-rocket mr-2'
}),
2025-08-12 13:55:07 -04:00
'Establish connection'
2025-08-11 20:52:14 -04:00
])
])
])
]);
}
if ( mode === 'join' ) {
return React . createElement ( 'div' , {
className : "min-h-[calc(100vh-104px)] flex items-center justify-center p-4"
}, [
React . createElement ( 'div' , {
key : 'join-flow' ,
className : "w-full max-w-3xl space-y-6"
}, [
React . createElement ( 'div' , {
key : 'header' ,
className : "text-center"
}, [
React . createElement ( 'button' , {
key : 'back' ,
onClick : resetToSelect ,
className : "mb-4 text-secondary hover:text-primary transition-colors flex items-center mx-auto text-sm"
}, [
React . createElement ( 'i' , {
className : 'fas fa-arrow-left mr-2'
}),
2025-08-12 13:55:07 -04:00
'Back to selection'
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'h2' , {
key : 'title' ,
className : "text-xl font-semibold text-primary mb-2"
2025-08-12 13:55:07 -04:00
}, 'Joining the secure channel' )
2025-08-11 20:52:14 -04:00
]),
// Step 1
React . createElement ( 'div' , {
key : 'step1' ,
className : "card-minimal rounded-xl p-6"
}, [
React . createElement ( 'div' , {
key : 'step-header' ,
className : "flex items-center mb-4"
}, [
React . createElement ( 'div' , {
key : 'number' ,
className : "w-8 h-8 bg-green-500 text-white rounded-lg flex items-center justify-center font-semibold text-sm mr-3"
}, '1' ),
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-medium text-primary"
2025-08-12 13:55:07 -04:00
}, "Paste secure invitation" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'p' , {
key : 'description' ,
className : "text-secondary text-sm mb-4"
2025-08-12 13:55:07 -04:00
}, "Copy and paste the encrypted invitation code from the initiator." ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'textarea' , {
key : 'input' ,
value : offerInput ,
onChange : ( e ) => setOfferInput ( e . target . value ),
rows : 8 ,
2025-08-12 13:55:07 -04:00
placeholder : "Paste the encrypted invitation code..." ,
2025-08-11 20:52:14 -04:00
className : "w-full p-3 bg-custom-bg border border-gray-500/20 rounded-lg resize-none mb-4 text-secondary placeholder-gray-500 focus:border-green-500/40 focus:outline-none transition-all custom-scrollbar text-sm"
}),
React . createElement ( 'button' , {
key : 'process-btn' ,
onClick : onCreateAnswer ,
disabled : ! offerInput . trim () || connectionStatus === 'connecting' ,
className : "w-full btn-secondary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
}, [
React . createElement ( 'i' , {
className : 'fas fa-cogs mr-2'
}),
2025-08-12 13:55:07 -04:00
'Process the invitation'
2025-08-11 20:52:14 -04:00
])
]),
// Step 2
showAnswerStep && React . createElement ( 'div' , {
key : 'step2' ,
className : "card-minimal rounded-xl p-6"
}, [
React . createElement ( 'div' , {
key : 'step-header' ,
className : "flex items-center mb-4"
}, [
React . createElement ( 'div' , {
key : 'number' ,
className : "step-number mr-3"
}, '2' ),
React . createElement ( 'h3' , {
key : 'title' ,
className : "text-lg font-medium text-primary"
2025-08-12 13:55:07 -04:00
}, "Sending a secure response" )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'success' ,
className : "p-3 bg-green-500/10 border border-green-500/20 rounded-lg mb-4"
}, [
React . createElement ( 'p' , {
className : "text-green-400 text-sm font-medium flex items-center"
}, [
React . createElement ( 'i' , {
className : 'fas fa-check-circle mr-2'
}),
2025-08-12 13:55:07 -04:00
'Encrypted response created! Send this code to the initiator.:'
2025-08-11 20:52:14 -04:00
]),
answerPassword && React . createElement ( 'div' , {
key : 'password-display' ,
className : "mt-3 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg"
}, [
React . createElement ( 'p' , {
key : 'password-label' ,
className : "text-blue-400 text-sm font-medium mb-2"
2025-08-12 13:55:07 -04:00
}, '🔑 Password for decryption:' ),
2025-08-11 20:52:14 -04:00
React . createElement ( 'div' , {
key : 'password-container' ,
className : "flex items-center space-x-2"
}, [
React . createElement ( 'code' , {
key : 'password' ,
className : "flex-1 p-2 bg-gray-900/50 border border-gray-500/30 rounded font-mono text-sm text-blue-300 font-medium"
}, answerPassword ),
React . createElement ( EnhancedCopyButton , {
key : 'copy-password' ,
text : answerPassword ,
className : "px-3 py-2 bg-blue-500/20 hover:bg-blue-500/30 text-blue-400 border border-blue-500/30 rounded text-sm"
2025-08-12 13:55:07 -04:00
}, 'Copy' )
2025-08-11 20:52:14 -04:00
])
])
]),
React . createElement ( 'div' , {
key : 'answer-data' ,
className : "space-y-3 mb-4"
}, [
React . createElement ( 'textarea' , {
key : 'textarea' ,
value : answerData ,
readOnly : true ,
rows : 6 ,
className : "w-full p-3 bg-custom-bg border border-green-500/20 rounded-lg font-mono text-xs text-secondary resize-none custom-scrollbar"
}),
React . createElement ( EnhancedCopyButton , {
key : 'copy' ,
text : answerData ,
className : "w-full px-3 py-2 bg-green-500/10 hover:bg-green-500/20 text-green-400 border border-green-500/20 rounded text-sm font-medium"
2025-08-12 13:55:07 -04:00
}, 'Copy the encrypted response' )
2025-08-11 20:52:14 -04:00
]),
React . createElement ( 'div' , {
key : 'info' ,
className : "p-3 bg-purple-500/10 border border-purple-500/20 rounded-lg"
}, [
React . createElement ( 'p' , {
className : "text-purple-400 text-sm flex items-center justify-center"
}, [
React . createElement ( 'i' , {
className : 'fas fa-shield-alt mr-2'
}),
2025-08-12 13:55:07 -04:00
'The connection will be established with verification'
2025-08-11 20:52:14 -04:00
])
])
])
])
]);
}
};
2025-08-20 03:53:58 -04:00
const EnhancedChatInterface = ({
messages ,
messageInput ,
setMessageInput ,
onSendMessage ,
onDisconnect ,
keyFingerprint ,
isVerified ,
chatMessagesRef ,
scrollToBottom ,
webrtcManager
}) => {
const [ showScrollButton , setShowScrollButton ] = React . useState ( false );
const [ showFileTransfer , setShowFileTransfer ] = React . useState ( false );
// Автоматическая прокрутка при изменении сообщений
React . useEffect (() => {
if ( chatMessagesRef . current && messages . length > 0 ) {
const { scrollTop , scrollHeight , clientHeight } = chatMessagesRef . current ;
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100 ;
if ( isNearBottom ) {
const smoothScroll = () => {
if ( chatMessagesRef . current ) {
chatMessagesRef . current . scrollTo ({
top : chatMessagesRef . current . scrollHeight ,
behavior : 'smooth'
});
2025-08-17 20:38:47 -04:00
}
2025-08-20 03:53:58 -04:00
};
smoothScroll ();
setTimeout ( smoothScroll , 50 );
setTimeout ( smoothScroll , 150 );
}
}
}, [ messages , chatMessagesRef ]);
// Обработчик скролла
const handleScroll = () => {
if ( chatMessagesRef . current ) {
const { scrollTop , scrollHeight , clientHeight } = chatMessagesRef . current ;
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100 ;
setShowScrollButton ( ! isNearBottom );
}
};
// Прокрутка вниз по кнопке
const handleScrollToBottom = () => {
scrollToBottom ();
setShowScrollButton ( false );
};
// Обработчик нажатия Enter
const handleKeyPress = ( e ) => {
if ( e . key === 'Enter' && ! e . shiftKey ) {
e . preventDefault ();
onSendMessage ();
}
};
2025-08-11 20:52:14 -04:00
2025-08-20 03:53:58 -04:00
// ИСПРАВЛЕНИЕ: Проверка готовности для файловых трансферов
const isFileTransferReady = () => {
if ( ! webrtcManager ) return false ;
const connected = webrtcManager . isConnected ? webrtcManager . isConnected () : false ;
const verified = webrtcManager . isVerified || false ;
const hasDataChannel = webrtcManager . dataChannel && webrtcManager . dataChannel . readyState === 'open' ;
return connected && verified && hasDataChannel ;
};
2025-08-11 20:52:14 -04:00
2025-08-20 03:53:58 -04:00
// Возврат JSX через React.createElement
return React . createElement (
'div' ,
{
className : "chat-container flex flex-col" ,
style : { backgroundColor : '#272827' , height : 'calc(100vh - 64px)' }
},
[
// Область сообщений
React . createElement (
'div' ,
{ className : "flex-1 flex flex-col overflow-hidden" },
React . createElement (
'div' ,
{ className : "flex-1 max-w-4xl mx-auto w-full p-4 overflow-hidden" },
React . createElement (
'div' ,
{
ref : chatMessagesRef ,
onScroll : handleScroll ,
className : "h-full overflow-y-auto space-y-3 hide-scrollbar pr-2 scroll-smooth"
},
messages . length === 0 ?
React . createElement (
'div' ,
{ className : "flex items-center justify-center h-full" },
React . createElement (
'div' ,
{ className : "text-center max-w-md" },
[
React . createElement (
'div' ,
{ className : "w-16 h-16 bg-green-500/10 border border-green-500/20 rounded-xl flex items-center justify-center mx-auto mb-4" },
React . createElement (
'svg' ,
{ className : "w-8 h-8 text-green-500" , fill : "none" , stroke : "currentColor" , viewBox : "0 0 24 24" },
React . createElement ( 'path' , {
strokeLinecap : "round" ,
strokeLinejoin : "round" ,
strokeWidth : 2 ,
d : "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
})
)
),
React . createElement ( 'h3' , { className : "text-lg font-medium text-gray-300 mb-2" }, "Secure channel is ready!" ),
React . createElement ( 'p' , { className : "text-gray-400 text-sm mb-4" }, "All messages are protected by modern cryptographic algorithms" ),
React . createElement (
'div' ,
{ className : "text-left space-y-2" },
[
[ 'End-to-end encryption' , 'M5 13l4 4L19 7' ],
[ 'Protection against replay attacks' , 'M5 13l4 4L19 7' ],
[ 'Integrity verification' , 'M5 13l4 4L19 7' ],
[ 'Perfect Forward Secrecy' , 'M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15' ]
]. map (([ text , d ], i ) =>
React . createElement (
'div' ,
{ key : `f ${ i } ` , className : "flex items-center text-sm text-gray-400" },
[
React . createElement (
'svg' ,
{
className : `w-4 h-4 mr-3 ${ i === 3 ? 'text-purple-500' : 'text-green-500' } ` ,
fill : "none" ,
stroke : "currentColor" ,
viewBox : "0 0 24 24"
},
React . createElement ( 'path' , {
strokeLinecap : "round" ,
strokeLinejoin : "round" ,
strokeWidth : 2 ,
d : d
})
),
text
]
)
)
)
]
)
) :
messages . map (( msg ) =>
React . createElement ( EnhancedChatMessage , {
key : msg . id ,
message : msg . message ,
type : msg . type ,
timestamp : msg . timestamp
})
)
)
)
),
// Кнопка прокрутки вниз
showScrollButton &&
React . createElement (
'button' ,
{
onClick : handleScrollToBottom ,
className : "fixed right-6 w-12 h-12 bg-green-500/20 hover:bg-green-500/30 border border-green-500/30 text-green-400 rounded-full flex items-center justify-center transition-all duration-200 shadow-lg z-50" ,
style : { bottom : '160px' }
},
React . createElement (
'svg' ,
{ className : "w-6 h-6" , fill : "none" , stroke : "currentColor" , viewBox : "0 0 24 24" },
React . createElement ( 'path' , {
strokeLinecap : "round" ,
strokeLinejoin : "round" ,
strokeWidth : 2 ,
d : "M19 14l-7 7m0 0l-7-7m7 7V3"
})
)
),
// Секция передачи файлов
React . createElement (
'div' ,
{
className : "flex-shrink-0 border-t border-gray-500/10" ,
style : { backgroundColor : '#272827' }
},
React . createElement (
'div' ,
{ className : "max-w-4xl mx-auto px-4" },
[
React . createElement (
'button' ,
{
onClick : () => setShowFileTransfer ( ! showFileTransfer ),
className : `flex items-center text-sm text-gray-400 hover:text-gray-300 transition-colors py-4 ${ showFileTransfer ? 'mb-4' : '' } `
},
[
React . createElement (
'svg' ,
{
className : `w-4 h-4 mr-2 transform transition-transform ${ showFileTransfer ? 'rotate-180' : '' } ` ,
fill : "none" ,
stroke : "currentColor" ,
viewBox : "0 0 24 24"
},
showFileTransfer ?
React . createElement ( 'path' , {
strokeLinecap : "round" ,
strokeLinejoin : "round" ,
strokeWidth : 2 ,
d : "M5 15l7-7 7 7"
}) :
React . createElement ( 'path' , {
strokeLinecap : "round" ,
strokeLinejoin : "round" ,
strokeWidth : 2 ,
d : "M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"
})
),
showFileTransfer ? 'Hide file transfer' : 'Send files'
]
),
// ИСПРАВЛЕНИЕ: Используем правильный компонент
showFileTransfer &&
React . createElement ( window . FileTransferComponent || (() =>
2025-08-11 20:52:14 -04:00
React . createElement ( 'div' , {
2025-08-20 03:53:58 -04:00
className : "p-4 text-center text-red-400"
}, 'FileTransferComponent not loaded' )
), {
webrtcManager : webrtcManager ,
isConnected : isFileTransferReady ()
2025-08-11 20:52:14 -04:00
})
2025-08-20 03:53:58 -04:00
]
)
),
// Область ввода сообщений
React . createElement (
'div' ,
{ className : "border-t border-gray-500/10" },
React . createElement (
'div' ,
{ className : "max-w-4xl mx-auto p-4" },
React . createElement (
'div' ,
{ className : "flex items-stretch space-x-3" },
[
React . createElement (
'div' ,
{ className : "flex-1 relative" },
[
React . createElement ( 'textarea' , {
value : messageInput ,
onChange : ( e ) => setMessageInput ( e . target . value ),
onKeyDown : handleKeyPress ,
placeholder : "Enter message to encrypt..." ,
rows : 2 ,
maxLength : 2000 ,
style : { backgroundColor : '#272827' },
className : "w-full p-3 border border-gray-600 rounded-lg resize-none text-gray-300 placeholder-gray-500 focus:border-green-500/40 focus:outline-none transition-all custom-scrollbar text-sm"
}),
React . createElement (
'div' ,
{ className : "absolute bottom-2 right-3 flex items-center space-x-2 text-xs text-gray-400" },
[
React . createElement ( 'span' , null , ` ${ messageInput . length } /2000` ),
React . createElement ( 'span' , null , "• Enter to send" )
]
)
]
),
React . createElement (
'button' ,
{
onClick : onSendMessage ,
disabled : ! messageInput . trim (),
className : "bg-green-400/20 text-green-400 p-3 rounded-lg transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center min-h-[72px]"
},
React . createElement (
'svg' ,
{ className : "w-6 h-6" , fill : "none" , stroke : "currentColor" , viewBox : "0 0 24 24" },
React . createElement ( 'path' , {
strokeLinecap : "round" ,
strokeLinejoin : "round" ,
strokeWidth : 2 ,
d : "M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
})
)
)
]
2025-08-11 20:52:14 -04:00
)
2025-08-20 03:53:58 -04:00
)
)
]
);
};
2025-08-11 20:52:14 -04:00
// Main Enhanced Application Component
const EnhancedSecureP2PChat = () => {
const [ messages , setMessages ] = React . useState ([]);
const [ connectionStatus , setConnectionStatus ] = React . useState ( 'disconnected' );
2025-08-17 20:38:47 -04:00
React . useEffect (() => {
if ( messages . length > 0 && chatMessagesRef . current ) {
const scrollToBottom = () => {
if ( chatMessagesRef . current ) {
chatMessagesRef . current . scrollTo ({
top : chatMessagesRef . current . scrollHeight ,
behavior : 'smooth'
});
}
};
scrollToBottom ();
setTimeout ( scrollToBottom , 50 );
setTimeout ( scrollToBottom , 150 );
}
}, [ messages ]);
2025-08-11 20:52:14 -04:00
const [ messageInput , setMessageInput ] = React . useState ( '' );
const [ offerData , setOfferData ] = React . useState ( '' );
const [ answerData , setAnswerData ] = React . useState ( '' );
const [ offerInput , setOfferInput ] = React . useState ( '' );
const [ answerInput , setAnswerInput ] = React . useState ( '' );
const [ keyFingerprint , setKeyFingerprint ] = React . useState ( '' );
const [ verificationCode , setVerificationCode ] = React . useState ( '' );
const [ showOfferStep , setShowOfferStep ] = React . useState ( false );
const [ showAnswerStep , setShowAnswerStep ] = React . useState ( false );
const [ showVerification , setShowVerification ] = React . useState ( false );
const [ isVerified , setIsVerified ] = React . useState ( false );
const [ securityLevel , setSecurityLevel ] = React . useState ( null );
// Password modal state
const [ showPasswordModal , setShowPasswordModal ] = React . useState ( false );
const [ passwordInput , setPasswordInput ] = React . useState ( '' );
const [ passwordAction , setPasswordAction ] = React . useState ( null ); // 'offer' or 'answer'
const [ passwordCallback , setPasswordCallback ] = React . useState ( null );
// Store generated passwords
const [ offerPassword , setOfferPassword ] = React . useState ( '' );
const [ answerPassword , setAnswerPassword ] = React . useState ( '' );
// Pay-per-session state
2025-08-14 23:34:54 -04:00
const [ sessionManager , setSessionManager ] = React . useState ( null );
2025-08-11 20:52:14 -04:00
const [ showPaymentModal , setShowPaymentModal ] = React . useState ( false );
const [ sessionTimeLeft , setSessionTimeLeft ] = React . useState ( 0 );
const [ pendingSession , setPendingSession ] = React . useState ( null ); // { type, preimage }
2025-08-14 23:34:54 -04:00
const [ selectedSessionType , setSelectedSessionType ] = React . useState ( null ); // 'demo', 'basic', 'premium'
// Initialize sessionManager after loading modules
React . useEffect (() => {
if ( window . PayPerSessionManager && ! sessionManager ) {
console . log ( '💰 Initializing PayPerSessionManager...' );
const newSessionManager = new window . PayPerSessionManager ();
setSessionManager ( newSessionManager );
window . sessionManager = newSessionManager ;
console . log ( '✅ PayPerSessionManager initialized successfully' );
}
}, [ sessionManager ]);
2025-08-14 03:28:23 -04:00
2025-08-14 23:34:54 -04:00
// Global functions for accessing modal windows
2025-08-14 03:28:23 -04:00
React . useEffect (() => {
2025-08-14 23:34:54 -04:00
if ( ! sessionManager ) return ;
2025-08-14 03:28:23 -04:00
window . showPaymentModal = ( sessionType ) => {
setShowPaymentModal ( true );
2025-08-14 23:34:54 -04:00
// Pass the selected session type to the modal window
2025-08-14 03:28:23 -04:00
if ( sessionType ) {
console . log ( 'Opening payment modal for session type:' , sessionType );
}
};
window . sessionManager = sessionManager ;
2025-08-17 20:38:47 -04:00
window . forceCleanup = () => {
handleClearData ();
if ( webrtcManagerRef . current ) {
webrtcManagerRef . current . disconnect ();
}
if ( sessionManager ) {
sessionManager . cleanup ();
}
};
window . forceSessionReset = () => {
if ( sessionManager ) {
sessionManager . resetSession ();
}
setSessionTimeLeft ( 0 );
};
window . forceSessionCleanup = () => {
if ( sessionManager ) {
sessionManager . cleanup ();
}
setSessionTimeLeft ( 0 );
setSessionManager ( null );
};
window . clearLogs = () => {
if ( typeof console . clear === 'function' ) {
console . clear ();
}
};
2025-08-14 03:28:23 -04:00
return () => {
delete window . showPaymentModal ;
delete window . sessionManager ;
2025-08-17 20:38:47 -04:00
delete window . forceCleanup ;
delete window . forceSessionReset ;
delete window . forceSessionCleanup ;
delete window . clearLogs ;
2025-08-14 03:28:23 -04:00
};
}, [ sessionManager ]);
2025-08-11 20:52:14 -04:00
const webrtcManagerRef = React . useRef ( null );
2025-08-18 21:45:50 -04:00
// Expose for modules/UI that run outside this closure (e.g., inline handlers)
// Safe because it's a ref object and we maintain it centrally here
window . webrtcManagerRef = webrtcManagerRef ;
2025-08-11 20:52:14 -04:00
2025-08-20 03:53:58 -04:00
const addMessageWithAutoScroll = React . useCallback (( message , type ) => {
2025-08-17 20:38:47 -04:00
const newMessage = {
message ,
type ,
id : Date . now () + Math . random (),
timestamp : Date . now ()
};
2025-08-20 03:53:58 -04:00
setMessages ( prev => {
const updated = [... prev , newMessage ];
setTimeout (() => {
if ( chatMessagesRef ? . current ) {
const container = chatMessagesRef . current ;
try {
const { scrollTop , scrollHeight , clientHeight } = container ;
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100 ;
if ( isNearBottom || prev . length === 0 ) {
requestAnimationFrame (() => {
if ( container && container . scrollTo ) {
container . scrollTo ({
top : container . scrollHeight ,
behavior : 'smooth'
});
}
});
}
} catch ( error ) {
console . warn ( 'Scroll error:' , error );
container . scrollTop = container . scrollHeight ;
}
}
}, 50 );
return updated ;
});
}, []);
2025-08-17 20:38:47 -04:00
2025-08-11 20:52:14 -04:00
// Update security level based on real verification
const updateSecurityLevel = React . useCallback ( async () => {
2025-08-17 20:38:47 -04:00
if ( window . isUpdatingSecurity ) {
return ;
}
window . isUpdatingSecurity = true ;
try {
if ( webrtcManagerRef . current ) {
2025-08-11 20:52:14 -04:00
const level = await webrtcManagerRef . current . calculateSecurityLevel ();
setSecurityLevel ( level );
2025-08-17 20:38:47 -04:00
if ( window . DEBUG_MODE ) {
console . log ( '🔒 Security level updated:' , {
level : level . level ,
score : level . score ,
sessionType : level . sessionType ,
passedChecks : level . passedChecks ,
totalChecks : level . totalChecks
});
}
2025-08-11 20:52:14 -04:00
}
2025-08-17 20:38:47 -04:00
} catch ( error ) {
console . error ( 'Failed to update security level:' , error );
setSecurityLevel ({
level : 'ERROR' ,
score : 0 ,
color : 'red' ,
details : 'Verification failed'
});
} finally {
setTimeout (() => {
window . isUpdatingSecurity = false ;
}, 2000 );
2025-08-11 20:52:14 -04:00
}
}, []);
// Session time ticker
React . useEffect (() => {
2025-08-14 23:34:54 -04:00
if ( ! sessionManager ) return ;
2025-08-11 20:52:14 -04:00
const timer = setInterval (() => {
if ( sessionManager . hasActiveSession ()) {
setSessionTimeLeft ( sessionManager . getTimeLeft ());
} else {
setSessionTimeLeft ( 0 );
}
}, 1000 );
return () => clearInterval ( timer );
}, [ sessionManager ]);
// Session expiration handler
React . useEffect (() => {
2025-08-14 23:34:54 -04:00
if ( ! sessionManager ) return ;
2025-08-11 20:52:14 -04:00
sessionManager . onSessionExpired = () => {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '⏰ Session time expired. The connection will be terminated.' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
setTimeout (() => handleDisconnect (), 3000 );
};
}, [ sessionManager ]);
2025-08-14 23:34:54 -04:00
// Automatic activation of demo session after successful verification
React . useEffect (() => {
if ( ! sessionManager ) return ;
// Listen to demo session verification events
const handleDemoVerification = async () => {
try {
// Check if there is an active demo session
if ( sessionManager . hasActiveSession ()) {
console . log ( '✅ Demo session already active' );
return ;
}
// Diagnose sessionManager state
console . log ( '🔍 SessionManager state before activation:' , {
hasActiveSession : sessionManager . hasActiveSession (),
timeLeft : sessionManager . getTimeLeft (),
currentSession : sessionManager . currentSession
});
window . pendingDemoActivation = true ;
setTimeout ( async () => {
if ( window . pendingDemoActivation && sessionManager ) {
let result = null ;
const demoSession = sessionManager . createDemoSessionForActivation ();
if ( ! demoSession . success ) {
return ;
}
result = await sessionManager . safeActivateSession (
'demo' ,
demoSession . preimage ,
demoSession . paymentHash
);
if ( result && result . success ) {
setSessionTimeLeft ( sessionManager . getTimeLeft ());
setMessages ( prev => [... prev , {
message : `🎮 Demo session activated for ${ Math . round ( result . timeLeft / 60000 ) } minutes` ,
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
window . pendingDemoActivation = false ;
} else {
window . pendingDemoActivation = false ;
}
}
}, 3000 );
} catch ( error ) {
console . error ( '❌ Error activating demo session automatically:' , error );
}
};
if ( connectionStatus === 'connected' && isVerified ) {
setTimeout ( handleDemoVerification , 1000 );
}
if ( selectedSessionType === 'demo' && connectionStatus === 'connected' && isVerified ) {
setTimeout ( handleDemoVerification , 1000 );
}
}, [ sessionManager , connectionStatus , isVerified , selectedSessionType ]);
2025-08-11 20:52:14 -04:00
const chatMessagesRef = React . useRef ( null );
2025-08-12 13:55:07 -04:00
// Scroll down function
2025-08-11 20:52:14 -04:00
const scrollToBottom = () => {
if ( chatMessagesRef . current ) {
2025-08-17 20:38:47 -04:00
const scrollAttempt = () => {
if ( chatMessagesRef . current ) {
chatMessagesRef . current . scrollTo ({
top : chatMessagesRef . current . scrollHeight ,
behavior : 'smooth'
});
}
};
scrollAttempt ();
setTimeout ( scrollAttempt , 50 );
setTimeout ( scrollAttempt , 150 );
setTimeout ( scrollAttempt , 300 );
requestAnimationFrame (() => {
setTimeout ( scrollAttempt , 100 );
});
2025-08-11 20:52:14 -04:00
}
};
// Password modal functions
const showPasswordPrompt = ( action , callback ) => {
setPasswordAction ( action );
setPasswordCallback (() => callback );
setShowPasswordModal ( true );
setPasswordInput ( '' );
};
const handlePasswordSubmit = ( password ) => {
setShowPasswordModal ( false );
if ( passwordCallback ) {
passwordCallback ( password );
}
};
const handlePasswordCancel = () => {
setShowPasswordModal ( false );
setPasswordInput ( '' );
setPasswordCallback ( null );
};
React . useEffect (() => {
2025-08-14 03:28:23 -04:00
// Prevent multiple initializations
if ( webrtcManagerRef . current ) {
console . log ( '⚠️ WebRTC Manager already initialized, skipping...' );
return ;
}
2025-08-11 20:52:14 -04:00
const handleMessage = ( message , type ) => {
2025-08-20 18:19:42 -04:00
// Дополнительная проверка на файловые и системные сообщения
if ( typeof message === 'string' && message . trim (). startsWith ( '{' )) {
try {
const parsedMessage = JSON . parse ( message );
const blockedTypes = [
'file_transfer_start' ,
'file_transfer_response' ,
'file_chunk' ,
'chunk_confirmation' ,
'file_transfer_complete' ,
'file_transfer_error' ,
'heartbeat' ,
'verification' ,
'verification_response' ,
'peer_disconnect' ,
'key_rotation_signal' ,
'key_rotation_ready' ,
'security_upgrade'
];
if ( parsedMessage . type && blockedTypes . includes ( parsedMessage . type )) {
console . log ( `🛑 Blocked system/file message from chat: ${ parsedMessage . type } ` );
return ; // Не показываем системные и файловые сообщения в чате
}
} catch ( parseError ) {
// Не JSON - это нормально для обычных текстовых сообщений
}
}
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( message , type );
2025-08-11 20:52:14 -04:00
};
const handleStatusChange = ( status ) => {
setConnectionStatus ( status );
if ( status === 'connected' ) {
2025-08-14 23:34:54 -04:00
document . dispatchEvent ( new CustomEvent ( 'new-connection' ));
2025-08-11 20:52:14 -04:00
setIsVerified ( true );
setShowVerification ( false );
2025-08-17 20:38:47 -04:00
if ( ! window . isUpdatingSecurity ) {
updateSecurityLevel (). catch ( console . error );
}
2025-08-11 20:52:14 -04:00
} else if ( status === 'verifying' ) {
setShowVerification ( true );
2025-08-17 20:38:47 -04:00
if ( ! window . isUpdatingSecurity ) {
updateSecurityLevel (). catch ( console . error );
}
2025-08-11 20:52:14 -04:00
} else if ( status === 'connecting' ) {
2025-08-17 20:38:47 -04:00
if ( ! window . isUpdatingSecurity ) {
updateSecurityLevel (). catch ( console . error );
}
2025-08-11 20:52:14 -04:00
} else if ( status === 'disconnected' ) {
2025-08-18 21:45:50 -04:00
// При ошибках соединения не сбрасываем сессию полностью
// только обновляем статус соединения
setConnectionStatus ( 'disconnected' );
2025-08-11 20:52:14 -04:00
setIsVerified ( false );
setShowVerification ( false );
2025-08-14 23:34:54 -04:00
2025-08-18 21:45:50 -04:00
// Не очищаем консоль и не сбрасываем сообщения
// чтобы пользователь мог видеть ошибки
// Не сбрасываем сессию при ошибках соединения
// только при намеренном отключении
2025-08-17 20:38:47 -04:00
} else if ( status === 'peer_disconnected' ) {
2025-08-14 23:34:54 -04:00
if ( sessionManager && sessionManager . hasActiveSession ()) {
sessionManager . resetSession ();
setSessionTimeLeft ( 0 );
setHasActiveSession ( false );
}
2025-08-17 20:38:47 -04:00
document . dispatchEvent ( new CustomEvent ( 'peer-disconnect' ));
2025-08-14 23:34:54 -04:00
2025-08-12 13:55:07 -04:00
// A short delay before clearing to display the status
2025-08-11 20:52:14 -04:00
setTimeout (() => {
setKeyFingerprint ( '' );
setVerificationCode ( '' );
setSecurityLevel ( null );
setIsVerified ( false );
setShowVerification ( false );
2025-08-17 20:38:47 -04:00
setConnectionStatus ( 'disconnected' );
2025-08-18 21:45:50 -04:00
// Не очищаем сообщения и консоль при отключении пира
// чтобы сохранить историю соединения
// setMessages([]);
// if (typeof console.clear === 'function') {
// console.clear();
// }
2025-08-17 20:38:47 -04:00
setSessionManager ( null );
2025-08-11 20:52:14 -04:00
}, 2000 );
}
};
const handleKeyExchange = ( fingerprint ) => {
if ( fingerprint === '' ) {
setKeyFingerprint ( '' );
} else {
setKeyFingerprint ( fingerprint );
}
};
const handleVerificationRequired = ( code ) => {
if ( code === '' ) {
setVerificationCode ( '' );
} else {
setVerificationCode ( code );
}
};
2025-08-12 13:55:07 -04:00
// Callback for handling response errors
2025-08-11 20:52:14 -04:00
const handleAnswerError = ( errorType , errorMessage ) => {
if ( errorType === 'replay_attack' ) {
2025-08-12 13:55:07 -04:00
// Reset the session upon replay attack
2025-08-11 20:52:14 -04:00
if ( sessionManager . hasActiveSession ()) {
sessionManager . resetSession ();
setSessionTimeLeft ( 0 );
}
setPendingSession ( null );
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( '💡 Data is outdated. Please create a new invitation or use a current response code.' , 'system' );
if ( typeof console . clear === 'function' ) {
console . clear ();
}
2025-08-11 20:52:14 -04:00
} else if ( errorType === 'security_violation' ) {
2025-08-12 13:55:07 -04:00
// Reset the session upon security breach
2025-08-11 20:52:14 -04:00
if ( sessionManager . hasActiveSession ()) {
sessionManager . resetSession ();
setSessionTimeLeft ( 0 );
}
setPendingSession ( null );
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( `🔒 Security breach: ${ errorMessage } ` , 'system' );
if ( typeof console . clear === 'function' ) {
console . clear ();
}
2025-08-11 20:52:14 -04:00
}
};
2025-08-14 03:28:23 -04:00
// Create WebRTC Manager only once
console . log ( '🔧 Initializing WebRTC Manager...' );
2025-08-17 20:38:47 -04:00
if ( typeof console . clear === 'function' ) {
console . clear ();
}
2025-08-11 20:52:14 -04:00
webrtcManagerRef . current = new EnhancedSecureWebRTCManager (
handleMessage ,
handleStatusChange ,
handleKeyExchange ,
handleVerificationRequired ,
handleAnswerError
);
2025-08-14 15:54:11 -04:00
handleMessage ( '🚀 SecureBit.chat Enhanced Edition initialized. Ready to establish a secure connection with ECDH, encrypted exchange, and verification.' , 'system' );
2025-08-11 20:52:14 -04:00
2025-08-14 23:34:54 -04:00
const handleBeforeUnload = ( event ) => {
if ( event . type === 'beforeunload' && ! isTabSwitching ) {
console . log ( '🔌 Page unloading (closing tab) - sending disconnect notification' );
if ( webrtcManagerRef . current && webrtcManagerRef . current . isConnected ()) {
try {
webrtcManagerRef . current . sendSystemMessage ({
type : 'peer_disconnect' ,
reason : 'user_disconnect' ,
timestamp : Date . now ()
});
} catch ( error ) {
console . log ( 'Could not send disconnect notification:' , error . message );
}
setTimeout (() => {
2025-08-11 20:52:14 -04:00
if ( webrtcManagerRef . current ) {
webrtcManagerRef . current . disconnect ();
2025-08-14 23:34:54 -04:00
}
}, 100 );
} else if ( webrtcManagerRef . current ) {
webrtcManagerRef . current . disconnect ();
}
} else if ( isTabSwitching ) {
console . log ( '📱 Tab switching detected - NOT disconnecting' );
event . preventDefault ();
event . returnValue = '' ;
2025-08-11 20:52:14 -04:00
}
};
window . addEventListener ( 'beforeunload' , handleBeforeUnload );
2025-08-14 23:34:54 -04:00
let isTabSwitching = false ;
let tabSwitchTimeout = null ;
const handleVisibilityChange = () => {
if ( document . visibilityState === 'hidden' ) {
console . log ( '📱 Page hidden (tab switch) - keeping connection alive' );
isTabSwitching = true ;
if ( tabSwitchTimeout ) {
clearTimeout ( tabSwitchTimeout );
}
tabSwitchTimeout = setTimeout (() => {
isTabSwitching = false ;
}, 5000 );
} else if ( document . visibilityState === 'visible' ) {
console . log ( '📱 Page visible (tab restored) - connection maintained' );
isTabSwitching = false ;
if ( tabSwitchTimeout ) {
clearTimeout ( tabSwitchTimeout );
tabSwitchTimeout = null ;
}
}
};
document . addEventListener ( 'visibilitychange' , handleVisibilityChange );
2025-08-18 21:45:50 -04:00
// Setup file transfer callbacks
if ( webrtcManagerRef . current ) {
webrtcManagerRef . current . setFileTransferCallbacks (
// Progress callback
( progress ) => {
console . log ( 'File progress:' , progress );
},
2025-08-14 23:34:54 -04:00
2025-08-18 21:45:50 -04:00
// File received callback
( fileData ) => {
2025-08-21 04:07:16 -04:00
const sizeMb = Math . max ( 1 , Math . round (( fileData . fileSize || 0 ) / ( 1024 * 1024 )));
const downloadMessage = React . createElement ( 'div' , {
className : 'flex items-center space-x-2'
}, [
2025-08-21 17:40:17 -04:00
React . createElement ( 'span' , { key : 'label' }, `📥 File received: ${ fileData . fileName } ( ${ sizeMb } MB)` ),
2025-08-21 04:07:16 -04:00
React . createElement ( 'button' , {
key : 'btn' ,
className : 'px-3 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white text-xs' ,
onClick : async () => {
try {
const url = await fileData . getObjectURL ();
2025-08-18 21:45:50 -04:00
const a = document . createElement ( 'a' );
a . href = url ;
a . download = fileData . fileName ;
a . click ();
2025-08-21 04:07:16 -04:00
// Даем браузеру время начать загрузку, затем освобождаем URL
setTimeout (() => fileData . revokeObjectURL ( url ), 15000 );
} catch ( e ) {
console . error ( 'Download failed:' , e );
2025-08-21 17:40:17 -04:00
addMessageWithAutoScroll ( `❌ File upload error: ${ String ( e ? . message || e ) } ` , 'system' );
2025-08-21 04:07:16 -04:00
}
}
2025-08-21 17:45:43 -04:00
}, 'Download' )
2025-08-21 04:07:16 -04:00
]);
2025-08-18 21:45:50 -04:00
2025-08-21 04:07:16 -04:00
addMessageWithAutoScroll ( downloadMessage , 'system' );
2025-08-18 21:45:50 -04:00
},
2025-08-14 23:34:54 -04:00
2025-08-18 21:45:50 -04:00
// Error callback
( error ) => {
console . error ( 'File transfer error:' , error );
if ( error . includes ( 'Connection not ready' )) {
2025-08-21 17:40:17 -04:00
addMessageWithAutoScroll ( `⚠️ File transfer error: connection not ready. Try again later.` , 'system' );
2025-08-18 21:45:50 -04:00
} else if ( error . includes ( 'File too large' )) {
2025-08-21 17:40:17 -04:00
addMessageWithAutoScroll ( `⚠️ File is too big. Maximum size: 100 MB` , 'system' );
2025-08-18 21:45:50 -04:00
} else {
2025-08-21 17:40:17 -04:00
addMessageWithAutoScroll ( `❌ File transfer error: ${ error } ` , 'system' );
2025-08-18 21:45:50 -04:00
}
2025-08-11 20:52:14 -04:00
}
2025-08-18 21:45:50 -04:00
);
}
return () => {
window . removeEventListener ( 'beforeunload' , handleBeforeUnload );
document . removeEventListener ( 'visibilitychange' , handleVisibilityChange );
if ( tabSwitchTimeout ) {
clearTimeout ( tabSwitchTimeout );
tabSwitchTimeout = null ;
}
if ( webrtcManagerRef . current ) {
console . log ( '🧹 Cleaning up WebRTC Manager...' );
webrtcManagerRef . current . disconnect ();
webrtcManagerRef . current = null ;
}
};
2025-08-14 03:28:23 -04:00
}, []); // Empty dependency array to run only once
2025-08-11 20:52:14 -04:00
const ensureActiveSessionOrPurchase = async () => {
if ( sessionManager . hasActiveSession ()) return true ;
2025-08-12 13:55:07 -04:00
if ( pendingSession ) return true ;
2025-08-11 20:52:14 -04:00
setShowPaymentModal ( true );
return false ;
};
const handleCreateOffer = async () => {
try {
const ok = await ensureActiveSessionOrPurchase ();
if ( ! ok ) return ;
setOfferData ( '' );
setShowOfferStep ( false );
const offer = await webrtcManagerRef . current . createSecureOffer ();
// Generate secure password for encryption
const password = EnhancedSecureCryptoUtils . generateSecurePassword ();
// Encrypt the offer data
const encryptedOffer = await EnhancedSecureCryptoUtils . encryptData ( offer , password );
setOfferData ( encryptedOffer );
setOfferPassword ( password );
setShowOfferStep ( true );
2025-08-17 20:38:47 -04:00
const existingMessages = messages . filter ( m =>
m . type === 'system' &&
( m . message . includes ( 'Secure invitation created' ) || m . message . includes ( 'Send the encrypted code' ))
);
2025-08-11 20:52:14 -04:00
2025-08-17 20:38:47 -04:00
if ( existingMessages . length === 0 ) {
setMessages ( prev => [... prev , {
message : '🔐 Secure invitation created and encrypted!' ,
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
setMessages ( prev => [... prev , {
message : '📤 Send the encrypted code and password to your interlocutor via a secure channel (voice call, SMS, etc.)..' ,
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
}
if ( ! window . isUpdatingSecurity ) {
updateSecurityLevel (). catch ( console . error );
}
} catch ( error ) {
setMessages ( prev => [... prev , {
message : `❌ Error creating invitation: ${ error . message } ` ,
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
}
2025-08-11 20:52:14 -04:00
};
const handleCreateAnswer = async () => {
try {
if ( ! offerInput . trim ()) {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '⚠️ You need to insert the encrypted invitation code from your interlocutor.' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
return ;
}
// Show password modal for offer decryption
showPasswordPrompt ( 'offer' , async ( password ) => {
if ( ! password ) {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '❌ Password not entered' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
return ;
}
try {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '🔄 Decrypting and processing the secure invitation...' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
setAnswerData ( '' );
setShowAnswerStep ( false );
let offer ;
try {
// Decrypt the offer data
offer = await EnhancedSecureCryptoUtils . decryptData ( offerInput . trim (), password );
} catch ( decryptError ) {
2025-08-12 13:55:07 -04:00
throw new Error ( `Decryption error: ${ decryptError . message } ` );
2025-08-11 20:52:14 -04:00
}
if ( ! offer || typeof offer !== 'object' ) {
2025-08-12 13:55:07 -04:00
throw new Error ( 'The invitation must be an object' );
2025-08-11 20:52:14 -04:00
}
if ( ! offer . type || offer . type !== 'enhanced_secure_offer' ) {
2025-08-12 13:55:07 -04:00
throw new Error ( 'Invalid invitation type. Expected enhanced_secure_offer' );
2025-08-11 20:52:14 -04:00
}
console . log ( 'Creating secure answer for offer:' , offer );
const answer = await webrtcManagerRef . current . createSecureAnswer ( offer );
console . log ( 'Secure answer created:' , answer );
// Generate new password for answer encryption
const answerPassword = EnhancedSecureCryptoUtils . generateSecurePassword ();
// Encrypt the answer data
const encryptedAnswer = await EnhancedSecureCryptoUtils . encryptData ( answer , answerPassword );
setAnswerData ( encryptedAnswer );
setAnswerPassword ( answerPassword ); // Store the password
setShowAnswerStep ( true );
2025-08-17 20:38:47 -04:00
const existingResponseMessages = messages . filter ( m =>
m . type === 'system' &&
( m . message . includes ( 'Secure response created' ) || m . message . includes ( 'Send the encrypted response' ))
);
if ( existingResponseMessages . length === 0 ) {
2025-08-11 20:52:14 -04:00
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '✅ Secure response created and encrypted!' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '📤 Send the encrypted response code and password to the initiator via a secure channel..' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
2025-08-17 20:38:47 -04:00
}
2025-08-11 20:52:14 -04:00
// Update security level after creating answer
2025-08-17 20:38:47 -04:00
if ( ! window . isUpdatingSecurity ) {
updateSecurityLevel (). catch ( console . error );
}
2025-08-11 20:52:14 -04:00
} catch ( error ) {
console . error ( 'Error in handleCreateAnswer:' , error );
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : `❌ Error processing the invitation: ${ error . message } ` ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
}
});
return ; // Exit early, callback will handle the rest
} catch ( error ) {
console . error ( 'Error in handleCreateAnswer:' , error );
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : `❌ Invitation processing error: ${ error . message } ` ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
}
};
const handleConnect = async () => {
try {
if ( ! answerInput . trim ()) {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '⚠️ You need to insert the encrypted response code from your interlocutor.' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
return ;
}
// Show password modal for answer decryption
showPasswordPrompt ( 'answer' , async ( password ) => {
if ( ! password ) {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '❌ Password not entered' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
return ;
}
try {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '🔄 Decrypting and processing the secure response...' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
let answer ;
try {
// Decrypt the answer data
answer = await EnhancedSecureCryptoUtils . decryptData ( answerInput . trim (), password );
} catch ( decryptError ) {
2025-08-12 13:55:07 -04:00
throw new Error ( `Decryption error: ${ decryptError . message } ` );
2025-08-11 20:52:14 -04:00
}
if ( ! answer || typeof answer !== 'object' ) {
2025-08-12 13:55:07 -04:00
throw new Error ( 'The response must be an object' );
2025-08-11 20:52:14 -04:00
}
if ( ! answer . type || answer . type !== 'enhanced_secure_answer' ) {
2025-08-12 13:55:07 -04:00
throw new Error ( 'Invalid response type. Expected enhanced\_secure\_answer' );
2025-08-11 20:52:14 -04:00
}
await webrtcManagerRef . current . handleSecureAnswer ( answer );
if ( sessionManager . canActivateSession () && pendingSession ) {
const result = sessionManager . safeActivateSession ( pendingSession . type , pendingSession . preimage , pendingSession . paymentHash );
if ( result . success ) {
setPendingSession ( null );
2025-08-12 13:55:07 -04:00
setSessionTimeLeft ( sessionManager . getTimeLeft ());
2025-08-11 20:52:14 -04:00
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : `💰 Session activated on ${ sessionManager . sessionPrices [ pendingSession . type ]. hours } ч ( ${ result . method } )` ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
} else {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : `❌ Session activation error: ${ result . reason } ` ,
2025-08-11 20:52:14 -04:00
type : 'error' ,
id : Date . now (),
timestamp : Date . now ()
}]);
}
}
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '🔄 Finalizing the secure connection...' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
// Update security level after handling answer
2025-08-17 20:38:47 -04:00
if ( ! window . isUpdatingSecurity ) {
updateSecurityLevel (). catch ( console . error );
}
2025-08-11 20:52:14 -04:00
} catch ( error ) {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : `❌ Connection setup error: ${ error . message } ` ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
2025-08-12 13:55:07 -04:00
if ( ! error . message . includes ( 'Too old' ) && ! error . message . includes ( 'too old' )) {
2025-08-11 20:52:14 -04:00
setPendingSession ( null );
}
}
});
2025-08-12 13:55:07 -04:00
return ;
2025-08-11 20:52:14 -04:00
} catch ( error ) {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : `❌ Connection setup error: ${ error . message } ` ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
2025-08-12 13:55:07 -04:00
if ( ! error . message . includes ( 'с Too old' ) && ! error . message . includes ( 'too old' )) {
2025-08-11 20:52:14 -04:00
setPendingSession ( null );
}
}
};
const handleVerifyConnection = ( isValid ) => {
if ( isValid ) {
webrtcManagerRef . current . confirmVerification ();
} else {
setMessages ( prev => [... prev , {
2025-08-12 13:55:07 -04:00
message : '❌ Verification rejected. The connection is unsafe! Session reset..' ,
2025-08-11 20:52:14 -04:00
type : 'system' ,
id : Date . now (),
timestamp : Date . now ()
}]);
sessionManager . resetSession ();
setSessionTimeLeft ( 0 );
setPendingSession ( null );
handleDisconnect ();
}
};
const handleSendMessage = async () => {
2025-08-14 23:34:54 -04:00
if ( ! messageInput . trim ()) {
return ;
}
if ( ! webrtcManagerRef . current ) {
return ;
}
if ( ! webrtcManagerRef . current . isConnected ()) {
2025-08-11 20:52:14 -04:00
return ;
}
try {
2025-08-14 23:34:54 -04:00
// Add the message to local messages immediately (sent message)
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( messageInput . trim (), 'sent' );
2025-08-14 23:34:54 -04:00
// Use sendMessage for simple text messages instead of sendSecureMessage
await webrtcManagerRef . current . sendMessage ( messageInput );
2025-08-11 20:52:14 -04:00
setMessageInput ( '' );
} catch ( error ) {
2025-08-21 04:07:16 -04:00
const msg = String ( error ? . message || error );
if ( ! /queued for sending|Data channel not ready/i . test ( msg )) {
addMessageWithAutoScroll ( `❌ Sending error: ${ msg } ` , 'system' );
}
2025-08-11 20:52:14 -04:00
}
};
const handleClearData = () => {
2025-08-17 20:38:47 -04:00
// Очищаем все состояния соединения
2025-08-11 20:52:14 -04:00
setOfferData ( '' );
setAnswerData ( '' );
setOfferInput ( '' );
setAnswerInput ( '' );
setShowOfferStep ( false );
setShowAnswerStep ( false );
setShowVerification ( false );
setVerificationCode ( '' );
setIsVerified ( false );
setKeyFingerprint ( '' );
setSecurityLevel ( null );
setConnectionStatus ( 'disconnected' );
setMessages ([]);
setMessageInput ( '' );
2025-08-12 13:55:07 -04:00
setOfferPassword ( '' );
setAnswerPassword ( '' );
2025-08-11 20:52:14 -04:00
2025-08-18 21:45:50 -04:00
// Не очищаем консоль при очистке данных
// чтобы пользователь мог видеть ошибки
// if (typeof console.clear === 'function') {
// console.clear();
// }
2025-08-11 20:52:14 -04:00
// Cleanup pay-per-session state
2025-08-17 20:38:47 -04:00
if ( sessionManager ) {
2025-08-11 20:52:14 -04:00
sessionManager . cleanup ();
setSessionTimeLeft ( 0 );
2025-08-17 20:38:47 -04:00
}
2025-08-11 20:52:14 -04:00
setShowPaymentModal ( false );
2025-08-17 20:38:47 -04:00
setPendingSession ( null );
document . dispatchEvent ( new CustomEvent ( 'peer-disconnect' ));
setSessionManager ( null );
2025-08-11 20:52:14 -04:00
};
const handleDisconnect = () => {
2025-08-17 20:38:47 -04:00
if ( sessionManager && sessionManager . hasActiveSession ()) {
sessionManager . resetSession ();
setSessionTimeLeft ( 0 );
}
2025-08-11 20:52:14 -04:00
// Cleanup pay-per-session state
2025-08-17 20:38:47 -04:00
if ( sessionManager ) {
2025-08-11 20:52:14 -04:00
sessionManager . cleanup ();
2025-08-17 20:38:47 -04:00
}
2025-08-11 20:52:14 -04:00
setShowPaymentModal ( false );
2025-08-17 20:38:47 -04:00
if ( webrtcManagerRef . current ) {
2025-08-11 20:52:14 -04:00
webrtcManagerRef . current . disconnect ();
2025-08-17 20:38:47 -04:00
}
2025-08-11 20:52:14 -04:00
setKeyFingerprint ( '' );
setVerificationCode ( '' );
setSecurityLevel ( null );
setIsVerified ( false );
setShowVerification ( false );
2025-08-17 20:38:47 -04:00
setConnectionStatus ( 'disconnected' );
setMessages ([]);
2025-08-18 21:45:50 -04:00
// Не очищаем консоль при отключении
// чтобы пользователь мог видеть ошибки
// if (typeof console.clear === 'function') {
// console.clear();
// }
2025-08-17 20:38:47 -04:00
document . dispatchEvent ( new CustomEvent ( 'peer-disconnect' ));
document . dispatchEvent ( new CustomEvent ( 'session-cleanup' , {
detail : {
timestamp : Date . now (),
reason : 'manual_disconnect'
}
}));
setTimeout (() => {
if ( sessionManager && sessionManager . hasActiveSession ()) {
sessionManager . resetSession ();
setSessionTimeLeft ( 0 );
}
}, 500 );
2025-08-11 20:52:14 -04:00
handleClearData ();
2025-08-17 20:38:47 -04:00
setTimeout (() => {
setSessionManager ( null );
}, 1000 );
2025-08-11 20:52:14 -04:00
};
const handleSessionActivated = ( session ) => {
2025-08-14 03:28:23 -04:00
let message ;
if ( session . type === 'demo' ) {
message = `🎮 Demo session activated for 6 minutes. You can create invitations!` ;
} else {
const hours = sessionManager . sessionPrices [ session . type ] ? . hours || 0 ;
message = `💰 Session activated for ${ hours } h. You can create invitations!` ;
}
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( message , 'system' );
2025-08-11 20:52:14 -04:00
};
React . useEffect (() => {
if ( connectionStatus === 'connected' && isVerified ) {
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( '🎉 Secure connection successfully established and verified! You can now communicate safely with full protection against MITM attacks and Perfect Forward Secrecy..' , 'system' );
2025-08-12 13:55:07 -04:00
2025-08-11 20:52:14 -04:00
}
}, [ connectionStatus , isVerified ]);
const isConnectedAndVerified = connectionStatus === 'connected' && isVerified ;
React . useEffect (() => {
if ( isConnectedAndVerified && sessionManager . canActivateSession () && pendingSession && connectionStatus !== 'failed' ) {
const result = sessionManager . safeActivateSession ( pendingSession . type , pendingSession . preimage , pendingSession . paymentHash );
if ( result . success ) {
setPendingSession ( null );
2025-08-12 13:55:07 -04:00
setSessionTimeLeft ( sessionManager . getTimeLeft ());
2025-08-14 03:28:23 -04:00
let message ;
if ( pendingSession . type === 'demo' ) {
message = `🎮 Demo session activated for 6 minutes ( ${ result . method } )` ;
} else {
const hours = sessionManager . sessionPrices [ pendingSession . type ] ? . hours || 0 ;
message = `💰 Session activated for ${ hours } h ( ${ result . method } )` ;
}
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( message , 'system' );
2025-08-11 20:52:14 -04:00
} else {
2025-08-17 20:38:47 -04:00
addMessageWithAutoScroll ( `❌ Session activation error: ${ result . reason } ` , 'error' );
2025-08-11 20:52:14 -04:00
}
}
}, [ isConnectedAndVerified , sessionManager , pendingSession , connectionStatus ]);
return React . createElement ( 'div' , {
className : "minimal-bg min-h-screen"
}, [
React . createElement ( EnhancedMinimalHeader , {
key : 'header' ,
status : connectionStatus ,
fingerprint : keyFingerprint ,
verificationCode : verificationCode ,
onDisconnect : handleDisconnect ,
isConnected : isConnectedAndVerified ,
securityLevel : securityLevel ,
sessionManager : sessionManager ,
sessionTimeLeft : sessionTimeLeft
}),
React . createElement ( 'main' , {
key : 'main'
},
isConnectedAndVerified
? React . createElement ( EnhancedChatInterface , {
messages : messages ,
messageInput : messageInput ,
setMessageInput : setMessageInput ,
onSendMessage : handleSendMessage ,
onDisconnect : handleDisconnect ,
keyFingerprint : keyFingerprint ,
isVerified : isVerified ,
chatMessagesRef : chatMessagesRef ,
2025-08-18 21:45:50 -04:00
webrtcManager : webrtcManagerRef . current
2025-08-11 20:52:14 -04:00
})
: React . createElement ( EnhancedConnectionSetup , {
onCreateOffer : handleCreateOffer ,
onCreateAnswer : handleCreateAnswer ,
onConnect : handleConnect ,
onClearData : handleClearData ,
onVerifyConnection : handleVerifyConnection ,
connectionStatus : connectionStatus ,
offerData : offerData ,
answerData : answerData ,
offerInput : offerInput ,
setOfferInput : setOfferInput ,
answerInput : answerInput ,
setAnswerInput : setAnswerInput ,
showOfferStep : showOfferStep ,
showAnswerStep : showAnswerStep ,
verificationCode : verificationCode ,
showVerification : showVerification ,
messages : messages ,
offerPassword : offerPassword ,
answerPassword : answerPassword
})
),
// Password Modal
React . createElement ( PasswordModal , {
key : 'password-modal' ,
isOpen : showPasswordModal ,
onClose : handlePasswordCancel ,
onSubmit : handlePasswordSubmit ,
action : passwordAction ,
password : passwordInput ,
setPassword : setPasswordInput
}),
// Payment Modal
React . createElement ( PaymentModal , {
key : 'payment-modal' ,
isOpen : showPaymentModal ,
onClose : () => setShowPaymentModal ( false ),
sessionManager : sessionManager ,
onSessionPurchased : ( session ) => { setPendingSession ( session ); handleSessionActivated ({ type : session . type }); }
})
]);
};
function initializeApp () {
if ( window . EnhancedSecureCryptoUtils && window . EnhancedSecureWebRTCManager ) {
ReactDOM . render ( React . createElement ( EnhancedSecureP2PChat ), document . getElementById ( 'root' ));
} else {
console . error ( '❌ Модули не загружены:' , {
hasCrypto : !! window . EnhancedSecureCryptoUtils ,
hasWebRTC : !! window . EnhancedSecureWebRTCManager
});
}
}
// Render Enhanced Application
// ReactDOM.render(React.createElement(EnhancedSecureP2PChat), document.getElementById('root'));
</ script >
< script type = "module" >
try {
const timestamp = Date . now ();
2025-08-18 21:45:50 -04:00
const [ cryptoModule , webrtcModule , paymentModule , fileTransferModule ] = await Promise . all ([
2025-08-11 20:52:14 -04:00
import ( `./src/crypto/EnhancedSecureCryptoUtils.js?v= ${ timestamp } ` ),
import ( `./src/network/EnhancedSecureWebRTCManager.js?v= ${ timestamp } ` ),
2025-08-18 21:45:50 -04:00
import ( `./src/session/PayPerSessionManager.js?v= ${ timestamp } ` ),
import ( `./src/transfer/EnhancedSecureFileTransfer.js?v= ${ timestamp } ` )
2025-08-11 20:52:14 -04:00
]);
const { EnhancedSecureCryptoUtils } = cryptoModule ;
window . EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils ;
const { EnhancedSecureWebRTCManager } = webrtcModule ;
window . EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager ;
const { PayPerSessionManager } = paymentModule ;
window . PayPerSessionManager = PayPerSessionManager ;
2025-08-18 21:45:50 -04:00
const { EnhancedSecureFileTransfer } = fileTransferModule ;
window . EnhancedSecureFileTransfer = EnhancedSecureFileTransfer ;
2025-08-11 20:52:14 -04:00
async function loadReactComponent ( path , componentName ) {
try {
const response = await fetch ( ` ${ path } ?v= ${ timestamp } ` );
if ( ! response . ok ) {
throw new Error ( `HTTP ${ response . status } : ${ response . statusText } ` );
}
const componentCode = await response . text ();
eval ( componentCode );
2025-08-12 13:56:40 -04:00
2025-08-11 20:52:14 -04:00
} catch ( error ) {
throw error ;
}
}
await Promise . all ([
loadReactComponent ( './src/components/ui/SessionTimer.jsx' , 'SessionTimer' ),
loadReactComponent ( './src/components/ui/Header.jsx' , 'EnhancedMinimalHeader' ),
loadReactComponent ( './src/components/ui/PasswordModal.jsx' , 'PasswordModal' ),
loadReactComponent ( './src/components/ui/SessionTypeSelector.jsx' , 'SessionTypeSelector' ),
loadReactComponent ( './src/components/ui/LightningPayment.jsx' , 'LightningPayment' ),
2025-08-17 00:10:33 -04:00
loadReactComponent ( './src/components/ui/PaymentModal.jsx' , 'PaymentModal' ),
2025-08-18 21:45:50 -04:00
loadReactComponent ( './src/components/ui/DownloadApps.jsx' , 'DownloadApps' ),
loadReactComponent ( './src/components/ui/FileTransfer.jsx' , 'FileTransferComponent' )
2025-08-11 20:52:14 -04:00
]);
2025-08-12 13:55:07 -04:00
2025-08-12 13:56:40 -04:00
if ( typeof initializeApp === 'function' ) {
initializeApp ();
} else {
console . error ( '❌ Function initializeApp not found' );
}
2025-08-11 20:52:14 -04:00
} catch ( error ) {
2025-08-12 13:55:07 -04:00
console . error ( '❌ Module loading error:' , error );
2025-08-11 20:52:14 -04:00
}
</ script >
2025-08-14 23:34:54 -04:00
< script >
window . forceUpdateHeader = ( timeLeft , sessionType ) => {
2025-08-17 20:38:47 -04:00
const event = new CustomEvent ( 'force-header-update' , {
detail : { timeLeft , sessionType , timestamp : Date . now () }
});
document . dispatchEvent ( event );
2025-08-14 23:34:54 -04:00
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 );
}
2025-08-18 21:45:50 -04:00
// Notify WebRTC Manager about session activation
if ( window . webrtcManager && window . webrtcManager . handleSessionActivation ) {
console . log ( '🔐 Notifying WebRTC Manager about session activation' );
window . webrtcManager . handleSessionActivation ({
sessionId : event . detail . sessionId ,
sessionType : event . detail . sessionType ,
timeLeft : event . detail . timeLeft ,
isDemo : event . detail . isDemo ,
sessionManager : window . sessionManager
});
}
2025-08-14 23:34:54 -04:00
});
if ( window . DEBUG_MODE ) {
console . log ( '✅ Global timer management functions loaded' );
}
</ script >
2025-08-17 16:45:30 -04:00
< script src = "./src/pwa/install-prompt.js" ></ script >
< script src = "./src/pwa/pwa-manager.js" ></ script >
< script src = "./src/pwa/offline-manager.js" ></ script >
< link rel = "stylesheet" href = "./src/styles/pwa.css" >
2025-08-17 16:04:45 -04:00
< script >
2025-08-19 21:54:17 -04:00
// PWA Service Worker Registration
2025-08-17 16:04:45 -04:00
if ( 'serviceWorker' in navigator ) {
window . addEventListener ( 'load' , async () => {
try {
2025-08-19 21:54:17 -04:00
const registration = await navigator . serviceWorker . register ( './sw.js' , {
scope : './'
});
console . log ( '✅ PWA: Service Worker registered successfully' );
console . log ( '📡 SW Scope:' , registration . scope );
// Store registration for use in other modules
window . swRegistration = registration ;
// Listen for updates
registration . addEventListener ( 'updatefound' , () => {
console . log ( '🔄 PWA: Service Worker update found' );
const newWorker = registration . installing ;
newWorker . addEventListener ( 'statechange' , () => {
if ( newWorker . state === 'installed' && navigator . serviceWorker . controller ) {
console . log ( '🆕 PWA: New version available' );
2025-08-23 17:21:32 -04:00
// Проверяем, установлено ли приложение как PWA
const isPWAInstalled = window . matchMedia ( '(display-mode: standalone)' ). matches ||
window . navigator . standalone === true ||
( window . pwaInstallPrompt && window . pwaInstallPrompt . isInstalled );
if ( isPWAInstalled ) {
// Если это PWA, показываем уведомление об обновлении
2025-08-23 17:48:46 -04:00
showUpdateNotification ();
2025-08-23 17:21:32 -04:00
} else {
// Если это браузер, показываем промпт установки
if ( window . pwaInstallPrompt && ! window . pwaInstallPrompt . isInstalled ) {
setTimeout (() => {
window . pwaInstallPrompt . showInstallOptions ();
}, 2000 );
}
}
2025-08-19 21:54:17 -04:00
}
});
});
2025-08-17 16:04:45 -04:00
} catch ( error ) {
console . error ( '❌ PWA: Service Worker registration failed:' , error );
2025-08-19 21:54:17 -04:00
// Show fallback notification
if ( window . DEBUG_MODE ) {
setTimeout (() => {
showServiceWorkerError ( error );
}, 2000 );
}
2025-08-17 16:04:45 -04:00
}
});
}
2025-08-19 21:54:17 -04:00
if ( 'serviceWorker' in navigator ) {
navigator . serviceWorker . ready . then ( registration => {
console . log ( '🎯 PWA: Service Worker ready' );
2025-08-23 17:21:32 -04:00
// Проверяем статус установки PWA
const isPWAInstalled = window . matchMedia ( '(display-mode: standalone)' ). matches ||
window . navigator . standalone === true ;
console . log ( '🔍 PWA Installation Status:' , {
isStandalone : isPWAInstalled ,
displayMode : window . matchMedia ( '(display-mode: standalone)' ). matches ,
iosStandalone : window . navigator . standalone === true
});
2025-08-19 21:54:17 -04:00
if ( window . pwaInstallPrompt && window . pwaInstallPrompt . setServiceWorkerRegistration ) {
window . pwaInstallPrompt . setServiceWorkerRegistration ( registration );
2025-08-23 17:21:32 -04:00
// Если PWA уже установлено, обновляем статус
if ( isPWAInstalled && ! window . pwaInstallPrompt . isInstalled ) {
console . log ( '✅ PWA already installed, updating status' );
window . pwaInstallPrompt . isInstalled = true ;
window . pwaInstallPrompt . hideInstallPrompts ();
}
2025-08-19 21:54:17 -04:00
}
if ( window . pwaOfflineManager && window . pwaOfflineManager . setServiceWorkerRegistration ) {
window . pwaOfflineManager . setServiceWorkerRegistration ( registration );
}
});
2025-08-23 17:21:32 -04:00
// Слушаем сообщения от Service Worker
navigator . serviceWorker . addEventListener ( 'message' , ( event ) => {
console . log ( '📨 Message from Service Worker:' , event . data );
if ( event . data && event . data . type === 'SW_ACTIVATED' ) {
console . log ( '🔄 Service Worker activated, checking for updates...' );
// Проверяем, установлено ли приложение как PWA
const isPWAInstalled = window . matchMedia ( '(display-mode: standalone)' ). matches ||
window . navigator . standalone === true ||
( window . pwaInstallPrompt && window . pwaInstallPrompt . isInstalled );
if ( isPWAInstalled ) {
// Если это PWA, показываем уведомление об обновлении
setTimeout (() => {
showUpdateNotification ();
}, 1000 );
} else {
// Если это браузер, показываем промпт установки
if ( window . pwaInstallPrompt && ! window . pwaInstallPrompt . isInstalled ) {
setTimeout (() => {
window . pwaInstallPrompt . showInstallOptions ();
}, 2000 );
}
}
}
});
2025-08-19 21:54:17 -04:00
}
2025-08-17 16:04:45 -04:00
2025-08-19 21:54:17 -04:00
function showUpdateNotification () {
2025-08-23 17:21:32 -04:00
console . log ( '🆕 Showing update notification for PWA' );
2025-08-19 21:54:17 -04:00
const notification = document . createElement ( 'div' );
notification . className = 'fixed top-4 left-1/2 transform -translate-x-1/2 bg-blue-500 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm' ;
notification . innerHTML = `
<div class="flex items-center space-x-3">
<i class="fas fa-download text-lg"></i>
<div class="flex-1">
<div class="font-medium">Update Available</div>
<div class="text-sm opacity-90">A new version of SecureBit.chat is ready</div>
</div>
<button onclick="window.location.reload()"
class="bg-white/20 hover:bg-white/30 px-3 py-1 rounded text-sm font-medium transition-colors">
Update
</button>
</div>
` ;
document . body . appendChild ( notification );
setTimeout (() => {
if ( notification . parentElement ) {
notification . remove ();
}
}, 30000 );
2025-08-17 16:04:45 -04:00
}
2025-08-19 21:54:17 -04:00
function showServiceWorkerError ( error ) {
const errorNotification = document . createElement ( 'div' );
errorNotification . className = 'fixed bottom-4 right-4 bg-red-500/90 text-white p-4 rounded-lg shadow-lg z-50 max-w-sm backdrop-blur-sm' ;
errorNotification . innerHTML = `
<div class="flex items-start space-x-3">
<i class="fas fa-exclamation-triangle text-lg mt-0.5"></i>
<div class="flex-1">
<div class="font-medium">PWA Setup Issue</div>
<div class="text-sm opacity-90 mt-1">
Service Worker registration failed. Some offline features may not work.
</div>
<details class="mt-2">
<summary class="text-xs cursor-pointer opacity-75">Technical details</summary>
<code class="text-xs opacity-60 block mt-1 break-all"> ${ error . message } </code>
</details>
</div>
<button onclick="this.parentElement.remove()"
class="text-white/70 hover:text-white transition-colors">
<i class="fas fa-times"></i>
</button>
</div>
` ;
document . body . appendChild ( errorNotification );
setTimeout (() => {
if ( errorNotification . parentElement ) {
errorNotification . remove ();
}
}, 15000 );
}
function checkPWASupport () {
const support = {
serviceWorker : 'serviceWorker' in navigator ,
installPrompt : 'BeforeInstallPromptEvent' in window ,
standalone : 'standalone' in navigator ,
manifest : document . querySelector ( 'link[rel="manifest"]' ) !== null
};
console . log ( '🔍 PWA Support Check:' , support );
if ( window . DEBUG_MODE ) {
if ( ! support . serviceWorker ) {
console . warn ( '⚠️ Service Workers not supported' );
}
if ( ! support . manifest ) {
console . warn ( '⚠️ Manifest not found' );
}
}
return support ;
}
document . addEventListener ( 'DOMContentLoaded' , () => {
checkPWASupport ();
2025-08-23 17:21:32 -04:00
// Дополнительная проверка PWA Install Prompt после полной загрузки
setTimeout (() => {
if ( window . pwaInstallPrompt ) {
console . log ( '🔍 Final PWA Install Prompt status check...' );
// Используем новый метод для проверки статуса
window . PWAUtils . checkInstallationStatus ();
console . log ( '📱 Final PWA status:' , {
isInstalled : window . pwaInstallPrompt . isInstalled ,
displayMode : window . matchMedia ( '(display-mode: standalone)' ). matches ,
iosStandalone : window . navigator . standalone === true
});
}
}, 2000 );
// Дополнительная проверка через 5 секунд для надежности
setTimeout (() => {
if ( window . pwaInstallPrompt ) {
console . log ( '🔍 Delayed PWA status check...' );
window . PWAUtils . checkInstallationStatus ();
}
}, 5000 );
2025-08-17 16:04:45 -04:00
});
2025-08-19 21:54:17 -04:00
window . PWAUtils = {
forceUpdate : () => {
if ( window . swRegistration ) {
window . swRegistration . update ();
}
},
checkForUpdates : async () => {
if ( window . swRegistration ) {
await window . swRegistration . update ();
console . log ( '🔄 Checked for PWA updates' );
}
},
getInstallStatus : () => {
if ( window . pwaInstallPrompt ) {
return window . pwaInstallPrompt . getInstallStatus ();
}
return { isInstalled : false , canPrompt : false };
},
showInstallPrompt : () => {
if ( window . pwaInstallPrompt ) {
window . pwaInstallPrompt . showInstallPrompt ();
} else {
console . warn ( '⚠️ PWA Install Prompt not initialized' );
}
2025-08-23 17:21:32 -04:00
},
// Новый метод для принудительной проверки статуса установки
checkInstallationStatus : () => {
const isPWAInstalled = window . matchMedia ( '(display-mode: standalone)' ). matches ||
window . navigator . standalone === true ;
console . log ( '🔍 PWA Installation Status Check:' , {
isStandalone : isPWAInstalled ,
displayMode : window . matchMedia ( '(display-mode: standalone)' ). matches ,
iosStandalone : window . navigator . standalone === true ,
pwaInstallPrompt : !! window . pwaInstallPrompt ,
pwaInstallPromptInstalled : window . pwaInstallPrompt ? window . pwaInstallPrompt . isInstalled : false
});
if ( window . pwaInstallPrompt && isPWAInstalled && ! window . pwaInstallPrompt . isInstalled ) {
console . log ( '✅ Updating PWA Install Prompt status to installed' );
window . pwaInstallPrompt . isInstalled = true ;
window . pwaInstallPrompt . hideInstallPrompts ();
}
return isPWAInstalled ;
},
// Метод для сброса статуса установки (для тестирования)
resetInstallationStatus : () => {
if ( window . pwaInstallPrompt ) {
window . pwaInstallPrompt . isInstalled = false ;
window . pwaInstallPrompt . installationChecked = false ;
window . pwaInstallPrompt . checkInstallationStatus ();
console . log ( '🔄 PWA Installation status reset' );
}
2025-08-23 17:30:12 -04:00
},
2025-08-23 17:40:32 -04:00
// Метод для перезапуска отложенного промпта
rescheduleDelayedPrompt : () => {
if ( window . pwaInstallPrompt && window . pwaInstallPrompt . scheduleDelayedPrompt ) {
// Отменяем существующий таймер и запускаем новый
if ( window . pwaInstallPrompt . delayedPromptTimeout ) {
clearTimeout ( window . pwaInstallPrompt . delayedPromptTimeout );
}
window . pwaInstallPrompt . scheduleDelayedPrompt ();
2025-08-23 17:30:12 -04:00
}
},
2025-08-23 17:40:32 -04:00
// Метод для отмены отложенного промпта
cancelDelayedPrompt : () => {
if ( window . pwaInstallPrompt && window . pwaInstallPrompt . delayedPromptTimeout ) {
clearTimeout ( window . pwaInstallPrompt . delayedPromptTimeout );
window . pwaInstallPrompt . delayedPromptTimeout = null ;
console . log ( '⏰ Delayed install prompt cancelled via PWAUtils' );
return true ;
2025-08-23 17:30:12 -04:00
}
2025-08-23 17:40:32 -04:00
return false ;
2025-08-19 21:54:17 -04:00
}
};
console . log ( '✅ PWA Registration and utilities loaded' );
2025-08-17 16:04:45 -04:00
</ script >
2025-08-11 20:52:14 -04:00
</ body >
</ html >