Files
securebit-chat/index.html
2025-08-13 23:02:04 -04:00

3571 lines
184 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<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';">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
<!-- GitHub Pages SEO -->
<meta name="description" content="LockBit.chat — P2P messenger with military-grade cryptography and Lightning Network payments">
<meta name="keywords" content="P2P messenger, encryption, Lightning Network, WebRTC, privacy">
<meta name="author" content="Volodymyr">
<link rel="canonical" href="https://github.com/lockbitchat/lockbit-chat/">
<!-- Open Graph -->
<meta property="og:title" content="LockBit.chat - Enhanced Security Edition">
<meta property="og:description" content="The first P2P messenger with Lightning Network payments">
<meta property="og:url" content="https://github.com/lockbitchat/lockbit-chat/">
<meta property="og:type" content="website">
<meta property="og:image" content="https://github.com/lockbitchat/lockbit-chat/assets/images/og-image.png">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="LockBit.chat - Enhanced Security Edition">
<meta name="twitter:description" content="P2P messenger with military-grade cryptography">
<title>LockBit.chat - Enhanced Security Edition</title>
<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>
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico">
<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>
// 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 = () => {
const [currentSlide, setCurrentSlide] = React.useState(0);
const slides = [
{
icon: "fas fa-shield-halved",
color: "orange",
title: "Military-grade encryption",
description: "ECDH P-384 + AES-GCM 256-bit + ECDSA digital signatures provide NSA Suite Blevel cryptographic strength"
},
{
icon: "fas fa-sync-alt",
color: "purple",
title: "Perfect Forward Secrecy",
description: "Automatic key rotation every 5 minutes ensures that even if one key is compromised, all other messages remain secure."
},
{
icon: "fas fa-user-shield",
color: "green",
title: "Protection against MITM attacks",
description: "Out-of-band verification with security codes plus mutual authentication eliminate the possibility of man-in-the-middle attacks."
},
{
icon: "fas fa-bolt",
color: "yellow",
title: "Lightning payments",
description: "Session payments in satoshis via Lightning Network. Payment privacy plus instant microtransactions without banks."
},
{
icon: "fas fa-eye-slash",
color: "blue",
title: "Zero data storage",
description: "All messages exist only in the browsers memory. No servers, logs, or databases. Complete anonymity."
},
{
icon: "fas fa-code",
color: "cyan",
title: "Open Source security",
description: "All code is open for audit. Cryptography runs directly in the browser without relying on servers or third parties."
}
];
const nextSlide = () => setCurrentSlide((prev) => (prev + 1) % slides.length);
const prevSlide = () => setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length);
const goToSlide = (index) => setCurrentSlide(index);
React.useEffect(() => {
const timer = setInterval(() => {
nextSlide();
}, 15000);
return () => clearInterval(timer);
}, []);
return (
<div className="mt-12">
<div className="text-center mb-8">
<h3 className="text-2xl font-semibold text-primary mb-3">
Why LockBit.chat is unique
</h3>
<p className="text-secondary max-w-2xl mx-auto">
The only messenger with military-grade cryptography and Lightning payments
</p>
</div>
<div className="relative max-w-4xl mx-auto">
<div className="overflow-hidden rounded-xl">
<div
className="flex transition-transform duration-500 ease-in-out"
style={{ transform: `translateX(-${currentSlide * 100}%)` }}
>
{slides.map((slide, index) => (
<div key={index} className="w-full flex-shrink-0 px-4">
<div className="card-minimal rounded-xl p-8 text-center min-h-[300px] flex flex-col justify-center relative overflow-hidden">
{/* Background icon */}
<i
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 === 'purple' ? 'text-purple-500' :
slide.color === 'green' ? 'text-green-500' :
slide.color === 'yellow' ? 'text-yellow-500' :
slide.color === 'blue' ? 'text-blue-500' :
'text-cyan-500'
}`}
></i>
{/* Content */}
<h4 className="text-xl font-semibold text-primary mb-4 relative z-10">
{slide.title}
</h4>
<p className="text-secondary leading-relaxed max-w-2xl mx-auto relative z-10">
{slide.description}
</p>
</div>
</div>
))}
</div>
</div>
{/* Navigation */}
<button
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"
>
<i className="fas fa-chevron-left"></i>
</button>
<button
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"
>
<i className="fas fa-chevron-right"></i>
</button>
</div>
{/* Dots */}
<div className="flex justify-center space-x-2 mt-6">
{slides.map((_, index) => (
<button
key={index}
onClick={() => goToSlide(index)}
className={`w-3 h-3 rounded-full transition-all duration-200 ${
index === currentSlide
? 'bg-orange-500'
: 'bg-gray-600 hover:bg-gray-500'
}`}
></button>
))}
</div>
</div>
);
};
const ComparisonTable = () => {
const [selectedFeature, setSelectedFeature] = React.useState(null);
const messengers = [
{
name: "LockBit.chat",
logo: React.createElement('div', {
className: "w-8 h-8 bg-orange-500/10 border border-orange-500/20 rounded-lg flex items-center justify-center"
}, [
React.createElement('i', {
key: 'icon',
className: 'fas fa-shield-halved text-orange-400'
})
]),
type: "P2P WebRTC",
color: "orange"
},
{
name: "Signal",
logo: React.createElement('svg', {
key: 'signal-logo',
className: "w-8 h-8",
viewBox: "0 0 122.88 122.31",
xmlns: "http://www.w3.org/2000/svg"
}, [
React.createElement('path', {
key: 'bg',
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"
}),
React.createElement('path', {
key: 'icon',
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"
})
]),
type: "Centralized",
color: "blue"
},
{
name: "Threema",
logo: React.createElement('svg', {
key: 'threema-logo',
className: "w-8 h-8",
viewBox: "0 0 122.88 122.88",
xmlns: "http://www.w3.org/2000/svg"
}, [
React.createElement('rect', {
key: 'bg',
width: "122.88",
height: "122.88",
rx: "18.43",
fill: "#474747"
}),
React.createElement('path', {
key: 'bubble',
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.32 c21.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.64 h-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.6 c0-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.64 h-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"
}),
React.createElement('circle', {
key: 'dot1',
cx: "37.44",
cy: "97.44",
r: "6.72",
fill: "#3fe669"
}),
React.createElement('circle', {
key: 'dot2',
cx: "61.44",
cy: "97.44",
r: "6.72",
fill: "#3fe669"
}),
React.createElement('circle', {
key: 'dot3',
cx: "85.44",
cy: "97.44",
r: "6.72",
fill: "#3fe669"
})
]),
type: "Centralized",
color: "green"
},
{
name: "Olvid",
logo: React.createElement('svg', {
key: 'olvid-logo',
className: "w-8 h-8",
viewBox: "0 0 128 128",
xmlns: "http://www.w3.org/2000/svg"
}, [
React.createElement('g', {
key: 'group',
transform: "translate(0,128) scale(0.1,-0.1)",
fill: "#0a4bd1",
stroke: "none"
}, [
React.createElement('path', {
key: 'p1',
d: "M262 1264 c-139 -37 -217 -120 -247 -260 -18 -85 -21 -627 -4 -720 21 -115 89 -201 198 -253 l56 -26 370 0 c284 0 379 3 410 13 108 37 203 140 225 247 7 36 10 169 8 402 -4 396 -6 405 -85 493 -50 55 -100 86 -178 106 -73 20 -679 18 -753 -2z m538 -215 c299 -105 388 -490 165 -714 -216 -216 -598 -152 -728 122 -30 64 -32 74 -32 183 0 114 1 117 38 192 99 201 337 294 557 217z"
}),
React.createElement('path', {
key: 'p2',
d: "M550 864 c-46 -20 -87 -59 -113 -109 -17 -31 -22 -58 -22 -115 0 -85 15 -122 72 -182 20 -20 32 -41 28 -47 -3 -6 -30 -25 -58 -41 l-52 -30 70 0 c137 0 262 46 329 120 51 57 69 103 69 181 0 106 -51 188 -140 226 -43 17 -139 16 -183 -3z"
})
])
]),
type: "Centralized",
color: "purple"
}
,
{
name: "Session",
logo: React.createElement('svg', {
key: 'olvid-logo',
className: "w-8 h-8",
viewBox: "0 0 1024 1024",
xmlns: "http://www.w3.org/2000/svg"
}, [
React.createElement('rect', {
key: 'bg',
width: "1024",
height: "1024",
fill: "#333132"
}),
React.createElement('path', {
key: 'icon',
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"
})
]),
type: "Onion Network",
color: "cyan"
}
];
const features = [
{
name: "Cryptography",
lockbit: { status: "🏆", detail: "ECDH P-384 + AES-GCM 256 + ECDSA" },
signal: { status: "✅", detail: "Signal Protocol + Double Ratchet" },
threema: { status: "✅", detail: "NaCl + XSalsa20 + Poly1305" },
olvid: { status: "✅", detail: "OlvidEngine + post-quantum" },
session: { status: "✅", detail: "Modified Signal Protocol" }
},
{
name: "Perfect Forward Secrecy",
lockbit: { status: "🏆", detail: "Automatic rotation every 5 minutes" },
signal: { status: "✅", detail: "Double Ratchet algorithm" },
threema: { status: "⚠️", detail: "Partial (group chats)" },
olvid: { status: "✅", detail: "Full PFS for all messages" },
session: { status: "✅", detail: "Session Ratchet algorithm" }
},
{
name: "Architecture",
lockbit: { status: "🏆", detail: "Pure P2P without servers" },
signal: { status: "❌", detail: "Centralized Signal servers" },
threema: { status: "❌", detail: "Threema servers in Switzerland" },
olvid: { status: "❌", detail: "Servers in France" },
session: { status: "⚠️", detail: "Onion routing via network nodes" }
},
{
name: "Registration Anonymity",
lockbit: { status: "🏆", detail: "No registration required" },
signal: { status: "❌", detail: "Phone number required" },
threema: { status: "✅", detail: "ID generated locally" },
olvid: { status: "✅", detail: "Cryptographic identity" },
session: { status: "✅", detail: "Random session ID" }
},
{
name: "Metadata Protection",
lockbit: { status: "🏆", detail: "Full metadata encryption" },
signal: { status: "⚠️", detail: "Sealed Sender (partial)" },
threema: { status: "⚠️", detail: "Minimal metadata" },
olvid: { status: "✅", detail: "Protection via obfuscation" },
session: { status: "✅", detail: "Onion routing hides metadata" }
},
{
name: "Open Source",
lockbit: { status: "🏆", detail: "100% open and auditable" },
signal: { status: "✅", detail: "Fully open" },
threema: { status: "⚠️", detail: "Only clients open" },
olvid: { status: "✅", detail: "Fully open" },
session: { status: "✅", detail: "Fully open" }
},
{
name: "Digital Signatures",
lockbit: { status: "🏆", detail: "Built-in ECDSA P-384" },
signal: { status: "✅", detail: "Ed25519 signatures" },
threema: { status: "✅", detail: "Ed25519 signatures" },
olvid: { status: "✅", detail: "Multiple algorithms" },
session: { status: "✅", detail: "Ed25519 signatures" }
},
{
name: "Economic Model",
lockbit: { status: "🏆", detail: "Lightning satoshis per session" },
signal: { status: "⚠️", detail: "Donations and grants" },
threema: { status: "✅", detail: "One-time app purchase" },
olvid: { status: "✅", detail: "Free + Enterprise" },
session: { status: "⚠️", detail: "Donations" }
},
{
name: "Censorship Resistance",
lockbit: { status: "🏆", detail: "Impossible to block P2P" },
signal: { status: "⚠️", detail: "Blocked in authoritarian countries" },
threema: { status: "⚠️", detail: "May be blocked" },
olvid: { status: "⚠️", detail: "May be blocked" },
session: { status: "✅", detail: "Onion routing bypasses blocks" }
},
{
name: "Data Storage",
lockbit: { status: "🏆", detail: "Only in browser memory" },
signal: { status: "⚠️", detail: "Local database" },
threema: { status: "⚠️", detail: "Local + optional backup" },
olvid: { status: "✅", detail: "Local without cloud backup" },
session: { status: "⚠️", detail: "Local database" }
},
{
name: "Post-Quantum Protection",
lockbit: { status: "⚠️", detail: "Planned in version 5.0" },
signal: { status: "⚠️", detail: "PQXDH in development" },
threema: { status: "❌", detail: "Not implemented" },
olvid: { status: "🏆", detail: "Already implemented" },
session: { status: "❌", detail: "Not implemented" }
},
{
name: "MITM Verification",
lockbit: { status: "🏆", detail: "Out-of-band codes + mutual auth" },
signal: { status: "✅", detail: "Safety numbers" },
threema: { status: "✅", detail: "QR code scanning" },
olvid: { status: "✅", detail: "SAS verification" },
session: { status: "⚠️", detail: "Basic key verification" }
}
];
const getStatusIcon = (status) => {
switch (status) {
case "🏆": return { icon: status, color: "text-yellow-400" };
case "✅": return { icon: status, color: "text-green-400" };
case "⚠️": return { icon: status, color: "text-yellow-400" };
case "❌": return { icon: status, color: "text-red-400" };
default: return { icon: status, color: "text-gray-400" };
}
};
const toggleFeatureDetail = (index) => {
setSelectedFeature(selectedFeature === index ? null : index);
};
return React.createElement('div', {
key: 'comparison-section',
className: "mt-16"
}, [
React.createElement('div', {
key: 'section-header',
className: "text-center mb-8"
}, [
React.createElement('h3', {
key: 'title',
className: "text-2xl font-semibold text-primary mb-3"
}, 'Comparison with privacy leaders'),
React.createElement('p', {
key: 'subtitle',
className: "text-secondary max-w-2xl mx-auto mb-4"
}, "A detailed comparison with the worlds most secure messengers"),
React.createElement('div', {
key: 'trophy-note',
className: "inline-flex items-center px-4 py-2 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"
}, [
React.createElement('span', {
key: 'trophy',
className: "text-yellow-400 mr-2"
}, "🏆"),
React.createElement('span', {
key: 'text',
className: "text-yellow-300 text-sm font-medium"
}, "Leader in the category")
])
]),
React.createElement('div', {
key: 'table-container',
className: "max-w-7xl mx-auto"
}, [
// Mobile warning
React.createElement('div', {
key: 'mobile-warning',
className: "md:hidden p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-lg mb-4"
}, [
React.createElement('p', {
className: "text-yellow-400 text-sm text-center"
}, "💡 Please rotate your device horizontally for better viewing.")
]),
// Table
React.createElement('div', {
key: 'table-wrapper',
className: "overflow-x-auto custom-scrollbar"
}, [
React.createElement('table', {
key: 'comparison-table',
className: "w-full border-collapse rounded-xl overflow-hidden",
style: { backgroundColor: "rgba(42, 43, 42, 0.8)" }
}, [
// Header
React.createElement('thead', {
key: 'table-head'
}, [
React.createElement('tr', {
key: 'header-row',
className: "bg-header"
}, [
React.createElement('th', {
key: 'feature-header',
className: "text-left p-4 border-b border-gray-600 text-primary font-semibold min-w-[220px]"
}, 'Security criterion'),
...messengers.map((messenger, index) =>
React.createElement('th', {
key: `messenger-${index}`,
className: "text-center p-4 border-b border-gray-600 min-w-[140px]"
}, [
React.createElement('div', {
key: 'messenger-info',
className: "flex flex-col items-center"
}, [
React.createElement('div', {
key: 'logo',
className: "mb-2"
}, messenger.logo),
React.createElement('div', {
key: 'name',
className: `text-sm font-semibold ${
messenger.color === 'orange' ? 'text-orange-400' :
messenger.color === 'blue' ? 'text-blue-400' :
messenger.color === 'green' ? 'text-green-400' :
messenger.color === 'purple' ? 'text-purple-400' :
'text-cyan-400'
}`
}, messenger.name),
React.createElement('div', {
key: 'type',
className: "text-xs text-gray-400"
}, messenger.type)
])
])
)
])
]),
// Body
React.createElement('tbody', {
key: 'table-body'
}, features.map((feature, featureIndex) => [
React.createElement('tr', {
key: `feature-${featureIndex}`,
className: `border-b border-gray-700/30 hover:bg-gray-800/20 transition-colors cursor-pointer ${
selectedFeature === featureIndex ? 'bg-gray-800/40' : ''
}`,
onClick: () => toggleFeatureDetail(featureIndex)
}, [
React.createElement('td', {
key: 'feature-name',
className: "p-4 text-primary font-medium"
}, [
React.createElement('div', {
key: 'feature-text',
className: "flex items-center justify-between"
}, [
React.createElement('span', {
key: 'name'
}, feature.name),
React.createElement('i', {
key: 'expand-icon',
className: `fas fa-chevron-${selectedFeature === featureIndex ? 'up' : 'down'} text-xs text-gray-400 opacity-50`
})
])
]),
React.createElement('td', {
key: 'lockbit-cell',
className: "p-4 text-center"
}, [
React.createElement('span', {
key: 'lockbit-status',
className: getStatusIcon(feature.lockbit.status).color + " text-xl"
}, getStatusIcon(feature.lockbit.status).icon)
]),
React.createElement('td', {
key: 'signal-cell',
className: "p-4 text-center"
}, [
React.createElement('span', {
key: 'signal-status',
className: getStatusIcon(feature.signal.status).color + " text-xl"
}, getStatusIcon(feature.signal.status).icon)
]),
React.createElement('td', {
key: 'threema-cell',
className: "p-4 text-center"
}, [
React.createElement('span', {
key: 'threema-status',
className: getStatusIcon(feature.threema.status).color + " text-xl"
}, getStatusIcon(feature.threema.status).icon)
]),
React.createElement('td', {
key: 'olvid-cell',
className: "p-4 text-center"
}, [
React.createElement('span', {
key: 'olvid-status',
className: getStatusIcon(feature.olvid.status).color + " text-xl"
}, getStatusIcon(feature.olvid.status).icon)
]),
React.createElement('td', {
key: 'session-cell',
className: "p-4 text-center"
}, [
React.createElement('span', {
key: 'session-status',
className: getStatusIcon(feature.session.status).color + " text-xl"
}, getStatusIcon(feature.session.status).icon)
])
]),
// Expanded details row
selectedFeature === featureIndex && React.createElement('tr', {
key: `details-${featureIndex}`,
className: "border-b border-gray-700/30 bg-gray-800/10"
}, [
React.createElement('td', {
key: 'details-spacer',
className: "p-4 text-xs text-gray-400"
}, "Детали:"),
React.createElement('td', {
key: 'lockbit-detail',
className: "p-4 text-center"
}, [
React.createElement('div', {
key: 'detail',
className: "text-xs text-orange-300 font-medium leading-relaxed"
}, feature.lockbit.detail)
]),
React.createElement('td', {
key: 'signal-detail',
className: "p-4 text-center"
}, [
React.createElement('div', {
key: 'detail',
className: "text-xs text-blue-300 leading-relaxed"
}, feature.signal.detail)
]),
React.createElement('td', {
key: 'threema-detail',
className: "p-4 text-center"
}, [
React.createElement('div', {
key: 'detail',
className: "text-xs text-green-300 leading-relaxed"
}, feature.threema.detail)
]),
React.createElement('td', {
key: 'olvid-detail',
className: "p-4 text-center"
}, [
React.createElement('div', {
key: 'detail',
className: "text-xs text-purple-300 leading-relaxed"
}, feature.olvid.detail)
]),
React.createElement('td', {
key: 'session-detail',
className: "p-4 text-center"
}, [
React.createElement('div', {
key: 'detail',
className: "text-xs text-cyan-300 leading-relaxed"
}, feature.session.detail)
])
])
]).flat())
])
])
]),
// Enhanced Legend
React.createElement('div', {
key: 'legend',
className: "mt-8 grid grid-cols-2 md:grid-cols-4 gap-4 max-w-4xl mx-auto"
}, [
React.createElement('div', {
key: 'legend-item-1',
className: "flex items-center justify-center p-3 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"
}, [
React.createElement('span', {
key: 'icon1',
className: "text-yellow-400 mr-2 text-lg"
}, "🏆"),
React.createElement('span', {
key: 'text1',
className: "text-yellow-300 text-sm font-medium"
}, "Leader")
]),
React.createElement('div', {
key: 'legend-item-2',
className: "flex items-center justify-center p-3 bg-green-500/10 border border-green-500/20 rounded-lg"
}, [
React.createElement('span', {
key: 'icon2',
className: "text-green-400 mr-2 text-lg"
}, "✅"),
React.createElement('span', {
key: 'text2',
className: "text-green-300 text-sm font-medium"
}, "Excellent")
]),
React.createElement('div', {
key: 'legend-item-3',
className: "flex items-center justify-center p-3 bg-yellow-500/10 border border-yellow-500/20 rounded-lg"
}, [
React.createElement('span', {
key: 'icon3',
className: "text-yellow-400 mr-2 text-lg"
}, "⚠️"),
React.createElement('span', {
key: 'text3',
className: "text-yellow-300 text-sm font-medium"
}, "Partially")
]),
React.createElement('div', {
key: 'legend-item-4',
className: "flex items-center justify-center p-3 bg-red-500/10 border border-red-500/20 rounded-lg"
}, [
React.createElement('span', {
key: 'icon4',
className: "text-red-400 mr-2 text-lg"
}, "❌"),
React.createElement('span', {
key: 'text4',
className: "text-red-300 text-sm font-medium"
}, "No")
])
]),
// Summary
React.createElement('div', {
key: 'summary',
className: "mt-8 p-6 bg-orange-500/10 border border-orange-500/20 rounded-xl max-w-4xl mx-auto"
}, [
React.createElement('h4', {
key: 'summary-title',
className: "text-lg font-semibold text-orange-400 mb-3 flex items-center"
}, [
React.createElement('i', {
key: 'icon',
className: 'fas fa-trophy mr-2'
}),
'Summary of the comparison'
]),
React.createElement('p', {
key: 'summary-text',
className: "text-secondary leading-relaxed"
}, "LockBit.chat leads in 8 out of 12 security categories, especially excelling over competitors in P2P architecture, anonymity, and metadata protection. Only Olvid surpasses it in post-quantum cryptography, while centralized solutions show significant privacy shortcomings.")
])
]);
};
function Roadmap() {
const [selectedPhase, setSelectedPhase] = React.useState(null);
const phases = [
{
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"
]
},
{
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"
]
},
{
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"
]
},
{
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"
]
},
{
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"
]
},
// current and future phases
{
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"
]
},
{
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"
]
},
{
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",
"Quantum-safe key exchange",
"Updated hashing algorithms",
"Migration of existing sessions",
"Compatibility with v4.x",
"Quantum-resistant protocols"
]
},
{
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"
]
},
{
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"
]
},
{
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",
"Personalized security recommendations",
"Zero-knowledge machine learning",
"Private AI assistant",
"Predictive security",
"Autonomous attack protection"
]
}
];
const getStatusConfig = (status) => {
switch (status) {
case 'current':
return {
color: 'green',
bgClass: 'bg-green-500/10 border-green-500/20',
textClass: 'text-green-400',
icon: 'fas fa-check-circle',
label: 'Current Version'
};
case 'development':
return {
color: 'orange',
bgClass: 'bg-orange-500/10 border-orange-500/20',
textClass: 'text-orange-400',
icon: 'fas fa-code',
label: 'In Development'
};
case 'planned':
return {
color: 'blue',
bgClass: 'bg-blue-500/10 border-blue-500/20',
textClass: 'text-blue-400',
icon: 'fas fa-calendar-alt',
label: 'Planned'
};
case 'research':
return {
color: 'purple',
bgClass: 'bg-purple-500/10 border-purple-500/20',
textClass: 'text-purple-400',
icon: 'fas fa-flask',
label: 'Research'
};
case 'done':
return {
color: 'gray',
bgClass: 'bg-gray-500/10 border-gray-500/20',
textClass: 'text-gray-300',
icon: 'fas fa-flag-checkered',
label: 'Released'
};
default:
return {
color: 'gray',
bgClass: 'bg-gray-500/10 border-gray-500/20',
textClass: 'text-gray-400',
icon: 'fas fa-question',
label: 'Unknown'
};
}
};
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">
Development Roadmap
</h3>
<p key="subtitle" className="text-secondary max-w-2xl mx-auto mb-6">
Evolution of LockBit.chat: from initial development to a quantum-resistant decentralized network
</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">
Click on a version for details
</span>
</div>
</div>
<div key="roadmap-container" className="max-w-6xl mx-auto">
<div key="timeline" className="relative">
{/* The line has been removed */}
<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">
{/* The dots are visible only on sm and larger screens */}
<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"
/>
Key features:
</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"
>
Join the future of privacy
</h4>
<p key="cta-description" className="text-secondary mb-6">
LockBit.chat grows thanks to the community. Your ideas and feedback help shape the future of secure communication.
</p>
<div
key="cta-buttons"
className="flex flex-col sm:flex-row gap-4 justify-center"
>
<a
key="github-link"
href="https://github.com/lockbitchat/lockbit-chat/"
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" />
Feedback
</a>
</div>
</div>
</div>
</div>
);
}
// Enhanced Header Component with verification status
const EnhancedMinimalHeader = ({ status, fingerprint, verificationCode, onDisconnect, isConnected, securityLevel, sessionManager, sessionTimeLeft }) => {
const getStatusConfig = () => {
switch (status) {
case 'connected':
return {
text: 'Connected',
className: 'status-connected',
badgeClass: 'bg-green-500/10 text-green-400 border-green-500/20'
};
case 'verifying':
return {
text: 'Verifying...',
className: 'status-verifying',
badgeClass: 'bg-purple-500/10 text-purple-400 border-purple-500/20'
};
case 'connecting':
return {
text: 'Connecting...',
className: 'status-connecting',
badgeClass: 'bg-blue-500/10 text-blue-400 border-blue-500/20'
};
case 'retrying':
return {
text: 'Reconnecting...',
className: 'status-connecting',
badgeClass: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20'
};
case 'failed':
return {
text: 'Error',
className: 'status-failed',
badgeClass: 'bg-red-500/10 text-red-400 border-red-500/20'
};
case 'reconnecting':
return {
text: 'Reconnecting...',
className: 'status-connecting',
badgeClass: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20'
};
case 'peer_disconnected':
return {
text: 'Peer disconnected',
className: 'status-failed',
badgeClass: 'bg-orange-500/10 text-orange-400 border-orange-500/20'
};
default:
return {
text: 'Not connected',
className: 'status-disconnected',
badgeClass: 'bg-gray-500/10 text-gray-400 border-gray-500/20'
};
}
};
const config = getStatusConfig();
return React.createElement('header', {
className: 'header-minimal sticky top-0 z-50'
}, [
React.createElement('div', {
key: 'container',
className: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8'
}, [
React.createElement('div', {
key: 'content',
className: 'flex items-center justify-between h-16'
}, [
// Logo and Title - Mobile Responsive
React.createElement('div', {
key: 'logo-section',
className: 'flex items-center space-x-2 sm:space-x-3'
}, [
React.createElement('div', {
key: 'logo',
className: 'icon-container w-8 h-8 sm:w-10 sm:h-10'
}, [
React.createElement('i', {
className: 'fas fa-shield-halved accent-orange text-sm sm:text-base'
})
]),
React.createElement('div', {
key: 'title-section'
}, [
React.createElement('h1', {
key: 'title',
className: 'text-lg sm:text-xl font-semibold text-primary'
}, 'LockBit.chat'),
React.createElement('p', {
key: 'subtitle',
className: 'text-xs sm:text-sm text-muted hidden sm:block'
}, 'End-to-end freedom')
])
]),
// Status and Controls - Mobile Responsive
React.createElement('div', {
key: 'status-section',
className: 'flex items-center space-x-2 sm:space-x-3'
}, [
// Session Timer — show only if there is an active session
sessionManager?.hasActiveSession() && React.createElement(SessionTimer, {
key: 'session-timer',
timeLeft: sessionTimeLeft,
sessionType: sessionManager.currentSession?.type || 'unknown'
}),
// Security Level Indicator - Hidden on mobile, shown on tablet+ (Clickable)
securityLevel && React.createElement('div', {
key: 'security-level',
className: 'hidden md:flex items-center space-x-2 cursor-pointer hover:opacity-80 transition-opacity duration-200',
onClick: () => {
if (securityLevel.verificationResults) {
console.log('Security verification results:', securityLevel.verificationResults);
alert('Security check details:\n\n' +
Object.entries(securityLevel.verificationResults)
.map(([key, result]) => `${key}: ${result.passed ? '✅' : '❌'} ${result.details}`)
.join('\n')
);
}
},
title: 'Click to view security details'
}, [
React.createElement('div', {
key: 'security-icon',
className: `w-6 h-6 rounded-full flex items-center justify-center ${
securityLevel.color === 'green' ? 'bg-green-500/20' :
securityLevel.color === 'yellow' ? 'bg-yellow-500/20' : 'bg-red-500/20'
}`
}, [
React.createElement('i', {
className: `fas fa-shield-alt text-xs ${
securityLevel.color === 'green' ? 'text-green-400' :
securityLevel.color === 'yellow' ? 'text-yellow-400' : 'text-red-400'
}`
})
]),
React.createElement('div', {
key: 'security-info',
className: 'flex flex-col'
}, [
React.createElement('div', {
key: 'security-level-text',
className: 'text-xs font-medium text-primary'
}, `${securityLevel.level} (${securityLevel.score}%)`),
securityLevel.details && React.createElement('div', {
key: 'security-details',
className: 'text-xs text-muted mt-1 hidden lg:block'
}, securityLevel.details),
React.createElement('div', {
key: 'security-progress',
className: 'w-16 h-1 bg-gray-600 rounded-full overflow-hidden'
}, [
React.createElement('div', {
key: 'progress-bar',
className: `h-full transition-all duration-500 ${
securityLevel.color === 'green' ? 'bg-green-400' :
securityLevel.color === 'yellow' ? 'bg-yellow-400' : 'bg-red-400'
}`,
style: { width: `${securityLevel.score}%` }
})
])
])
]),
// Mobile Security Indicator - Only icon on mobile (Clickable)
securityLevel && React.createElement('div', {
key: 'mobile-security',
className: 'md:hidden flex items-center'
}, [
React.createElement('div', {
key: 'mobile-security-icon',
className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer hover:opacity-80 transition-opacity duration-200 ${
securityLevel.color === 'green' ? 'bg-green-500/20' :
securityLevel.color === 'yellow' ? 'bg-yellow-500/20' : 'bg-red-500/20'
}`,
title: `${securityLevel.level} (${securityLevel.score}%) - Нажмите для деталей`,
onClick: () => {
if (securityLevel.verificationResults) {
console.log('Security verification results:', securityLevel.verificationResults);
alert('Детали проверки безопасности:\n\n' +
Object.entries(securityLevel.verificationResults)
.map(([key, result]) => `${key}: ${result.passed ? '✅' : '❌'} ${result.details}`)
.join('\n')
);
}
}
}, [
React.createElement('i', {
className: `fas fa-shield-alt text-sm ${
securityLevel.color === 'green' ? 'text-green-400' :
securityLevel.color === 'yellow' ? 'text-yellow-400' : 'text-red-400'
}`
})
])
]),
// Status Badge - Compact on mobile
React.createElement('div', {
key: 'status-badge',
className: `px-2 sm:px-3 py-1.5 rounded-lg border ${config.badgeClass} flex items-center space-x-1 sm:space-x-2`
}, [
React.createElement('span', {
key: 'status-dot',
className: `status-dot ${config.className}`
}),
React.createElement('span', {
key: 'status-text',
className: 'text-xs sm:text-sm font-medium'
}, config.text)
]),
// Disconnect Button - Icon only on mobile
isConnected && React.createElement('button', {
key: 'disconnect-btn',
onClick: onDisconnect,
className: 'p-1.5 sm:px-3 sm:py-1.5 bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 rounded-lg transition-all duration-200 text-sm'
}, [
React.createElement('i', {
key: 'disconnect-icon',
className: 'fas fa-power-off sm:mr-2'
}),
React.createElement('span', {
key: 'disconnect-text',
className: 'hidden sm:inline'
}, 'Disconnect')
])
])
])
]),
]);
};
// 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`
}),
copied ? 'Copied!' : children
]);
};
// 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"
}, "Security verification")
]),
React.createElement('div', {
key: 'content',
className: "space-y-4"
}, [
React.createElement('p', {
key: 'description',
className: "text-secondary text-sm"
}, "Verify the security code with your contact via another communication channel (voice, SMS, etc.):"),
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'
}),
'Make sure the codes match exactly.!'
])
]),
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'
}),
'The codes match'
]),
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'
}),
'The codes do not match'
])
])
])
]);
};
// 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",
label: "Encrypted"
};
case 'received':
return {
container: "mr-auto card-minimal text-primary",
icon: "fas fa-unlock-alt accent-green",
label: "Decrypted"
};
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",
label: "System"
};
default:
return {
container: "mx-auto card-minimal text-secondary",
icon: "fas fa-circle text-muted",
label: "Unknown"
};
}
};
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"
}, 'Start secure communication'),
React.createElement('p', {
key: 'subtitle',
className: "text-secondary max-w-2xl mx-auto"
}, "Choose a connection method for a secure channel with ECDH encryption and Perfect Forward Secrecy.")
]),
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"
}, "Create channel"),
React.createElement('p', {
key: 'description',
className: "text-secondary text-center text-sm mb-4"
}, "Initiate a new secure connection with encrypted exchange"),
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'
}),
'Generating ECDH keys'
]),
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'
}),
'Verification code'
]),
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'
}),
'PFS key rotation'
])
])
]),
// 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"
}, "Join"),
React.createElement('p', {
key: 'description',
className: "text-secondary text-center text-sm mb-4"
}, "Connect to an existing secure channel"),
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'
}),
'Paste Offer invitation'
]),
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'
}),
'Automatic verification'
]),
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'
}),
'PFS protection'
])
])
])
]),
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" }, [
React.createElement('i', { className: 'fas fa-exchange-alt accent-green' })
]),
React.createElement('h4', { key: 'title', className: "text-xs sm:text-sm font-medium text-primary mb-1" }, "ECDH Key Exchange"),
React.createElement('p', { key: 'desc', className: "text-xs text-muted leading-tight" }, "Secure key exchange")
]),
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" }, [
React.createElement('i', { className: 'fas fa-shield-alt accent-purple' })
]),
React.createElement('h4', { key: 'title', className: "text-xs sm:text-sm font-medium text-primary mb-1" }, "Out-of-Band Verification"),
React.createElement('p', { key: 'desc', className: "text-xs text-muted leading-tight" }, "MITM attack protection")
]),
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' })
]),
React.createElement('h4', { key: 'title', className: "text-xs sm:text-sm font-medium text-primary mb-1" }, "Encryption"),
React.createElement('p', { key: 'desc', className: "text-xs text-muted leading-tight" }, "Encryption + Authentication")
]),
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"),
React.createElement('p', { key: 'desc', className: "text-xs text-muted leading-tight" }, "Automatic Key Rotation")
]),
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" }, [
React.createElement('i', { className: 'fas fa-fingerprint accent-blue' })
]),
React.createElement('h4', { key: 'title', className: "text-xs sm:text-sm font-medium text-primary mb-1" }, "Digital Signatures"),
React.createElement('p', { key: 'desc', className: "text-xs text-muted leading-tight" }, "ECDSA Message Verification")
]),
React.createElement('div', { key: 'feature6', 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-red-500/10 border border-red-500/20 rounded-lg flex items-center justify-center mx-auto mb-2 sm:mb-3" }, [
React.createElement('i', { className: 'fas fa-ban accent-red' })
]),
React.createElement('h4', { key: 'title', className: "text-xs sm:text-sm font-medium text-primary mb-1" }, "Interception Protection"),
React.createElement('p', { key: 'desc', className: "text-xs text-muted leading-tight" }, "Encrypted Data Exchange")
])
]),
// 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"
}, "Supported Lightning wallets"),
React.createElement('p', {
key: 'subtitle',
className: "text-secondary text-sm"
}, "To pay for sessions, use any of the popular wallets.")
]),
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' }),
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'
}),
'Back to selection'
]),
React.createElement('h2', {
key: 'title',
className: "text-xl font-semibold text-primary mb-2"
}, 'Creating a secure channel')
]),
// 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"
}, "Generating ECDH keys and verification code")
]),
React.createElement('p', {
key: 'description',
className: "text-secondary text-sm mb-4"
}, "Creating cryptographically strong keys and codes to protect against attacks"),
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'
}),
showOfferStep ? 'Keys created ✓' : 'Create secure keys'
]),
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'
}),
'Encrypted invitation created! Send the code and password to your contact.:'
]),
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"
}, '🔑 Decryption password:'),
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"
}, 'Copy')
])
])
]),
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"
}, 'Copy encrypted code')
])
])
]),
// Step 2
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"
}, "Waiting for the peer's response")
]),
React.createElement('p', {
key: 'description',
className: "text-secondary text-sm mb-4"
}, "Paste the encrypted invitation code from your contact."),
React.createElement('textarea', {
key: 'input',
value: answerInput,
onChange: (e) => setAnswerInput(e.target.value),
rows: 6,
placeholder: "Paste the encrypted response code from your contact...",
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'
}),
'Establish connection'
])
])
])
]);
}
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'
}),
'Back to selection'
]),
React.createElement('h2', {
key: 'title',
className: "text-xl font-semibold text-primary mb-2"
}, 'Joining the secure channel')
]),
// 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"
}, "Paste secure invitation")
]),
React.createElement('p', {
key: 'description',
className: "text-secondary text-sm mb-4"
}, "Copy and paste the encrypted invitation code from the initiator."),
React.createElement('textarea', {
key: 'input',
value: offerInput,
onChange: (e) => setOfferInput(e.target.value),
rows: 8,
placeholder: "Paste the encrypted invitation code...",
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'
}),
'Process the invitation'
])
]),
// 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"
}, "Sending a secure response")
]),
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'
}),
'Encrypted response created! Send this code to the initiator.:'
]),
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"
}, '🔑 Password for decryption:'),
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"
}, 'Copy')
])
])
]),
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"
}, 'Copy the encrypted response')
]),
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'
}),
'The connection will be established with verification'
])
])
])
])
]);
}
};
// Enhanced Chat Interface with better security indicators
const EnhancedChatInterface = ({
messages,
messageInput,
setMessageInput,
onSendMessage,
onDisconnect,
keyFingerprint,
isVerified,
chatMessagesRef,
scrollToBottom
}) => {
const [showScrollButton, setShowScrollButton] = React.useState(false);
React.useEffect(() => {
if (chatMessagesRef.current) {
// Smooth scroll down
chatMessagesRef.current.scrollTo({
top: chatMessagesRef.current.scrollHeight,
behavior: 'smooth'
});
}
}, [messages]);
// Scroll handler to show the button
const handleScroll = () => {
if (chatMessagesRef.current) {
const { scrollTop, scrollHeight, clientHeight } = chatMessagesRef.current;
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
setShowScrollButton(!isNearBottom);
}
};
// Wrapper for scrollToBottom with button state update
const handleScrollToBottom = () => {
scrollToBottom();
setShowScrollButton(false);
};
const handleKeyPress = (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
onSendMessage();
}
};
return React.createElement('div', {
className: "chat-container"
}, [
// Chat Messages Area
React.createElement('div', {
key: 'chat-body',
className: "chat-messages-area max-w-4xl mx-auto w-full p-4 relative"
}, [
React.createElement('div', {
key: 'messages-container',
ref: chatMessagesRef,
onScroll: handleScroll,
className: "h-full overflow-y-auto space-y-3 custom-scrollbar pr-2 scroll-smooth"
},
messages.length === 0 ?
React.createElement('div', {
key: 'empty-state',
className: "flex items-center justify-center h-full"
}, [
React.createElement('div', {
className: "text-center max-w-md"
}, [
React.createElement('div', {
key: 'icon',
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('i', {
className: 'fas fa-comments text-2xl accent-green'
})
]),
React.createElement('h3', {
key: 'title',
className: "text-lg font-medium text-primary mb-2"
}, "Secure channel is ready!"),
React.createElement('p', {
key: 'description',
className: "text-secondary text-sm mb-4"
}, "All messages are protected by modern cryptographic algorithms"),
React.createElement('div', {
key: 'features',
className: "text-left space-y-2"
}, [
React.createElement('div', {
key: 'f1',
className: "flex items-center text-sm text-muted"
}, [
React.createElement('i', {
className: 'fas fa-check accent-green mr-3'
}),
'End-to-end encryption'
]),
React.createElement('div', {
key: 'f2',
className: "flex items-center text-sm text-muted"
}, [
React.createElement('i', {
className: 'fas fa-check accent-green mr-3'
}),
'Protection against replay attacks'
]),
React.createElement('div', {
key: 'f3',
className: "flex items-center text-sm text-muted"
}, [
React.createElement('i', {
className: 'fas fa-check accent-green mr-3'
}),
'Integrity verification'
]),
React.createElement('div', {
key: 'f4',
className: "flex items-center text-sm text-muted"
}, [
React.createElement('i', {
className: 'fas fa-sync-alt accent-purple mr-3'
}),
'Perfect Forward Secrecy'
])
])
])
]) :
messages.map((msg) =>
React.createElement(EnhancedChatMessage, {
key: msg.id,
message: msg.message,
type: msg.type,
timestamp: msg.timestamp
})
)
)
]),
// Scroll down button
showScrollButton && React.createElement('button', {
key: 'scroll-down-btn',
onClick: handleScrollToBottom,
className: "absolute bottom-4 right-4 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 shadow-lg",
style: { zIndex: 10 }
}, [
React.createElement('i', {
className: 'fas fa-chevron-down'
})
]),
// Enhanced Chat Input Area
React.createElement('div', {
key: 'chat-input',
className: "chat-input-area border-t border-gray-500/10"
}, [
React.createElement('div', {
key: 'input-container',
className: "max-w-4xl mx-auto p-4"
}, [
React.createElement('div', {
key: 'input-wrapper',
className: "flex items-end space-x-3"
}, [
React.createElement('div', {
key: 'text-area-wrapper',
className: "flex-1 relative"
}, [
React.createElement('textarea', {
key: 'input',
value: messageInput,
onChange: (e) => setMessageInput(e.target.value),
onKeyDown: handleKeyPress,
placeholder: "Enter message to encrypt...",
rows: 2,
maxLength: 2000,
className: "w-full p-3 bg-gray-900/30 border border-gray-500/20 rounded-lg resize-none text-primary placeholder-gray-500 focus:border-green-500/40 focus:outline-none transition-all custom-scrollbar text-sm"
}),
React.createElement('div', {
key: 'input-info',
className: "absolute bottom-2 right-3 flex items-center space-x-2 text-xs text-muted"
}, [
React.createElement('span', {
key: 'counter'
}, `${messageInput.length}/2000`),
React.createElement('span', {
key: 'hint'
}, "• Enter to send")
])
]),
React.createElement('button', {
key: 'send',
onClick: onSendMessage,
disabled: !messageInput.trim(),
className: "security-shield text-white p-3 rounded-lg transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
}, [
React.createElement('i', {
className: 'fas fa-paper-plane'
})
])
])
])
])
]);
};
// Main Enhanced Application Component
const EnhancedSecureP2PChat = () => {
const [messages, setMessages] = React.useState([]);
const [connectionStatus, setConnectionStatus] = React.useState('disconnected');
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
const [sessionManager] = React.useState(() => new PayPerSessionManager());
const [showPaymentModal, setShowPaymentModal] = React.useState(false);
const [sessionTimeLeft, setSessionTimeLeft] = React.useState(0);
const [pendingSession, setPendingSession] = React.useState(null); // { type, preimage }
const webrtcManagerRef = React.useRef(null);
// Update security level based on real verification
const updateSecurityLevel = React.useCallback(async () => {
if (webrtcManagerRef.current) {
try {
const level = await webrtcManagerRef.current.calculateSecurityLevel();
setSecurityLevel(level);
} catch (error) {
console.error('Failed to update security level:', error);
setSecurityLevel({
level: 'ERROR',
score: 0,
color: 'red',
details: 'Verification failed'
});
}
}
}, []);
// Session time ticker
React.useEffect(() => {
const timer = setInterval(() => {
if (sessionManager.hasActiveSession()) {
setSessionTimeLeft(sessionManager.getTimeLeft());
} else {
setSessionTimeLeft(0);
}
}, 1000);
return () => clearInterval(timer);
}, [sessionManager]);
// Session expiration handler
React.useEffect(() => {
sessionManager.onSessionExpired = () => {
setMessages(prev => [...prev, {
message: '⏰ Session time expired. The connection will be terminated.',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
setTimeout(() => handleDisconnect(), 3000);
};
}, [sessionManager]);
const chatMessagesRef = React.useRef(null);
// Scroll down function
const scrollToBottom = () => {
if (chatMessagesRef.current) {
setTimeout(() => {
chatMessagesRef.current.scrollTo({
top: chatMessagesRef.current.scrollHeight,
behavior: 'smooth'
});
}, 100);
}
};
// 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(() => {
const handleMessage = (message, type) => {
setMessages(prev => [...prev, {
message,
type,
id: Date.now() + Math.random(),
timestamp: Date.now()
}]);
// Scroll on receiving a new message
setTimeout(scrollToBottom, 100);
};
const handleStatusChange = (status) => {
setConnectionStatus(status);
if (status === 'connected') {
setIsVerified(true);
setShowVerification(false);
updateSecurityLevel().catch(console.error);
} else if (status === 'verifying') {
setShowVerification(true);
updateSecurityLevel().catch(console.error);
} else if (status === 'connecting') {
updateSecurityLevel().catch(console.error);
} else if (status === 'disconnected') {
// Complete UI reset on disconnect
setKeyFingerprint('');
setVerificationCode('');
setSecurityLevel(null);
setIsVerified(false);
setShowVerification(false);
} else if (status === 'peer_disconnected') {
// A short delay before clearing to display the status
setTimeout(() => {
setKeyFingerprint('');
setVerificationCode('');
setSecurityLevel(null);
setIsVerified(false);
setShowVerification(false);
}, 2000);
}
};
const handleKeyExchange = (fingerprint) => {
if (fingerprint === '') {
setKeyFingerprint('');
} else {
setKeyFingerprint(fingerprint);
}
};
const handleVerificationRequired = (code) => {
if (code === '') {
setVerificationCode('');
} else {
setVerificationCode(code);
}
};
// Callback for handling response errors
const handleAnswerError = (errorType, errorMessage) => {
console.log('Answer error callback:', errorType, errorMessage);
if (errorType === 'replay_attack') {
// Reset the session upon replay attack
if (sessionManager.hasActiveSession()) {
sessionManager.resetSession();
setSessionTimeLeft(0);
}
setPendingSession(null);
setMessages(prev => [...prev, {
message: '💡 Data is outdated. Please create a new invitation or use a current response code.',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
} else if (errorType === 'security_violation') {
// Reset the session upon security breach
if (sessionManager.hasActiveSession()) {
sessionManager.resetSession();
setSessionTimeLeft(0);
}
setPendingSession(null);
setMessages(prev => [...prev, {
message: `🔒 Security breach: ${errorMessage}`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
}
};
webrtcManagerRef.current = new EnhancedSecureWebRTCManager(
handleMessage,
handleStatusChange,
handleKeyExchange,
handleVerificationRequired,
handleAnswerError
);
handleMessage('🚀 LockBit.chat Enhanced Edition initialized. Ready to establish a secure connection with ECDH, encrypted exchange, and verification.', 'system');
// Cleanup on page unload
const handleBeforeUnload = () => {
if (webrtcManagerRef.current) {
webrtcManagerRef.current.disconnect();
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
if (webrtcManagerRef.current) {
webrtcManagerRef.current.disconnect();
}
};
}, []);
const ensureActiveSessionOrPurchase = async () => {
if (sessionManager.hasActiveSession()) return true;
if (pendingSession) return true;
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);
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()
}]);
updateSecurityLevel().catch(console.error);
} catch (error) {
setMessages(prev => [...prev, {
message: `❌ Error creating invitation: ${error.message}`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
}
};
const handleCreateAnswer = async () => {
try {
if (!offerInput.trim()) {
setMessages(prev => [...prev, {
message: '⚠️ You need to insert the encrypted invitation code from your interlocutor.',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
return;
}
// Show password modal for offer decryption
showPasswordPrompt('offer', async (password) => {
if (!password) {
setMessages(prev => [...prev, {
message: '❌ Password not entered',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
return;
}
try {
setMessages(prev => [...prev, {
message: '🔄 Decrypting and processing the secure invitation...',
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) {
throw new Error(`Decryption error: ${decryptError.message}`);
}
if (!offer || typeof offer !== 'object') {
throw new Error('The invitation must be an object');
}
if (!offer.type || offer.type !== 'enhanced_secure_offer') {
throw new Error('Invalid invitation type. Expected enhanced_secure_offer');
}
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);
setMessages(prev => [...prev, {
message: '✅ Secure response created and encrypted!',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
setMessages(prev => [...prev, {
message: '📤 Send the encrypted response code and password to the initiator via a secure channel..',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
// Update security level after creating answer
updateSecurityLevel().catch(console.error);
} catch (error) {
console.error('Error in handleCreateAnswer:', error);
setMessages(prev => [...prev, {
message: `❌ Error processing the invitation: ${error.message}`,
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, {
message: `❌ Invitation processing error: ${error.message}`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
}
};
const handleConnect = async () => {
try {
if (!answerInput.trim()) {
setMessages(prev => [...prev, {
message: '⚠️ You need to insert the encrypted response code from your interlocutor.',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
return;
}
// Show password modal for answer decryption
showPasswordPrompt('answer', async (password) => {
if (!password) {
setMessages(prev => [...prev, {
message: '❌ Password not entered',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
return;
}
try {
setMessages(prev => [...prev, {
message: '🔄 Decrypting and processing the secure response...',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
let answer;
try {
// Decrypt the answer data
answer = await EnhancedSecureCryptoUtils.decryptData(answerInput.trim(), password);
} catch (decryptError) {
throw new Error(`Decryption error: ${decryptError.message}`);
}
if (!answer || typeof answer !== 'object') {
throw new Error('The response must be an object');
}
if (!answer.type || answer.type !== 'enhanced_secure_answer') {
throw new Error('Invalid response type. Expected enhanced\_secure\_answer');
}
await webrtcManagerRef.current.handleSecureAnswer(answer);
if (sessionManager.canActivateSession() && pendingSession) {
const result = sessionManager.safeActivateSession(pendingSession.type, pendingSession.preimage, pendingSession.paymentHash);
if (result.success) {
setPendingSession(null);
setSessionTimeLeft(sessionManager.getTimeLeft());
setMessages(prev => [...prev, {
message: `💰 Session activated on ${sessionManager.sessionPrices[pendingSession.type].hours}ч (${result.method})`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
} else {
setMessages(prev => [...prev, {
message: `❌ Session activation error: ${result.reason}`,
type: 'error',
id: Date.now(),
timestamp: Date.now()
}]);
}
}
setMessages(prev => [...prev, {
message: '🔄 Finalizing the secure connection...',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
// Update security level after handling answer
updateSecurityLevel().catch(console.error);
} catch (error) {
setMessages(prev => [...prev, {
message: `❌ Connection setup error: ${error.message}`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
if (!error.message.includes('Too old') && !error.message.includes('too old')) {
setPendingSession(null);
}
}
});
return;
} catch (error) {
setMessages(prev => [...prev, {
message: `❌ Connection setup error: ${error.message}`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
if (!error.message.includes('сToo old') && !error.message.includes('too old')) {
setPendingSession(null);
}
}
};
const handleVerifyConnection = (isValid) => {
if (isValid) {
webrtcManagerRef.current.confirmVerification();
} else {
setMessages(prev => [...prev, {
message: '❌ Verification rejected. The connection is unsafe! Session reset..',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
sessionManager.resetSession();
setSessionTimeLeft(0);
setPendingSession(null);
handleDisconnect();
}
};
const handleSendMessage = async () => {
if (!messageInput.trim() || !webrtcManagerRef.current.isConnected()) {
return;
}
try {
await webrtcManagerRef.current.sendSecureMessage(messageInput);
setMessageInput('');
setTimeout(scrollToBottom, 50);
} catch (error) {
setMessages(prev => [...prev, {
message: `❌ Sending error: ${error.message}`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
setTimeout(scrollToBottom, 50);
}
};
const handleClearData = () => {
setOfferData('');
setAnswerData('');
setOfferInput('');
setAnswerInput('');
setShowOfferStep(false);
setShowAnswerStep(false);
setShowVerification(false);
setVerificationCode('');
setIsVerified(false);
setKeyFingerprint('');
setSecurityLevel(null);
setConnectionStatus('disconnected');
setMessages([]);
setMessageInput('');
setOfferPassword('');
setAnswerPassword('');
if (typeof console.clear === 'function') {
console.clear();
}
// Cleanup pay-per-session state
sessionManager.cleanup();
setSessionTimeLeft(0);
setShowPaymentModal(false);
};
const handleDisconnect = () => {
// Cleanup pay-per-session state
sessionManager.cleanup();
setSessionTimeLeft(0);
setShowPaymentModal(false);
webrtcManagerRef.current.disconnect();
setKeyFingerprint('');
setVerificationCode('');
setSecurityLevel(null);
setIsVerified(false);
setShowVerification(false);
setMessages(prev => [...prev, {
message: '🔌 Secure connection terminated',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
handleClearData();
};
const handleSessionActivated = (session) => {
setMessages(prev => [...prev, {
message: `💰 Session activated for \${sessionManager.sessionPrices\[session.type].hours}h. You can create invitations!`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
};
React.useEffect(() => {
if (connectionStatus === 'connected' && isVerified) {
setMessages(prev => [...prev, {
message: '🎉 Secure connection successfully established and verified! You can now communicate safely with full protection against MITM attacks and Perfect Forward Secrecy..',
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
setTimeout(scrollToBottom, 200);
}
}, [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);
setSessionTimeLeft(sessionManager.getTimeLeft());
setMessages(prev => [...prev, {
message: `💰 Session activated for \${sessionManager.sessionPrices\[pendingSession.type].hours}h (\${result.method})`,
type: 'system',
id: Date.now(),
timestamp: Date.now()
}]);
} else {
setMessages(prev => [...prev, {
message: `❌ Session activation error: ${result.reason}`,
type: 'error',
id: Date.now(),
timestamp: Date.now()
}]);
}
}
}, [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,
scrollToBottom: scrollToBottom
})
: 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();
const [cryptoModule, webrtcModule, paymentModule] = await Promise.all([
import(`./src/crypto/EnhancedSecureCryptoUtils.js?v=${timestamp}`),
import(`./src/network/EnhancedSecureWebRTCManager.js?v=${timestamp}`),
import(`./src/session/PayPerSessionManager.js?v=${timestamp}`)
]);
const { EnhancedSecureCryptoUtils } = cryptoModule;
window.EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils;
const { EnhancedSecureWebRTCManager } = webrtcModule;
window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager;
const { PayPerSessionManager } = paymentModule;
window.PayPerSessionManager = PayPerSessionManager;
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);
} 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'),
loadReactComponent('./src/components/ui/PaymentModal.jsx', 'PaymentModal')
]);
if (typeof initializeApp === 'function') {
initializeApp();
} else {
console.error('❌ Function initializeApp not found');
}
} catch (error) {
console.error('❌ Module loading error:', error);
}
</script>
</body>
</html>