From bf5d43b2f1e588031518789d2e718a5ae18405c1 Mon Sep 17 00:00:00 2001 From: lockbitchat Date: Mon, 28 Sep 2026 01:23:50 -0400 Subject: [PATCH] v6.8.15: the Android app is out for testing - Android APK download, served from securebit.chat (/downloads/, never committed): a "Download Android APK" badge next to the Snap Store one, drawn for both themes, and an Android entry in the download menu (recommended on Android devices). nginx serves .apk as an attachment; the service worker leaves /downloads/ alone. The APK version is one constant in three places, checked by tests/desktop-download-links.test.mjs. - Roadmap versions follow the real releases: Group Communications v6.0 shipped, Mobile Edition v6.8 is current, Quantum-Resistant v7.0 is in development (2027), then v8.0 and v9.0. - "Download desktop app" is now "Download the app"; the "You're on Web" pill in the download menu is gone. --- .gitignore | 3 + CHANGELOG.md | 7 +++ README.md | 2 +- ar/index.html | 44 +++++++-------- assets/badges/android-apk.svg | 56 +++++++++++++++++++ de/index.html | 44 +++++++-------- deploy/nginx.conf | 10 ++++ dist/app-boot.js | 22 ++++---- dist/app-boot.js.map | 6 +- dist/app.js | 14 ++--- dist/app.js.map | 4 +- doc/CRYPTOGRAPHY.md | 4 +- docs/cryptography/index.html | 4 +- es/index.html | 44 +++++++-------- fa/index.html | 44 +++++++-------- fr/index.html | 44 +++++++-------- he/index.html | 44 +++++++-------- hi/index.html | 44 +++++++-------- index.html | 42 +++++++------- ko/index.html | 44 +++++++-------- locales/ar.json | 11 ++-- locales/de.json | 11 ++-- locales/en.json | 11 ++-- locales/es.json | 11 ++-- locales/fa.json | 11 ++-- locales/fr.json | 9 ++- locales/he.json | 11 ++-- locales/hi.json | 11 ++-- locales/ko.json | 11 ++-- locales/ru.json | 9 ++- locales/uk.json | 9 ++- locales/ur.json | 11 ++-- locales/zh.json | 11 ++-- meta.json | 14 ++--- package.json | 2 +- ru/index.html | 44 +++++++-------- sitemap.xml | 46 ++++++++-------- src/app.jsx | 30 ++++++++-- src/components/ui/CommunityCTA.jsx | 79 +++++++++++++++++++-------- src/components/ui/DownloadApps.jsx | 6 +- src/components/ui/Roadmap.jsx | 10 ++-- src/i18n/dict/ar.js | 11 ++-- src/i18n/dict/de.js | 11 ++-- src/i18n/dict/en.js | 11 ++-- src/i18n/dict/es.js | 11 ++-- src/i18n/dict/fa.js | 11 ++-- src/i18n/dict/fr.js | 9 ++- src/i18n/dict/he.js | 11 ++-- src/i18n/dict/hi.js | 11 ++-- src/i18n/dict/ko.js | 11 ++-- src/i18n/dict/ru.js | 9 ++- src/i18n/dict/uk.js | 9 ++- src/i18n/dict/ur.js | 11 ++-- src/i18n/dict/zh.js | 11 ++-- sw.js | 8 ++- tests/desktop-download-links.test.mjs | 21 +++++++ uk/index.html | 44 +++++++-------- ur/index.html | 44 +++++++-------- zh/index.html | 44 +++++++-------- 59 files changed, 663 insertions(+), 529 deletions(-) create mode 100644 assets/badges/android-apk.svg diff --git a/.gitignore b/.gitignore index e752168..94afb2d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ audit/ .agents/ .claude/ skills-lock.json + +# Android APKs are served from the Fly image, never committed (45 MB each). +downloads/*.apk diff --git a/CHANGELOG.md b/CHANGELOG.md index 097bb00..fe68dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v6.8.15 — Android app for testing + +The Android app is now available for testing. Download the APK with the "Download +Android APK" button at the bottom of the page, or from the download menu. The +roadmap is updated too: mobile apps are now the current step, and the +quantum-resistant edition is in development. + ## v6.8.14 — Desktop 1.0.6 downloads The download buttons now give you desktop version 1.0.6, which adds a light theme diff --git a/README.md b/README.md index 4e3c736..6b3b155 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ No accounts. No servers storing your messages. No installation required. [![License: MIT](https://img.shields.io/badge/License-MIT-f0892a.svg)](LICENSE) -[![Version](https://img.shields.io/badge/version-6.8.14-3ecf8e.svg)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-6.8.15-3ecf8e.svg)](CHANGELOG.md) [![Get it from the Snap Store](https://snapcraft.io/securebit-chat/badge.svg)](https://snapcraft.io/securebit-chat) [![PWA](https://img.shields.io/badge/PWA-installable-3ecf8e.svg)](#install-as-an-app) [![Encryption](https://img.shields.io/badge/crypto-ECDH%20P--384%20%C2%B7%20AES--256--GCM-blue.svg)](#security-model) diff --git a/ar/index.html b/ar/index.html index 9d1d225..73ade5d 100644 --- a/ar/index.html +++ b/ar/index.html @@ -30,18 +30,18 @@ - + - + - + @@ -116,7 +116,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -264,7 +264,7 @@ - + - - + + - + - + - + - - + + - + - + - + @@ -116,7 +116,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -264,7 +264,7 @@ - + - - + + - + - + - + - - + + "),typeof C!="string"&&!ut(C)&&(C=xs(C),typeof C!="string"))throw $e("dirty is not a string, aborting");if(!e.isSupported)return C;rr||hr(l),e.removed=[];let $=sr&&typeof C!="string"&&ut(C);if($){let we=E?E(C):C.nodeName;if(typeof we=="string"){let Ee=re(we);if(!X[Ee]||ct[Ee])throw $e("root node is forbidden and cannot be sanitized in-place")}if(xt(C))throw $e("root node is clobbered and cannot be sanitized in-place");try{pr(C)}catch(Ee){throw hi(C),Ee}}else if(ut(C))y=fi(""),v=y.ownerDocument.importNode(C,!0),v.nodeType===ke.element&&v.nodeName==="BODY"||v.nodeName==="HTML"?y=v:y.appendChild(v),pr(v);else{if(!Xe&&!Le&&!Be&&C.indexOf("<")===-1)return _&&Tt?R(C):C;if(y=fi(C),!y)return Xe?null:Tt?A:""}y&&ir&&De(y.firstChild);let ae=pi($?C:y);try{for(;L=ae.nextNode();)yi(L),Si(L),et(L.content)&&It(L.content)}catch(we){throw $&&hi(C),we}if($)return ht(e.removed,we=>{we.element&&ts(we.element)}),Le&&fr(C),C;if(Xe){if(Le&&fr(y),vt)for(V=ge.call(y.ownerDocument);y.firstChild;)V.appendChild(y.firstChild);else V=y;return(ie.shadowroot||ie.shadowrootmode)&&(V=U.call(r,V,!0)),V}let ne=Be?y.outerHTML:y.innerHTML;return Be&&X["!doctype"]&&y.ownerDocument&&y.ownerDocument.doctype&&y.ownerDocument.doctype.name&&oe(Us,y.ownerDocument.doctype.name)&&(ne=" -`+ne),Le&&(ne=At(ne)),_&&Tt?R(ne):ne},e.setConfig=function(){let C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};hr(C),rr=!0},e.clearConfig=function(){Ze=null,rr=!1,_=x,A=""},e.isValidAttribute=function(C,l,y){Ze||hr({});let v=re(C),L=re(l);return gi(v,L,y)},e.addHook=function(C,l){typeof l=="function"&&tt(I[C],l)},e.removeHook=function(C,l){if(l!==void 0){let y=ws(I[C],l);return y===-1?void 0:Es(I[C],y,1)[0]}return Ti(I[C])},e.removeHooks=function(C){I[C]=[]},e.removeAllHooks=function(){I=Fi()},e}var Ui=Oi();var Mt=class s{static _keyMetadata=new WeakMap;static _messageSanitizer=null;static sortObjectKeys(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(s.sortObjectKeys);let t={};return Object.keys(e).sort().forEach(r=>{t[r]=s.sortObjectKeys(e[r])}),t}static assertCryptoKey(e,t=null,r=[]){if(!(e instanceof CryptoKey))throw new Error("Expected CryptoKey");if(t&&e.algorithm?.name!==t)throw new Error(`Expected algorithm ${t}, got ${e.algorithm?.name}`);for(let i of r)if(!e.usages||!e.usages.includes(i))throw new Error(`Missing required key usage: ${i}`)}static arrayBufferToBase64(e){let t="",r=new Uint8Array(e),i=r.byteLength;for(let n=0;n=4294967296-4294967296%t);i+=e[a%t]}return i}static async calculateSecurityLevel(e){let t=0,r=100,i={};try{if(!e||!e.securityFeatures)return console.warn("Security manager not fully initialized, using fallback calculation"),{level:"INITIALIZING",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:"Security system initializing...",isRealData:!1};let n="full",a=!1;try{let h=await s.verifyEncryption(e);h.passed?(t+=20,i.verifyEncryption={passed:!0,details:h.details,points:20}):i.verifyEncryption={passed:!1,details:h.details,points:0}}catch(h){i.verifyEncryption={passed:!1,details:`Encryption check failed: ${h.message}`,points:0}}try{let h=await s.verifyECDHKeyExchange(e);h.passed?(t+=15,i.verifyECDHKeyExchange={passed:!0,details:h.details,points:15}):i.verifyECDHKeyExchange={passed:!1,details:h.details,points:0}}catch(h){i.verifyECDHKeyExchange={passed:!1,details:`Key exchange check failed: ${h.message}`,points:0}}try{let h=await s.verifyMessageIntegrity(e);h.passed?(t+=10,i.verifyMessageIntegrity={passed:!0,details:h.details,points:10}):i.verifyMessageIntegrity={passed:!1,details:h.details,points:0}}catch(h){i.verifyMessageIntegrity={passed:!1,details:`Message integrity check failed: ${h.message}`,points:0}}try{let h=await s.verifyECDSASignatures(e);h.passed?(t+=15,i.verifyECDSASignatures={passed:!0,details:h.details,points:15}):i.verifyECDSASignatures={passed:!1,details:h.details,points:0}}catch(h){i.verifyECDSASignatures={passed:!1,details:`Digital signatures check failed: ${h.message}`,points:0}}try{let h=await s.verifyRateLimiting(e);h.passed?(t+=5,i.verifyRateLimiting={passed:!0,details:h.details,points:5}):i.verifyRateLimiting={passed:!1,details:h.details,points:0}}catch(h){i.verifyRateLimiting={passed:!1,details:`Rate limiting check failed: ${h.message}`,points:0}}try{let h=await s.verifyMetadataProtection(e);h.passed?(t+=10,i.verifyMetadataProtection={passed:!0,details:h.details,points:10}):i.verifyMetadataProtection={passed:!1,details:h.details,points:0}}catch(h){i.verifyMetadataProtection={passed:!1,details:`Metadata protection check failed: ${h.message}`,points:0}}try{let h=await s.verifyPerfectForwardSecrecy(e);h.passed?(t+=10,i.verifyPerfectForwardSecrecy={passed:!0,details:h.details,points:10}):i.verifyPerfectForwardSecrecy={passed:!1,details:h.details,points:0}}catch(h){i.verifyPerfectForwardSecrecy={passed:!1,details:`PFS check failed: ${h.message}`,points:0}}await s.verifyNestedEncryption(e)?(t+=5,i.nestedEncryption={passed:!0,details:"Nested encryption active",points:5}):i.nestedEncryption={passed:!1,details:"Nested encryption failed",points:0},await s.verifyPacketPadding(e)?(t+=5,i.packetPadding={passed:!0,details:"Packet padding active",points:5}):i.packetPadding={passed:!1,details:"Packet padding failed",points:0},await s.verifyAdvancedFeatures(e)?(t+=10,i.advancedFeatures={passed:!0,details:"Advanced features active",points:10}):i.advancedFeatures={passed:!1,details:"Advanced features failed",points:0};let o=Math.round(t/r*100),c=10,d=Object.values(i).filter(h=>h.passed).length;return{level:o>=85?"HIGH":o>=65?"MEDIUM":o>=35?"LOW":"CRITICAL",score:o,color:o>=85?"green":o>=65?"orange":o>=35?"yellow":"red",verificationResults:i,timestamp:Date.now(),details:`Real verification: ${t}/${r} security checks passed (${d}/${c} available)`,isRealData:!0,passedChecks:d,totalChecks:c,sessionType:n,maxPossibleScore:100}}catch(n){return console.error("Security level calculation failed:",n.message),{level:"UNKNOWN",score:0,color:"red",verificationResults:{},timestamp:Date.now(),details:`Verification failed: ${n.message}`,isRealData:!1}}}static async verifyEncryption(e){try{if(!e.encryptionKey)return{passed:!1,details:"No encryption key available"};let t=["Test encryption verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"A".repeat(1e3)];for(let r of t){let n=new TextEncoder().encode(r),a=crypto.getRandomValues(new Uint8Array(12)),o=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e.encryptionKey,n),c=await crypto.subtle.decrypt({name:"AES-GCM",iv:a},e.encryptionKey,o);if(new TextDecoder().decode(c)!==r)return{passed:!1,details:`Decryption mismatch for: ${r.substring(0,20)}...`}}return{passed:!0,details:"AES-GCM encryption/decryption working correctly"}}catch(t){return console.error("Encryption verification failed:",t.message),{passed:!1,details:`Encryption test failed: ${t.message}`}}}static async verifyECDHKeyExchange(e){try{if(!e.ecdhKeyPair||!e.ecdhKeyPair.privateKey||!e.ecdhKeyPair.publicKey)return{passed:!1,details:"No ECDH key pair available"};let t=e.ecdhKeyPair.privateKey.algorithm.name,r=e.ecdhKeyPair.privateKey.algorithm.namedCurve;if(t!=="ECDH")return{passed:!1,details:`Invalid key type: ${t}, expected ECDH`};if(r!=="P-384"&&r!=="P-256")return{passed:!1,details:`Unsupported curve: ${r}, expected P-384 or P-256`};try{if(!await crypto.subtle.deriveKey({name:"ECDH",public:e.ecdhKeyPair.publicKey},e.ecdhKeyPair.privateKey,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]))return{passed:!1,details:"Key derivation failed"}}catch(i){return{passed:!1,details:`Key derivation test failed: ${i.message}`}}return{passed:!0,details:`ECDH key exchange working with ${r} curve`}}catch(t){return console.error("ECDH verification failed:",t.message),{passed:!1,details:`ECDH test failed: ${t.message}`}}}static async verifyECDSASignatures(e){try{if(!e.ecdsaKeyPair||!e.ecdsaKeyPair.privateKey||!e.ecdsaKeyPair.publicKey)return{passed:!1,details:"No ECDSA key pair available"};let t=["Test ECDSA signature verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"B".repeat(2e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.privateKey,n);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.publicKey,a,n))return{passed:!1,details:`Signature verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"ECDSA digital signatures working correctly"}}catch(t){return console.error("ECDSA verification failed:",t.message),{passed:!1,details:`ECDSA test failed: ${t.message}`}}}static async verifyMessageIntegrity(e){try{if(!e.macKey||!(e.macKey instanceof CryptoKey))return{passed:!1,details:"MAC key not available or invalid"};let t=["Test message integrity verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0446\u0435\u043B\u043E\u0441\u0442\u043D\u043E\u0441\u0442\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"C".repeat(3e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"HMAC",hash:"SHA-256"},e.macKey,n);if(!await crypto.subtle.verify({name:"HMAC",hash:"SHA-256"},e.macKey,a,n))return{passed:!1,details:`HMAC verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"Message integrity (HMAC) working correctly"}}catch(t){return console.error("Message integrity verification failed:",t.message),{passed:!1,details:`Message integrity test failed: ${t.message}`}}}static async verifyRateLimiting(e){try{let t=s.rateLimiter;if(!t||typeof t.checkMessageRate!="function")return{passed:!1,details:"Rate limiter is not available"};let r=`selftest_${crypto.getRandomValues(new Uint32Array(1))[0]}`,i=3;for(let a=0;a0}catch(t){return console.error("Nested encryption verification failed:",t.message),!1}}static async verifyPacketPadding(e){try{if(!e.paddingConfig||!e.paddingConfig.enabled)return!1;let i=new TextEncoder().encode("Test packet padding verification"),n=Math.floor(Math.random()*(e.paddingConfig.maxPadding-e.paddingConfig.minPadding))+e.paddingConfig.minPadding,a=new Uint8Array(i.byteLength+n);return a.set(new Uint8Array(i),0),a.byteLength>=i.byteLength+e.paddingConfig.minPadding}catch(t){return s.secureLog.log("error","Packet padding verification failed",{error:t.message}),!1}}static async verifyAdvancedFeatures(e){try{let t=e.fakeTrafficConfig&&e.fakeTrafficConfig.enabled,r=e.decoyChannelsConfig&&e.decoyChannelsConfig.enabled,i=e.antiFingerprintingConfig&&e.antiFingerprintingConfig.enabled;return t||r||i}catch(t){return s.secureLog.log("error","Advanced features verification failed",{error:t.message}),!1}}static async verifyMutualAuth(e){try{return!e.isVerified||!e.verificationCode?!1:e.isVerified&&e.verificationCode.length>0}catch(t){return s.secureLog.log("error","Mutual auth verification failed",{error:t.message}),!1}}static async verifyNonExtractableKeys(e){let t=[["encryptionKey",e?.encryptionKey],["macKey",e?.macKey],["metadataKey",e?.metadataKey]];for(let[r,i]of t){if(!i||!(i instanceof CryptoKey))return!1;if(i.extractable!==!1)return s.secureLog.log("error","Session key is extractable",{keyName:r}),!1}return!0}static async verifyEnhancedValidation(e){try{return e.securityFeatures?e.securityFeatures.hasEnhancedValidation||e.securityFeatures.hasEnhancedReplayProtection:!1}catch(t){return s.secureLog.log("error","Enhanced validation verification failed",{error:t.message}),!1}}static async verifyPFS(e){try{return e.securityFeatures&&e.securityFeatures.hasPFS===!0&&e.keyRotationInterval&&e.currentKeyVersion!==void 0&&e.keyVersions&&e.keyVersions instanceof Map}catch(t){return s.secureLog.log("error","PFS verification failed",{error:t.message}),!1}}static rateLimiter={messages:new Map,connections:new Map,locks:new Map,async checkMessageRate(e,t=60,r=6e4){if(typeof e!="string"||e.length>256)return!1;let i=`msg_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkMessageRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.messages.has(i)||this.messages.set(i,[]);let o=this.messages.get(i).filter(c=>n-c=t?!1:(o.push(n),this.messages.set(i,o),!0)}finally{this.locks.delete(i)}},async checkConnectionRate(e,t=5,r=3e5){if(typeof e!="string"||e.length>256)return!1;let i=`conn_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkConnectionRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.connections.has(i)||this.connections.set(i,[]);let o=this.connections.get(i).filter(c=>n-c=t?!1:(o.push(n),this.connections.set(i,o),!0)}finally{this.locks.delete(i)}},cleanup(){let e=Date.now(),t=36e5;for(let[r,i]of this.messages.entries()){if(this.locks.has(r))continue;let n=i.filter(a=>e-ae-a3e4&&this.locks.delete(r)}}};static validateSalt(e){if(!e||e.length!==64)throw new Error("Salt must be exactly 64 bytes");if(new Set(e).size<16)throw new Error("Salt has insufficient entropy");return!0}static secureLog={logs:[],maxLogs:100,isProductionMode:!1,init(){this.isProductionMode=this._detectProductionMode(),this.isProductionMode&&console.log("[SecureChat] Production mode detected - sensitive logging disabled")},_detectProductionMode(){return typeof process<"u"&&!0||!window.DEBUG_MODE&&!window.DEVELOPMENT_MODE||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")},log(e,t,r={}){let i=this.sanitizeContext(r),n={timestamp:Date.now(),level:e,message:t,context:i,id:crypto.getRandomValues(new Uint32Array(1))[0]};if(this.logs.push(n),this.logs.length>this.maxLogs&&(this.logs=this.logs.slice(-this.maxLogs)),this.isProductionMode)if(e==="error")console.error(`\u274C [SecureChat] ${t} [ERROR_CODE: ${this._generateErrorCode(t)}]`);else if(e==="warn")console.warn(`\u26A0\uFE0F [SecureChat] ${t}`);else return;else e==="error"?console.error(`\u274C [SecureChat] ${t}`,{errorType:i?.constructor?.name||"Unknown"}):e==="warn"?console.warn(`\u26A0\uFE0F [SecureChat] ${t}`,{details:i}):console.log(`[SecureChat] ${t}`,i)},_generateErrorCode(e){let t=e.split("").reduce((r,i)=>(r=(r<<5)-r+i.charCodeAt(0),r&r),0);return Math.abs(t).toString(36).substring(0,6).toUpperCase()},sanitizeContext(e){if(!e||typeof e!="object")return e;let t=[/key/i,/secret/i,/password/i,/token/i,/signature/i,/challenge/i,/proof/i,/salt/i,/iv/i,/nonce/i,/hash/i,/fingerprint/i,/mac/i,/private/i,/encryption/i,/decryption/i],r={};for(let[i,n]of Object.entries(e))t.some(o=>o.test(i)||typeof n=="string"&&o.test(n))?r[i]="[REDACTED]":typeof n=="string"&&n.length>100?r[i]=n.substring(0,100)+"...[TRUNCATED]":n instanceof ArrayBuffer||n instanceof Uint8Array?r[i]=`[${n.constructor.name}(${n.byteLength||n.length} bytes)]`:n&&typeof n=="object"&&!Array.isArray(n)?r[i]=this.sanitizeContext(n):r[i]=n;return r},getLogs(e=null){return e?this.logs.filter(t=>t.level===e):[...this.logs]},clearLogs(){this.logs=[]},async sendErrorToServer(e,t,r={}){if(this.isProductionMode)try{let i={errorCode:e,timestamp:Date.now(),userAgent:navigator.userAgent.substring(0,100),url:window.location.href.substring(0,100)};window.DEBUG_MODE&&console.log("[SecureChat] Error logged to server:",i)}catch{}}};static async generateECDHKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-384"},!1,["deriveKey","deriveBits"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-256"},!1,["deriveKey","deriveBits"])}}catch(e){throw s.secureLog.log("error","ECDH key generation failed",{error:e.message}),new Error("Failed to create keys for secure exchange")}}static async generateECDSAKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-384"},!1,["sign","verify"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"])}}catch(e){throw s.secureLog.log("error","ECDSA key generation failed",{error:e.message}),new Error("Failed to generate keys for digital signatures")}}static async signData(e,t){try{let r=new TextEncoder,i=typeof t=="string"?r.encode(t):t;try{let n=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},e,i);return Array.from(new Uint8Array(n))}catch(n){s.secureLog.log("warn","SHA-384 signing failed, trying SHA-256",{error:n.message});let a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e,i);return Array.from(new Uint8Array(a))}}catch(r){throw s.secureLog.log("error","Data signing failed",{error:r.message}),new Error("Failed to sign data")}}static async verifySignature(e,t,r){try{let i=new TextEncoder,n=typeof r=="string"?i.encode(r):r,a=new Uint8Array(t);try{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},e,a,n)}catch{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e,a,n)}}catch(i){throw s.secureLog.log("error","Signature verification failed",{error:i.message}),new Error("Failed to verify digital signature")}}static async validateKeyStructure(e,t="ECDH"){try{if(!Array.isArray(e)||e.length===0)throw new Error("Invalid key data format");let r=new Uint8Array(e);if(r.length<50)throw new Error("Key data too short - invalid SPKI structure");if(r.length>2e3)throw new Error("Key data too long - possible attack");let i=s.parseASN1(r);if(!i||i.tag!==48)throw new Error("Invalid SPKI structure - missing SEQUENCE tag");if(i.children.length!==2)throw new Error(`Invalid SPKI structure - expected 2 elements, got ${i.children.length}`);let n=i.children[0];if(n.tag!==48)throw new Error("Invalid AlgorithmIdentifier - not a SEQUENCE");let a=n.children[0];if(a.tag!==6)throw new Error("Invalid algorithm OID - not an OBJECT IDENTIFIER");let o=a.value,c=s.oidToString(o),u={ECDH:["1.2.840.10045.2.1"],ECDSA:["1.2.840.10045.2.1"],RSA:["1.2.840.113549.1.1.1"],"AES-GCM":["2.16.840.1.101.3.4.1.6","2.16.840.1.101.3.4.1.46"]}[t];if(!u)throw new Error(`Unknown algorithm: ${t}`);if(!u.includes(c))throw new Error(`Invalid algorithm OID: expected ${u.join(" or ")}, got ${c}`);if(t==="ECDH"||t==="ECDSA"){if(n.children.length<2)throw new Error("Missing curve parameters for EC key");let m=n.children[1];if(m.tag!==6)throw new Error("Invalid curve OID - not an OBJECT IDENTIFIER");let p=s.oidToString(m.value);if(!{"1.2.840.10045.3.1.7":"P-256","1.3.132.0.34":"P-384"}[p])throw new Error(`Invalid or unsupported curve OID: ${p}`)}let h=i.children[1];if(h.tag!==3)throw new Error("Invalid public key - not a BIT STRING");if(h.value[0]!==0)throw new Error(`Invalid BIT STRING - unexpected unused bits: ${h.value[0]}`);if(t==="ECDH"||t==="ECDSA"){let m=h.value.slice(1);if(m[0]!==4)throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${m[0].toString(16)}`);let p={"P-256":65,"P-384":97},g=s.oidToString(n.children[1].value)==="1.2.840.10045.3.1.7"?"P-256":"P-384",b=p[g];if(m.length!==b)throw new Error(`Invalid EC point size for ${g}: expected ${b}, got ${m.length}`)}try{let m=t==="ECDSA"||t==="ECDH"?{name:t,namedCurve:"P-384"}:{name:t},p=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,m,!1,p)}catch(m){if(t==="ECDSA"||t==="ECDH")try{let p={name:t,namedCurve:"P-256"},S=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,p,!1,S)}catch(p){throw new Error(`Key import validation failed: ${p.message}`)}else throw new Error(`Key import validation failed: ${m.message}`)}return!0}catch(r){throw s.secureLog.log("error","Key structure validation failed",{error:r.message,algorithm:t}),new Error(`Invalid key structure: ${r.message}`)}}static parseASN1(e,t=0){if(t>=e.length)return null;let r=e[t],i=t+1;if(i>=e.length)throw new Error("Truncated ASN.1 structure");let n=e[i],a=i+1;if(n&128){let d=n&127;if(d>4)throw new Error("ASN.1 length too large");n=0;for(let u=0;u=e.length)throw new Error("Truncated ASN.1 length");n=n<<8|e[a+u]}a+=d}if(a+n>e.length)throw new Error("ASN.1 structure extends beyond data");let o=e.slice(a,a+n),c={tag:r,length:n,value:o,children:[]};if(r===48||r===49){let d=0;for(;d2)throw new Error(`Invalid OID first component: ${r[0]}`);if((r[0]===0||r[0]===1)&&r[1]>39)throw new Error(`Invalid OID second component: ${r[1]} (must be <= 39 for first component ${r[0]})`);return!0}static async exportPublicKeyWithSignature(e,t,r="ECDH"){try{if(!["ECDH","ECDSA"].includes(r))throw new Error("Invalid key type");let i=await crypto.subtle.exportKey("spki",e),n=Array.from(new Uint8Array(i));await s.validateKeyStructure(n,r);let a={keyType:r,keyData:n,timestamp:Date.now(),version:"4.0"},o=JSON.stringify(a),c=await s.signData(t,o);return{...a,signature:c}}catch(i){throw s.secureLog.log("error","Public key export failed",{error:i.message,keyType:r}),new Error(`Failed to export ${r} key: ${i.message}`)}}static async importSignedPublicKey(e,t,r="ECDH"){try{if(!e||typeof e!="object")throw new Error("Invalid signed package format");let{keyType:i,keyData:n,timestamp:a,version:o,signature:c}=e;if(!i||!n||!a||!c)throw new Error("Missing required fields in signed package");if(!s.constantTimeCompare(i,r))throw new Error(`Key type mismatch: expected ${r}, got ${i}`);if(Date.now()-a>36e5)throw new Error("Signed key package is too old");await s.validateKeyStructure(n,i);let h=JSON.stringify({keyType:i,keyData:n,timestamp:a,version:o});if(!await s.verifySignature(t,c,h))throw new Error("Invalid signature on key package - possible MITM attack");let p=new Uint8Array(n);try{let S=i==="ECDH"?{name:"ECDH",namedCurve:"P-384"}:{name:"ECDSA",namedCurve:"P-384"},g=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,S,!1,g)}catch(S){s.secureLog.log("warn","Elliptic curve P-384 import failed, switching curve",{error:S.message});let g=i==="ECDH"?{name:"ECDH",namedCurve:"P-256"}:{name:"ECDSA",namedCurve:"P-256"},b=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,g,!1,b)}}catch(i){throw s.secureLog.log("error","Signed public key import failed",{error:i.message,expectedKeyType:r}),new Error(`Failed to import the signed key: ${i.message}`)}}static async exportPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=Array.from(new Uint8Array(t));return await s.validateKeyStructure(r,"ECDH"),r}catch(t){throw s.secureLog.log("error","Legacy public key export failed",{error:t.message}),new Error("Failed to export the public key")}}static async importPublicKey(e){try{await s.validateKeyStructure(e,"ECDH");let t=new Uint8Array(e);try{return await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-384"},!1,[])}catch(r){return s.secureLog.log("warn","P-384 import failed, trying P-256",{error:r.message}),await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-256"},!1,[])}}catch(t){throw s.secureLog.log("error","Legacy public key import failed",{error:t.message}),new Error("Failed to import the public key")}}static isKeyTrusted(e){if(e instanceof CryptoKey){let t=s._keyMetadata.get(e);return t?t.trusted===!0:!1}else if(e&&e._securityMetadata)return e._securityMetadata.trusted===!0;return!1}static async importPublicKeyFromSignedPackage(e,t=null,r={}){try{if(!e||!e.keyData||!e.signature)throw new Error("Invalid signed key package format");let n=["keyData","signature","keyType","timestamp","version"].filter(m=>!e[m]);if(n.length>0)throw s.secureLog.log("error","Missing required fields in signed package",{missingFields:n,availableFields:Object.keys(e)}),new Error(`Required fields are missing in the signed package: ${n.join(", ")}`);if(!t)throw s.secureLog.log("error","SECURITY VIOLATION: Signed package received without verifying key",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,securityRisk:"HIGH - Potential MITM attack vector"}),new Error("CRITICAL SECURITY ERROR: Signed key package received without a verification key. This may indicate a possible MITM attack attempt. Import rejected for security reasons.");await s.validateKeyStructure(e.keyData,e.keyType||"ECDH");let a={...e};delete a.signature;let o=JSON.stringify(a);if(!await s.verifySignature(t,e.signature,o))throw s.secureLog.log("error","SECURITY BREACH: Invalid signature detected - MITM attack prevented",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,attackPrevented:!0}),new Error("CRITICAL SECURITY ERROR: Invalid key signature detected. This indicates a possible MITM attack attempt. Key import rejected.");let d=await s.calculateKeyFingerprint(e.keyData),u=new Uint8Array(e.keyData),h=e.keyType||"ECDH";try{let m=await crypto.subtle.importKey("spki",u,{name:h,namedCurve:"P-384"},!1,h==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(m,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),m}catch(m){s.secureLog.log("warn","P-384 import failed, trying P-256",{error:m.message});let p=await crypto.subtle.importKey("spki",u,{name:h,namedCurve:"P-256"},!1,h==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(p,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),p}}catch(i){throw s.secureLog.log("error","Signed package key import failed",{error:i.message,securityImplications:"Potential security breach prevented"}),new Error(`Failed to import the public key from the signed package: ${i.message}`)}}static async deriveSharedKeys(e,t,r){try{if(!(e instanceof CryptoKey))throw s.secureLog.log("error","Private key is not a CryptoKey",{privateKeyType:typeof e,privateKeyAlgorithm:e?.algorithm?.name}),new Error("The private key is not a valid CryptoKey.");if(!(t instanceof CryptoKey))throw s.secureLog.log("error","Public key is not a CryptoKey",{publicKeyType:typeof t,publicKeyAlgorithm:t?.algorithm?.name}),new Error("The public key is not a valid CryptoKey.");if(!r||r.length!==64)throw new Error("Salt must be exactly 64 bytes for enhanced security");let i=new Uint8Array(r),n=new TextEncoder,a,o=null;try{o=await crypto.subtle.deriveBits({name:"ECDH",public:t},e,256),a=await crypto.subtle.importKey("raw",o,{name:"HKDF",hash:"SHA-256"},!1,["deriveKey","deriveBits"])}catch(b){throw s.secureLog.log("error","ECDH derivation failed",{error:b.message}),b}finally{o&&(s.zeroizeBuffer(o),o=null)}let c;c=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-encryption-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let d;d=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-authentication-v4")},a,{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"]);let u;u=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("perfect-forward-secrecy-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let h;h=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("metadata-protection-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let m=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("double-ratchet-root-v1")},a,256),p=new Uint8Array(m),S=null,g;try{S=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("fingerprint-generation-v4")},a,256),g=await s.generateKeyFingerprint(new Uint8Array(S))}finally{S&&(s.zeroizeBuffer(S),S=null)}if(!(c instanceof CryptoKey))throw s.secureLog.log("error","Derived message key is not a CryptoKey",{messageKeyType:typeof c,messageKeyAlgorithm:c?.algorithm?.name}),new Error("The derived message key is not a valid CryptoKey.");if(!(d instanceof CryptoKey))throw s.secureLog.log("error","Derived MAC key is not a CryptoKey",{macKeyType:typeof d,macKeyAlgorithm:d?.algorithm?.name}),new Error("The derived MAC key is not a valid CryptoKey.");if(!(u instanceof CryptoKey))throw s.secureLog.log("error","Derived PFS key is not a CryptoKey",{pfsKeyType:typeof u,pfsKeyAlgorithm:u?.algorithm?.name}),new Error("The derived PFS key is not a valid CryptoKey.");if(!(h instanceof CryptoKey))throw s.secureLog.log("error","Derived metadata key is not a CryptoKey",{metadataKeyType:typeof h,metadataKeyAlgorithm:h?.algorithm?.name}),new Error("The derived metadata key is not a valid CryptoKey.");return{messageKey:c,macKey:d,pfsKey:u,metadataKey:h,ratchetRoot:p,fingerprint:g,timestamp:Date.now(),version:"4.0"}}catch(i){throw s.secureLog.log("error","Enhanced key derivation failed",{error:i.message,errorStack:i.stack,privateKeyType:typeof e,publicKeyType:typeof t,saltLength:r?.length,privateKeyAlgorithm:e?.algorithm?.name,publicKeyAlgorithm:t?.algorithm?.name}),new Error(`Failed to create shared encryption keys: ${i.message}`)}}static async generateKeyFingerprint(e){let t=new Uint8Array(e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).slice(0,12).map(n=>n.toString(16).padStart(2,"0")).join(":")}static generateMutualAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(48)),t=Date.now(),r=crypto.getRandomValues(new Uint8Array(16));return{challenge:Array.from(e),timestamp:t,nonce:Array.from(r),version:"4.0"}}static async createAuthProof(e,t,r){try{if(!e||!e.challenge||!e.timestamp||!e.nonce)throw new Error("Invalid challenge structure");let i=Date.now()-e.timestamp;if(i>12e4)throw new Error("Challenge expired");let n={challenge:e.challenge,timestamp:e.timestamp,nonce:e.nonce,responseTimestamp:Date.now(),publicKeyHash:await s.hashPublicKey(r)},a=JSON.stringify(n),o=await s.signData(t,a),c={...n,signature:o,version:"4.0"};return s.secureLog.log("info","Authentication proof created",{challengeAge:Math.round(i/1e3)+"s"}),c}catch(i){throw s.secureLog.log("error","Authentication proof creation failed",{error:i.message}),new Error(`Failed to create cryptographic proof: ${i.message}`)}}static async verifyAuthProof(e,t,r){try{if(await new Promise(u=>setTimeout(u,Math.floor(Math.random()*20)+5)),s.assertCryptoKey(r,"ECDSA",["verify"]),!e||!t||!r)throw new Error("Missing required parameters for proof verification");let i=["challenge","timestamp","nonce","responseTimestamp","publicKeyHash","signature"];for(let u of i)if(!e[u])throw new Error(`Missing required field: ${u}`);if(!s.constantTimeCompareArrays(e.challenge,t.challenge)||e.timestamp!==t.timestamp||!s.constantTimeCompareArrays(e.nonce,t.nonce))throw new Error("Challenge mismatch - possible replay attack");let n=Date.now()-e.responseTimestamp;if(n>18e5)throw new Error("Proof response expired");let a=await s.hashPublicKey(r);if(!s.constantTimeCompare(e.publicKeyHash,a))throw new Error("Public key hash mismatch");let o={...e};delete o.signature;let c=JSON.stringify(o);if(!await s.verifySignature(r,e.signature,c))throw new Error("Invalid proof signature");return s.secureLog.log("info","Authentication proof verified successfully",{responseAge:Math.round(n/1e3)+"s"}),!0}catch(i){throw s.secureLog.log("error","Authentication proof verification failed",{error:i.message}),new Error(`Failed to verify cryptographic proof: ${i.message}`)}}static async hashPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Public key hashing failed",{error:t.message}),new Error("Failed to create hash of the public key")}}static generateAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(32));return Array.from(e)}static generateVerificationCode(){let e="0123456789ABCDEF",t=e.length,r="";for(let i=0;i<6;i++){let n;do n=crypto.getRandomValues(new Uint8Array(1))[0];while(n>=256-256%t);r+=e[n%t]}return r.match(/.{1,2}/g).join("-")}static async encryptMessage(e,t,r,i,n,a=0){try{if(!e||typeof e!="string")throw new Error("Invalid message format");s.assertCryptoKey(t,"AES-GCM",["encrypt"]),s.assertCryptoKey(r,"HMAC",["sign"]),s.assertCryptoKey(i,"AES-GCM",["encrypt"]);let o=new TextEncoder,c=o.encode(e),d=crypto.getRandomValues(new Uint8Array(12)),u=crypto.getRandomValues(new Uint8Array(12)),h=Date.now(),m=16-c.length%16,p=new Uint8Array(c.length+m);p.set(c);let S=crypto.getRandomValues(new Uint8Array(m));p.set(S,c.length);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:d},t,p),b={id:n,timestamp:h,sequenceNumber:a,originalLength:c.length,version:"4.0"},w=JSON.stringify(s.sortObjectKeys(b)),M=await crypto.subtle.encrypt({name:"AES-GCM",iv:u},i,o.encode(w)),F={messageIv:Array.from(d),messageData:Array.from(new Uint8Array(g)),metadataIv:Array.from(u),metadataData:Array.from(new Uint8Array(M)),version:"4.0"},k=s.sortObjectKeys(F),E=JSON.stringify(k),_=await crypto.subtle.sign("HMAC",r,o.encode(E));return F.mac=Array.from(new Uint8Array(_)),F}catch(o){throw s.secureLog.log("error","Message encryption failed",{error:o.message,messageId:n}),new Error(`Failed to encrypt the message: ${o.message}`)}}static async decryptMessage(e,t,r,i,n=null){try{s.assertCryptoKey(t,"AES-GCM",["decrypt"]),s.assertCryptoKey(r,"HMAC",["verify"]),s.assertCryptoKey(i,"AES-GCM",["decrypt"]);let a=["messageIv","messageData","metadataIv","metadataData","mac","version"];for(let x of a)if(!e[x])throw new Error(`Missing required field: ${x}`);let o={...e};delete o.mac;let c=s.sortObjectKeys(o),d=JSON.stringify(c);if(!await crypto.subtle.verify("HMAC",r,new Uint8Array(e.mac),new TextEncoder().encode(d)))throw s.secureLog.log("error","MAC verification failed",{payloadFields:Object.keys(e),macLength:e.mac?.length}),new Error("Message authentication failed - possible tampering");let h=new Uint8Array(e.metadataIv),m=new Uint8Array(e.metadataData),p=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},i,m),S=new TextDecoder().decode(p),g=JSON.parse(S);if(!g.id||!g.timestamp||g.sequenceNumber===void 0||!g.originalLength)throw new Error("Invalid metadata structure");let b=Date.now()-g.timestamp;if(b>18e5)throw new Error("Message expired (older than 30 minutes)");if(n!==null){if(g.sequenceNumbern+10)throw new Error(`Sequence number gap too large: expected around ${n}, got ${g.sequenceNumber}`)}let w=new Uint8Array(e.messageIv),M=new Uint8Array(e.messageData),F=await crypto.subtle.decrypt({name:"AES-GCM",iv:w},t,M),E=new Uint8Array(F).slice(0,g.originalLength),A=new TextDecoder().decode(E);return s.secureLog.log("info","Message decrypted successfully",{messageId:g.id,sequenceNumber:g.sequenceNumber,messageAge:Math.round(b/1e3)+"s"}),{message:A,messageId:g.id,timestamp:g.timestamp,sequenceNumber:g.sequenceNumber}}catch(a){throw s.secureLog.log("error","Message decryption failed",{error:a.message}),new Error(`Failed to decrypt the message: ${a.message}`)}}static _getMessageSanitizer(){if(s._messageSanitizer)return s._messageSanitizer;if(typeof window>"u"||!window?.document)throw new Error("DOMPurify requires a browser-like window for message sanitization");return s._messageSanitizer=Ui(window),s._messageSanitizer}static sanitizeMessage(e){if(typeof e!="string")throw new Error("Message must be a string");let t=s._getMessageSanitizer().sanitize(e,{ALLOWED_TAGS:[],ALLOWED_ATTR:[],ALLOW_UNKNOWN_PROTOCOLS:!1,FORBID_TAGS:["script","style","svg","math","template"],FORBID_ATTR:["style"],KEEP_CONTENT:!0,RETURN_TRUSTED_TYPE:!1,USE_PROFILES:{html:!1,svg:!1,svgFilters:!1,mathMl:!1}});return String(t).trim().substring(0,2e3)}static generateSalt(){return Array.from(crypto.getRandomValues(new Uint8Array(64)))}static async calculateKeyFingerprint(e){try{let t=new TextEncoder,r=new Uint8Array(e),i=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(i)).map(o=>o.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Key fingerprint calculation failed",{error:t.message}),new Error("Failed to compute the key fingerprint")}}static constantTimeCompare(e,t){let r=typeof e=="string"?e:JSON.stringify(e),i=typeof t=="string"?t:JSON.stringify(t);if(r.length!==i.length){let a=0;for(let o=0;oa.toLowerCase()===t);if(r)return r;let i=t.split("-")[0],n=Ke.find(a=>a.toLowerCase().split("-")[0]===i);if(n)return n}return null}function Xs({pathname:s="/",stored:e=null,languages:t=[]}={}){let r=Bi(s);return r||(Qs(s)?"en":e&&Ke.includes(e)?e:Ys(t)||"en")}function Qs(s){return s==="/"||s==="/index.html"}function Js(s,e="/"){let t=Bi(e),i=(t?String(e).slice(t.length+1):String(e)).replace(/^\/+/,"");return s==="en"?`/${i}`:`/${s}/${i}`}function Hi(s){try{localStorage.setItem(Vi,s)}catch{}}function Zs(){try{return localStorage.getItem(Vi)}catch{return null}}var Lt=null;function Ge(){if(Lt)return Lt;let s=typeof window>"u"?null:window;return!s||!s.location?"en":(Lt=Xs({pathname:s.location.pathname||"/",stored:Zs(),languages:s.navigator?.languages||[]}),Lt)}function ea(s=Ge()){return it[s]?.dir==="rtl"?"rtl":"ltr"}function Pt(s=Ge()){return ea(s)==="rtl"}function $i(s=Ge()){return Pt(s)?-1:1}function Oe(s,e=Ge()){let t=Dt(e)?.[s]??Dt("en")?.[s];return Array.isArray(t)?t:[]}function Gi({pathname:s="/",active:e="en"}={}){return Ke.map(t=>({code:t,href:Js(t,s),hrefLang:it[t]?.htmlLang||t,label:it[t]?.nativeName||t,abbr:it[t]?.abbr||t.toUpperCase(),dir:it[t]?.dir||"ltr",isCurrent:t===e}))}function f(s,e,t=Ge()){let r=Dt(t)?.[s]??zi[t]?.[s]??Dt("en")?.[s]??s;return e?String(r).replace(/\{(\w+)\}/g,(i,n)=>Object.prototype.hasOwnProperty.call(e,n)?String(e[n]):i):r}var Ie=class s{static#e=null;static#n=Symbol("SecureFileTransferContext");static getInstance(){return this.#e||(this.#e=new s),this.#e}#t=null;#r=!1;#i="high";setFileTransferSystem(e){if(!(e instanceof je))throw new Error("Invalid file transfer system instance");this.#t=e,this.#r=!0}getFileTransferSystem(){return this.#t}isActive(){return this.#r&&this.#t!==null}deactivate(){this.#r=!1,this.#t=null}getSecurityLevel(){return this.#i}setSecurityLevel(e){["low","medium","high"].includes(e)&&(this.#i=e)}},ee=class{static#e=new Set(["File size exceeds maximum limit","Unsupported file type","Transfer timeout","Connection lost","Invalid file data","File transfer failed","Transfer cancelled","Network error","File not found","Permission denied"]);static sanitizeError(e){let t=e.message||e;for(let r of this.#e)if(t.includes(r))return r;return console.error("\u{1F512} Internal file transfer error:",{message:e.message,stack:e.stack,timestamp:new Date().toISOString()}),"File transfer failed"}static logSecurityEvent(e,t={}){console.warn("\u{1F512} Security event:",{event:e,timestamp:new Date().toISOString(),...t})}},Ft=class{static async signFileMetadata(e,t){try{let i=new TextEncoder().encode(JSON.stringify({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,fileHash:e.fileHash,timestamp:e.timestamp,version:e.version||"2.0"})),n=await crypto.subtle.sign("RSASSA-PKCS1-v1_5",t,i);return Array.from(new Uint8Array(n))}catch(r){throw ee.logSecurityEvent("signature_failed",{error:r.message}),new Error("Failed to sign file metadata")}}static async verifyFileMetadata(e,t,r){try{let n=new TextEncoder().encode(JSON.stringify({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,fileHash:e.fileHash,timestamp:e.timestamp,version:e.version||"2.0"})),a=new Uint8Array(t),o=await crypto.subtle.verify("RSASSA-PKCS1-v1_5",r,a,n);return o||ee.logSecurityEvent("invalid_signature",{fileId:e.fileId}),o}catch(i){return ee.logSecurityEvent("verification_failed",{error:i.message}),!1}}},Kt=class{static MAX_MESSAGE_SIZE=1024*1024;static isMessageSizeValid(e){let t=JSON.stringify(e),r=new Blob([t]).size;if(r>this.MAX_MESSAGE_SIZE)throw ee.logSecurityEvent("message_too_large",{size:r,limit:this.MAX_MESSAGE_SIZE}),new Error("Message too large");return!0}},vr=class{constructor(){this.locks=new Map}async withLock(e,t){for(;this.locks.has(e);)await this.locks.get(e);let r,i=new Promise(n=>{r=n});this.locks.set(e,i);try{return await t()}finally{this.locks.delete(e),r()}}},nt=class{constructor(e,t){this.maxRequests=e,this.windowMs=t,this.requests=new Map}isAllowed(e){let t=Date.now(),r=t-this.windowMs;this.requests.has(e)||this.requests.set(e,[]);let n=this.requests.get(e).filter(a=>a>r);return this.requests.set(e,n),n.length>=this.maxRequests?(ee.logSecurityEvent("rate_limit_exceeded",{identifier:e,requestCount:n.length,limit:this.maxRequests}),!1):(n.push(t),!0)}},qe=class{static secureWipe(e){if(e instanceof ArrayBuffer){let t=new Uint8Array(e);crypto.getRandomValues(t)}else e instanceof Uint8Array&&crypto.getRandomValues(e)}static secureDelete(e,t){e[t]&&(this.secureWipe(e[t]),delete e[t])}},je=class{constructor(e,t,r,i,n,a){if(this.webrtcManager=e,this.onProgress=t,this.onComplete=r,this.onError=i,this.onFileReceived=n,this.onIncomingFileRequest=a,!e)throw new Error("webrtcManager is required for EnhancedSecureFileTransfer");Ie.getInstance().setFileTransferSystem(this),this.atomicOps=new vr,this.rateLimiter=new nt(10,6e4),this.signingKey=null,this.verificationKey=null,this.CHUNK_SIZE=16*1024,this.MAX_RECEIVE_CHUNK_SIZE=64*1024,this.MAX_FILE_SIZE=100*1024*1024,this.MAX_CONCURRENT_TRANSFERS=3,this.CHUNK_TIMEOUT=3e4,this.RETRY_ATTEMPTS=3,this.FILE_TYPE_RESTRICTIONS={pdf:{extensions:[".pdf"],mimeTypes:["application/pdf","application/x-pdf","application/acrobat"],maxSize:50*1024*1024,category:"PDF",description:"PDF"},text:{extensions:[".txt"],mimeTypes:["text/plain","application/txt"],maxSize:10*1024*1024,category:f("fileType.text"),description:"TXT"},images:{extensions:[".jpg",".jpeg",".png",".gif",".webp",".bmp",".ico"],mimeTypes:["image/jpeg","image/jpg","image/pjpeg","image/png","image/gif","image/webp","image/bmp","image/x-windows-bmp","image/x-icon","image/vnd.microsoft.icon"],maxSize:25*1024*1024,category:f("fileType.images"),description:"JPG, JPEG, PNG, GIF, WEBP, BMP, ICO"},archives:{extensions:[".zip"],mimeTypes:["application/zip","application/x-zip","application/x-zip-compressed","multipart/x-zip"],maxSize:100*1024*1024,category:f("fileType.archives"),description:"ZIP"},voice:{extensions:[".webm",".ogg",".oga",".opus",".m4a",".mp4",".mp3",".wav"],mimeTypes:["audio/webm","audio/ogg","audio/opus","audio/mp4","audio/mpeg","audio/mp3","audio/wav","audio/x-m4a","audio/aac"],maxSize:20*1024*1024,category:"Voice",description:f("fileType.voice")}},this.BLOCKED_EXTENSIONS=new Set([".exe",".bat",".cmd",".sh",".js",".msi",".dmg",".app",".jar",".scr",".ps1",".vbs",".html",".svg"]),this._genericMimeTypes=new Set(["application/octet-stream","application/binary"]),this._allowedMimeTypes=new Set;for(let o of Object.values(this.FILE_TYPE_RESTRICTIONS))for(let c of o.mimeTypes)this._allowedMimeTypes.add(c);this.activeTransfers=new Map,this.receivingTransfers=new Map,this.pendingIncomingTransfers=new Map,this.transferQueue=[],this.pendingChunks=new Map,this.incomingOfferLimiter=new nt(5,6e4),this.incomingChunkLimiter=new nt(6e4,6e4),this.incomingTransferChunkLimiters=new Map,this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE=3e4,this.MAX_PENDING_INCOMING_TRANSFERS=3,this.MAX_AUTO_ACCEPT_VOICE_SIZE=4*1024*1024,this.MAX_AUTO_ACCEPT_VOICE_SESSION_BYTES=64*1024*1024,this.autoAcceptedVoiceBytes=0,this.sessionKeys=new Map,this.processedChunks=new Set,this.transferNonces=new Map,this.receivedFileBuffers=new Map,this.MAX_RETAINED_RECEIVED_FILE_BUFFERS=3,this.setupFileMessageHandlers(),this.webrtcManager&&(this.webrtcManager.fileTransferSystem=this)}getFileType(e){let t=String(e?.name||"").toLowerCase(),r=t.lastIndexOf("."),i=r>=0?t.substring(r):"",n=String(e?.type||"").toLowerCase();for(let[a,o]of Object.entries(this.FILE_TYPE_RESTRICTIONS)){if(!o.extensions.includes(i))continue;if(!n||this._genericMimeTypes.has(n)||this._allowedMimeTypes.has(n))return{type:a,category:o.category,description:o.description,maxSize:o.maxSize,allowed:!0,extension:i,mimeType:n}}return{type:"blocked",category:f("fileType.unsupported"),description:"Allowed: JPG, JPEG, PNG, GIF, WEBP, BMP, ICO, PDF, TXT, ZIP",maxSize:this.MAX_FILE_SIZE,allowed:!1,extension:i,mimeType:n}}validateFile(e){let t=this.getFileType(e),r=[],n=String(e?.name||"").toLowerCase(),a=n.lastIndexOf("."),o=a>=0?n.substring(a):"";return this.BLOCKED_EXTENSIONS.has(o)&&r.push(`File rejected: ${o} files are not allowed for security reasons.`),e.size>t.maxSize&&r.push(`File size (${this.formatFileSize(e.size)}) exceeds maximum allowed for ${t.category} (${this.formatFileSize(t.maxSize)})`),!t.allowed&&!this.BLOCKED_EXTENSIONS.has(o)&&r.push(`File rejected: unsupported file type. Supported types: ${t.description}`),e.size>this.MAX_FILE_SIZE&&r.push(`File size (${this.formatFileSize(e.size)}) exceeds general limit (${this.formatFileSize(this.MAX_FILE_SIZE)})`),{isValid:r.length===0,errors:r,fileType:t,fileSize:e.size,formattedSize:this.formatFileSize(e.size)}}normalizeDisplayFileName(e){return String(e||"").normalize("NFKC").replace(/[\u0000-\u001F\u007F]/g,"").replace(/[\\/]+/g,"_").trim().slice(0,255)}validateIncomingMetadata(e){let t=[];(!e||typeof e!="object")&&t.push("Invalid file transfer metadata"),(!e?.fileId||typeof e.fileId!="string")&&t.push("Invalid file id"),(!Number.isSafeInteger(e?.fileSize)||e.fileSize<=0)&&t.push("Invalid file size"),(!Number.isSafeInteger(e?.totalChunks)||e.totalChunks<=0)&&t.push("Invalid chunk count"),(!Number.isSafeInteger(e?.chunkSize)||e.chunkSize<=0||e.chunkSize>this.MAX_RECEIVE_CHUNK_SIZE)&&t.push("Invalid chunk size"),(!Array.isArray(e?.salt)||e.salt.length!==32)&&t.push("Invalid salt");let r=typeof e?.fileName=="string"?e.fileName:"",i=this.normalizeDisplayFileName(r);if((!r||r!==r.trim()||/[\u0000-\u001F\u007F]/.test(r)||/[\\/]/.test(r)||r==="."||r===".."||i.length===0)&&t.push("Dangerous file name"),t.length===0){let c=this.validateFile({name:i,size:e.fileSize,type:e.fileType||"application/octet-stream"});c.isValid||t.push(...c.errors)}let a=!!e?.isVoice,o=a?this.rejectVoiceAutoAcceptReason(e):null;return{isValid:t.length===0,errors:t,displayName:i,isVoice:a&&!o,voiceRejection:o}}rejectVoiceAutoAcceptReason(e){let t=String(e?.fileType||"").toLowerCase(),r=e?.fileSize;return t.startsWith("audio/")?this.FILE_TYPE_RESTRICTIONS.voice.mimeTypes.includes(t)?!Number.isSafeInteger(r)||r<=0||r>this.MAX_AUTO_ACCEPT_VOICE_SIZE?`too large to auto-accept (${this.formatFileSize(r||0)} > ${this.formatFileSize(this.MAX_AUTO_ACCEPT_VOICE_SIZE)})`:this.autoAcceptedVoiceBytes+r>this.MAX_AUTO_ACCEPT_VOICE_SESSION_BYTES?"session auto-accept budget for voice notes is exhausted":null:`unsupported audio MIME type (${t})`:`not an audio MIME type (${t||"absent"})`}formatFileSize(e){if(e===0)return"0 B";let t=1024,r=["B","KB","MB","GB"],i=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,i)).toFixed(2))+" "+r[i]}getSupportedFileTypes(){let e={};for(let[t,r]of Object.entries(this.FILE_TYPE_RESTRICTIONS))e[t]={category:r.category,description:r.description,extensions:r.extensions,maxSize:this.formatFileSize(r.maxSize),maxSizeBytes:r.maxSize};return e}getFileTypeInfo(){return{supportedTypes:this.getSupportedFileTypes(),generalMaxSize:this.formatFileSize(this.MAX_FILE_SIZE),generalMaxSizeBytes:this.MAX_FILE_SIZE,restrictions:this.FILE_TYPE_RESTRICTIONS}}arrayBufferToBase64(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),r="",i=t.byteLength;for(let n=0;n{this.webrtcManager.dataChannel&&(clearInterval(e),this.setupMessageInterception())},100);setTimeout(()=>{clearInterval(e)},5e3);return}this.setupMessageInterception()}setupMessageInterception(){try{if(!this.webrtcManager.dataChannel)return;this.webrtcManager&&(this.webrtcManager.fileTransferSystem=this),this.webrtcManager.dataChannel.onmessage&&(this.originalOnMessage=this.webrtcManager.dataChannel.onmessage),this.webrtcManager.dataChannel.onmessage=async e=>{try{if(e.data.length>Kt.MAX_MESSAGE_SIZE){console.warn("\u{1F512} Message too large, ignoring"),ee.logSecurityEvent("oversized_message_blocked");return}if(typeof e.data=="string")try{let t=JSON.parse(e.data);if(Kt.isMessageSizeValid(t),this.isFileTransferMessage(t)){await this.handleFileMessage(t);return}}catch(t){if(t.message==="Message too large")return}if(this.originalOnMessage)return this.originalOnMessage.call(this.webrtcManager.dataChannel,e)}catch(t){if(console.error("\u274C Error in file system message interception:",t),this.originalOnMessage)return this.originalOnMessage.call(this.webrtcManager.dataChannel,e)}}}catch(e){console.error("\u274C Failed to set up message interception:",e)}}isFileTransferMessage(e){return!e||typeof e!="object"||!e.type?!1:["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_chunk_request","file_transfer_complete","file_transfer_error"].includes(e.type)}async handleFileMessage(e){try{if(!this.webrtcManager.fileTransferSystem)try{if(typeof this.webrtcManager.initializeFileTransfer=="function"){this.webrtcManager.initializeFileTransfer();let t=0,r=50;for(;!this.webrtcManager.fileTransferSystem&&tsetTimeout(i,100)),t++;if(!this.webrtcManager.fileTransferSystem)throw new Error("File transfer system initialization timeout")}else throw new Error("initializeFileTransfer method not available")}catch(t){if(console.error("\u274C Failed to initialize file transfer system:",t),e.fileId){let r={type:"file_transfer_error",fileId:e.fileId,error:"File transfer system not available",timestamp:Date.now()};await this.sendSecureMessage(r)}return}switch(e.type){case"file_transfer_start":await this.handleFileTransferStart(e);break;case"file_transfer_response":this.handleTransferResponse(e);break;case"file_chunk":await this.handleFileChunk(e);break;case"chunk_confirmation":this.handleChunkConfirmation(e);break;case"file_chunk_request":await this.handleChunkRequest(e);break;case"file_transfer_complete":this.handleTransferComplete(e);break;case"file_transfer_error":this.handleTransferError(e);break;default:console.warn("\u26A0\uFE0F Unknown file message type:",e.type)}}catch(t){if(console.error("\u274C Error handling file message:",t),e.fileId){let r={type:"file_transfer_error",fileId:e.fileId,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(r)}}}async deriveFileSessionKey(e){try{if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("WebRTC session data not available");let t=crypto.getRandomValues(new Uint8Array(32)),r=new TextEncoder,i=r.encode(this.webrtcManager.keyFingerprint),n=r.encode(e),a=new Uint8Array(this.webrtcManager.sessionSalt),o=new Uint8Array(i.length+a.length+t.length+n.length),c=0;o.set(i,c),c+=i.length,o.set(a,c),c+=a.length,o.set(t,c),c+=t.length,o.set(n,c);let d=await crypto.subtle.digest("SHA-256",o),u=await crypto.subtle.importKey("raw",d,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return this.sessionKeys.set(e,{key:u,salt:Array.from(t),created:Date.now()}),{key:u,salt:Array.from(t)}}catch(t){throw console.error("\u274C Failed to derive file session key:",t),t}}async deriveFileSessionKeyFromSalt(e,t){try{if(!t||!Array.isArray(t)||t.length!==32)throw new Error(`Invalid salt: ${t?.length||0} bytes`);if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("WebRTC session data not available");let r=new TextEncoder,i=r.encode(this.webrtcManager.keyFingerprint),n=r.encode(e),a=new Uint8Array(t),o=new Uint8Array(this.webrtcManager.sessionSalt),c=new Uint8Array(i.length+o.length+a.length+n.length),d=0;c.set(i,d),d+=i.length,c.set(o,d),d+=o.length,c.set(a,d),d+=a.length,c.set(n,d);let u=await crypto.subtle.digest("SHA-256",c),h=await crypto.subtle.importKey("raw",u,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return this.sessionKeys.set(e,{key:h,salt:t,created:Date.now()}),h}catch(r){throw console.error("\u274C Failed to derive session key from salt:",r),r}}_emitTransferProgress(e,t){if(typeof this.onProgress!="function"||!e)return;let r=e.totalChunks||0,i=t==="up"?e.sentChunks||0:e.receivedCount||0,n=r>0?Math.min(100,Math.round(i/r*100)):0;try{this.onProgress({fileId:e.fileId,uiId:e.uiId||null,direction:t,progress:n,transferredChunks:i,totalChunks:r,isVoice:!!e.isVoice,voice:e.voice||null})}catch{}}async sendFile(e,t={}){try{if(!this.webrtcManager)throw new Error("WebRTC Manager not initialized");let r=this.getClientIdentifier();if(!this.rateLimiter.isAllowed(r))throw ee.logSecurityEvent("rate_limit_exceeded",{clientId:r}),new Error("Rate limit exceeded. Please wait before sending another file.");if(!e||!e.size)throw new Error("Invalid file object");let i=this.validateFile(e);if(!i.isValid){let m=i.errors.join(". ");throw new Error(m)}if(this.activeTransfers.size>=this.MAX_CONCURRENT_TRANSFERS)throw new Error("Maximum concurrent transfers reached");let n=`file_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,a=await this.calculateFileHash(e),o=await this.deriveFileSessionKey(n),c=o.key,d=o.salt,u={fileId:n,file:e,fileHash:a,sessionKey:c,salt:d,totalChunks:Math.ceil(e.size/this.CHUNK_SIZE),sentChunks:0,confirmedChunks:0,startTime:Date.now(),status:"preparing",retryCount:0,lastChunkTime:Date.now(),isVoice:!!(t&&t.voice),voice:t&&t.voice?t.voice:null,uiId:t&&t.uiId?t.uiId:null};this.activeTransfers.set(n,u),this.transferNonces.set(n,0);let h=new Promise((m,p)=>{u.resolveConsent=m,u.rejectConsent=p,u.consentTimeout=setTimeout(()=>{u.consentTimeout=null,p(new Error("Transfer timeout"))},3e4)});return await this.sendFileMetadata(u),await h,await this.startChunkTransmission(u),n}catch(r){let i=ee.sanitizeError(r);throw console.error("\u274C File sending failed:",i),this.onError&&this.onError(i),new Error(i)}}async sendFileMetadata(e){try{let t={type:"file_transfer_start",fileId:e.fileId,fileName:e.file.name,fileSize:e.file.size,fileType:e.file.type||"application/octet-stream",fileHash:e.fileHash,totalChunks:e.totalChunks,chunkSize:this.CHUNK_SIZE,salt:e.salt,timestamp:Date.now(),version:"2.0"};if(e.isVoice&&(t.isVoice=!0,e.voice&&(t.voice=e.voice)),this.signingKey)try{t.signature=await Ft.signFileMetadata(t,this.signingKey),console.log("\u{1F512} File metadata signed successfully")}catch(r){ee.logSecurityEvent("signature_failed",{fileId:e.fileId,error:r.message})}await this.sendSecureMessage(t),e.status="metadata_sent"}catch(t){let r=ee.sanitizeError(t);throw console.error("\u274C Failed to send file metadata:",r),e.status="failed",new Error(r)}}async startChunkTransmission(e){try{e.status="transmitting";let t=e.file,r=e.totalChunks;for(let i=0;i{let r=this.activeTransfers.get(e.fileId);r&&r.status!=="completed"&&this.cleanupTransfer(e.fileId)},18e4)}async handleChunkRequest(e){let t=this.activeTransfers.get(e?.fileId);if(!t||!t.file)return;let r=Array.isArray(e.missing)?e.missing:[];if(r.length===0)return;this._armSenderIdleTimeout(t),t.status="transmitting";let n=r.slice(0,512);for(let a of n)if(!(!Number.isInteger(a)||a<0||a>=t.totalChunks))try{let o=a*this.CHUNK_SIZE,c=Math.min(o+this.CHUNK_SIZE,t.file.size),d=await this.readFileChunk(t.file,o,c);await this.sendFileChunk(t,a,d),await this.waitForBackpressure()}catch(o){console.warn("\u26A0\uFE0F Failed to retransmit chunk",a,ee.sanitizeError(o))}t.status==="transmitting"&&(t.status="waiting_confirmation"),this._armSenderIdleTimeout(t)}async readFileChunk(e,t,r){try{return await e.slice(t,r).arrayBuffer()}catch(i){let n=ee.sanitizeError(i);throw console.error("\u274C Failed to read file chunk:",n),new Error(n)}}async sendFileChunk(e,t,r){try{let i=e.sessionKey,n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},i,r),o=this.arrayBufferToBase64(new Uint8Array(a)),c={type:"file_chunk",fileId:e.fileId,chunkIndex:t,totalChunks:e.totalChunks,nonce:Array.from(n),encryptedDataB64:o,chunkSize:r.byteLength,timestamp:Date.now()};await this.waitForBackpressure(),await this.sendSecureMessage(c)}catch(i){let n=ee.sanitizeError(i);throw console.error("\u274C Failed to send file chunk:",n),new Error(n)}}async sendSecureMessage(e){let t=JSON.stringify(e),r=this.webrtcManager?.dataChannel,i=10,n=0,a=o=>new Promise(c=>setTimeout(c,o));for(;;)try{if(!r||r.readyState!=="open")throw new Error("Data channel not ready");await this.waitForBackpressure(),r.send(t);return}catch(o){let c=String(o?.message||""),d=c.includes("send queue is full")||c.includes("bufferedAmount"),u=o?.name==="OperationError";if((d||u)&&ne.bufferedAmountLowThreshold&&await new Promise(r=>{let i=()=>{e.removeEventListener("bufferedamountlow",i),r()};e.addEventListener("bufferedamountlow",i,{once:!0})});return}let t=4*1024*1024;for(;e.bufferedAmount>t;)await new Promise(r=>setTimeout(r,20))}catch{}}async calculateFileHash(e){try{let t=await e.arrayBuffer(),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw console.error("\u274C File hash calculation failed:",t),t}}async handleFileTransferStart(e){try{let t=this.getClientIdentifier();if(!this.incomingOfferLimiter.isAllowed(t))throw new Error("Incoming file request rate limit exceeded");let r=this.validateIncomingMetadata(e);if(!r.isValid)throw new Error(r.errors.join(". "));if(e.signature&&this.verificationKey)try{if(!await Ft.verifyFileMetadata(e,e.signature,this.verificationKey))throw ee.logSecurityEvent("invalid_metadata_signature",{fileId:e.fileId}),new Error("Invalid file metadata signature");console.log("\u{1F512} File metadata signature verified successfully")}catch(n){throw ee.logSecurityEvent("verification_failed",{fileId:e.fileId,error:n.message}),new Error("File metadata verification failed")}if(this.receivingTransfers.has(e.fileId)||this.pendingIncomingTransfers.has(e.fileId))return;if(this.pendingIncomingTransfers.size>=this.MAX_PENDING_INCOMING_TRANSFERS)throw new Error("Too many pending incoming file requests");r.voiceRejection&&console.warn(`Voice auto-accept declined, falling back to consent: ${r.voiceRejection}`);let i={...e,isVoice:r.isVoice,fileName:r.displayName,receivedAt:Date.now()};this.pendingIncomingTransfers.set(e.fileId,i),r.isVoice&&(this.autoAcceptedVoiceBytes+=e.fileSize),typeof this.onIncomingFileRequest=="function"?this.onIncomingFileRequest({fileId:i.fileId,fileName:i.fileName,fileSize:i.fileSize,mimeType:i.fileType||"application/octet-stream",isVoice:r.isVoice,voice:i.voice||null}):await this.rejectIncomingFile(e.fileId,f("file.consentUnavailable"))}catch(t){let r=ee.sanitizeError(t);console.error("\u274C Failed to handle file transfer start:",r);let i={type:"file_transfer_response",fileId:e.fileId,accepted:!1,error:r,timestamp:Date.now()};await this.sendSecureMessage(i)}}async handleFileChunk(e){return this.atomicOps.withLock(`chunk-${e.fileId}`,async()=>{try{let t=this.receivingTransfers.get(e.fileId);if(!t||t._assembled||t.status==="completed")return;if(!this._isIncomingChunkAllowed(e.fileId)){console.warn("\u26A0\uFE0F Incoming file chunk rate limit exceeded; cleaning up transfer:",e.fileId),this.cleanupReceivingTransfer(e.fileId);return}if(t.lastChunkTime=Date.now(),t.receivedChunks.has(e.chunkIndex))return;if(e.chunkIndex<0||e.chunkIndex>=t.totalChunks)throw new Error(`Invalid chunk index: ${e.chunkIndex}`);let r=new Uint8Array(e.nonce),i;if(e.encryptedDataB64)i=this.base64ToUint8Array(e.encryptedDataB64);else if(e.encryptedData)i=new Uint8Array(e.encryptedData);else throw new Error("Missing encrypted data");let n=await crypto.subtle.decrypt({name:"AES-GCM",iv:r},t.sessionKey,i);if(n.byteLength!==e.chunkSize)throw new Error(`Chunk size mismatch: expected ${e.chunkSize}, got ${n.byteLength}`);t.receivedChunks.set(e.chunkIndex,n),t.receivedCount++,this._emitTransferProgress(t,"down");let a={type:"chunk_confirmation",fileId:e.fileId,chunkIndex:e.chunkIndex,timestamp:Date.now()};await this.sendSecureMessage(a),t.receivedCount===t.totalChunks&&await this.assembleFile(t)}catch(t){let r=ee.sanitizeError(t);console.warn("\u26A0\uFE0F Dropping unprocessable file chunk (will be re-requested):",e.chunkIndex,r)}})}_isIncomingChunkAllowed(e){let t=this.getClientIdentifier();return this.incomingChunkLimiter.isAllowed(t)?(this.incomingTransferChunkLimiters.has(e)||this.incomingTransferChunkLimiters.set(e,new nt(this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE,6e4)),this.incomingTransferChunkLimiters.get(e).isAllowed(e)?!0:(ee.logSecurityEvent("incoming_chunk_transfer_rate_limit_exceeded",{clientId:t,fileId:e}),!1)):(ee.logSecurityEvent("incoming_chunk_aggregate_rate_limit_exceeded",{clientId:t,fileId:e}),!1)}async assembleFile(e){if(!e._assembled){e._assembled=!0;try{e.status="assembling";for(let u=0;uu+h.length,0);if(r!==e.fileSize)throw new Error(`File size mismatch: expected ${e.fileSize}, got ${r}`);let i=new Uint8Array(r),n=0;for(let u of t)i.set(u,n),n+=u.length;if(await this.calculateFileHashFromData(i)!==e.fileHash)throw new Error("File integrity check failed - hash mismatch");let o=i.buffer,c=new Blob([o],{type:e.fileType});if(e.endTime=Date.now(),e.status="completed",this._storeReceivedFileBuffer(e.fileId,{buffer:o,type:e.fileType,name:e.fileName,size:e.fileSize}),this.onFileReceived){let u=async()=>{let p=await this.getBlob(e.fileId);if(!p)throw new Error("This file is no longer available for download.");return p},h=async()=>{let p=await u();return URL.createObjectURL(p)},m=p=>{try{URL.revokeObjectURL(p)}catch{}};this.onFileReceived({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,mimeType:e.fileType,transferTime:e.endTime-e.startTime,isVoice:!!e.isVoice,voice:e.voice||null,fileBlob:c,getBlob:u,getObjectURL:h,revokeObjectURL:m})}let d={type:"file_transfer_complete",fileId:e.fileId,success:!0,timestamp:Date.now()};await this.sendSecureMessage(d),e._stallTimer&&(clearInterval(e._stallTimer),e._stallTimer=null),e.receivedChunks&&e.receivedChunks.clear(),e.sessionKey=null}catch(t){console.error("\u274C File assembly failed:",t),e.status="failed",this.onError&&this.onError(`File assembly failed: ${t.message}`);let r={type:"file_transfer_complete",fileId:e.fileId,success:!1,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(r),this.cleanupReceivingTransfer(e.fileId)}}}async calculateFileHashFromData(e){try{let t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(i=>i.toString(16).padStart(2,"0")).join("")}catch(t){throw console.error("\u274C Hash calculation failed:",t),t}}handleTransferResponse(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;e.accepted?(t.status="accepted",t.consentTimeout&&clearTimeout(t.consentTimeout),t.consentTimeout=null,t.resolveConsent?.(),t.resolveConsent=null,t.rejectConsent=null):(t.status="rejected",t.consentTimeout&&clearTimeout(t.consentTimeout),t.consentTimeout=null,t.rejectConsent?.(new Error(e.error||"Transfer rejected")),t.rejectConsent=null,t.resolveConsent=null,this.onError&&this.onError(`Transfer rejected: ${e.error||"Unknown reason"}`),this.cleanupTransfer(e.fileId))}catch(t){console.error("\u274C Failed to handle transfer response:",t)}}handleChunkConfirmation(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;t.confirmedChunks++,t.lastChunkTime=Date.now(),t.status==="waiting_confirmation"&&this._armSenderIdleTimeout(t)}catch(t){console.error("\u274C Failed to handle chunk confirmation:",t)}}handleTransferComplete(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;e.success?(t.status="completed",t.endTime=Date.now(),this.onComplete&&this.onComplete({fileId:t.fileId,fileName:t.file.name,fileSize:t.file.size,transferTime:t.endTime-t.startTime,status:"completed"})):(t.status="failed",this.onError&&this.onError(`Transfer failed: ${e.error||"Unknown error"}`)),this.cleanupTransfer(e.fileId)}catch(t){console.error("\u274C Failed to handle transfer completion:",t)}}handleTransferError(e){try{let t=this.activeTransfers.get(e.fileId);t&&(t.status="failed",this.cleanupTransfer(e.fileId));let r=this.receivingTransfers.get(e.fileId);r&&(r.status="failed",this.cleanupReceivingTransfer(e.fileId)),this.onError&&this.onError(`Transfer error: ${e.error||"Unknown error"}`)}catch(t){console.error("\u274C Failed to handle transfer error:",t)}}getActiveTransfers(){return Array.from(this.activeTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.file?.name||"Unknown",fileSize:e.file?.size||0,progress:Math.round(e.sentChunks/e.totalChunks*100),totalChunks:e.totalChunks||0,transferredChunks:e.sentChunks||0,status:e.status,startTime:e.startTime}))}getReceivingTransfers(){return Array.from(this.receivingTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.fileName||"Unknown",fileSize:e.fileSize||0,progress:Math.round(e.receivedCount/e.totalChunks*100),totalChunks:e.totalChunks||0,transferredChunks:e.receivedCount||0,status:e.status,startTime:e.startTime}))}getPendingIncomingTransfers(){return Array.from(this.pendingIncomingTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,mimeType:e.fileType||"application/octet-stream",receivedAt:e.receivedAt}))}async acceptIncomingFile(e){let t=this.pendingIncomingTransfers.get(e);if(!t)return!1;let r=await this.deriveFileSessionKeyFromSalt(e,t.salt);return this.receivingTransfers.set(e,{fileId:e,fileName:t.fileName,fileSize:t.fileSize,fileType:t.fileType||"application/octet-stream",fileHash:t.fileHash,totalChunks:t.totalChunks,chunkSize:t.chunkSize||this.CHUNK_SIZE,sessionKey:r,salt:t.salt,receivedChunks:new Map,receivedCount:0,startTime:Date.now(),lastChunkTime:Date.now(),status:"receiving",isVoice:!!t.isVoice,voice:t.voice||null}),this.pendingIncomingTransfers.delete(e),await this.sendSecureMessage({type:"file_transfer_response",fileId:e,accepted:!0,timestamp:Date.now()}),this._startReceiverStallDetector(e),!0}_startReceiverStallDetector(e){let n=this.receivingTransfers.get(e);n&&(n._stallTimer&&clearInterval(n._stallTimer),n._lastProgressCount=n.receivedCount||0,n._lastProgressTime=Date.now(),n._stallTimer=setInterval(async()=>{let a=this.receivingTransfers.get(e);if(!a||a._stallTimer!==n._stallTimer){clearInterval(n._stallTimer);return}if(a.status==="completed"||a._assembled){clearInterval(a._stallTimer),a._stallTimer=null;return}if(a.receivedCount!==a._lastProgressCount&&(a._lastProgressCount=a.receivedCount,a._lastProgressTime=Date.now()),!(a.receivedCount>=a.totalChunks)&&!(Date.now()-(a.lastChunkTime||0)<5e3)){if(Date.now()-a._lastProgressTime>18e4){clearInterval(a._stallTimer),a._stallTimer=null,a.status="failed",this.onError&&this.onError("File transfer stalled \u2014 no data received. Please try again."),this.cleanupReceivingTransfer(e);return}await this._requestMissingChunks(e)}},2500))}async _requestMissingChunks(e){let t=this.receivingTransfers.get(e);if(!t||!t.receivedChunks)return;let r=256,i=[];for(let n=0;nthis.MAX_RETAINED_RECEIVED_FILE_BUFFERS;){let r=this.receivedFileBuffers.keys().next().value;this._discardReceivedFileBuffer(r)}}_discardReceivedFileBuffer(e){let t=this.receivedFileBuffers.get(e);if(!t)return;try{t.buffer&&(qe.secureWipe(t.buffer),new Uint8Array(t.buffer).fill(0))}catch{}this.receivedFileBuffers.delete(e);let r=this.receivingTransfers.get(e);r&&(r.status==="completed"||r._assembled)&&(r._stallTimer&&(clearInterval(r._stallTimer),r._stallTimer=null),this.receivingTransfers.delete(e))}cleanupReceivingTransfer(e){try{this.pendingChunks.delete(e);let t=this.receivingTransfers.get(e);if(t){if(t._stallTimer&&(clearInterval(t._stallTimer),t._stallTimer=null),t.receivedChunks&&t.receivedChunks.size>0){for(let[n,a]of t.receivedChunks)try{a&&(a instanceof ArrayBuffer||a instanceof Uint8Array)&&(qe.secureWipe(a),a instanceof ArrayBuffer?new Uint8Array(a).fill(0):a instanceof Uint8Array&&a.fill(0))}catch(o){console.warn("\u26A0\uFE0F Failed to securely wipe chunk:",o)}t.receivedChunks.clear()}if(t.sessionKey)try{t.sessionKey=null}catch(n){console.warn("\u26A0\uFE0F Failed to clear session key:",n)}if(t.salt)try{Array.isArray(t.salt)&&t.salt.fill(0),t.salt=null}catch(n){console.warn("\u26A0\uFE0F Failed to clear salt:",n)}for(let[n,a]of Object.entries(t))a&&typeof a=="object"&&(a instanceof ArrayBuffer||a instanceof Uint8Array?qe.secureWipe(a):Array.isArray(a)&&a.fill(0),t[n]=null)}this.receivingTransfers.delete(e),this.sessionKeys.delete(e),this.incomingTransferChunkLimiters.delete(e);let r=this.receivedFileBuffers.get(e);if(r)try{r.buffer&&(qe.secureWipe(r.buffer),new Uint8Array(r.buffer).fill(0));for(let[n,a]of Object.entries(r))a&&typeof a=="object"&&((a instanceof ArrayBuffer||a instanceof Uint8Array)&&qe.secureWipe(a),r[n]=null);this.receivedFileBuffers.delete(e)}catch(n){console.warn("\u26A0\uFE0F Failed to securely clear file buffer:",n),this.receivedFileBuffers.delete(e)}let i=[];for(let n of this.processedChunks)n.startsWith(e)&&i.push(n);for(let n of i)this.processedChunks.delete(n);if(typeof global<"u"&&global.gc)try{global.gc()}catch{}console.log(`\u{1F512} Memory safely cleaned for file transfer: ${e}`)}catch(t){throw console.error("\u274C Error during secure memory cleanup:",t),this.receivingTransfers.delete(e),this.sessionKeys.delete(e),this.receivedFileBuffers.delete(e),this.pendingChunks.delete(e),new Error(`Memory cleanup failed: ${t.message}`)}}getTransferStatus(e){if(this.activeTransfers.has(e)){let t=this.activeTransfers.get(e);return{type:"sending",fileId:t.fileId,fileName:t.file.name,progress:Math.round(t.sentChunks/t.totalChunks*100),status:t.status,startTime:t.startTime}}if(this.receivingTransfers.has(e)){let t=this.receivingTransfers.get(e);return{type:"receiving",fileId:t.fileId,fileName:t.fileName,progress:Math.round(t.receivedCount/t.totalChunks*100),status:t.status,startTime:t.startTime}}return null}getSystemStatus(){return{initialized:!0,activeTransfers:this.activeTransfers.size,receivingTransfers:this.receivingTransfers.size,totalTransfers:this.activeTransfers.size+this.receivingTransfers.size,maxConcurrentTransfers:this.MAX_CONCURRENT_TRANSFERS,maxFileSize:this.MAX_FILE_SIZE,chunkSize:this.CHUNK_SIZE,hasWebrtcManager:!!this.webrtcManager,isConnected:this.webrtcManager?.isConnected?.()||!1,hasDataChannel:!!this.webrtcManager?.dataChannel,dataChannelState:this.webrtcManager?.dataChannel?.readyState,isVerified:this.webrtcManager?.isVerified,hasEncryptionKey:!!this.webrtcManager?.encryptionKey,hasMacKey:!!this.webrtcManager?.macKey,linkedToWebRTCManager:this.webrtcManager?.fileTransferSystem===this,supportedFileTypes:this.getSupportedFileTypes(),fileTypeInfo:this.getFileTypeInfo()}}cleanup(){Ie.getInstance().deactivate(),this.webrtcManager&&this.webrtcManager.dataChannel&&this.originalOnMessage&&(this.webrtcManager.dataChannel.onmessage=this.originalOnMessage,this.originalOnMessage=null),this.webrtcManager&&this.originalProcessMessage&&(this.webrtcManager.processMessage=this.originalProcessMessage,this.originalProcessMessage=null),this.webrtcManager&&this.originalRemoveSecurityLayers&&(this.webrtcManager.removeSecurityLayers=this.originalRemoveSecurityLayers,this.originalRemoveSecurityLayers=null);for(let e of this.activeTransfers.keys())this.cleanupTransfer(e);for(let e of this.receivingTransfers.keys())this.cleanupReceivingTransfer(e);this.atomicOps&&this.atomicOps.locks.clear(),this.rateLimiter&&this.rateLimiter.requests.clear(),this.incomingChunkLimiter&&this.incomingChunkLimiter.requests.clear(),this.incomingTransferChunkLimiters.clear(),this.pendingChunks.clear(),this.pendingIncomingTransfers.clear(),this.activeTransfers.clear(),this.receivingTransfers.clear(),this.transferQueue.length=0,this.sessionKeys.clear(),this.transferNonces.clear(),this.processedChunks.clear();for(let e of Array.from(this.receivedFileBuffers.keys()))this._discardReceivedFileBuffer(e);this.clearKeys()}onSessionUpdate(e){this.sessionKeys.clear()}diagnoseFileTransferIssue(){return{timestamp:new Date().toISOString(),fileTransferSystem:{initialized:!!this,hasWebrtcManager:!!this.webrtcManager,webrtcManagerType:this.webrtcManager?.constructor?.name,linkedToWebRTCManager:this.webrtcManager?.fileTransferSystem===this},webrtcManager:{hasDataChannel:!!this.webrtcManager?.dataChannel,dataChannelState:this.webrtcManager?.dataChannel?.readyState,isConnected:this.webrtcManager?.isConnected?.()||!1,isVerified:this.webrtcManager?.isVerified,hasEncryptionKey:!!this.webrtcManager?.encryptionKey,hasMacKey:!!this.webrtcManager?.macKey,hasKeyFingerprint:!!this.webrtcManager?.keyFingerprint,hasSessionSalt:!!this.webrtcManager?.sessionSalt},securityContext:{contextActive:Ie.getInstance().isActive(),securityLevel:Ie.getInstance().getSecurityLevel(),hasAtomicOps:!!this.atomicOps,hasRateLimiter:!!this.rateLimiter},transfers:{activeTransfers:this.activeTransfers.size,receivingTransfers:this.receivingTransfers.size,pendingChunks:this.pendingChunks.size,sessionKeys:this.sessionKeys.size},fileTypeSupport:{supportedTypes:this.getSupportedFileTypes(),generalMaxSize:this.formatFileSize(this.MAX_FILE_SIZE),restrictions:Object.keys(this.FILE_TYPE_RESTRICTIONS)}}}async debugKeyDerivation(e){try{if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("Session data not available");let t=await this.deriveFileSessionKey(e),r=await this.deriveFileSessionKeyFromSalt(e,t.salt),i=new TextEncoder().encode("test data"),n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},t.key,i),o=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},r,a);if(new TextDecoder().decode(o)==="test data")return{success:!0,message:"All tests passed"};throw new Error("Decryption verification failed")}catch(t){return console.error("\u274C Key derivation test failed:",t),{success:!1,error:t.message}}}registerWithWebRTCManager(){if(!this.webrtcManager)throw new Error("WebRTC manager not available");this.webrtcManager.fileTransferSystem=this,this.webrtcManager.setFileMessageHandler=e=>{this.webrtcManager._fileMessageHandler=e},this.webrtcManager.setFileMessageHandler(e=>this.handleFileMessage(e))}static createFileMessageFilter(e){return async t=>{try{if(typeof t.data=="string"){let r=JSON.parse(t.data);if(e.isFileTransferMessage(r))return await e.handleFileMessage(r),!0}}catch{}return!1}}setSigningKey(e){if(!e||!(e instanceof CryptoKey))throw new Error("Invalid private key for signing");this.signingKey=e,console.log("\u{1F512} Signing key set successfully")}setVerificationKey(e){if(!e||!(e instanceof CryptoKey))throw new Error("Invalid public key for verification");this.verificationKey=e,console.log("\u{1F512} Verification key set successfully")}async generateSigningKeyPair(){try{let e=await crypto.subtle.generateKey({name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},!0,["sign","verify"]);return this.signingKey=e.privateKey,this.verificationKey=e.publicKey,console.log("\u{1F512} RSA key pair generated successfully"),e}catch(e){let t=ee.sanitizeError(e);throw console.error("\u274C Failed to generate signing key pair:",t),new Error(t)}}clearKeys(){this.signingKey=null,this.verificationKey=null,console.log("\u{1F512} Security keys cleared")}getSecurityStatus(){return{signingEnabled:this.signingKey!==null,verificationEnabled:this.verificationKey!==null,contextActive:Ie.getInstance().isActive(),securityLevel:Ie.getInstance().getSecurityLevel()}}getClientIdentifier(){return this.webrtcManager?.connectionId||this.webrtcManager?.keyFingerprint?.substring(0,16)||"default-client"}destroy(){Ie.getInstance().deactivate(),this.clearKeys(),console.log("\u{1F512} File transfer system destroyed safely")}};var Ue=typeof navigator<"u"&&/AppleWebKit/.test(navigator.userAgent)&&!/Chrome|Chromium|Edg\//.test(navigator.userAgent),st={opusFmtp:{minptime:10,useinbandfec:1,usedtx:1,stereo:0,maxaveragebitrate:32e3,cbr:0},preferRed:!0,sender:{maxBitrate:4e4,priority:"high",networkPriority:"high"}},Re={codecPreferenceOrder:["VP9","AV1","H264","VP8"],vp9:{preferredScalabilityMode:"L3T3_KEY",simulcast:[{rid:"low",scaleResolutionDownBy:4,maxBitrate:15e4,scalabilityMode:"L1T3"},{rid:"mid",scaleResolutionDownBy:2,maxBitrate:5e5,scalabilityMode:"L1T3"},{rid:"high",scaleResolutionDownBy:1,maxBitrate:15e5,scalabilityMode:"L1T3"}],degradationPreference:"balanced"},av1:{scalabilityMode:"L1T3",maxBitrate:12e5,degradationPreference:"maintain-framerate"},simulcast:[{rid:"low",scaleResolutionDownBy:4,maxBitrate:15e4},{rid:"mid",scaleResolutionDownBy:2,maxBitrate:5e5},{rid:"high",scaleResolutionDownBy:1,maxBitrate:15e5}],networkPriority:"medium"},qi={twccUri:"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",video:{rtcpFb:["transport-cc","nack","nack pli","ccm fir","goog-remb"],twcc:!0},audio:{rtcpFb:["transport-cc","nack"],twcc:!0}},Tr={intervalMs:1e3,loss:{highPct:.1,recoverPct:.03,audioProtectPct:.25},rtt:{highMs:300,recoverMs:150},stepDownPct:.2,stepUpPct:.1,minVideoBitrate:1e5,recoverStableTicks:5,cpuScaleStep:1.5};function ta(s){return s.indexOf(`\r +var os=Object.create;var bi=Object.defineProperty;var cs=Object.getOwnPropertyDescriptor;var ls=Object.getOwnPropertyNames;var ds=Object.getPrototypeOf,us=Object.prototype.hasOwnProperty;var _i=(s,e)=>()=>{try{return e||s((e={exports:{}}).exports,e),e.exports}catch(t){throw e=0,t}};var hs=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ls(e))!us.call(s,i)&&i!==t&&bi(s,i,{get:()=>e[i],enumerable:!(r=cs(e,i))||r.enumerable});return s};var wi=(s,e,t)=>(t=s!=null?os(ds(s)):{},hs(e||!s||!s.__esModule?bi(t,"default",{value:s,enumerable:!0}):t,s));var Ln=_i((Fo,Wt)=>{var wt=class{constructor(e={}){this.permission=typeof Notification<"u"&&Notification&&typeof Notification.permission=="string"?Notification.permission:"denied",this.isTabActive=this.checkTabActive(),this.unreadCount=0,this.originalTitle=document.title,this.notificationQueue=[],this.maxQueueSize=e.maxQueueSize||5,this.rateLimitMs=e.rateLimitMs||2e3,this.lastNotificationTime=0,this.trustedOrigins=e.trustedOrigins||[],this.isSecureContext=window.isSecureContext,this.hidden=this.getHiddenProperty(),this.visibilityChange=this.getVisibilityChangeEvent(),this.initVisibilityTracking(),this.initSecurityChecks()}initSecurityChecks(){}getHiddenProperty(){return typeof document.hidden<"u"?"hidden":typeof document.msHidden<"u"?"msHidden":typeof document.webkitHidden<"u"?"webkitHidden":"hidden"}getVisibilityChangeEvent(){return typeof document.hidden<"u"?"visibilitychange":typeof document.msHidden<"u"?"msvisibilitychange":typeof document.webkitHidden<"u"?"webkitvisibilitychange":"visibilitychange"}checkTabActive(){return this.hidden&&typeof document[this.hidden]<"u"?!document[this.hidden]:typeof document.hasFocus=="function"?document.hasFocus():!0}initVisibilityTracking(){typeof document.addEventListener<"u"&&typeof document[this.hidden]<"u"&&document.addEventListener(this.visibilityChange,()=>{this.isTabActive=this.checkTabActive(),this.isTabActive&&(this.resetUnreadCount(),this.clearNotificationQueue())}),window.addEventListener("focus",()=>{this.isTabActive=this.checkTabActive(),this.isTabActive&&this.resetUnreadCount()}),window.addEventListener("blur",()=>{this.isTabActive=this.checkTabActive()}),window.addEventListener("beforeunload",()=>{this.clearNotificationQueue()})}async requestPermission(){if(!this.isSecureContext||!("Notification"in window))return!1;if(this.permission==="granted")return!0;if(this.permission==="denied")return!1;try{return this.permission=await Notification.requestPermission(),this.permission==="granted"}catch{return!1}}updateTitle(){this.unreadCount>0?document.title=`(${this.unreadCount}) ${this.originalTitle}`:document.title=this.originalTitle}sanitizeText(e){if(typeof e!="string")return"";let t=document.createElement("div");return t.textContent=e,t.innerHTML.replace(//g,">").replace(/"/g,""").replace(/'/g,"'").substring(0,500)}validateIconUrl(e){if(!e)return null;try{let t=new URL(e,window.location.origin);return t.protocol==="https:"||t.protocol==="data:"?this.trustedOrigins.length>0?this.trustedOrigins.some(i=>t.origin===i)?t.href:null:t.href:null}catch{return null}}checkRateLimit(){let e=Date.now();return e-this.lastNotificationTime"u"||(this.isTabActive=this.checkTabActive(),this.isTabActive)||this.permission!=="granted"||!this.checkRateLimit())return null;let i=this.sanitizeText(e||"Unknown"),n=this.sanitizeText(t||""),a=this.validateIconUrl(r.icon)||"/logo/icon-192x192.png";this.notificationQueue.length>=this.maxQueueSize&&this.clearNotificationQueue();try{let o=new Notification(`${i}`,{body:n.substring(0,200),icon:a,badge:a,tag:`chat-${r.senderId||"unknown"}`,requireInteraction:!1,silent:r.silent||!1,vibrate:navigator.vibrate?[200,100,200]:void 0,data:{senderId:this.sanitizeText(r.senderId),timestamp:Date.now()}});this.unreadCount++,this.updateTitle(),this.notificationQueue.push(o),o.onclick=d=>{if(d.preventDefault(),window.focus(),o.close(),typeof r.onClick=="function")try{r.onClick(r.senderId)}catch(h){console.error("[Notifications] Error in onClick handler:",h)}},o.onerror=d=>{console.error("[Notifications] Error showing notification:",d)};let c=Math.min(r.autoClose||5e3,1e4);return setTimeout(()=>{o.close(),this.removeFromQueue(o)},c),o}catch(o){return console.error("[Notifications] Failed to create notification:",o),null}}removeFromQueue(e){let t=this.notificationQueue.indexOf(e);t>-1&&this.notificationQueue.splice(t,1)}clearNotificationQueue(){this.notificationQueue.forEach(e=>{try{e.close()}catch{}}),this.notificationQueue=[]}resetUnreadCount(){this.unreadCount=0,this.updateTitle()}getStatus(){return{permission:this.permission,isTabActive:this.isTabActive,unreadCount:this.unreadCount,isSecureContext:this.isSecureContext,queueSize:this.notificationQueue.length}}},Yt=class{constructor(){this.notificationManager=new wt({maxQueueSize:5,rateLimitMs:2e3,trustedOrigins:[window.location.origin]}),this.dataChannel=null,this.peerConnection=null,this.remotePeerName="Peer",this.messageHistory=[],this.maxHistorySize=100}async init(){}async enableNotifications(){return await this.notificationManager.requestPermission()}setupDataChannel(e){if(!e){console.error("[Chat] Invalid DataChannel");return}this.dataChannel=e,this.dataChannel.onmessage=t=>{this.handleIncomingMessage(t.data)},this.dataChannel.onerror=t=>{}}validateMessage(e){try{let t=typeof e=="string"?JSON.parse(e):e;if(!t||typeof t!="object")throw new Error("Invalid message structure");if(!t.text||typeof t.text!="string")throw new Error("Invalid message text");if(t.text.length>1e4)throw new Error("Message too long");return{text:t.text,senderName:t.senderName||"Unknown",senderId:t.senderId||"unknown",timestamp:t.timestamp||Date.now(),senderAvatar:t.senderAvatar||null}}catch(t){return console.error("[Chat] Message validation failed:",t),null}}handleIncomingMessage(e){let t=this.validateMessage(e);t&&(this.messageHistory.push(t),this.messageHistory.length>this.maxHistorySize&&this.messageHistory.shift(),this.displayMessage(t),this.notificationManager.notify(t.senderName,t.text,{icon:t.senderAvatar,senderId:t.senderId,onClick:r=>{this.scrollToLatestMessage()}}),this.notificationManager.isTabActive||this.playNotificationSound())}displayMessage(e){let t=document.getElementById("messages");if(!t)return;let r=document.createElement("div");r.className="message";let i=document.createElement("strong");i.textContent=e.senderName+": ";let n=document.createElement("span");n.textContent=e.text,n.style.wordWrap="break-word",n.style.overflowWrap="break-word",n.style.whiteSpace="normal";let a=document.createElement("small");a.textContent=new Date(e.timestamp).toLocaleTimeString(),r.appendChild(i),r.appendChild(n),r.appendChild(document.createElement("br")),r.appendChild(a),t.appendChild(r),this.scrollToLatestMessage()}playNotificationSound(){try{let e=new Audio("/assets/audio/notification.mp3");e.volume=.3,e.play().catch(t=>{})}catch{}}scrollToLatestMessage(){let e=document.getElementById("messages");e&&(e.scrollTop=e.scrollHeight)}getStatus(){return{notifications:this.notificationManager.getStatus(),messageCount:this.messageHistory.length,connected:this.dataChannel?.readyState==="open"}}};typeof Wt<"u"&&Wt.exports&&(Wt.exports={SecureChatNotificationManager:wt,SecureP2PChat:Yt});typeof window<"u"&&(window.SecureChatNotificationManager=wt,window.SecureP2PChat=Yt)});var Pn=_i((Ko,Xt)=>{var Dn=wi(Ln());var Qt=class{constructor(e){this.webrtcManager=e,this.notificationManager=new Dn.SecureChatNotificationManager({maxQueueSize:10,rateLimitMs:1e3,trustedOrigins:[window.location.origin]}),this.isInitialized=!1,this.originalOnMessage=null,this.originalOnStatusChange=null,this.processedMessages=new Set}async init(){try{return this.isInitialized||(this.originalOnMessage=this.webrtcManager.onMessage,this.originalOnStatusChange=this.webrtcManager.onStatusChange,this.webrtcManager.onMessage=(e,t,...r)=>{this.handleIncomingMessage(e,t,r[0]),this.originalOnMessage&&this.originalOnMessage(e,t,...r)},this.webrtcManager.onStatusChange=e=>{this.handleStatusChange(e),this.originalOnStatusChange&&this.originalOnStatusChange(e)},this.webrtcManager.deliverMessageToUI&&(this.originalDeliverMessageToUI=this.webrtcManager.deliverMessageToUI.bind(this.webrtcManager),this.webrtcManager.deliverMessageToUI=(e,t,...r)=>{this.handleIncomingMessage(e,t,r[0]),this.originalDeliverMessageToUI(e,t,...r)}),this.isInitialized=!0),!0}catch{return!1}}handleIncomingMessage(e,t,r){try{let i=`${t}:${typeof e=="string"?e:JSON.stringify(e)}`;if(this.processedMessages.has(i))return;if(this.processedMessages.add(i),this.processedMessages.size>100){let d=Array.from(this.processedMessages);this.processedMessages.clear(),d.slice(-50).forEach(h=>this.processedMessages.add(h))}if(t==="system"||t==="file-transfer"||t==="heartbeat")return;let n=this.extractMessageInfo(e,t);if(!n)return;let o=!!r&&typeof r=="object"&&(r.once===!0||Number.isFinite(r.ttl)&&r.ttl>0)?"Sent you a private message":n.text,c=this.notificationManager.notify(n.senderName,o,{icon:n.senderAvatar,senderId:n.senderId,onClick:d=>{this.focusChatWindow()}})}catch{}}handleStatusChange(e){try{(e==="disconnected"||e==="failed")&&(this.notificationManager.clearNotificationQueue(),this.notificationManager.resetUnreadCount())}catch{}}extractMessageInfo(e,t){try{let r=e;if(typeof e=="string")try{r=JSON.parse(e)}catch{return{senderName:"Peer",text:e,senderId:"peer",senderAvatar:null}}return typeof r=="object"&&r!==null?{senderName:r.senderName||r.name||"Peer",text:r.text||r.message||r.content||"",senderId:r.senderId||r.id||"peer",senderAvatar:r.senderAvatar||r.avatar||null}:null}catch{return null}}focusChatWindow(){try{window.focus();let e=document.getElementById("messages");e&&(e.scrollTop=e.scrollHeight)}catch{}}async requestPermission(){try{return await this.notificationManager.requestPermission()}catch{return!1}}getStatus(){return this.notificationManager.getStatus()}clearNotifications(){this.notificationManager.clearNotificationQueue(),this.notificationManager.resetUnreadCount()}cleanup(){try{this.isInitialized&&(this.originalOnMessage&&(this.webrtcManager.onMessage=this.originalOnMessage),this.originalOnStatusChange&&(this.webrtcManager.onStatusChange=this.originalOnStatusChange),this.originalDeliverMessageToUI&&(this.webrtcManager.deliverMessageToUI=this.originalDeliverMessageToUI),this.clearNotifications(),this.isInitialized=!1)}catch{}}};typeof Xt<"u"&&Xt.exports&&(Xt.exports={NotificationIntegration:Qt});typeof window<"u"&&(window.NotificationIntegration=Qt)});function Ei(s,e){(e==null||e>s.length)&&(e=s.length);for(var t=0,r=Array(e);t2?r-2:0),n=2;n1?t-1:0),i=1;i"u"?null:se(BigInt.prototype.toString),xi=typeof Symbol>"u"?null:se(Symbol.prototype.toString),ye=se(Object.prototype.hasOwnProperty),pt=se(Object.prototype.toString),oe=se(RegExp.prototype.test),$e=ks(TypeError);function se(s){return function(e){e instanceof RegExp&&(e.lastIndex=0);for(var t=arguments.length,r=new Array(t>1?t-1:0),i=1;i2&&arguments[2]!==void 0?arguments[2]:yt;if(vi&&vi(s,null),!Fe(e))return s;let r=e.length;for(;r--;){let i=e[r];if(typeof i=="string"){let n=t(i);n!==i&&(Ss(e)||(e[r]=n),i=n)}s[i]=!0}return s}function As(s){for(let e=0;e/g),Ps=le(/\${[\w\W]*/g),Fs=le(/^data-[\-\w.\u00B7-\uFFFF]+$/),Ks=le(/^aria-[\-\w]+$/),Di=le(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Ns=le(/^(?:\w+script|data):/i),Os=le(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Us=le(/^html$/i),zs=le(/^[a-z][.\w]*(-[.\w]+)+$/i),Pi=le(/<[/\w!]/g),Vs=le(/<[/\w]/g),Bs=le(/<\/no(script|embed|frames)/i),Hs=le(/\/>/i),ke={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,processingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},$s=function(){return typeof window>"u"?null:window},Gs=function(e,t){if(typeof e!="object"||typeof e.createPolicy!="function")return null;let r=null,i="data-tt-policy-suffix";t&&t.hasAttribute(i)&&(r=t.getAttribute(i));let n="dompurify"+(r?"#"+r:"");try{return e.createPolicy(n,{createHTML(a){return a},createScriptURL(a){return a}})}catch{return console.warn("TrustedTypes policy "+n+" could not be created."),null}},Fi=function(){return{afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},Pe=function(e,t,r,i){return ye(e,t)&&Fe(e[t])?H(i.base?pe(i.base):{},e[t],i.transform):r};function Oi(){let s=arguments.length>0&&arguments[0]!==void 0?arguments[0]:$s(),e=C=>Oi(C);if(e.version="3.4.10",e.removed=[],!s||!s.document||s.document.nodeType!==ke.document||!s.Element)return e.isSupported=!1,e;let t=s.document,r=t,i=r.currentScript;s.DocumentFragment;let n=s.HTMLTemplateElement,a=s.Node,o=s.Element,c=s.NodeFilter,d=s.NamedNodeMap;d===void 0&&(s.NamedNodeMap||s.MozNamedAttrMap),s.HTMLFormElement;let h=s.DOMParser,u=s.trustedTypes,m=o.prototype,y=Ae(m,"cloneNode"),b=Ae(m,"remove"),p=Ae(m,"nextSibling"),S=Ae(m,"childNodes"),w=Ae(m,"parentNode"),M=Ae(m,"shadowRoot"),F=Ae(m,"attributes"),k=a&&a.prototype?Ae(a.prototype,"nodeType"):null,E=a&&a.prototype?Ae(a.prototype,"nodeName"):null;if(typeof n=="function"){let C=t.createElement("template");C.content&&C.content.ownerDocument&&(t=C.content.ownerDocument)}let _,A="",x,T=!1,Y=0,B=function(){if(Y>0)throw $e('A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted Types" section of the README.')},R=function(l){B(),Y++;try{return _.createHTML(l)}finally{Y--}},ue=function(l){B(),Y++;try{return _.createScriptURL(l)}finally{Y--}},K=function(){return T||(x=Gs(u,i),T=!0),x},O=t,Q=O.implementation,J=O.createNodeIterator,ge=O.createDocumentFragment,G=O.getElementsByTagName,U=r.importNode,I=Fi();e.isSupported=typeof Ki=="function"&&typeof w=="function"&&Q&&Q.createHTMLDocument!==void 0;let D=Ls,N=Ds,z=Ps,W=Fs,Z=Ks,be=Ns,_e=Os,me=zs,Ye=Di,X=null,Zt=H({},[...Ii,...mr,...Sr,...br,...Ri]),ie=null,er=H({},[...Mi,..._r,...Li,...Rt]),te=Object.seal(rt(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ct=null,Qr=null,Me=Object.seal(rt(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}})),Jr=!0,tr=!0,Zr=!1,ei=!0,Le=!1,lt=!0,Be=!1,rr=!1,ir=!1,Xe=!1,vt=!1,Tt=!1,ti=!0,ri=!1,ii="user-content-",nr=!0,sr=!1,Qe={},Te=null,ar=H({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","selectedcontent","style","svg","template","thead","title","video","xmp"]),ni=null,si=H({},["audio","video","img","source","image","track"]),or=null,ai=H({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ct="http://www.w3.org/1998/Math/MathML",kt="http://www.w3.org/2000/svg",Ce="http://www.w3.org/1999/xhtml",Je=Ce,cr=!1,lr=null,Gn=H({},[Ct,kt,Ce],gr),oi=ce(["mi","mo","mn","ms","mtext"]),dr=H({},oi),ci=ce(["annotation-xml"]),ur=H({},ci),qn=H({},["title","style","font","a","script"]),dt=null,jn=["application/xhtml+xml","text/html"],Wn="text/html",re=null,Ze=null,Yn=t.createElement("form"),li=function(l){return l instanceof RegExp||l instanceof Function},hr=function(){let l=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(Ze&&Ze===l)return;(!l||typeof l!="object")&&(l={}),l=pe(l),dt=jn.indexOf(l.PARSER_MEDIA_TYPE)===-1?Wn:l.PARSER_MEDIA_TYPE,re=dt==="application/xhtml+xml"?gr:yt,X=Pe(l,"ALLOWED_TAGS",Zt,{transform:re}),ie=Pe(l,"ALLOWED_ATTR",er,{transform:re}),lr=Pe(l,"ALLOWED_NAMESPACES",Gn,{transform:gr}),or=Pe(l,"ADD_URI_SAFE_ATTR",ai,{transform:re,base:ai}),ni=Pe(l,"ADD_DATA_URI_TAGS",si,{transform:re,base:si}),Te=Pe(l,"FORBID_CONTENTS",ar,{transform:re}),ct=Pe(l,"FORBID_TAGS",pe({}),{transform:re}),Qr=Pe(l,"FORBID_ATTR",pe({}),{transform:re}),Qe=ye(l,"USE_PROFILES")?l.USE_PROFILES&&typeof l.USE_PROFILES=="object"?pe(l.USE_PROFILES):l.USE_PROFILES:!1,Jr=l.ALLOW_ARIA_ATTR!==!1,tr=l.ALLOW_DATA_ATTR!==!1,Zr=l.ALLOW_UNKNOWN_PROTOCOLS||!1,ei=l.ALLOW_SELF_CLOSE_IN_ATTR!==!1,Le=l.SAFE_FOR_TEMPLATES||!1,lt=l.SAFE_FOR_XML!==!1,Be=l.WHOLE_DOCUMENT||!1,Xe=l.RETURN_DOM||!1,vt=l.RETURN_DOM_FRAGMENT||!1,Tt=l.RETURN_TRUSTED_TYPE||!1,ir=l.FORCE_BODY||!1,ti=l.SANITIZE_DOM!==!1,ri=l.SANITIZE_NAMED_PROPS||!1,nr=l.KEEP_CONTENT!==!1,sr=l.IN_PLACE||!1,Ye=Is(l.ALLOWED_URI_REGEXP)?l.ALLOWED_URI_REGEXP:Di,Je=typeof l.NAMESPACE=="string"?l.NAMESPACE:Ce,dr=ye(l,"MATHML_TEXT_INTEGRATION_POINTS")&&l.MATHML_TEXT_INTEGRATION_POINTS&&typeof l.MATHML_TEXT_INTEGRATION_POINTS=="object"?pe(l.MATHML_TEXT_INTEGRATION_POINTS):H({},oi),ur=ye(l,"HTML_INTEGRATION_POINTS")&&l.HTML_INTEGRATION_POINTS&&typeof l.HTML_INTEGRATION_POINTS=="object"?pe(l.HTML_INTEGRATION_POINTS):H({},ci);let g=ye(l,"CUSTOM_ELEMENT_HANDLING")&&l.CUSTOM_ELEMENT_HANDLING&&typeof l.CUSTOM_ELEMENT_HANDLING=="object"?pe(l.CUSTOM_ELEMENT_HANDLING):rt(null);if(te=rt(null),ye(g,"tagNameCheck")&&li(g.tagNameCheck)&&(te.tagNameCheck=g.tagNameCheck),ye(g,"attributeNameCheck")&&li(g.attributeNameCheck)&&(te.attributeNameCheck=g.attributeNameCheck),ye(g,"allowCustomizedBuiltInElements")&&typeof g.allowCustomizedBuiltInElements=="boolean"&&(te.allowCustomizedBuiltInElements=g.allowCustomizedBuiltInElements),le(te),Le&&(tr=!1),vt&&(Xe=!0),Qe&&(X=H({},Ri),ie=rt(null),Qe.html===!0&&(H(X,Ii),H(ie,Mi)),Qe.svg===!0&&(H(X,mr),H(ie,_r),H(ie,Rt)),Qe.svgFilters===!0&&(H(X,Sr),H(ie,_r),H(ie,Rt)),Qe.mathMl===!0&&(H(X,br),H(ie,Li),H(ie,Rt))),Me.tagCheck=null,Me.attributeCheck=null,ye(l,"ADD_TAGS")&&(typeof l.ADD_TAGS=="function"?Me.tagCheck=l.ADD_TAGS:Fe(l.ADD_TAGS)&&(X===Zt&&(X=pe(X)),H(X,l.ADD_TAGS,re))),ye(l,"ADD_ATTR")&&(typeof l.ADD_ATTR=="function"?Me.attributeCheck=l.ADD_ATTR:Fe(l.ADD_ATTR)&&(ie===er&&(ie=pe(ie)),H(ie,l.ADD_ATTR,re))),ye(l,"ADD_URI_SAFE_ATTR")&&Fe(l.ADD_URI_SAFE_ATTR)&&H(or,l.ADD_URI_SAFE_ATTR,re),ye(l,"FORBID_CONTENTS")&&Fe(l.FORBID_CONTENTS)&&(Te===ar&&(Te=pe(Te)),H(Te,l.FORBID_CONTENTS,re)),ye(l,"ADD_FORBID_CONTENTS")&&Fe(l.ADD_FORBID_CONTENTS)&&(Te===ar&&(Te=pe(Te)),H(Te,l.ADD_FORBID_CONTENTS,re)),nr&&(X["#text"]=!0),Be&&H(X,["html","head","body"]),X.table&&(H(X,["tbody"]),delete ct.tbody),l.TRUSTED_TYPES_POLICY){if(typeof l.TRUSTED_TYPES_POLICY.createHTML!="function")throw $e('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if(typeof l.TRUSTED_TYPES_POLICY.createScriptURL!="function")throw $e('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');let v=_;_=l.TRUSTED_TYPES_POLICY;try{A=R("")}catch(L){throw _=v,L}}else l.TRUSTED_TYPES_POLICY===null?(_=void 0,A=""):(_===void 0&&(_=K()),_&&typeof A=="string"&&(A=R("")));(I.uponSanitizeElement.length>0||I.uponSanitizeAttribute.length>0)&&X===Zt&&(X=pe(X)),I.uponSanitizeAttribute.length>0&&ie===er&&(ie=pe(ie)),ce&&ce(l),Ze=l},di=H({},[...mr,...Sr,...Rs]),ui=H({},[...br,...Ms]),Xn=function(l,g,v){return g.namespaceURI===Ce?l==="svg":g.namespaceURI===Ct?l==="svg"&&(v==="annotation-xml"||dr[v]):!!di[l]},Qn=function(l,g,v){return g.namespaceURI===Ce?l==="math":g.namespaceURI===kt?l==="math"&&ur[v]:!!ui[l]},Jn=function(l,g,v){return g.namespaceURI===kt&&!ur[v]||g.namespaceURI===Ct&&!dr[v]?!1:!ui[l]&&(qn[l]||!di[l])},Zn=function(l){let g=w(l);(!g||!g.tagName)&&(g={namespaceURI:Je,tagName:"template"});let v=yt(l.tagName),L=yt(g.tagName);return lr[l.namespaceURI]?l.namespaceURI===kt?Xn(v,g,L):l.namespaceURI===Ct?Qn(v,g,L):l.namespaceURI===Ce?Jn(v,g,L):!!(dt==="application/xhtml+xml"&&lr[l.namespaceURI]):!1},De=function(l){tt(e.removed,{element:l});try{w(l).removeChild(l)}catch{if(b(l),!w(l))throw $e("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place")}},hi=function(l){let g=S(l);if(g){let L=[];ht(g,V=>{tt(L,V)}),ht(L,V=>{try{b(V)}catch{}})}let v=F(l);if(v)for(let L=v.length-1;L>=0;--L){let V=v[L],$=V&&V.name;if(typeof $=="string")try{l.removeAttribute($)}catch{}}},He=function(l,g){try{tt(e.removed,{attribute:g.getAttributeNode(l),from:g})}catch{tt(e.removed,{attribute:null,from:g})}if(g.removeAttribute(l),l==="is")if(Xe||vt)try{De(g)}catch{}else try{g.setAttribute(l,"")}catch{}},es=function(l){let g=F(l);if(g)for(let v=g.length-1;v>=0;--v){let L=g[v],V=L&&L.name;if(!(typeof V!="string"||ie[re(V)]))try{l.removeAttribute(V)}catch{}}},ts=function(l){let g=[l];for(;g.length>0;){let v=g.pop();(k?k(v):v.nodeType)===ke.element&&es(v);let V=S(v);if(V)for(let $=V.length-1;$>=0;--$)g.push(V[$])}},fi=function(l){let g=null,v=null;if(ir)l=""+l;else{let $=Ci(l,/^[\r\n\t ]+/);v=$&&$[0]}dt==="application/xhtml+xml"&&Je===Ce&&(l=''+l+"");let L=_?R(l):l;if(Je===Ce)try{g=new h().parseFromString(L,dt)}catch{}if(!g||!g.documentElement){g=Q.createDocument(Je,"template",null);try{g.documentElement.innerHTML=cr?A:L}catch{}}let V=g.body||g.documentElement;return l&&v&&V.insertBefore(t.createTextNode(v),V.childNodes[0]||null),Je===Ce?G.call(g,Be?"html":"body")[0]:Be?g.documentElement:V},pi=function(l){return J.call(l.ownerDocument||l,l,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT|c.SHOW_PROCESSING_INSTRUCTION|c.SHOW_CDATA_SECTION,null)},At=function(l){return l=ft(l,D," "),l=ft(l,N," "),l=ft(l,z," "),l},fr=function(l){var g;l.normalize();let v=J.call(l.ownerDocument||l,l,c.SHOW_TEXT|c.SHOW_COMMENT|c.SHOW_CDATA_SECTION|c.SHOW_PROCESSING_INSTRUCTION,null),L=v.nextNode();for(;L;)L.data=At(L.data),L=v.nextNode();let V=(g=l.querySelectorAll)===null||g===void 0?void 0:g.call(l,"template");V&&ht(V,$=>{et($.content)&&fr($.content)})},xt=function(l){let g=E?E(l):null;return typeof g!="string"||re(g)!=="form"?!1:typeof l.nodeName!="string"||typeof l.textContent!="string"||typeof l.removeChild!="function"||l.attributes!==F(l)||typeof l.removeAttribute!="function"||typeof l.setAttribute!="function"||typeof l.namespaceURI!="string"||typeof l.insertBefore!="function"||typeof l.hasChildNodes!="function"||l.nodeType!==k(l)||l.childNodes!==S(l)},et=function(l){if(!k||typeof l!="object"||l===null)return!1;try{return k(l)===ke.documentFragment}catch{return!1}},ut=function(l){if(!k||typeof l!="object"||l===null)return!1;try{return typeof k(l)=="number"}catch{return!1}};function xe(C,l,g){C.length!==0&&ht(C,v=>{v.call(e,l,g,Ze)})}let rs=function(l,g){return!!(lt&&l.hasChildNodes()&&!ut(l.firstElementChild)&&oe(Pi,l.textContent)&&oe(Pi,l.innerHTML)||lt&&l.namespaceURI===Ce&&g==="style"&&ut(l.firstElementChild)||l.nodeType===ke.processingInstruction||lt&&l.nodeType===ke.comment&&oe(Vs,l.data))},is=function(l,g){if(!ct[g]&&mi(g)&&(te.tagNameCheck instanceof RegExp&&oe(te.tagNameCheck,g)||te.tagNameCheck instanceof Function&&te.tagNameCheck(g)))return!1;if(nr&&!Te[g]){let v=w(l),L=S(l);if(L&&v){let V=L.length;for(let $=V-1;$>=0;--$){let ae=sr?L[$]:y(L[$],!0);v.insertBefore(ae,p(l))}}}return De(l),!0},yi=function(l){if(xe(I.beforeSanitizeElements,l,null),xt(l))return De(l),!0;let g=re(E?E(l):l.nodeName);if(xe(I.uponSanitizeElement,l,{tagName:g,allowedTags:X}),rs(l,g))return De(l),!0;if(ct[g]||!(Me.tagCheck instanceof Function&&Me.tagCheck(g))&&!X[g])return is(l,g);if((k?k(l):l.nodeType)===ke.element&&!Zn(l)||(g==="noscript"||g==="noembed"||g==="noframes")&&oe(Bs,l.innerHTML))return De(l),!0;if(Le&&l.nodeType===ke.text){let L=At(l.textContent);l.textContent!==L&&(tt(e.removed,{element:l.cloneNode()}),l.textContent=L)}return xe(I.afterSanitizeElements,l,null),!1},gi=function(l,g,v){if(Qr[g]||ti&&(g==="id"||g==="name")&&(v in t||v in Yn))return!1;let L=ie[g]||Me.attributeCheck instanceof Function&&Me.attributeCheck(g,l);if(!(tr&&oe(W,g))){if(!(Jr&&oe(Z,g))){if(L){if(!or[g]){if(!oe(Ye,ft(v,_e,""))){if(!((g==="src"||g==="xlink:href"||g==="href")&&l!=="script"&&ki(v,"data:")===0&&ni[l])){if(!(Zr&&!oe(be,ft(v,_e,"")))){if(v)return!1}}}}}else if(!(mi(l)&&(te.tagNameCheck instanceof RegExp&&oe(te.tagNameCheck,l)||te.tagNameCheck instanceof Function&&te.tagNameCheck(l))&&(te.attributeNameCheck instanceof RegExp&&oe(te.attributeNameCheck,g)||te.attributeNameCheck instanceof Function&&te.attributeNameCheck(g,l))||g==="is"&&te.allowCustomizedBuiltInElements&&(te.tagNameCheck instanceof RegExp&&oe(te.tagNameCheck,v)||te.tagNameCheck instanceof Function&&te.tagNameCheck(v))))return!1}}return!0},ns=H({},["annotation-xml","color-profile","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","missing-glyph"]),mi=function(l){return!ns[yt(l)]&&oe(me,l)},ss=function(l,g,v,L){if(_&&typeof u=="object"&&typeof u.getAttributeType=="function"&&!v)switch(u.getAttributeType(l,g)){case"TrustedHTML":return R(L);case"TrustedScriptURL":return ue(L)}return L},as=function(l,g,v,L){try{v?l.setAttributeNS(v,g,L):l.setAttribute(g,L),xt(l)?De(l):Ti(e.removed)}catch{He(g,l)}},Si=function(l){xe(I.beforeSanitizeAttributes,l,null);let g=l.attributes;if(!g||xt(l))return;let v={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:ie,forceKeepAttr:void 0},L=g.length,V=re(l.nodeName);for(;L--;){let $=g[L],ae=$.name,ne=$.namespaceURI,we=$.value,Ee=re(ae),yr=we,fe=ae==="value"?yr:vs(yr);if(v.attrName=Ee,v.attrValue=fe,v.keepAttr=!0,v.forceKeepAttr=void 0,xe(I.uponSanitizeAttribute,l,v),fe=v.attrValue,ri&&(Ee==="id"||Ee==="name")&&ki(fe,ii)!==0&&(He(ae,l),fe=ii+fe),lt&&oe(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,fe)){He(ae,l);continue}if(Ee==="attributename"&&Ci(fe,"href")){He(ae,l);continue}if(!v.forceKeepAttr){if(!v.keepAttr){He(ae,l);continue}if(!ei&&oe(Hs,fe)){He(ae,l);continue}if(Le&&(fe=At(fe)),!gi(V,Ee,fe)){He(ae,l);continue}fe=ss(V,Ee,ne,fe),fe!==yr&&as(l,ae,ne,fe)}}xe(I.afterSanitizeAttributes,l,null)},It=function(l){let g=null,v=pi(l);for(xe(I.beforeSanitizeShadowDOM,l,null);g=v.nextNode();)if(xe(I.uponSanitizeShadowNode,g,null),yi(g),Si(g),et(g.content)&&It(g.content),(k?k(g):g.nodeType)===ke.element){let V=M(g);et(V)&&(pr(V),It(V))}xe(I.afterSanitizeShadowDOM,l,null)},pr=function(l){let g=[{node:l,shadow:null}];for(;g.length>0;){let v=g.pop();if(v.shadow){It(v.shadow);continue}let L=v.node,$=(k?k(L):L.nodeType)===ke.element,ae=S(L);if(ae)for(let ne=ae.length-1;ne>=0;--ne)g.push({node:ae[ne],shadow:null});if($){let ne=E?E(L):null;if(typeof ne=="string"&&re(ne)==="template"){let we=L.content;et(we)&&g.push({node:we,shadow:null})}}if($){let ne=M(L);et(ne)&&g.push({node:null,shadow:ne},{node:ne,shadow:null})}}};return e.sanitize=function(C){let l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},g=null,v=null,L=null,V=null;if(cr=!C,cr&&(C=""),typeof C!="string"&&!ut(C)&&(C=xs(C),typeof C!="string"))throw $e("dirty is not a string, aborting");if(!e.isSupported)return C;rr||hr(l),e.removed=[];let $=sr&&typeof C!="string"&&ut(C);if($){let we=E?E(C):C.nodeName;if(typeof we=="string"){let Ee=re(we);if(!X[Ee]||ct[Ee])throw $e("root node is forbidden and cannot be sanitized in-place")}if(xt(C))throw $e("root node is clobbered and cannot be sanitized in-place");try{pr(C)}catch(Ee){throw hi(C),Ee}}else if(ut(C))g=fi(""),v=g.ownerDocument.importNode(C,!0),v.nodeType===ke.element&&v.nodeName==="BODY"||v.nodeName==="HTML"?g=v:g.appendChild(v),pr(v);else{if(!Xe&&!Le&&!Be&&C.indexOf("<")===-1)return _&&Tt?R(C):C;if(g=fi(C),!g)return Xe?null:Tt?A:""}g&&ir&&De(g.firstChild);let ae=pi($?C:g);try{for(;L=ae.nextNode();)yi(L),Si(L),et(L.content)&&It(L.content)}catch(we){throw $&&hi(C),we}if($)return ht(e.removed,we=>{we.element&&ts(we.element)}),Le&&fr(C),C;if(Xe){if(Le&&fr(g),vt)for(V=ge.call(g.ownerDocument);g.firstChild;)V.appendChild(g.firstChild);else V=g;return(ie.shadowroot||ie.shadowrootmode)&&(V=U.call(r,V,!0)),V}let ne=Be?g.outerHTML:g.innerHTML;return Be&&X["!doctype"]&&g.ownerDocument&&g.ownerDocument.doctype&&g.ownerDocument.doctype.name&&oe(Us,g.ownerDocument.doctype.name)&&(ne=" +`+ne),Le&&(ne=At(ne)),_&&Tt?R(ne):ne},e.setConfig=function(){let C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};hr(C),rr=!0},e.clearConfig=function(){Ze=null,rr=!1,_=x,A=""},e.isValidAttribute=function(C,l,g){Ze||hr({});let v=re(C),L=re(l);return gi(v,L,g)},e.addHook=function(C,l){typeof l=="function"&&tt(I[C],l)},e.removeHook=function(C,l){if(l!==void 0){let g=ws(I[C],l);return g===-1?void 0:Es(I[C],g,1)[0]}return Ti(I[C])},e.removeHooks=function(C){I[C]=[]},e.removeAllHooks=function(){I=Fi()},e}var Ui=Oi();var Mt=class s{static _keyMetadata=new WeakMap;static _messageSanitizer=null;static sortObjectKeys(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(s.sortObjectKeys);let t={};return Object.keys(e).sort().forEach(r=>{t[r]=s.sortObjectKeys(e[r])}),t}static assertCryptoKey(e,t=null,r=[]){if(!(e instanceof CryptoKey))throw new Error("Expected CryptoKey");if(t&&e.algorithm?.name!==t)throw new Error(`Expected algorithm ${t}, got ${e.algorithm?.name}`);for(let i of r)if(!e.usages||!e.usages.includes(i))throw new Error(`Missing required key usage: ${i}`)}static arrayBufferToBase64(e){let t="",r=new Uint8Array(e),i=r.byteLength;for(let n=0;n=4294967296-4294967296%t);i+=e[a%t]}return i}static async calculateSecurityLevel(e){let t=0,r=100,i={};try{if(!e||!e.securityFeatures)return console.warn("Security manager not fully initialized, using fallback calculation"),{level:"INITIALIZING",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:"Security system initializing...",isRealData:!1};let n="full",a=!1;try{let u=await s.verifyEncryption(e);u.passed?(t+=20,i.verifyEncryption={passed:!0,details:u.details,points:20}):i.verifyEncryption={passed:!1,details:u.details,points:0}}catch(u){i.verifyEncryption={passed:!1,details:`Encryption check failed: ${u.message}`,points:0}}try{let u=await s.verifyECDHKeyExchange(e);u.passed?(t+=15,i.verifyECDHKeyExchange={passed:!0,details:u.details,points:15}):i.verifyECDHKeyExchange={passed:!1,details:u.details,points:0}}catch(u){i.verifyECDHKeyExchange={passed:!1,details:`Key exchange check failed: ${u.message}`,points:0}}try{let u=await s.verifyMessageIntegrity(e);u.passed?(t+=10,i.verifyMessageIntegrity={passed:!0,details:u.details,points:10}):i.verifyMessageIntegrity={passed:!1,details:u.details,points:0}}catch(u){i.verifyMessageIntegrity={passed:!1,details:`Message integrity check failed: ${u.message}`,points:0}}try{let u=await s.verifyECDSASignatures(e);u.passed?(t+=15,i.verifyECDSASignatures={passed:!0,details:u.details,points:15}):i.verifyECDSASignatures={passed:!1,details:u.details,points:0}}catch(u){i.verifyECDSASignatures={passed:!1,details:`Digital signatures check failed: ${u.message}`,points:0}}try{let u=await s.verifyRateLimiting(e);u.passed?(t+=5,i.verifyRateLimiting={passed:!0,details:u.details,points:5}):i.verifyRateLimiting={passed:!1,details:u.details,points:0}}catch(u){i.verifyRateLimiting={passed:!1,details:`Rate limiting check failed: ${u.message}`,points:0}}try{let u=await s.verifyMetadataProtection(e);u.passed?(t+=10,i.verifyMetadataProtection={passed:!0,details:u.details,points:10}):i.verifyMetadataProtection={passed:!1,details:u.details,points:0}}catch(u){i.verifyMetadataProtection={passed:!1,details:`Metadata protection check failed: ${u.message}`,points:0}}try{let u=await s.verifyPerfectForwardSecrecy(e);u.passed?(t+=10,i.verifyPerfectForwardSecrecy={passed:!0,details:u.details,points:10}):i.verifyPerfectForwardSecrecy={passed:!1,details:u.details,points:0}}catch(u){i.verifyPerfectForwardSecrecy={passed:!1,details:`PFS check failed: ${u.message}`,points:0}}await s.verifyNestedEncryption(e)?(t+=5,i.nestedEncryption={passed:!0,details:"Nested encryption active",points:5}):i.nestedEncryption={passed:!1,details:"Nested encryption failed",points:0},await s.verifyPacketPadding(e)?(t+=5,i.packetPadding={passed:!0,details:"Packet padding active",points:5}):i.packetPadding={passed:!1,details:"Packet padding failed",points:0},await s.verifyAdvancedFeatures(e)?(t+=10,i.advancedFeatures={passed:!0,details:"Advanced features active",points:10}):i.advancedFeatures={passed:!1,details:"Advanced features failed",points:0};let o=Math.round(t/r*100),c=10,d=Object.values(i).filter(u=>u.passed).length;return{level:o>=85?"HIGH":o>=65?"MEDIUM":o>=35?"LOW":"CRITICAL",score:o,color:o>=85?"green":o>=65?"orange":o>=35?"yellow":"red",verificationResults:i,timestamp:Date.now(),details:`Real verification: ${t}/${r} security checks passed (${d}/${c} available)`,isRealData:!0,passedChecks:d,totalChecks:c,sessionType:n,maxPossibleScore:100}}catch(n){return console.error("Security level calculation failed:",n.message),{level:"UNKNOWN",score:0,color:"red",verificationResults:{},timestamp:Date.now(),details:`Verification failed: ${n.message}`,isRealData:!1}}}static async verifyEncryption(e){try{if(!e.encryptionKey)return{passed:!1,details:"No encryption key available"};let t=["Test encryption verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"A".repeat(1e3)];for(let r of t){let n=new TextEncoder().encode(r),a=crypto.getRandomValues(new Uint8Array(12)),o=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e.encryptionKey,n),c=await crypto.subtle.decrypt({name:"AES-GCM",iv:a},e.encryptionKey,o);if(new TextDecoder().decode(c)!==r)return{passed:!1,details:`Decryption mismatch for: ${r.substring(0,20)}...`}}return{passed:!0,details:"AES-GCM encryption/decryption working correctly"}}catch(t){return console.error("Encryption verification failed:",t.message),{passed:!1,details:`Encryption test failed: ${t.message}`}}}static async verifyECDHKeyExchange(e){try{if(!e.ecdhKeyPair||!e.ecdhKeyPair.privateKey||!e.ecdhKeyPair.publicKey)return{passed:!1,details:"No ECDH key pair available"};let t=e.ecdhKeyPair.privateKey.algorithm.name,r=e.ecdhKeyPair.privateKey.algorithm.namedCurve;if(t!=="ECDH")return{passed:!1,details:`Invalid key type: ${t}, expected ECDH`};if(r!=="P-384"&&r!=="P-256")return{passed:!1,details:`Unsupported curve: ${r}, expected P-384 or P-256`};try{if(!await crypto.subtle.deriveKey({name:"ECDH",public:e.ecdhKeyPair.publicKey},e.ecdhKeyPair.privateKey,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]))return{passed:!1,details:"Key derivation failed"}}catch(i){return{passed:!1,details:`Key derivation test failed: ${i.message}`}}return{passed:!0,details:`ECDH key exchange working with ${r} curve`}}catch(t){return console.error("ECDH verification failed:",t.message),{passed:!1,details:`ECDH test failed: ${t.message}`}}}static async verifyECDSASignatures(e){try{if(!e.ecdsaKeyPair||!e.ecdsaKeyPair.privateKey||!e.ecdsaKeyPair.publicKey)return{passed:!1,details:"No ECDSA key pair available"};let t=["Test ECDSA signature verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"B".repeat(2e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.privateKey,n);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.publicKey,a,n))return{passed:!1,details:`Signature verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"ECDSA digital signatures working correctly"}}catch(t){return console.error("ECDSA verification failed:",t.message),{passed:!1,details:`ECDSA test failed: ${t.message}`}}}static async verifyMessageIntegrity(e){try{if(!e.macKey||!(e.macKey instanceof CryptoKey))return{passed:!1,details:"MAC key not available or invalid"};let t=["Test message integrity verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0446\u0435\u043B\u043E\u0441\u0442\u043D\u043E\u0441\u0442\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"C".repeat(3e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"HMAC",hash:"SHA-256"},e.macKey,n);if(!await crypto.subtle.verify({name:"HMAC",hash:"SHA-256"},e.macKey,a,n))return{passed:!1,details:`HMAC verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"Message integrity (HMAC) working correctly"}}catch(t){return console.error("Message integrity verification failed:",t.message),{passed:!1,details:`Message integrity test failed: ${t.message}`}}}static async verifyRateLimiting(e){try{let t=s.rateLimiter;if(!t||typeof t.checkMessageRate!="function")return{passed:!1,details:"Rate limiter is not available"};let r=`selftest_${crypto.getRandomValues(new Uint32Array(1))[0]}`,i=3;for(let a=0;a0}catch(t){return console.error("Nested encryption verification failed:",t.message),!1}}static async verifyPacketPadding(e){try{if(!e.paddingConfig||!e.paddingConfig.enabled)return!1;let i=new TextEncoder().encode("Test packet padding verification"),n=Math.floor(Math.random()*(e.paddingConfig.maxPadding-e.paddingConfig.minPadding))+e.paddingConfig.minPadding,a=new Uint8Array(i.byteLength+n);return a.set(new Uint8Array(i),0),a.byteLength>=i.byteLength+e.paddingConfig.minPadding}catch(t){return s.secureLog.log("error","Packet padding verification failed",{error:t.message}),!1}}static async verifyAdvancedFeatures(e){try{let t=e.fakeTrafficConfig&&e.fakeTrafficConfig.enabled,r=e.decoyChannelsConfig&&e.decoyChannelsConfig.enabled,i=e.antiFingerprintingConfig&&e.antiFingerprintingConfig.enabled;return t||r||i}catch(t){return s.secureLog.log("error","Advanced features verification failed",{error:t.message}),!1}}static async verifyMutualAuth(e){try{return!e.isVerified||!e.verificationCode?!1:e.isVerified&&e.verificationCode.length>0}catch(t){return s.secureLog.log("error","Mutual auth verification failed",{error:t.message}),!1}}static async verifyNonExtractableKeys(e){let t=[["encryptionKey",e?.encryptionKey],["macKey",e?.macKey],["metadataKey",e?.metadataKey]];for(let[r,i]of t){if(!i||!(i instanceof CryptoKey))return!1;if(i.extractable!==!1)return s.secureLog.log("error","Session key is extractable",{keyName:r}),!1}return!0}static async verifyEnhancedValidation(e){try{return e.securityFeatures?e.securityFeatures.hasEnhancedValidation||e.securityFeatures.hasEnhancedReplayProtection:!1}catch(t){return s.secureLog.log("error","Enhanced validation verification failed",{error:t.message}),!1}}static async verifyPFS(e){try{return e.securityFeatures&&e.securityFeatures.hasPFS===!0&&e.keyRotationInterval&&e.currentKeyVersion!==void 0&&e.keyVersions&&e.keyVersions instanceof Map}catch(t){return s.secureLog.log("error","PFS verification failed",{error:t.message}),!1}}static rateLimiter={messages:new Map,connections:new Map,locks:new Map,async checkMessageRate(e,t=60,r=6e4){if(typeof e!="string"||e.length>256)return!1;let i=`msg_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkMessageRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.messages.has(i)||this.messages.set(i,[]);let o=this.messages.get(i).filter(c=>n-c=t?!1:(o.push(n),this.messages.set(i,o),!0)}finally{this.locks.delete(i)}},async checkConnectionRate(e,t=5,r=3e5){if(typeof e!="string"||e.length>256)return!1;let i=`conn_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkConnectionRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.connections.has(i)||this.connections.set(i,[]);let o=this.connections.get(i).filter(c=>n-c=t?!1:(o.push(n),this.connections.set(i,o),!0)}finally{this.locks.delete(i)}},cleanup(){let e=Date.now(),t=36e5;for(let[r,i]of this.messages.entries()){if(this.locks.has(r))continue;let n=i.filter(a=>e-ae-a3e4&&this.locks.delete(r)}}};static validateSalt(e){if(!e||e.length!==64)throw new Error("Salt must be exactly 64 bytes");if(new Set(e).size<16)throw new Error("Salt has insufficient entropy");return!0}static secureLog={logs:[],maxLogs:100,isProductionMode:!1,init(){this.isProductionMode=this._detectProductionMode(),this.isProductionMode&&console.log("[SecureChat] Production mode detected - sensitive logging disabled")},_detectProductionMode(){return typeof process<"u"&&!0||!window.DEBUG_MODE&&!window.DEVELOPMENT_MODE||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")},log(e,t,r={}){let i=this.sanitizeContext(r),n={timestamp:Date.now(),level:e,message:t,context:i,id:crypto.getRandomValues(new Uint32Array(1))[0]};if(this.logs.push(n),this.logs.length>this.maxLogs&&(this.logs=this.logs.slice(-this.maxLogs)),this.isProductionMode)if(e==="error")console.error(`\u274C [SecureChat] ${t} [ERROR_CODE: ${this._generateErrorCode(t)}]`);else if(e==="warn")console.warn(`\u26A0\uFE0F [SecureChat] ${t}`);else return;else e==="error"?console.error(`\u274C [SecureChat] ${t}`,{errorType:i?.constructor?.name||"Unknown"}):e==="warn"?console.warn(`\u26A0\uFE0F [SecureChat] ${t}`,{details:i}):console.log(`[SecureChat] ${t}`,i)},_generateErrorCode(e){let t=e.split("").reduce((r,i)=>(r=(r<<5)-r+i.charCodeAt(0),r&r),0);return Math.abs(t).toString(36).substring(0,6).toUpperCase()},sanitizeContext(e){if(!e||typeof e!="object")return e;let t=[/key/i,/secret/i,/password/i,/token/i,/signature/i,/challenge/i,/proof/i,/salt/i,/iv/i,/nonce/i,/hash/i,/fingerprint/i,/mac/i,/private/i,/encryption/i,/decryption/i],r={};for(let[i,n]of Object.entries(e))t.some(o=>o.test(i)||typeof n=="string"&&o.test(n))?r[i]="[REDACTED]":typeof n=="string"&&n.length>100?r[i]=n.substring(0,100)+"...[TRUNCATED]":n instanceof ArrayBuffer||n instanceof Uint8Array?r[i]=`[${n.constructor.name}(${n.byteLength||n.length} bytes)]`:n&&typeof n=="object"&&!Array.isArray(n)?r[i]=this.sanitizeContext(n):r[i]=n;return r},getLogs(e=null){return e?this.logs.filter(t=>t.level===e):[...this.logs]},clearLogs(){this.logs=[]},async sendErrorToServer(e,t,r={}){if(this.isProductionMode)try{let i={errorCode:e,timestamp:Date.now(),userAgent:navigator.userAgent.substring(0,100),url:window.location.href.substring(0,100)};window.DEBUG_MODE&&console.log("[SecureChat] Error logged to server:",i)}catch{}}};static async generateECDHKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-384"},!1,["deriveKey","deriveBits"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-256"},!1,["deriveKey","deriveBits"])}}catch(e){throw s.secureLog.log("error","ECDH key generation failed",{error:e.message}),new Error("Failed to create keys for secure exchange")}}static async generateECDSAKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-384"},!1,["sign","verify"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"])}}catch(e){throw s.secureLog.log("error","ECDSA key generation failed",{error:e.message}),new Error("Failed to generate keys for digital signatures")}}static async signData(e,t){try{let r=new TextEncoder,i=typeof t=="string"?r.encode(t):t;try{let n=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},e,i);return Array.from(new Uint8Array(n))}catch(n){s.secureLog.log("warn","SHA-384 signing failed, trying SHA-256",{error:n.message});let a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e,i);return Array.from(new Uint8Array(a))}}catch(r){throw s.secureLog.log("error","Data signing failed",{error:r.message}),new Error("Failed to sign data")}}static async verifySignature(e,t,r){try{let i=new TextEncoder,n=typeof r=="string"?i.encode(r):r,a=new Uint8Array(t);try{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},e,a,n)}catch{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e,a,n)}}catch(i){throw s.secureLog.log("error","Signature verification failed",{error:i.message}),new Error("Failed to verify digital signature")}}static async validateKeyStructure(e,t="ECDH"){try{if(!Array.isArray(e)||e.length===0)throw new Error("Invalid key data format");let r=new Uint8Array(e);if(r.length<50)throw new Error("Key data too short - invalid SPKI structure");if(r.length>2e3)throw new Error("Key data too long - possible attack");let i=s.parseASN1(r);if(!i||i.tag!==48)throw new Error("Invalid SPKI structure - missing SEQUENCE tag");if(i.children.length!==2)throw new Error(`Invalid SPKI structure - expected 2 elements, got ${i.children.length}`);let n=i.children[0];if(n.tag!==48)throw new Error("Invalid AlgorithmIdentifier - not a SEQUENCE");let a=n.children[0];if(a.tag!==6)throw new Error("Invalid algorithm OID - not an OBJECT IDENTIFIER");let o=a.value,c=s.oidToString(o),h={ECDH:["1.2.840.10045.2.1"],ECDSA:["1.2.840.10045.2.1"],RSA:["1.2.840.113549.1.1.1"],"AES-GCM":["2.16.840.1.101.3.4.1.6","2.16.840.1.101.3.4.1.46"]}[t];if(!h)throw new Error(`Unknown algorithm: ${t}`);if(!h.includes(c))throw new Error(`Invalid algorithm OID: expected ${h.join(" or ")}, got ${c}`);if(t==="ECDH"||t==="ECDSA"){if(n.children.length<2)throw new Error("Missing curve parameters for EC key");let m=n.children[1];if(m.tag!==6)throw new Error("Invalid curve OID - not an OBJECT IDENTIFIER");let y=s.oidToString(m.value);if(!{"1.2.840.10045.3.1.7":"P-256","1.3.132.0.34":"P-384"}[y])throw new Error(`Invalid or unsupported curve OID: ${y}`)}let u=i.children[1];if(u.tag!==3)throw new Error("Invalid public key - not a BIT STRING");if(u.value[0]!==0)throw new Error(`Invalid BIT STRING - unexpected unused bits: ${u.value[0]}`);if(t==="ECDH"||t==="ECDSA"){let m=u.value.slice(1);if(m[0]!==4)throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${m[0].toString(16)}`);let y={"P-256":65,"P-384":97},p=s.oidToString(n.children[1].value)==="1.2.840.10045.3.1.7"?"P-256":"P-384",S=y[p];if(m.length!==S)throw new Error(`Invalid EC point size for ${p}: expected ${S}, got ${m.length}`)}try{let m=t==="ECDSA"||t==="ECDH"?{name:t,namedCurve:"P-384"}:{name:t},y=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,m,!1,y)}catch(m){if(t==="ECDSA"||t==="ECDH")try{let y={name:t,namedCurve:"P-256"},b=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,y,!1,b)}catch(y){throw new Error(`Key import validation failed: ${y.message}`)}else throw new Error(`Key import validation failed: ${m.message}`)}return!0}catch(r){throw s.secureLog.log("error","Key structure validation failed",{error:r.message,algorithm:t}),new Error(`Invalid key structure: ${r.message}`)}}static parseASN1(e,t=0){if(t>=e.length)return null;let r=e[t],i=t+1;if(i>=e.length)throw new Error("Truncated ASN.1 structure");let n=e[i],a=i+1;if(n&128){let d=n&127;if(d>4)throw new Error("ASN.1 length too large");n=0;for(let h=0;h=e.length)throw new Error("Truncated ASN.1 length");n=n<<8|e[a+h]}a+=d}if(a+n>e.length)throw new Error("ASN.1 structure extends beyond data");let o=e.slice(a,a+n),c={tag:r,length:n,value:o,children:[]};if(r===48||r===49){let d=0;for(;d2)throw new Error(`Invalid OID first component: ${r[0]}`);if((r[0]===0||r[0]===1)&&r[1]>39)throw new Error(`Invalid OID second component: ${r[1]} (must be <= 39 for first component ${r[0]})`);return!0}static async exportPublicKeyWithSignature(e,t,r="ECDH"){try{if(!["ECDH","ECDSA"].includes(r))throw new Error("Invalid key type");let i=await crypto.subtle.exportKey("spki",e),n=Array.from(new Uint8Array(i));await s.validateKeyStructure(n,r);let a={keyType:r,keyData:n,timestamp:Date.now(),version:"4.0"},o=JSON.stringify(a),c=await s.signData(t,o);return{...a,signature:c}}catch(i){throw s.secureLog.log("error","Public key export failed",{error:i.message,keyType:r}),new Error(`Failed to export ${r} key: ${i.message}`)}}static async importSignedPublicKey(e,t,r="ECDH"){try{if(!e||typeof e!="object")throw new Error("Invalid signed package format");let{keyType:i,keyData:n,timestamp:a,version:o,signature:c}=e;if(!i||!n||!a||!c)throw new Error("Missing required fields in signed package");if(!s.constantTimeCompare(i,r))throw new Error(`Key type mismatch: expected ${r}, got ${i}`);if(Date.now()-a>36e5)throw new Error("Signed key package is too old");await s.validateKeyStructure(n,i);let u=JSON.stringify({keyType:i,keyData:n,timestamp:a,version:o});if(!await s.verifySignature(t,c,u))throw new Error("Invalid signature on key package - possible MITM attack");let y=new Uint8Array(n);try{let b=i==="ECDH"?{name:"ECDH",namedCurve:"P-384"}:{name:"ECDSA",namedCurve:"P-384"},p=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",y,b,!1,p)}catch(b){s.secureLog.log("warn","Elliptic curve P-384 import failed, switching curve",{error:b.message});let p=i==="ECDH"?{name:"ECDH",namedCurve:"P-256"}:{name:"ECDSA",namedCurve:"P-256"},S=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",y,p,!1,S)}}catch(i){throw s.secureLog.log("error","Signed public key import failed",{error:i.message,expectedKeyType:r}),new Error(`Failed to import the signed key: ${i.message}`)}}static async exportPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=Array.from(new Uint8Array(t));return await s.validateKeyStructure(r,"ECDH"),r}catch(t){throw s.secureLog.log("error","Legacy public key export failed",{error:t.message}),new Error("Failed to export the public key")}}static async importPublicKey(e){try{await s.validateKeyStructure(e,"ECDH");let t=new Uint8Array(e);try{return await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-384"},!1,[])}catch(r){return s.secureLog.log("warn","P-384 import failed, trying P-256",{error:r.message}),await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-256"},!1,[])}}catch(t){throw s.secureLog.log("error","Legacy public key import failed",{error:t.message}),new Error("Failed to import the public key")}}static isKeyTrusted(e){if(e instanceof CryptoKey){let t=s._keyMetadata.get(e);return t?t.trusted===!0:!1}else if(e&&e._securityMetadata)return e._securityMetadata.trusted===!0;return!1}static async importPublicKeyFromSignedPackage(e,t=null,r={}){try{if(!e||!e.keyData||!e.signature)throw new Error("Invalid signed key package format");let n=["keyData","signature","keyType","timestamp","version"].filter(m=>!e[m]);if(n.length>0)throw s.secureLog.log("error","Missing required fields in signed package",{missingFields:n,availableFields:Object.keys(e)}),new Error(`Required fields are missing in the signed package: ${n.join(", ")}`);if(!t)throw s.secureLog.log("error","SECURITY VIOLATION: Signed package received without verifying key",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,securityRisk:"HIGH - Potential MITM attack vector"}),new Error("CRITICAL SECURITY ERROR: Signed key package received without a verification key. This may indicate a possible MITM attack attempt. Import rejected for security reasons.");await s.validateKeyStructure(e.keyData,e.keyType||"ECDH");let a={...e};delete a.signature;let o=JSON.stringify(a);if(!await s.verifySignature(t,e.signature,o))throw s.secureLog.log("error","SECURITY BREACH: Invalid signature detected - MITM attack prevented",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,attackPrevented:!0}),new Error("CRITICAL SECURITY ERROR: Invalid key signature detected. This indicates a possible MITM attack attempt. Key import rejected.");let d=await s.calculateKeyFingerprint(e.keyData),h=new Uint8Array(e.keyData),u=e.keyType||"ECDH";try{let m=await crypto.subtle.importKey("spki",h,{name:u,namedCurve:"P-384"},!1,u==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(m,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),m}catch(m){s.secureLog.log("warn","P-384 import failed, trying P-256",{error:m.message});let y=await crypto.subtle.importKey("spki",h,{name:u,namedCurve:"P-256"},!1,u==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(y,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),y}}catch(i){throw s.secureLog.log("error","Signed package key import failed",{error:i.message,securityImplications:"Potential security breach prevented"}),new Error(`Failed to import the public key from the signed package: ${i.message}`)}}static async deriveSharedKeys(e,t,r){try{if(!(e instanceof CryptoKey))throw s.secureLog.log("error","Private key is not a CryptoKey",{privateKeyType:typeof e,privateKeyAlgorithm:e?.algorithm?.name}),new Error("The private key is not a valid CryptoKey.");if(!(t instanceof CryptoKey))throw s.secureLog.log("error","Public key is not a CryptoKey",{publicKeyType:typeof t,publicKeyAlgorithm:t?.algorithm?.name}),new Error("The public key is not a valid CryptoKey.");if(!r||r.length!==64)throw new Error("Salt must be exactly 64 bytes for enhanced security");let i=new Uint8Array(r),n=new TextEncoder,a,o=null;try{o=await crypto.subtle.deriveBits({name:"ECDH",public:t},e,256),a=await crypto.subtle.importKey("raw",o,{name:"HKDF",hash:"SHA-256"},!1,["deriveKey","deriveBits"])}catch(S){throw s.secureLog.log("error","ECDH derivation failed",{error:S.message}),S}finally{o&&(s.zeroizeBuffer(o),o=null)}let c;c=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-encryption-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let d;d=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-authentication-v4")},a,{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"]);let h;h=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("perfect-forward-secrecy-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let u;u=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("metadata-protection-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let m=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("double-ratchet-root-v1")},a,256),y=new Uint8Array(m),b=null,p;try{b=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("fingerprint-generation-v4")},a,256),p=await s.generateKeyFingerprint(new Uint8Array(b))}finally{b&&(s.zeroizeBuffer(b),b=null)}if(!(c instanceof CryptoKey))throw s.secureLog.log("error","Derived message key is not a CryptoKey",{messageKeyType:typeof c,messageKeyAlgorithm:c?.algorithm?.name}),new Error("The derived message key is not a valid CryptoKey.");if(!(d instanceof CryptoKey))throw s.secureLog.log("error","Derived MAC key is not a CryptoKey",{macKeyType:typeof d,macKeyAlgorithm:d?.algorithm?.name}),new Error("The derived MAC key is not a valid CryptoKey.");if(!(h instanceof CryptoKey))throw s.secureLog.log("error","Derived PFS key is not a CryptoKey",{pfsKeyType:typeof h,pfsKeyAlgorithm:h?.algorithm?.name}),new Error("The derived PFS key is not a valid CryptoKey.");if(!(u instanceof CryptoKey))throw s.secureLog.log("error","Derived metadata key is not a CryptoKey",{metadataKeyType:typeof u,metadataKeyAlgorithm:u?.algorithm?.name}),new Error("The derived metadata key is not a valid CryptoKey.");return{messageKey:c,macKey:d,pfsKey:h,metadataKey:u,ratchetRoot:y,fingerprint:p,timestamp:Date.now(),version:"4.0"}}catch(i){throw s.secureLog.log("error","Enhanced key derivation failed",{error:i.message,errorStack:i.stack,privateKeyType:typeof e,publicKeyType:typeof t,saltLength:r?.length,privateKeyAlgorithm:e?.algorithm?.name,publicKeyAlgorithm:t?.algorithm?.name}),new Error(`Failed to create shared encryption keys: ${i.message}`)}}static async generateKeyFingerprint(e){let t=new Uint8Array(e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).slice(0,12).map(n=>n.toString(16).padStart(2,"0")).join(":")}static generateMutualAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(48)),t=Date.now(),r=crypto.getRandomValues(new Uint8Array(16));return{challenge:Array.from(e),timestamp:t,nonce:Array.from(r),version:"4.0"}}static async createAuthProof(e,t,r){try{if(!e||!e.challenge||!e.timestamp||!e.nonce)throw new Error("Invalid challenge structure");let i=Date.now()-e.timestamp;if(i>12e4)throw new Error("Challenge expired");let n={challenge:e.challenge,timestamp:e.timestamp,nonce:e.nonce,responseTimestamp:Date.now(),publicKeyHash:await s.hashPublicKey(r)},a=JSON.stringify(n),o=await s.signData(t,a),c={...n,signature:o,version:"4.0"};return s.secureLog.log("info","Authentication proof created",{challengeAge:Math.round(i/1e3)+"s"}),c}catch(i){throw s.secureLog.log("error","Authentication proof creation failed",{error:i.message}),new Error(`Failed to create cryptographic proof: ${i.message}`)}}static async verifyAuthProof(e,t,r){try{if(await new Promise(h=>setTimeout(h,Math.floor(Math.random()*20)+5)),s.assertCryptoKey(r,"ECDSA",["verify"]),!e||!t||!r)throw new Error("Missing required parameters for proof verification");let i=["challenge","timestamp","nonce","responseTimestamp","publicKeyHash","signature"];for(let h of i)if(!e[h])throw new Error(`Missing required field: ${h}`);if(!s.constantTimeCompareArrays(e.challenge,t.challenge)||e.timestamp!==t.timestamp||!s.constantTimeCompareArrays(e.nonce,t.nonce))throw new Error("Challenge mismatch - possible replay attack");let n=Date.now()-e.responseTimestamp;if(n>18e5)throw new Error("Proof response expired");let a=await s.hashPublicKey(r);if(!s.constantTimeCompare(e.publicKeyHash,a))throw new Error("Public key hash mismatch");let o={...e};delete o.signature;let c=JSON.stringify(o);if(!await s.verifySignature(r,e.signature,c))throw new Error("Invalid proof signature");return s.secureLog.log("info","Authentication proof verified successfully",{responseAge:Math.round(n/1e3)+"s"}),!0}catch(i){throw s.secureLog.log("error","Authentication proof verification failed",{error:i.message}),new Error(`Failed to verify cryptographic proof: ${i.message}`)}}static async hashPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Public key hashing failed",{error:t.message}),new Error("Failed to create hash of the public key")}}static generateAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(32));return Array.from(e)}static generateVerificationCode(){let e="0123456789ABCDEF",t=e.length,r="";for(let i=0;i<6;i++){let n;do n=crypto.getRandomValues(new Uint8Array(1))[0];while(n>=256-256%t);r+=e[n%t]}return r.match(/.{1,2}/g).join("-")}static async encryptMessage(e,t,r,i,n,a=0){try{if(!e||typeof e!="string")throw new Error("Invalid message format");s.assertCryptoKey(t,"AES-GCM",["encrypt"]),s.assertCryptoKey(r,"HMAC",["sign"]),s.assertCryptoKey(i,"AES-GCM",["encrypt"]);let o=new TextEncoder,c=o.encode(e),d=crypto.getRandomValues(new Uint8Array(12)),h=crypto.getRandomValues(new Uint8Array(12)),u=Date.now(),m=16-c.length%16,y=new Uint8Array(c.length+m);y.set(c);let b=crypto.getRandomValues(new Uint8Array(m));y.set(b,c.length);let p=await crypto.subtle.encrypt({name:"AES-GCM",iv:d},t,y),S={id:n,timestamp:u,sequenceNumber:a,originalLength:c.length,version:"4.0"},w=JSON.stringify(s.sortObjectKeys(S)),M=await crypto.subtle.encrypt({name:"AES-GCM",iv:h},i,o.encode(w)),F={messageIv:Array.from(d),messageData:Array.from(new Uint8Array(p)),metadataIv:Array.from(h),metadataData:Array.from(new Uint8Array(M)),version:"4.0"},k=s.sortObjectKeys(F),E=JSON.stringify(k),_=await crypto.subtle.sign("HMAC",r,o.encode(E));return F.mac=Array.from(new Uint8Array(_)),F}catch(o){throw s.secureLog.log("error","Message encryption failed",{error:o.message,messageId:n}),new Error(`Failed to encrypt the message: ${o.message}`)}}static async decryptMessage(e,t,r,i,n=null){try{s.assertCryptoKey(t,"AES-GCM",["decrypt"]),s.assertCryptoKey(r,"HMAC",["verify"]),s.assertCryptoKey(i,"AES-GCM",["decrypt"]);let a=["messageIv","messageData","metadataIv","metadataData","mac","version"];for(let x of a)if(!e[x])throw new Error(`Missing required field: ${x}`);let o={...e};delete o.mac;let c=s.sortObjectKeys(o),d=JSON.stringify(c);if(!await crypto.subtle.verify("HMAC",r,new Uint8Array(e.mac),new TextEncoder().encode(d)))throw s.secureLog.log("error","MAC verification failed",{payloadFields:Object.keys(e),macLength:e.mac?.length}),new Error("Message authentication failed - possible tampering");let u=new Uint8Array(e.metadataIv),m=new Uint8Array(e.metadataData),y=await crypto.subtle.decrypt({name:"AES-GCM",iv:u},i,m),b=new TextDecoder().decode(y),p=JSON.parse(b);if(!p.id||!p.timestamp||p.sequenceNumber===void 0||!p.originalLength)throw new Error("Invalid metadata structure");let S=Date.now()-p.timestamp;if(S>18e5)throw new Error("Message expired (older than 30 minutes)");if(n!==null){if(p.sequenceNumbern+10)throw new Error(`Sequence number gap too large: expected around ${n}, got ${p.sequenceNumber}`)}let w=new Uint8Array(e.messageIv),M=new Uint8Array(e.messageData),F=await crypto.subtle.decrypt({name:"AES-GCM",iv:w},t,M),E=new Uint8Array(F).slice(0,p.originalLength),A=new TextDecoder().decode(E);return s.secureLog.log("info","Message decrypted successfully",{messageId:p.id,sequenceNumber:p.sequenceNumber,messageAge:Math.round(S/1e3)+"s"}),{message:A,messageId:p.id,timestamp:p.timestamp,sequenceNumber:p.sequenceNumber}}catch(a){throw s.secureLog.log("error","Message decryption failed",{error:a.message}),new Error(`Failed to decrypt the message: ${a.message}`)}}static _getMessageSanitizer(){if(s._messageSanitizer)return s._messageSanitizer;if(typeof window>"u"||!window?.document)throw new Error("DOMPurify requires a browser-like window for message sanitization");return s._messageSanitizer=Ui(window),s._messageSanitizer}static sanitizeMessage(e){if(typeof e!="string")throw new Error("Message must be a string");let t=s._getMessageSanitizer().sanitize(e,{ALLOWED_TAGS:[],ALLOWED_ATTR:[],ALLOW_UNKNOWN_PROTOCOLS:!1,FORBID_TAGS:["script","style","svg","math","template"],FORBID_ATTR:["style"],KEEP_CONTENT:!0,RETURN_TRUSTED_TYPE:!1,USE_PROFILES:{html:!1,svg:!1,svgFilters:!1,mathMl:!1}});return String(t).trim().substring(0,2e3)}static generateSalt(){return Array.from(crypto.getRandomValues(new Uint8Array(64)))}static async calculateKeyFingerprint(e){try{let t=new TextEncoder,r=new Uint8Array(e),i=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(i)).map(o=>o.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Key fingerprint calculation failed",{error:t.message}),new Error("Failed to compute the key fingerprint")}}static constantTimeCompare(e,t){let r=typeof e=="string"?e:JSON.stringify(e),i=typeof t=="string"?t:JSON.stringify(t);if(r.length!==i.length){let a=0;for(let o=0;oa.toLowerCase()===t);if(r)return r;let i=t.split("-")[0],n=Ke.find(a=>a.toLowerCase().split("-")[0]===i);if(n)return n}return null}function Xs({pathname:s="/",stored:e=null,languages:t=[]}={}){let r=Bi(s);return r||(Qs(s)?"en":e&&Ke.includes(e)?e:Ys(t)||"en")}function Qs(s){return s==="/"||s==="/index.html"}function Js(s,e="/"){let t=Bi(e),i=(t?String(e).slice(t.length+1):String(e)).replace(/^\/+/,"");return s==="en"?`/${i}`:`/${s}/${i}`}function Hi(s){try{localStorage.setItem(Vi,s)}catch{}}function Zs(){try{return localStorage.getItem(Vi)}catch{return null}}var Lt=null;function Ge(){if(Lt)return Lt;let s=typeof window>"u"?null:window;return!s||!s.location?"en":(Lt=Xs({pathname:s.location.pathname||"/",stored:Zs(),languages:s.navigator?.languages||[]}),Lt)}function ea(s=Ge()){return it[s]?.dir==="rtl"?"rtl":"ltr"}function Pt(s=Ge()){return ea(s)==="rtl"}function $i(s=Ge()){return Pt(s)?-1:1}function Oe(s,e=Ge()){let t=Dt(e)?.[s]??Dt("en")?.[s];return Array.isArray(t)?t:[]}function Gi({pathname:s="/",active:e="en"}={}){return Ke.map(t=>({code:t,href:Js(t,s),hrefLang:it[t]?.htmlLang||t,label:it[t]?.nativeName||t,abbr:it[t]?.abbr||t.toUpperCase(),dir:it[t]?.dir||"ltr",isCurrent:t===e}))}function f(s,e,t=Ge()){let r=Dt(t)?.[s]??zi[t]?.[s]??Dt("en")?.[s]??s;return e?String(r).replace(/\{(\w+)\}/g,(i,n)=>Object.prototype.hasOwnProperty.call(e,n)?String(e[n]):i):r}var Ie=class s{static#e=null;static#n=Symbol("SecureFileTransferContext");static getInstance(){return this.#e||(this.#e=new s),this.#e}#t=null;#r=!1;#i="high";setFileTransferSystem(e){if(!(e instanceof je))throw new Error("Invalid file transfer system instance");this.#t=e,this.#r=!0}getFileTransferSystem(){return this.#t}isActive(){return this.#r&&this.#t!==null}deactivate(){this.#r=!1,this.#t=null}getSecurityLevel(){return this.#i}setSecurityLevel(e){["low","medium","high"].includes(e)&&(this.#i=e)}},ee=class{static#e=new Set(["File size exceeds maximum limit","Unsupported file type","Transfer timeout","Connection lost","Invalid file data","File transfer failed","Transfer cancelled","Network error","File not found","Permission denied"]);static sanitizeError(e){let t=e.message||e;for(let r of this.#e)if(t.includes(r))return r;return console.error("\u{1F512} Internal file transfer error:",{message:e.message,stack:e.stack,timestamp:new Date().toISOString()}),"File transfer failed"}static logSecurityEvent(e,t={}){console.warn("\u{1F512} Security event:",{event:e,timestamp:new Date().toISOString(),...t})}},Ft=class{static async signFileMetadata(e,t){try{let i=new TextEncoder().encode(JSON.stringify({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,fileHash:e.fileHash,timestamp:e.timestamp,version:e.version||"2.0"})),n=await crypto.subtle.sign("RSASSA-PKCS1-v1_5",t,i);return Array.from(new Uint8Array(n))}catch(r){throw ee.logSecurityEvent("signature_failed",{error:r.message}),new Error("Failed to sign file metadata")}}static async verifyFileMetadata(e,t,r){try{let n=new TextEncoder().encode(JSON.stringify({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,fileHash:e.fileHash,timestamp:e.timestamp,version:e.version||"2.0"})),a=new Uint8Array(t),o=await crypto.subtle.verify("RSASSA-PKCS1-v1_5",r,a,n);return o||ee.logSecurityEvent("invalid_signature",{fileId:e.fileId}),o}catch(i){return ee.logSecurityEvent("verification_failed",{error:i.message}),!1}}},Kt=class{static MAX_MESSAGE_SIZE=1024*1024;static isMessageSizeValid(e){let t=JSON.stringify(e),r=new Blob([t]).size;if(r>this.MAX_MESSAGE_SIZE)throw ee.logSecurityEvent("message_too_large",{size:r,limit:this.MAX_MESSAGE_SIZE}),new Error("Message too large");return!0}},vr=class{constructor(){this.locks=new Map}async withLock(e,t){for(;this.locks.has(e);)await this.locks.get(e);let r,i=new Promise(n=>{r=n});this.locks.set(e,i);try{return await t()}finally{this.locks.delete(e),r()}}},nt=class{constructor(e,t){this.maxRequests=e,this.windowMs=t,this.requests=new Map}isAllowed(e){let t=Date.now(),r=t-this.windowMs;this.requests.has(e)||this.requests.set(e,[]);let n=this.requests.get(e).filter(a=>a>r);return this.requests.set(e,n),n.length>=this.maxRequests?(ee.logSecurityEvent("rate_limit_exceeded",{identifier:e,requestCount:n.length,limit:this.maxRequests}),!1):(n.push(t),!0)}},qe=class{static secureWipe(e){if(e instanceof ArrayBuffer){let t=new Uint8Array(e);crypto.getRandomValues(t)}else e instanceof Uint8Array&&crypto.getRandomValues(e)}static secureDelete(e,t){e[t]&&(this.secureWipe(e[t]),delete e[t])}},je=class{constructor(e,t,r,i,n,a){if(this.webrtcManager=e,this.onProgress=t,this.onComplete=r,this.onError=i,this.onFileReceived=n,this.onIncomingFileRequest=a,!e)throw new Error("webrtcManager is required for EnhancedSecureFileTransfer");Ie.getInstance().setFileTransferSystem(this),this.atomicOps=new vr,this.rateLimiter=new nt(10,6e4),this.signingKey=null,this.verificationKey=null,this.CHUNK_SIZE=16*1024,this.MAX_RECEIVE_CHUNK_SIZE=64*1024,this.MAX_FILE_SIZE=100*1024*1024,this.MAX_CONCURRENT_TRANSFERS=3,this.CHUNK_TIMEOUT=3e4,this.RETRY_ATTEMPTS=3,this.FILE_TYPE_RESTRICTIONS={pdf:{extensions:[".pdf"],mimeTypes:["application/pdf","application/x-pdf","application/acrobat"],maxSize:50*1024*1024,category:"PDF",description:"PDF"},text:{extensions:[".txt"],mimeTypes:["text/plain","application/txt"],maxSize:10*1024*1024,category:f("fileType.text"),description:"TXT"},images:{extensions:[".jpg",".jpeg",".png",".gif",".webp",".bmp",".ico"],mimeTypes:["image/jpeg","image/jpg","image/pjpeg","image/png","image/gif","image/webp","image/bmp","image/x-windows-bmp","image/x-icon","image/vnd.microsoft.icon"],maxSize:25*1024*1024,category:f("fileType.images"),description:"JPG, JPEG, PNG, GIF, WEBP, BMP, ICO"},archives:{extensions:[".zip"],mimeTypes:["application/zip","application/x-zip","application/x-zip-compressed","multipart/x-zip"],maxSize:100*1024*1024,category:f("fileType.archives"),description:"ZIP"},voice:{extensions:[".webm",".ogg",".oga",".opus",".m4a",".mp4",".mp3",".wav"],mimeTypes:["audio/webm","audio/ogg","audio/opus","audio/mp4","audio/mpeg","audio/mp3","audio/wav","audio/x-m4a","audio/aac"],maxSize:20*1024*1024,category:"Voice",description:f("fileType.voice")}},this.BLOCKED_EXTENSIONS=new Set([".exe",".bat",".cmd",".sh",".js",".msi",".dmg",".app",".jar",".scr",".ps1",".vbs",".html",".svg"]),this._genericMimeTypes=new Set(["application/octet-stream","application/binary"]),this._allowedMimeTypes=new Set;for(let o of Object.values(this.FILE_TYPE_RESTRICTIONS))for(let c of o.mimeTypes)this._allowedMimeTypes.add(c);this.activeTransfers=new Map,this.receivingTransfers=new Map,this.pendingIncomingTransfers=new Map,this.transferQueue=[],this.pendingChunks=new Map,this.incomingOfferLimiter=new nt(5,6e4),this.incomingChunkLimiter=new nt(6e4,6e4),this.incomingTransferChunkLimiters=new Map,this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE=3e4,this.MAX_PENDING_INCOMING_TRANSFERS=3,this.MAX_AUTO_ACCEPT_VOICE_SIZE=4*1024*1024,this.MAX_AUTO_ACCEPT_VOICE_SESSION_BYTES=64*1024*1024,this.autoAcceptedVoiceBytes=0,this.sessionKeys=new Map,this.processedChunks=new Set,this.transferNonces=new Map,this.receivedFileBuffers=new Map,this.MAX_RETAINED_RECEIVED_FILE_BUFFERS=3,this.setupFileMessageHandlers(),this.webrtcManager&&(this.webrtcManager.fileTransferSystem=this)}getFileType(e){let t=String(e?.name||"").toLowerCase(),r=t.lastIndexOf("."),i=r>=0?t.substring(r):"",n=String(e?.type||"").toLowerCase();for(let[a,o]of Object.entries(this.FILE_TYPE_RESTRICTIONS)){if(!o.extensions.includes(i))continue;if(!n||this._genericMimeTypes.has(n)||this._allowedMimeTypes.has(n))return{type:a,category:o.category,description:o.description,maxSize:o.maxSize,allowed:!0,extension:i,mimeType:n}}return{type:"blocked",category:f("fileType.unsupported"),description:"Allowed: JPG, JPEG, PNG, GIF, WEBP, BMP, ICO, PDF, TXT, ZIP",maxSize:this.MAX_FILE_SIZE,allowed:!1,extension:i,mimeType:n}}validateFile(e){let t=this.getFileType(e),r=[],n=String(e?.name||"").toLowerCase(),a=n.lastIndexOf("."),o=a>=0?n.substring(a):"";return this.BLOCKED_EXTENSIONS.has(o)&&r.push(`File rejected: ${o} files are not allowed for security reasons.`),e.size>t.maxSize&&r.push(`File size (${this.formatFileSize(e.size)}) exceeds maximum allowed for ${t.category} (${this.formatFileSize(t.maxSize)})`),!t.allowed&&!this.BLOCKED_EXTENSIONS.has(o)&&r.push(`File rejected: unsupported file type. Supported types: ${t.description}`),e.size>this.MAX_FILE_SIZE&&r.push(`File size (${this.formatFileSize(e.size)}) exceeds general limit (${this.formatFileSize(this.MAX_FILE_SIZE)})`),{isValid:r.length===0,errors:r,fileType:t,fileSize:e.size,formattedSize:this.formatFileSize(e.size)}}normalizeDisplayFileName(e){return String(e||"").normalize("NFKC").replace(/[\u0000-\u001F\u007F]/g,"").replace(/[\\/]+/g,"_").trim().slice(0,255)}validateIncomingMetadata(e){let t=[];(!e||typeof e!="object")&&t.push("Invalid file transfer metadata"),(!e?.fileId||typeof e.fileId!="string")&&t.push("Invalid file id"),(!Number.isSafeInteger(e?.fileSize)||e.fileSize<=0)&&t.push("Invalid file size"),(!Number.isSafeInteger(e?.totalChunks)||e.totalChunks<=0)&&t.push("Invalid chunk count"),(!Number.isSafeInteger(e?.chunkSize)||e.chunkSize<=0||e.chunkSize>this.MAX_RECEIVE_CHUNK_SIZE)&&t.push("Invalid chunk size"),(!Array.isArray(e?.salt)||e.salt.length!==32)&&t.push("Invalid salt");let r=typeof e?.fileName=="string"?e.fileName:"",i=this.normalizeDisplayFileName(r);if((!r||r!==r.trim()||/[\u0000-\u001F\u007F]/.test(r)||/[\\/]/.test(r)||r==="."||r===".."||i.length===0)&&t.push("Dangerous file name"),t.length===0){let c=this.validateFile({name:i,size:e.fileSize,type:e.fileType||"application/octet-stream"});c.isValid||t.push(...c.errors)}let a=!!e?.isVoice,o=a?this.rejectVoiceAutoAcceptReason(e):null;return{isValid:t.length===0,errors:t,displayName:i,isVoice:a&&!o,voiceRejection:o}}rejectVoiceAutoAcceptReason(e){let t=String(e?.fileType||"").toLowerCase(),r=e?.fileSize;return t.startsWith("audio/")?this.FILE_TYPE_RESTRICTIONS.voice.mimeTypes.includes(t)?!Number.isSafeInteger(r)||r<=0||r>this.MAX_AUTO_ACCEPT_VOICE_SIZE?`too large to auto-accept (${this.formatFileSize(r||0)} > ${this.formatFileSize(this.MAX_AUTO_ACCEPT_VOICE_SIZE)})`:this.autoAcceptedVoiceBytes+r>this.MAX_AUTO_ACCEPT_VOICE_SESSION_BYTES?"session auto-accept budget for voice notes is exhausted":null:`unsupported audio MIME type (${t})`:`not an audio MIME type (${t||"absent"})`}formatFileSize(e){if(e===0)return"0 B";let t=1024,r=["B","KB","MB","GB"],i=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,i)).toFixed(2))+" "+r[i]}getSupportedFileTypes(){let e={};for(let[t,r]of Object.entries(this.FILE_TYPE_RESTRICTIONS))e[t]={category:r.category,description:r.description,extensions:r.extensions,maxSize:this.formatFileSize(r.maxSize),maxSizeBytes:r.maxSize};return e}getFileTypeInfo(){return{supportedTypes:this.getSupportedFileTypes(),generalMaxSize:this.formatFileSize(this.MAX_FILE_SIZE),generalMaxSizeBytes:this.MAX_FILE_SIZE,restrictions:this.FILE_TYPE_RESTRICTIONS}}arrayBufferToBase64(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),r="",i=t.byteLength;for(let n=0;n{this.webrtcManager.dataChannel&&(clearInterval(e),this.setupMessageInterception())},100);setTimeout(()=>{clearInterval(e)},5e3);return}this.setupMessageInterception()}setupMessageInterception(){try{if(!this.webrtcManager.dataChannel)return;this.webrtcManager&&(this.webrtcManager.fileTransferSystem=this),this.webrtcManager.dataChannel.onmessage&&(this.originalOnMessage=this.webrtcManager.dataChannel.onmessage),this.webrtcManager.dataChannel.onmessage=async e=>{try{if(e.data.length>Kt.MAX_MESSAGE_SIZE){console.warn("\u{1F512} Message too large, ignoring"),ee.logSecurityEvent("oversized_message_blocked");return}if(typeof e.data=="string")try{let t=JSON.parse(e.data);if(Kt.isMessageSizeValid(t),this.isFileTransferMessage(t)){await this.handleFileMessage(t);return}}catch(t){if(t.message==="Message too large")return}if(this.originalOnMessage)return this.originalOnMessage.call(this.webrtcManager.dataChannel,e)}catch(t){if(console.error("\u274C Error in file system message interception:",t),this.originalOnMessage)return this.originalOnMessage.call(this.webrtcManager.dataChannel,e)}}}catch(e){console.error("\u274C Failed to set up message interception:",e)}}isFileTransferMessage(e){return!e||typeof e!="object"||!e.type?!1:["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_chunk_request","file_transfer_complete","file_transfer_error"].includes(e.type)}async handleFileMessage(e){try{if(!this.webrtcManager.fileTransferSystem)try{if(typeof this.webrtcManager.initializeFileTransfer=="function"){this.webrtcManager.initializeFileTransfer();let t=0,r=50;for(;!this.webrtcManager.fileTransferSystem&&tsetTimeout(i,100)),t++;if(!this.webrtcManager.fileTransferSystem)throw new Error("File transfer system initialization timeout")}else throw new Error("initializeFileTransfer method not available")}catch(t){if(console.error("\u274C Failed to initialize file transfer system:",t),e.fileId){let r={type:"file_transfer_error",fileId:e.fileId,error:"File transfer system not available",timestamp:Date.now()};await this.sendSecureMessage(r)}return}switch(e.type){case"file_transfer_start":await this.handleFileTransferStart(e);break;case"file_transfer_response":this.handleTransferResponse(e);break;case"file_chunk":await this.handleFileChunk(e);break;case"chunk_confirmation":this.handleChunkConfirmation(e);break;case"file_chunk_request":await this.handleChunkRequest(e);break;case"file_transfer_complete":this.handleTransferComplete(e);break;case"file_transfer_error":this.handleTransferError(e);break;default:console.warn("\u26A0\uFE0F Unknown file message type:",e.type)}}catch(t){if(console.error("\u274C Error handling file message:",t),e.fileId){let r={type:"file_transfer_error",fileId:e.fileId,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(r)}}}async deriveFileSessionKey(e){try{if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("WebRTC session data not available");let t=crypto.getRandomValues(new Uint8Array(32)),r=new TextEncoder,i=r.encode(this.webrtcManager.keyFingerprint),n=r.encode(e),a=new Uint8Array(this.webrtcManager.sessionSalt),o=new Uint8Array(i.length+a.length+t.length+n.length),c=0;o.set(i,c),c+=i.length,o.set(a,c),c+=a.length,o.set(t,c),c+=t.length,o.set(n,c);let d=await crypto.subtle.digest("SHA-256",o),h=await crypto.subtle.importKey("raw",d,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return this.sessionKeys.set(e,{key:h,salt:Array.from(t),created:Date.now()}),{key:h,salt:Array.from(t)}}catch(t){throw console.error("\u274C Failed to derive file session key:",t),t}}async deriveFileSessionKeyFromSalt(e,t){try{if(!t||!Array.isArray(t)||t.length!==32)throw new Error(`Invalid salt: ${t?.length||0} bytes`);if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("WebRTC session data not available");let r=new TextEncoder,i=r.encode(this.webrtcManager.keyFingerprint),n=r.encode(e),a=new Uint8Array(t),o=new Uint8Array(this.webrtcManager.sessionSalt),c=new Uint8Array(i.length+o.length+a.length+n.length),d=0;c.set(i,d),d+=i.length,c.set(o,d),d+=o.length,c.set(a,d),d+=a.length,c.set(n,d);let h=await crypto.subtle.digest("SHA-256",c),u=await crypto.subtle.importKey("raw",h,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return this.sessionKeys.set(e,{key:u,salt:t,created:Date.now()}),u}catch(r){throw console.error("\u274C Failed to derive session key from salt:",r),r}}_emitTransferProgress(e,t){if(typeof this.onProgress!="function"||!e)return;let r=e.totalChunks||0,i=t==="up"?e.sentChunks||0:e.receivedCount||0,n=r>0?Math.min(100,Math.round(i/r*100)):0;try{this.onProgress({fileId:e.fileId,uiId:e.uiId||null,direction:t,progress:n,transferredChunks:i,totalChunks:r,isVoice:!!e.isVoice,voice:e.voice||null})}catch{}}async sendFile(e,t={}){try{if(!this.webrtcManager)throw new Error("WebRTC Manager not initialized");let r=this.getClientIdentifier();if(!this.rateLimiter.isAllowed(r))throw ee.logSecurityEvent("rate_limit_exceeded",{clientId:r}),new Error("Rate limit exceeded. Please wait before sending another file.");if(!e||!e.size)throw new Error("Invalid file object");let i=this.validateFile(e);if(!i.isValid){let m=i.errors.join(". ");throw new Error(m)}if(this.activeTransfers.size>=this.MAX_CONCURRENT_TRANSFERS)throw new Error("Maximum concurrent transfers reached");let n=`file_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,a=await this.calculateFileHash(e),o=await this.deriveFileSessionKey(n),c=o.key,d=o.salt,h={fileId:n,file:e,fileHash:a,sessionKey:c,salt:d,totalChunks:Math.ceil(e.size/this.CHUNK_SIZE),sentChunks:0,confirmedChunks:0,startTime:Date.now(),status:"preparing",retryCount:0,lastChunkTime:Date.now(),isVoice:!!(t&&t.voice),voice:t&&t.voice?t.voice:null,uiId:t&&t.uiId?t.uiId:null};this.activeTransfers.set(n,h),this.transferNonces.set(n,0);let u=new Promise((m,y)=>{h.resolveConsent=m,h.rejectConsent=y,h.consentTimeout=setTimeout(()=>{h.consentTimeout=null,y(new Error("Transfer timeout"))},3e4)});return await this.sendFileMetadata(h),await u,await this.startChunkTransmission(h),n}catch(r){let i=ee.sanitizeError(r);throw console.error("\u274C File sending failed:",i),this.onError&&this.onError(i),new Error(i)}}async sendFileMetadata(e){try{let t={type:"file_transfer_start",fileId:e.fileId,fileName:e.file.name,fileSize:e.file.size,fileType:e.file.type||"application/octet-stream",fileHash:e.fileHash,totalChunks:e.totalChunks,chunkSize:this.CHUNK_SIZE,salt:e.salt,timestamp:Date.now(),version:"2.0"};if(e.isVoice&&(t.isVoice=!0,e.voice&&(t.voice=e.voice)),this.signingKey)try{t.signature=await Ft.signFileMetadata(t,this.signingKey),console.log("\u{1F512} File metadata signed successfully")}catch(r){ee.logSecurityEvent("signature_failed",{fileId:e.fileId,error:r.message})}await this.sendSecureMessage(t),e.status="metadata_sent"}catch(t){let r=ee.sanitizeError(t);throw console.error("\u274C Failed to send file metadata:",r),e.status="failed",new Error(r)}}async startChunkTransmission(e){try{e.status="transmitting";let t=e.file,r=e.totalChunks;for(let i=0;i{let r=this.activeTransfers.get(e.fileId);r&&r.status!=="completed"&&this.cleanupTransfer(e.fileId)},18e4)}async handleChunkRequest(e){let t=this.activeTransfers.get(e?.fileId);if(!t||!t.file)return;let r=Array.isArray(e.missing)?e.missing:[];if(r.length===0)return;this._armSenderIdleTimeout(t),t.status="transmitting";let n=r.slice(0,512);for(let a of n)if(!(!Number.isInteger(a)||a<0||a>=t.totalChunks))try{let o=a*this.CHUNK_SIZE,c=Math.min(o+this.CHUNK_SIZE,t.file.size),d=await this.readFileChunk(t.file,o,c);await this.sendFileChunk(t,a,d),await this.waitForBackpressure()}catch(o){console.warn("\u26A0\uFE0F Failed to retransmit chunk",a,ee.sanitizeError(o))}t.status==="transmitting"&&(t.status="waiting_confirmation"),this._armSenderIdleTimeout(t)}async readFileChunk(e,t,r){try{return await e.slice(t,r).arrayBuffer()}catch(i){let n=ee.sanitizeError(i);throw console.error("\u274C Failed to read file chunk:",n),new Error(n)}}async sendFileChunk(e,t,r){try{let i=e.sessionKey,n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},i,r),o=this.arrayBufferToBase64(new Uint8Array(a)),c={type:"file_chunk",fileId:e.fileId,chunkIndex:t,totalChunks:e.totalChunks,nonce:Array.from(n),encryptedDataB64:o,chunkSize:r.byteLength,timestamp:Date.now()};await this.waitForBackpressure(),await this.sendSecureMessage(c)}catch(i){let n=ee.sanitizeError(i);throw console.error("\u274C Failed to send file chunk:",n),new Error(n)}}async sendSecureMessage(e){let t=JSON.stringify(e),r=this.webrtcManager?.dataChannel,i=10,n=0,a=o=>new Promise(c=>setTimeout(c,o));for(;;)try{if(!r||r.readyState!=="open")throw new Error("Data channel not ready");await this.waitForBackpressure(),r.send(t);return}catch(o){let c=String(o?.message||""),d=c.includes("send queue is full")||c.includes("bufferedAmount"),h=o?.name==="OperationError";if((d||h)&&ne.bufferedAmountLowThreshold&&await new Promise(r=>{let i=()=>{e.removeEventListener("bufferedamountlow",i),r()};e.addEventListener("bufferedamountlow",i,{once:!0})});return}let t=4*1024*1024;for(;e.bufferedAmount>t;)await new Promise(r=>setTimeout(r,20))}catch{}}async calculateFileHash(e){try{let t=await e.arrayBuffer(),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw console.error("\u274C File hash calculation failed:",t),t}}async handleFileTransferStart(e){try{let t=this.getClientIdentifier();if(!this.incomingOfferLimiter.isAllowed(t))throw new Error("Incoming file request rate limit exceeded");let r=this.validateIncomingMetadata(e);if(!r.isValid)throw new Error(r.errors.join(". "));if(e.signature&&this.verificationKey)try{if(!await Ft.verifyFileMetadata(e,e.signature,this.verificationKey))throw ee.logSecurityEvent("invalid_metadata_signature",{fileId:e.fileId}),new Error("Invalid file metadata signature");console.log("\u{1F512} File metadata signature verified successfully")}catch(n){throw ee.logSecurityEvent("verification_failed",{fileId:e.fileId,error:n.message}),new Error("File metadata verification failed")}if(this.receivingTransfers.has(e.fileId)||this.pendingIncomingTransfers.has(e.fileId))return;if(this.pendingIncomingTransfers.size>=this.MAX_PENDING_INCOMING_TRANSFERS)throw new Error("Too many pending incoming file requests");r.voiceRejection&&console.warn(`Voice auto-accept declined, falling back to consent: ${r.voiceRejection}`);let i={...e,isVoice:r.isVoice,fileName:r.displayName,receivedAt:Date.now()};this.pendingIncomingTransfers.set(e.fileId,i),r.isVoice&&(this.autoAcceptedVoiceBytes+=e.fileSize),typeof this.onIncomingFileRequest=="function"?this.onIncomingFileRequest({fileId:i.fileId,fileName:i.fileName,fileSize:i.fileSize,mimeType:i.fileType||"application/octet-stream",isVoice:r.isVoice,voice:i.voice||null}):await this.rejectIncomingFile(e.fileId,f("file.consentUnavailable"))}catch(t){let r=ee.sanitizeError(t);console.error("\u274C Failed to handle file transfer start:",r);let i={type:"file_transfer_response",fileId:e.fileId,accepted:!1,error:r,timestamp:Date.now()};await this.sendSecureMessage(i)}}async handleFileChunk(e){return this.atomicOps.withLock(`chunk-${e.fileId}`,async()=>{try{let t=this.receivingTransfers.get(e.fileId);if(!t||t._assembled||t.status==="completed")return;if(!this._isIncomingChunkAllowed(e.fileId)){console.warn("\u26A0\uFE0F Incoming file chunk rate limit exceeded; cleaning up transfer:",e.fileId),this.cleanupReceivingTransfer(e.fileId);return}if(t.lastChunkTime=Date.now(),t.receivedChunks.has(e.chunkIndex))return;if(e.chunkIndex<0||e.chunkIndex>=t.totalChunks)throw new Error(`Invalid chunk index: ${e.chunkIndex}`);let r=new Uint8Array(e.nonce),i;if(e.encryptedDataB64)i=this.base64ToUint8Array(e.encryptedDataB64);else if(e.encryptedData)i=new Uint8Array(e.encryptedData);else throw new Error("Missing encrypted data");let n=await crypto.subtle.decrypt({name:"AES-GCM",iv:r},t.sessionKey,i);if(n.byteLength!==e.chunkSize)throw new Error(`Chunk size mismatch: expected ${e.chunkSize}, got ${n.byteLength}`);t.receivedChunks.set(e.chunkIndex,n),t.receivedCount++,this._emitTransferProgress(t,"down");let a={type:"chunk_confirmation",fileId:e.fileId,chunkIndex:e.chunkIndex,timestamp:Date.now()};await this.sendSecureMessage(a),t.receivedCount===t.totalChunks&&await this.assembleFile(t)}catch(t){let r=ee.sanitizeError(t);console.warn("\u26A0\uFE0F Dropping unprocessable file chunk (will be re-requested):",e.chunkIndex,r)}})}_isIncomingChunkAllowed(e){let t=this.getClientIdentifier();return this.incomingChunkLimiter.isAllowed(t)?(this.incomingTransferChunkLimiters.has(e)||this.incomingTransferChunkLimiters.set(e,new nt(this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE,6e4)),this.incomingTransferChunkLimiters.get(e).isAllowed(e)?!0:(ee.logSecurityEvent("incoming_chunk_transfer_rate_limit_exceeded",{clientId:t,fileId:e}),!1)):(ee.logSecurityEvent("incoming_chunk_aggregate_rate_limit_exceeded",{clientId:t,fileId:e}),!1)}async assembleFile(e){if(!e._assembled){e._assembled=!0;try{e.status="assembling";for(let h=0;hh+u.length,0);if(r!==e.fileSize)throw new Error(`File size mismatch: expected ${e.fileSize}, got ${r}`);let i=new Uint8Array(r),n=0;for(let h of t)i.set(h,n),n+=h.length;if(await this.calculateFileHashFromData(i)!==e.fileHash)throw new Error("File integrity check failed - hash mismatch");let o=i.buffer,c=new Blob([o],{type:e.fileType});if(e.endTime=Date.now(),e.status="completed",this._storeReceivedFileBuffer(e.fileId,{buffer:o,type:e.fileType,name:e.fileName,size:e.fileSize}),this.onFileReceived){let h=async()=>{let y=await this.getBlob(e.fileId);if(!y)throw new Error("This file is no longer available for download.");return y},u=async()=>{let y=await h();return URL.createObjectURL(y)},m=y=>{try{URL.revokeObjectURL(y)}catch{}};this.onFileReceived({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,mimeType:e.fileType,transferTime:e.endTime-e.startTime,isVoice:!!e.isVoice,voice:e.voice||null,fileBlob:c,getBlob:h,getObjectURL:u,revokeObjectURL:m})}let d={type:"file_transfer_complete",fileId:e.fileId,success:!0,timestamp:Date.now()};await this.sendSecureMessage(d),e._stallTimer&&(clearInterval(e._stallTimer),e._stallTimer=null),e.receivedChunks&&e.receivedChunks.clear(),e.sessionKey=null}catch(t){console.error("\u274C File assembly failed:",t),e.status="failed",this.onError&&this.onError(`File assembly failed: ${t.message}`);let r={type:"file_transfer_complete",fileId:e.fileId,success:!1,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(r),this.cleanupReceivingTransfer(e.fileId)}}}async calculateFileHashFromData(e){try{let t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(i=>i.toString(16).padStart(2,"0")).join("")}catch(t){throw console.error("\u274C Hash calculation failed:",t),t}}handleTransferResponse(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;e.accepted?(t.status="accepted",t.consentTimeout&&clearTimeout(t.consentTimeout),t.consentTimeout=null,t.resolveConsent?.(),t.resolveConsent=null,t.rejectConsent=null):(t.status="rejected",t.consentTimeout&&clearTimeout(t.consentTimeout),t.consentTimeout=null,t.rejectConsent?.(new Error(e.error||"Transfer rejected")),t.rejectConsent=null,t.resolveConsent=null,this.onError&&this.onError(`Transfer rejected: ${e.error||"Unknown reason"}`),this.cleanupTransfer(e.fileId))}catch(t){console.error("\u274C Failed to handle transfer response:",t)}}handleChunkConfirmation(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;t.confirmedChunks++,t.lastChunkTime=Date.now(),t.status==="waiting_confirmation"&&this._armSenderIdleTimeout(t)}catch(t){console.error("\u274C Failed to handle chunk confirmation:",t)}}handleTransferComplete(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;e.success?(t.status="completed",t.endTime=Date.now(),this.onComplete&&this.onComplete({fileId:t.fileId,fileName:t.file.name,fileSize:t.file.size,transferTime:t.endTime-t.startTime,status:"completed"})):(t.status="failed",this.onError&&this.onError(`Transfer failed: ${e.error||"Unknown error"}`)),this.cleanupTransfer(e.fileId)}catch(t){console.error("\u274C Failed to handle transfer completion:",t)}}handleTransferError(e){try{let t=this.activeTransfers.get(e.fileId);t&&(t.status="failed",this.cleanupTransfer(e.fileId));let r=this.receivingTransfers.get(e.fileId);r&&(r.status="failed",this.cleanupReceivingTransfer(e.fileId)),this.onError&&this.onError(`Transfer error: ${e.error||"Unknown error"}`)}catch(t){console.error("\u274C Failed to handle transfer error:",t)}}getActiveTransfers(){return Array.from(this.activeTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.file?.name||"Unknown",fileSize:e.file?.size||0,progress:Math.round(e.sentChunks/e.totalChunks*100),totalChunks:e.totalChunks||0,transferredChunks:e.sentChunks||0,status:e.status,startTime:e.startTime}))}getReceivingTransfers(){return Array.from(this.receivingTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.fileName||"Unknown",fileSize:e.fileSize||0,progress:Math.round(e.receivedCount/e.totalChunks*100),totalChunks:e.totalChunks||0,transferredChunks:e.receivedCount||0,status:e.status,startTime:e.startTime}))}getPendingIncomingTransfers(){return Array.from(this.pendingIncomingTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,mimeType:e.fileType||"application/octet-stream",receivedAt:e.receivedAt}))}async acceptIncomingFile(e){let t=this.pendingIncomingTransfers.get(e);if(!t)return!1;let r=await this.deriveFileSessionKeyFromSalt(e,t.salt);return this.receivingTransfers.set(e,{fileId:e,fileName:t.fileName,fileSize:t.fileSize,fileType:t.fileType||"application/octet-stream",fileHash:t.fileHash,totalChunks:t.totalChunks,chunkSize:t.chunkSize||this.CHUNK_SIZE,sessionKey:r,salt:t.salt,receivedChunks:new Map,receivedCount:0,startTime:Date.now(),lastChunkTime:Date.now(),status:"receiving",isVoice:!!t.isVoice,voice:t.voice||null}),this.pendingIncomingTransfers.delete(e),await this.sendSecureMessage({type:"file_transfer_response",fileId:e,accepted:!0,timestamp:Date.now()}),this._startReceiverStallDetector(e),!0}_startReceiverStallDetector(e){let n=this.receivingTransfers.get(e);n&&(n._stallTimer&&clearInterval(n._stallTimer),n._lastProgressCount=n.receivedCount||0,n._lastProgressTime=Date.now(),n._stallTimer=setInterval(async()=>{let a=this.receivingTransfers.get(e);if(!a||a._stallTimer!==n._stallTimer){clearInterval(n._stallTimer);return}if(a.status==="completed"||a._assembled){clearInterval(a._stallTimer),a._stallTimer=null;return}if(a.receivedCount!==a._lastProgressCount&&(a._lastProgressCount=a.receivedCount,a._lastProgressTime=Date.now()),!(a.receivedCount>=a.totalChunks)&&!(Date.now()-(a.lastChunkTime||0)<5e3)){if(Date.now()-a._lastProgressTime>18e4){clearInterval(a._stallTimer),a._stallTimer=null,a.status="failed",this.onError&&this.onError("File transfer stalled \u2014 no data received. Please try again."),this.cleanupReceivingTransfer(e);return}await this._requestMissingChunks(e)}},2500))}async _requestMissingChunks(e){let t=this.receivingTransfers.get(e);if(!t||!t.receivedChunks)return;let r=256,i=[];for(let n=0;nthis.MAX_RETAINED_RECEIVED_FILE_BUFFERS;){let r=this.receivedFileBuffers.keys().next().value;this._discardReceivedFileBuffer(r)}}_discardReceivedFileBuffer(e){let t=this.receivedFileBuffers.get(e);if(!t)return;try{t.buffer&&(qe.secureWipe(t.buffer),new Uint8Array(t.buffer).fill(0))}catch{}this.receivedFileBuffers.delete(e);let r=this.receivingTransfers.get(e);r&&(r.status==="completed"||r._assembled)&&(r._stallTimer&&(clearInterval(r._stallTimer),r._stallTimer=null),this.receivingTransfers.delete(e))}cleanupReceivingTransfer(e){try{this.pendingChunks.delete(e);let t=this.receivingTransfers.get(e);if(t){if(t._stallTimer&&(clearInterval(t._stallTimer),t._stallTimer=null),t.receivedChunks&&t.receivedChunks.size>0){for(let[n,a]of t.receivedChunks)try{a&&(a instanceof ArrayBuffer||a instanceof Uint8Array)&&(qe.secureWipe(a),a instanceof ArrayBuffer?new Uint8Array(a).fill(0):a instanceof Uint8Array&&a.fill(0))}catch(o){console.warn("\u26A0\uFE0F Failed to securely wipe chunk:",o)}t.receivedChunks.clear()}if(t.sessionKey)try{t.sessionKey=null}catch(n){console.warn("\u26A0\uFE0F Failed to clear session key:",n)}if(t.salt)try{Array.isArray(t.salt)&&t.salt.fill(0),t.salt=null}catch(n){console.warn("\u26A0\uFE0F Failed to clear salt:",n)}for(let[n,a]of Object.entries(t))a&&typeof a=="object"&&(a instanceof ArrayBuffer||a instanceof Uint8Array?qe.secureWipe(a):Array.isArray(a)&&a.fill(0),t[n]=null)}this.receivingTransfers.delete(e),this.sessionKeys.delete(e),this.incomingTransferChunkLimiters.delete(e);let r=this.receivedFileBuffers.get(e);if(r)try{r.buffer&&(qe.secureWipe(r.buffer),new Uint8Array(r.buffer).fill(0));for(let[n,a]of Object.entries(r))a&&typeof a=="object"&&((a instanceof ArrayBuffer||a instanceof Uint8Array)&&qe.secureWipe(a),r[n]=null);this.receivedFileBuffers.delete(e)}catch(n){console.warn("\u26A0\uFE0F Failed to securely clear file buffer:",n),this.receivedFileBuffers.delete(e)}let i=[];for(let n of this.processedChunks)n.startsWith(e)&&i.push(n);for(let n of i)this.processedChunks.delete(n);if(typeof global<"u"&&global.gc)try{global.gc()}catch{}console.log(`\u{1F512} Memory safely cleaned for file transfer: ${e}`)}catch(t){throw console.error("\u274C Error during secure memory cleanup:",t),this.receivingTransfers.delete(e),this.sessionKeys.delete(e),this.receivedFileBuffers.delete(e),this.pendingChunks.delete(e),new Error(`Memory cleanup failed: ${t.message}`)}}getTransferStatus(e){if(this.activeTransfers.has(e)){let t=this.activeTransfers.get(e);return{type:"sending",fileId:t.fileId,fileName:t.file.name,progress:Math.round(t.sentChunks/t.totalChunks*100),status:t.status,startTime:t.startTime}}if(this.receivingTransfers.has(e)){let t=this.receivingTransfers.get(e);return{type:"receiving",fileId:t.fileId,fileName:t.fileName,progress:Math.round(t.receivedCount/t.totalChunks*100),status:t.status,startTime:t.startTime}}return null}getSystemStatus(){return{initialized:!0,activeTransfers:this.activeTransfers.size,receivingTransfers:this.receivingTransfers.size,totalTransfers:this.activeTransfers.size+this.receivingTransfers.size,maxConcurrentTransfers:this.MAX_CONCURRENT_TRANSFERS,maxFileSize:this.MAX_FILE_SIZE,chunkSize:this.CHUNK_SIZE,hasWebrtcManager:!!this.webrtcManager,isConnected:this.webrtcManager?.isConnected?.()||!1,hasDataChannel:!!this.webrtcManager?.dataChannel,dataChannelState:this.webrtcManager?.dataChannel?.readyState,isVerified:this.webrtcManager?.isVerified,hasEncryptionKey:!!this.webrtcManager?.encryptionKey,hasMacKey:!!this.webrtcManager?.macKey,linkedToWebRTCManager:this.webrtcManager?.fileTransferSystem===this,supportedFileTypes:this.getSupportedFileTypes(),fileTypeInfo:this.getFileTypeInfo()}}cleanup(){Ie.getInstance().deactivate(),this.webrtcManager&&this.webrtcManager.dataChannel&&this.originalOnMessage&&(this.webrtcManager.dataChannel.onmessage=this.originalOnMessage,this.originalOnMessage=null),this.webrtcManager&&this.originalProcessMessage&&(this.webrtcManager.processMessage=this.originalProcessMessage,this.originalProcessMessage=null),this.webrtcManager&&this.originalRemoveSecurityLayers&&(this.webrtcManager.removeSecurityLayers=this.originalRemoveSecurityLayers,this.originalRemoveSecurityLayers=null);for(let e of this.activeTransfers.keys())this.cleanupTransfer(e);for(let e of this.receivingTransfers.keys())this.cleanupReceivingTransfer(e);this.atomicOps&&this.atomicOps.locks.clear(),this.rateLimiter&&this.rateLimiter.requests.clear(),this.incomingChunkLimiter&&this.incomingChunkLimiter.requests.clear(),this.incomingTransferChunkLimiters.clear(),this.pendingChunks.clear(),this.pendingIncomingTransfers.clear(),this.activeTransfers.clear(),this.receivingTransfers.clear(),this.transferQueue.length=0,this.sessionKeys.clear(),this.transferNonces.clear(),this.processedChunks.clear();for(let e of Array.from(this.receivedFileBuffers.keys()))this._discardReceivedFileBuffer(e);this.clearKeys()}onSessionUpdate(e){this.sessionKeys.clear()}diagnoseFileTransferIssue(){return{timestamp:new Date().toISOString(),fileTransferSystem:{initialized:!!this,hasWebrtcManager:!!this.webrtcManager,webrtcManagerType:this.webrtcManager?.constructor?.name,linkedToWebRTCManager:this.webrtcManager?.fileTransferSystem===this},webrtcManager:{hasDataChannel:!!this.webrtcManager?.dataChannel,dataChannelState:this.webrtcManager?.dataChannel?.readyState,isConnected:this.webrtcManager?.isConnected?.()||!1,isVerified:this.webrtcManager?.isVerified,hasEncryptionKey:!!this.webrtcManager?.encryptionKey,hasMacKey:!!this.webrtcManager?.macKey,hasKeyFingerprint:!!this.webrtcManager?.keyFingerprint,hasSessionSalt:!!this.webrtcManager?.sessionSalt},securityContext:{contextActive:Ie.getInstance().isActive(),securityLevel:Ie.getInstance().getSecurityLevel(),hasAtomicOps:!!this.atomicOps,hasRateLimiter:!!this.rateLimiter},transfers:{activeTransfers:this.activeTransfers.size,receivingTransfers:this.receivingTransfers.size,pendingChunks:this.pendingChunks.size,sessionKeys:this.sessionKeys.size},fileTypeSupport:{supportedTypes:this.getSupportedFileTypes(),generalMaxSize:this.formatFileSize(this.MAX_FILE_SIZE),restrictions:Object.keys(this.FILE_TYPE_RESTRICTIONS)}}}async debugKeyDerivation(e){try{if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("Session data not available");let t=await this.deriveFileSessionKey(e),r=await this.deriveFileSessionKeyFromSalt(e,t.salt),i=new TextEncoder().encode("test data"),n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},t.key,i),o=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},r,a);if(new TextDecoder().decode(o)==="test data")return{success:!0,message:"All tests passed"};throw new Error("Decryption verification failed")}catch(t){return console.error("\u274C Key derivation test failed:",t),{success:!1,error:t.message}}}registerWithWebRTCManager(){if(!this.webrtcManager)throw new Error("WebRTC manager not available");this.webrtcManager.fileTransferSystem=this,this.webrtcManager.setFileMessageHandler=e=>{this.webrtcManager._fileMessageHandler=e},this.webrtcManager.setFileMessageHandler(e=>this.handleFileMessage(e))}static createFileMessageFilter(e){return async t=>{try{if(typeof t.data=="string"){let r=JSON.parse(t.data);if(e.isFileTransferMessage(r))return await e.handleFileMessage(r),!0}}catch{}return!1}}setSigningKey(e){if(!e||!(e instanceof CryptoKey))throw new Error("Invalid private key for signing");this.signingKey=e,console.log("\u{1F512} Signing key set successfully")}setVerificationKey(e){if(!e||!(e instanceof CryptoKey))throw new Error("Invalid public key for verification");this.verificationKey=e,console.log("\u{1F512} Verification key set successfully")}async generateSigningKeyPair(){try{let e=await crypto.subtle.generateKey({name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},!0,["sign","verify"]);return this.signingKey=e.privateKey,this.verificationKey=e.publicKey,console.log("\u{1F512} RSA key pair generated successfully"),e}catch(e){let t=ee.sanitizeError(e);throw console.error("\u274C Failed to generate signing key pair:",t),new Error(t)}}clearKeys(){this.signingKey=null,this.verificationKey=null,console.log("\u{1F512} Security keys cleared")}getSecurityStatus(){return{signingEnabled:this.signingKey!==null,verificationEnabled:this.verificationKey!==null,contextActive:Ie.getInstance().isActive(),securityLevel:Ie.getInstance().getSecurityLevel()}}getClientIdentifier(){return this.webrtcManager?.connectionId||this.webrtcManager?.keyFingerprint?.substring(0,16)||"default-client"}destroy(){Ie.getInstance().deactivate(),this.clearKeys(),console.log("\u{1F512} File transfer system destroyed safely")}};var Ue=typeof navigator<"u"&&/AppleWebKit/.test(navigator.userAgent)&&!/Chrome|Chromium|Edg\//.test(navigator.userAgent),st={opusFmtp:{minptime:10,useinbandfec:1,usedtx:1,stereo:0,maxaveragebitrate:32e3,cbr:0},preferRed:!0,sender:{maxBitrate:4e4,priority:"high",networkPriority:"high"}},Re={codecPreferenceOrder:["VP9","AV1","H264","VP8"],vp9:{preferredScalabilityMode:"L3T3_KEY",simulcast:[{rid:"low",scaleResolutionDownBy:4,maxBitrate:15e4,scalabilityMode:"L1T3"},{rid:"mid",scaleResolutionDownBy:2,maxBitrate:5e5,scalabilityMode:"L1T3"},{rid:"high",scaleResolutionDownBy:1,maxBitrate:15e5,scalabilityMode:"L1T3"}],degradationPreference:"balanced"},av1:{scalabilityMode:"L1T3",maxBitrate:12e5,degradationPreference:"maintain-framerate"},simulcast:[{rid:"low",scaleResolutionDownBy:4,maxBitrate:15e4},{rid:"mid",scaleResolutionDownBy:2,maxBitrate:5e5},{rid:"high",scaleResolutionDownBy:1,maxBitrate:15e5}],networkPriority:"medium"},qi={twccUri:"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",video:{rtcpFb:["transport-cc","nack","nack pli","ccm fir","goog-remb"],twcc:!0},audio:{rtcpFb:["transport-cc","nack"],twcc:!0}},Tr={intervalMs:1e3,loss:{highPct:.1,recoverPct:.03,audioProtectPct:.25},rtt:{highMs:300,recoverMs:150},stepDownPct:.2,stepUpPct:.1,minVideoBitrate:1e5,recoverStableTicks:5,cpuScaleStep:1.5};function ta(s){return s.indexOf(`\r `)!==-1?`\r `:` -`}function Wi(s){let e=ta(s),t=s.split(/\r\n|\n/),r=[],i=[],n=null;for(let a of t)a.startsWith("m=")?(n={lines:[a]},i.push(n)):n?n.lines.push(a):r.push(a);return{eol:e,session:r,media:i}}function Yi(s){let e=[...s.session];for(let t of s.media)e.push(...t.lines);return e.join(s.eol)}function Xi(s){let e=s.lines[0].match(/^m=(\w+)/);return e?e[1]:null}function ra(s,e){let t=new RegExp("^a=rtpmap:(\\d+)\\s+"+e+"\\/","i"),r=[];for(let i of s.lines){let n=i.match(t);n&&r.push(n[1])}return r}function ia(s){let e=new Map;for(let t of s.split(";")){let r=t.trim();if(!r)continue;let i=r.indexOf("=");i===-1?e.set(r,void 0):e.set(r.slice(0,i).trim(),r.slice(i+1).trim())}return e}function ji(s){let e=[];for(let[t,r]of s)e.push(r===void 0?t:`${t}=${r}`);return e.join(";")}function na(s,e,t){let r=s.lines.findIndex(o=>o.startsWith(`a=fmtp:${e} `)||o===`a=fmtp:${e}`);if(r!==-1){let o=s.lines[r].slice(`a=fmtp:${e} `.length),c=ia(o);for(let[d,u]of Object.entries(t))c.set(d,String(u));s.lines[r]=`a=fmtp:${e} ${ji(c)}`;return}let i=new Map;for(let[o,c]of Object.entries(t))i.set(o,String(c));let n=`a=fmtp:${e} ${ji(i)}`,a=s.lines.findIndex(o=>o.startsWith(`a=rtpmap:${e} `));a!==-1?s.lines.splice(a+1,0,n):s.lines.push(n)}function Cr(s,e){if(!s||typeof s!="string")return s;let t=Wi(s),r=!1;for(let i of t.media)if(Xi(i)==="audio")for(let n of ra(i,"opus"))na(i,n,e),r=!0;return r?Yi(t):s}var sa=/^(rtx|red|ulpfec|flexfec-03|telephone-event|CN)$/i;function aa(s){let e=[];for(let t of s.lines){let r=t.match(/^a=rtpmap:(\d+)\s+([^/]+)\//);r&&!sa.test(r[2])&&e.push(r[1])}return e}function oa(s,e){for(let t of aa(s))for(let r of e){let i=`a=rtcp-fb:${t} ${r}`;if(s.lines.includes(i))continue;let n=-1;for(let a=0;ai.startsWith("a=extmap:")&&i.includes(e)))return;let t=0,r=-1;for(let i=0;ii.startsWith("a=mid:")),r===-1&&(r=s.lines.length-1)),s.lines.splice(r+1,0,`a=extmap:${t+1} ${e}`)}function Qi(s,e){if(!s||typeof s!="string"||!e)return s;let t=Wi(s),r=!1;for(let i of t.media){let n=Xi(i),a=n==="video"?e.video:n==="audio"?e.audio:null;a&&(Array.isArray(a.rtcpFb)&&(oa(i,a.rtcpFb),r=!0),a.twcc&&e.twccUri&&(ca(i,e.twccUri),r=!0))}return r?Yi(t):s}function Ji(s){try{if(Ue||!s||typeof s.setCodecPreferences!="function"||!st.preferRed)return!1;let e=typeof RTCRtpSender<"u"&&RTCRtpSender.getCapabilities?RTCRtpSender.getCapabilities("audio"):null;if(!e||!Array.isArray(e.codecs))return!1;let t=o=>/red$/i.test(o.mimeType),r=o=>/opus$/i.test(o.mimeType);if(!e.codecs.some(t))return!1;let i=e.codecs.filter(t),n=e.codecs.filter(r),a=e.codecs.filter(o=>!t(o)&&!r(o));return s.setCodecPreferences([...i,...n,...a]),!0}catch{return!1}}async function Zi(s,e={}){try{if(Ue||!s||typeof s.getParameters!="function")return!1;let t={...st.sender,...e},r=s.getParameters();(!r.encodings||r.encodings.length===0)&&(r.encodings=[{}]);for(let i of r.encodings)i.maxBitrate=t.maxBitrate,i.priority=t.priority,i.networkPriority=t.networkPriority;return await s.setParameters(r),!0}catch{return!1}}var en={VP9:0,AV1:1,H264:2,VP8:3};function tn(s){return(String(s||"").split("/")[1]||"").toUpperCase()}function la(s){let e=t=>{let r=tn(t.mimeType);return Object.prototype.hasOwnProperty.call(en,r)?en[r]:99};return s.map((t,r)=>({c:t,i:r})).sort((t,r)=>e(t.c)-e(r.c)||t.i-r.i).map(t=>t.c)}function rn(s){if(!s||!Array.isArray(s.codecs))return null;let e=new Set(s.codecs.map(t=>tn(t.mimeType)));for(let t of Re.codecPreferenceOrder)if(e.has(t))return t;return null}function nn(){return typeof RTCRtpSender<"u"&&RTCRtpSender.getCapabilities?RTCRtpSender.getCapabilities("video"):null}function sn(s){try{if(Ue||!s||typeof s.setCodecPreferences!="function")return!1;let e=nn();return!e||!Array.isArray(e.codecs)?!1:(s.setCodecPreferences(la(e.codecs)),rn(e))}catch{return!1}}function da(s){return s==="VP9"?{scalabilityMode:Re.vp9.preferredScalabilityMode,maxBitrate:15e5,degradationPreference:Re.vp9.degradationPreference}:s==="AV1"?{scalabilityMode:Re.av1.scalabilityMode,maxBitrate:Re.av1.maxBitrate,degradationPreference:Re.av1.degradationPreference}:{scalabilityMode:void 0,maxBitrate:15e5,degradationPreference:"balanced"}}async function an(s,e={}){try{if(Ue||!s||typeof s.getParameters!="function")return!1;let t=rn(nn())||"VP8",r={...da(t),...e},i=s.getParameters();(!i.encodings||i.encodings.length===0)&&(i.encodings=[{}]);let n=i.encodings.length>1;if(n)for(let a of i.encodings)a.networkPriority=Re.networkPriority;else{let a=i.encodings[0];a.maxBitrate=r.maxBitrate,a.networkPriority=Re.networkPriority,r.scalabilityMode&&(a.scalabilityMode=r.scalabilityMode)}r.degradationPreference&&(i.degradationPreference=r.degradationPreference);try{return await s.setParameters(i),!0}catch{if(!n&&r.scalabilityMode){delete i.encodings[0].scalabilityMode;try{return await s.setParameters(i),!0}catch{return!1}}return!1}}catch{return!1}}function on(s,e={}){let t=null,r=null,i=null;for(let b of s)!b||typeof b.type!="string"||(b.type==="outbound-rtp"&&!b.isRemote?(!t||b.kind==="video")&&(t=b):b.type==="remote-inbound-rtp"?(!r||b.kind==="video")&&(r=b):b.type==="candidate-pair"&&(b.nominated||b.selected||b.state==="succeeded")&&(!i||b.nominated)&&(i=b));let n=Number(t?.packetsSent??0),a=Number(r?.packetsLost??0),o=n-(e.packetsSent??n),c=a-(e.packetsLost??a),d=o+c,u=d>0?Math.min(1,Math.max(0,c/d)):0,h=i?.currentRoundTripTime??r?.roundTripTime??0,m=Number(h)*1e3,p=Number(r?.jitter??0)*1e3,S=i?.availableOutgoingBitrate!=null?Number(i.availableOutgoingBitrate):null,g=t?.qualityLimitationReason??"none";return{lossPct:u,rttMs:m,jitterMs:p,availableOutgoingBitrate:S,qualityLimitationReason:g,counters:{packetsSent:n,packetsLost:a},hasData:!!(t&&(r||i))}}function cn(s){if(!s||!s.hasData)return null;let e=s.lossPct,t=s.rttMs;return e<.03&&t<150?"excellent":e<.07&&t<250?"good":e<.15&&t<400?"fair":"poor"}function ua(s,e,t=Tr){let{targetBitrate:r,ceilingBitrate:i,scaleResolutionDownBy:n,goodTicks:a}=e,o=!1,c="steady";if(s.qualityLimitationReason==="cpu"){let d=Math.min(4,+(n*t.cpuScaleStep).toFixed(3));d!==n&&(n=d,o=!0),a=0,c="cpu"}else if(s.lossPct>t.loss.highPct||s.rttMs>t.rtt.highMs){let d=Math.max(t.minVideoBitrate,Math.round(r*(1-t.stepDownPct)));d!==r&&(r=d,o=!0),a=0,c="backoff"}else if(s.lossPct=t.recoverStableTicks){let d=Math.min(i,Math.round(r*(1+t.stepUpPct)));d!==r&&(r=d,o=!0,c="rampup"),a=0}}else a=0;return{targetBitrate:r,scaleResolutionDownBy:n,goodTicks:a,changed:o,reason:c}}var Nt=class{constructor(e,t={}){this.pc=e,this.getVideoSender=t.getVideoSender||(()=>null),this.onQuality=t.onQuality||(()=>{}),this.cfg=t.cfg||Tr,this._timer=null,this._prevCounters={},this._lastQuality=void 0,this.state={targetBitrate:t.ceilingBitrate||15e5,ceilingBitrate:t.ceilingBitrate||15e5,scaleResolutionDownBy:1,goodTicks:0}}start(){this._timer||(this._timer=setInterval(()=>{this._tick().catch(()=>{})},this.cfg.intervalMs))}stop(){this._timer&&(clearInterval(this._timer),this._timer=null)}async _tick(){if(!this.pc||typeof this.pc.getStats!="function")return;let e=await this.pc.getStats(),t=typeof e.values=="function"?Array.from(e.values()):e,r=on(t,this._prevCounters);this._prevCounters=r.counters;let i=cn(r);if(i&&i!==this._lastQuality){this._lastQuality=i;try{this.onQuality(i,r)}catch{}}if(!r.hasData)return;let n=ua(r,this.state,this.cfg);this.state={targetBitrate:n.targetBitrate,ceilingBitrate:this.state.ceilingBitrate,scaleResolutionDownBy:n.scaleResolutionDownBy,goodTicks:n.goodTicks},n.changed&&await this._applyToVideoSender()}async _applyToVideoSender(){if(Ue)return;let e=this.getVideoSender();if(!(!e||typeof e.getParameters!="function"))try{let t=e.getParameters();if((!t.encodings||t.encodings.length===0)&&(t.encodings=[{}]),t.encodings.length===1)t.encodings[0].maxBitrate=this.state.targetBitrate,t.encodings[0].scaleResolutionDownBy=this.state.scaleResolutionDownBy;else{let r=t.encodings[t.encodings.length-1];r.maxBitrate=this.state.targetBitrate}await e.setParameters(t)}catch{}}};var ha="SecureBit-DR-Root-v1",fa="SecureBit-DR-Message-v1",pa="SecureBit-DR-Init-v1",ya=Uint8Array.of(1),ga=Uint8Array.of(2),Ut=new TextEncoder,ma=new TextDecoder,Ot=Object.freeze({MAX_SKIP_PER_CHAIN:512,MAX_SKIPPED_KEYS:1024,SKIPPED_KEY_TTL_MS:300*1e3});function ln(s){let e="",t=new Uint8Array(s);for(let r=0;r{o&&o.apply(),this._receivingChainKey&&this._receivingChainKey!==p&&q(this._receivingChainKey);for(let S of a)q(S);this._receivingChainKey=p,this._receiveCount=r+1,this._remotePublicKeyB64=u;for(let{id:S,key:g}of n)this._rememberSkipped(S,g);q(m)},discard:()=>{o&&o.discard();for(let{key:S}of n)q(S);for(let S of a)q(S);q(p),q(m)}}}async _collectSkipped(e,t,r,i){if(rOt.MAX_SKIP_PER_CHAIN)throw new Error(`DoubleRatchet: refusing to skip ${r-t} messages (limit ${Ot.MAX_SKIP_PER_CHAIN})`);let n=[],a=e;for(let o=t;o=Ot.MAX_SKIPPED_KEYS;){let r=this._skipped.keys().next().value,i=this._skipped.get(r);this._skipped.delete(r),i&&q(i.key)}this._skipped.set(e,{key:t,storedAt:Date.now()})}_pruneSkipped(){let e=Date.now()-Ot.SKIPPED_KEY_TTL_MS;for(let[t,r]of this._skipped)r.storedAt{q(this._rootKey),q(i.nextRoot),this._sendingChainKey&&q(this._sendingChainKey),this._rootKey=o.nextRoot,this._sendingChainKey=o.chainKey,this._selfKeyPair=n,this._remotePublicKey=t,this._remotePublicKeyB64=e,this._previousSendCount=this._sendCount,this._sendCount=0},discard:()=>{q(i.nextRoot),q(i.chainKey),q(o.nextRoot),q(o.chainKey)}}}destroy(){q(this._rootKey),q(this._sendingChainKey),q(this._receivingChainKey);for(let e of this._skipped.values())q(e.key);this._skipped.clear(),this._rootKey=null,this._sendingChainKey=null,this._receivingChainKey=null,this._selfKeyPair=null,this._remotePublicKey=null,this._remotePublicKeyB64=null,this._initialised=!1}};var j=Object.freeze({MAX_PAYLOAD_BYTES:512,MAX_CANDIDATES:8,MIN_UFRAG:4,MAX_UFRAG:64,MIN_PWD:22,MAX_PWD:64,FINGERPRINT_BYTES:32,COMMITMENT_BYTES:16,BINDING_BYTES:8,MAX_LIFETIME_MINUTES:60,MAX_EXT_BYTES:255,SURPLUS_CANDIDATE_BYTES:48,CLOCK_SKEW_MS:12e4}),pn=Date.UTC(2024,0,1),Sa=16777215,de=Object.freeze({OFFER:0,ANSWER:1}),yn=Object.freeze(["actpass","active","passive"]),Lr=Object.freeze([262144,1073741823,65536,null]),gn=3,St=Object.freeze({MAX_MESSAGE_SIZE:1}),Se=Object.freeze({HOST_V4:0,HOST_MDNS:1,SRFLX_V4:2,RELAY_V4:3,HOST_V6:4,SRFLX_V6:5,RELAY_V6:6}),mn=Object.freeze({0:4,1:16,2:4,3:4,4:16,5:16,6:16}),at=Object.freeze({0:"host",1:"host",2:"srflx",3:"relay",4:"host",5:"srflx",6:"relay"}),Ir=Object.freeze({0:"v4",1:"mdns",2:"v4",3:"v4",4:"v6",5:"v6",6:"v6"}),Dr=Object.freeze([null,"passive","active","so"]),ba=Object.freeze({host:126,srflx:100,relay:0}),Vt=/^[A-Za-z0-9+/]+$/,Rr=class extends Error{constructor(e,t="malformed"){super(e),this.name="DescriptorError",this.code=t}},P=(s,e)=>{throw new Rr(s,e)},_a=/^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\.local$/i,wa=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;function Sn(s){let e=wa.exec(s);if(!e)return null;let t=new Uint8Array(4);for(let r=0;r<4;r++){let i=Number(e[r+1]);if(!Number.isInteger(i)||i<0||i>255)return null;t[r]=i}return t}function Ea(s){if(!/^[0-9a-fA-F:.]+$/.test(s)||s.length>45)return null;let e=s,t=null,r=e.lastIndexOf(":");if(e.includes(".")){if(t=Sn(e.slice(r+1)),!t)return null;e=e.slice(0,r+1)+"0:0"}let i=e.split("::");if(i.length>2)return null;let n=u=>u===""?[]:u.split(":").map(h=>h.length===0||h.length>4?NaN:parseInt(h,16)),a=n(i[0]),o=i.length===2?n(i[1]):[];if([...a,...o].some(u=>!Number.isInteger(u)||u<0||u>65535))return null;let c;if(i.length===2){let u=8-a.length-o.length;if(u<1)return null;c=[...a,...new Array(u).fill(0),...o]}else c=a;if(c.length!==8)return null;let d=new Uint8Array(16);return c.forEach((u,h)=>{d[h*2]=u>>8,d[h*2+1]=u&255}),t&&d.set(t,12),d}function va(s){let e=_a.exec(s);if(!e)return null;let t=(e[1]+e[2]+e[3]+e[4]+e[5]).toLowerCase(),r=new Uint8Array(16);for(let i=0;i<16;i++)r[i]=parseInt(t.substr(i*2,2),16);return r}function Ta(s){return typeof s!="string"&&P("SDP must be a string"),s.length>64*1024&&P("SDP is too large"),s.split(/\r\n|\n/).filter(e=>e.length>0)}function gt(s,e){let t=`a=${e}:`;for(let r of s)if(r.startsWith(t))return r.slice(t.length).trim();return null}function bn(s){let e=Ta(s),t=gt(e,"ice-ufrag"),r=gt(e,"ice-pwd");(!t||!r)&&P("SDP is missing ICE credentials");let i=gt(e,"fingerprint");i||P("SDP is missing a DTLS fingerprint");let[n,a]=i.split(/\s+/);(!n||n.toLowerCase()!=="sha-256")&&P(`unsupported DTLS fingerprint algorithm: ${String(n).slice(0,16)}`);let o=String(a).split(":");o.length!==j.FINGERPRINT_BYTES&&P("DTLS fingerprint has the wrong length");let c=new Uint8Array(j.FINGERPRINT_BYTES);o.forEach((S,g)=>{/^[0-9a-fA-F]{2}$/.test(S)||P("DTLS fingerprint is not hex"),c[g]=parseInt(S,16)});let d=gt(e,"setup")||"actpass",u=yn.indexOf(d);u<0&&P(`unsupported DTLS setup role: ${d.slice(0,16)}`);let h=gt(e,"max-message-size"),m=h===null?65536:Number(h);(!Number.isInteger(m)||m<0)&&P("invalid a=max-message-size");let p=[];for(let S of e){if(!S.startsWith("a=candidate:"))continue;let g=S.slice(12).split(/\s+/);if(g.length<8||g[6]!=="typ"||g[1]!=="1")continue;let b=g[2].toLowerCase(),w=Number(g[3]),M=g[4],F=Number(g[5]),k=g[7];if(!Number.isInteger(F)||F<1||F>65535)continue;let E=0;if(b==="tcp"){let T=g.indexOf("tcptype"),Y=T>=0?Dr.indexOf(g[T+1]):-1;if(Y<=0)continue;E=Y}else if(b!=="udp")continue;let _=null,A=null,x=va(M);if(x&&k==="host")_=Se.HOST_MDNS,A=x;else{let T=Sn(M),Y=T?null:Ea(M),B=T||Y;if(!B)continue;if(k==="host")_=T?Se.HOST_V4:Se.HOST_V6;else if(k==="srflx"||k==="prflx")_=T?Se.SRFLX_V4:Se.SRFLX_V6;else if(k==="relay")_=T?Se.RELAY_V4:Se.RELAY_V6;else continue;A=B}p.push({kind:_,tcptype:E,addr:A,port:F,priority:Number.isFinite(w)?w:0})}return{ufrag:t,pwd:r,fingerprint:c,setup:u,maxMessageSize:m,candidates:p}}function hn(s){return 1+mn[s.kind]+2}var Ca=s=>s.tcptype!==2&&s.tcptype!==3;function Pr(s,{maxCandidates:e=j.MAX_CANDIDATES,maxBytes:t=j.SURPLUS_CANDIDATE_BYTES,keepMdns:r=!0,maxRelays:i=2}={}){let n=s.filter(b=>r||b.kind!==Se.HOST_MDNS),a=[],o=new Set;for(let b of n){let w=`${b.kind}:${b.tcptype}:${Array.from(b.addr).join(".")}:${b.port}`;o.has(w)||(o.add(w),a.push(b))}let c=(b,w)=>(w.priority||0)-(b.priority||0),d=b=>`${Ir[b.kind]}/${at[b.kind]}/${b.tcptype===0?"udp":"tcp"}`,u=new Map;for(let b of[...a].sort(c)){if(!Ca(b))continue;let w=d(b);u.has(w)||u.set(w,[]),u.get(w).push(b)}let h=[],m=new Set,p=0,S=0,g=b=>{h.push(b),m.add(b),p+=hn(b),at[b.kind]==="relay"&&S++};for(let b of u.values())g(b[0]);for(let b of[...a].sort(c))if(!m.has(b)){if(h.length>=e)break;p+hn(b)>t||at[b.kind]==="relay"&&S>=i||g(b)}return h.sort(c)}var bt=class{constructor(){this.b=[]}u8(e){this.b.push(e&255)}u16(e){this.b.push(e>>8&255,e&255)}u24(e){this.b.push(e>>16&255,e>>8&255,e&255)}u32(e){this.b.push(e>>>24&255,e>>>16&255,e>>>8&255,e&255)}bytes(e){for(let t of e)this.b.push(t&255)}ascii(e){for(let t=0;t2147483647)&&P("max-message-size must be an integer between 1024 and 2^31-1");let e=[],t=Lr.indexOf(s);if(t<0){t=gn;let r=new bt;r.u32(s),e.push({type:St.MAX_MESSAGE_SIZE,value:r.done()})}return{mmsIndex:t,records:e}}function _n(s){let{type:e,bindingTag:t=null,expiresAtMs:r,sdpFields:i,commitment:n=null}=s;e!==de.OFFER&&e!==de.ANSWER&&P("invalid descriptor type"),e===de.ANSWER?(!(t instanceof Uint8Array)||t.length!==j.BINDING_BYTES)&&P("answer needs an 8-byte binding tag"):t!==null&&P("offers do not carry a binding tag"),n!==null&&(!(n instanceof Uint8Array)||n.length!==j.COMMITMENT_BYTES)&&P("commitment must be 16 bytes");let{ufrag:a,pwd:o,fingerprint:c,setup:d,maxMessageSize:u,candidates:h}=i;(a.lengthj.MAX_UFRAG||!Vt.test(a))&&P("invalid ice-ufrag"),(o.lengthj.MAX_PWD||!Vt.test(o))&&P("invalid ice-pwd"),h.length>j.MAX_CANDIDATES&&P("too many candidates");let m=Math.ceil((r-pn)/6e4);(!Number.isInteger(m)||m<0||m>Sa)&&P("expiry out of range");let{mmsIndex:p,records:S}=ka(u),g=new bt;for(let k of S)k.value.length>255&&P("extension value is too long"),g.u8(k.type),g.u8(k.value.length),g.bytes(k.value);let b=g.done();b.length>j.MAX_EXT_BYTES&&P("extension area is too long");let w=e&3|(d&3)<<2|(p&3)<<4|(n?64:0)|(b.length?128:0),M=new bt;M.u8(2),M.u8(w),M.u24(m),e===de.ANSWER&&M.bytes(t),M.bytes(c),M.u8(a.length),M.ascii(a),M.u8(o.length),M.ascii(o),M.u8(h.length);for(let k of h)M.u8((k.kind&15)<<4|k.tcptype&15),M.bytes(k.addr),M.u16(k.port);n&&M.bytes(n),b.length&&(M.u8(b.length),M.bytes(b));let F=M.done();return F.length>j.MAX_PAYLOAD_BYTES&&P("descriptor exceeds the payload limit"),F}var _t=class{constructor(e){this.buf=e,this.i=0}need(e){this.i+e>this.buf.length&&P("descriptor is truncated")}u8(){return this.need(1),this.buf[this.i++]}u16(){this.need(2);let e=this.buf[this.i]<<8|this.buf[this.i+1];return this.i+=2,e}u24(){this.need(3);let e=this.buf[this.i]<<16|this.buf[this.i+1]<<8|this.buf[this.i+2];return this.i+=3,e}u32(){this.need(4);let e=(this.buf[this.i]<<24>>>0)+(this.buf[this.i+1]<<16)+(this.buf[this.i+2]<<8)+this.buf[this.i+3];return this.i+=4,e>>>0}bytes(e){return this.need(e),this.buf.slice(this.i,this.i+=e)}ascii(e){this.need(e);let t="";for(let r=0;r126)&&P("non-printable byte in a text field"),t+=String.fromCharCode(i)}return this.i+=e,t}get rest(){return this.buf.length-this.i}};function Aa(s){let e=new _t(s),t=new Map,r=-1;for(;e.rest>0;){let i=e.u8(),n=e.u8(),a=e.bytes(n);if(i<=r&&P("extension records must be in ascending type order without duplicates"),r=i,i===St.MAX_MESSAGE_SIZE){n!==4&&P("extension 0x01 must be 4 bytes");let o=new _t(a).u32();(o<1024||o>2147483647)&&P("extension 0x01 value is out of range"),Lr.includes(o)&&P("extension 0x01 duplicates a value the flags already encode"),t.set(i,o)}else P(`unknown extension type 0x${i.toString(16).padStart(2,"0")}`,"unknown_extension")}return t}function Fr(s,{nowMs:e=Date.now()}={}){s instanceof Uint8Array||P("descriptor must be a Uint8Array"),s.length===0&&P("descriptor is empty"),s.length>j.MAX_PAYLOAD_BYTES&&P("descriptor exceeds the payload limit");let t=new _t(s),r=t.u8();r!==2&&P(`unsupported descriptor version 0x${r.toString(16)}`,"version");let i=t.u8(),n=i&3;n!==de.OFFER&&n!==de.ANSWER&&P("reserved descriptor type");let a=i>>2&3;a>2&&P("reserved DTLS setup role");let o=i>>4&3,c=(i&64)!==0,d=(i&128)!==0,u=t.u24(),h=pn+u*6e4;if(e-j.CLOCK_SKEW_MS>h){let A=Math.round((e-h)/6e4);P(`this code expired ${A} minute(s) ago. If it was just created, this device's clock or time zone is probably wrong \u2014 check the date and time settings.`,"expired")}h-e>j.MAX_LIFETIME_MINUTES*6e4+j.CLOCK_SKEW_MS&&P("descriptor lifetime is implausibly long","lifetime");let m=n===de.ANSWER?t.bytes(j.BINDING_BYTES):null,p=t.bytes(j.FINGERPRINT_BYTES),S=t.u8();(Sj.MAX_UFRAG)&&P("ice-ufrag length out of range");let g=t.ascii(S);Vt.test(g)||P("ice-ufrag contains characters outside the ICE alphabet");let b=t.u8();(bj.MAX_PWD)&&P("ice-pwd length out of range");let w=t.ascii(b);Vt.test(w)||P("ice-pwd contains characters outside the ICE alphabet");let M=t.u8();M>j.MAX_CANDIDATES&&P("too many candidates");let F=[];for(let A=0;A>4&15,Y=x&15,B=mn[T];B===void 0&&P(`reserved candidate kind ${T}`),Y>=Dr.length&&P("reserved TCP candidate type");let R=t.bytes(B),ue=t.u16();ue<1&&P("candidate port must be non-zero"),F.push({kind:T,tcptype:Y,addr:R,port:ue})}let k=null;c&&(k=t.bytes(j.COMMITMENT_BYTES));let E=new Map;if(d){let A=t.u8();A===0&&P("extension area is flagged but empty"),E=Aa(t.bytes(A))}t.rest!==0&&P(`${t.rest} trailing byte(s) after the descriptor`);let _;return o===gn?(E.has(St.MAX_MESSAGE_SIZE)||P("flags promise an explicit max-message-size but no extension carries it"),_=E.get(St.MAX_MESSAGE_SIZE)):(E.has(St.MAX_MESSAGE_SIZE)&&P("extension 0x01 present but the flags do not select it"),_=Lr[o]),{version:r,type:n,setup:a,maxMessageSize:_,expiresAtMs:h,bindingTag:m,fingerprint:p,ufrag:g,pwd:w,candidates:F,commitment:k,extensions:E}}var wn=s=>s.toString(16).padStart(2,"0");function fn(s,e){switch(s){case Se.HOST_MDNS:{let t=Array.from(e,wn).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}.local`}case Se.HOST_V4:case Se.SRFLX_V4:case Se.RELAY_V4:return`${e[0]}.${e[1]}.${e[2]}.${e[3]}`;default:{let t=[];for(let r=0;r<16;r+=2)t.push((e[r]<<8|e[r+1]).toString(16));return t.join(":")}}}function Kr(s,{sessionId:e="1"}={}){let t=s.type===de.OFFER,r={relay:0,srflx:1,host:2},i=s.candidates.filter(h=>h.kind!==Se.HOST_MDNS&&h.tcptype===0).sort((h,m)=>r[at[h.kind]]-r[at[m.kind]])[0],n=i&&Ir[i.kind]==="v6",a=i?i.port:9,o=i?`c=IN IP${n?"6":"4"} ${fn(i.kind,i.addr)}`:"c=IN IP4 0.0.0.0",c=["v=0",`o=- ${e} 2 IN IP4 127.0.0.1`,"s=-","t=0 0","a=group:BUNDLE 0","a=msid-semantic: WMS",`m=application ${a} UDP/DTLS/SCTP webrtc-datachannel`,o,"a=ice-ufrag:"+s.ufrag,"a=ice-pwd:"+s.pwd,"a=fingerprint:sha-256 "+Array.from(s.fingerprint,h=>wn(h).toUpperCase()).join(":"),"a=setup:"+yn[s.setup],"a=mid:0","a=sctp-port:5000","a=max-message-size:"+s.maxMessageSize],d=s.candidates.map((h,m)=>{let p=at[h.kind],S=h.tcptype===0?"udp":"tcp",g=Math.max(0,65535-m),b=ba[p]*16777216+g*256+255,M=`a=candidate:${String(h.kind*4+h.tcptype+1)} 1 ${S} ${b} ${fn(h.kind,h.addr)} ${h.port} typ ${p}`;return p!=="host"&&(M+=Ir[h.kind]==="v6"?" raddr :: rport 0":" raddr 0.0.0.0 rport 0"),S==="tcp"&&(M+=` tcptype ${Dr[h.tcptype]}`),M});d.push("a=end-of-candidates");let u=c.indexOf(o)+1;return c.splice(u,0,...d),{type:t?"offer":"answer",sdp:c.join(`\r +`}function Wi(s){let e=ta(s),t=s.split(/\r\n|\n/),r=[],i=[],n=null;for(let a of t)a.startsWith("m=")?(n={lines:[a]},i.push(n)):n?n.lines.push(a):r.push(a);return{eol:e,session:r,media:i}}function Yi(s){let e=[...s.session];for(let t of s.media)e.push(...t.lines);return e.join(s.eol)}function Xi(s){let e=s.lines[0].match(/^m=(\w+)/);return e?e[1]:null}function ra(s,e){let t=new RegExp("^a=rtpmap:(\\d+)\\s+"+e+"\\/","i"),r=[];for(let i of s.lines){let n=i.match(t);n&&r.push(n[1])}return r}function ia(s){let e=new Map;for(let t of s.split(";")){let r=t.trim();if(!r)continue;let i=r.indexOf("=");i===-1?e.set(r,void 0):e.set(r.slice(0,i).trim(),r.slice(i+1).trim())}return e}function ji(s){let e=[];for(let[t,r]of s)e.push(r===void 0?t:`${t}=${r}`);return e.join(";")}function na(s,e,t){let r=s.lines.findIndex(o=>o.startsWith(`a=fmtp:${e} `)||o===`a=fmtp:${e}`);if(r!==-1){let o=s.lines[r].slice(`a=fmtp:${e} `.length),c=ia(o);for(let[d,h]of Object.entries(t))c.set(d,String(h));s.lines[r]=`a=fmtp:${e} ${ji(c)}`;return}let i=new Map;for(let[o,c]of Object.entries(t))i.set(o,String(c));let n=`a=fmtp:${e} ${ji(i)}`,a=s.lines.findIndex(o=>o.startsWith(`a=rtpmap:${e} `));a!==-1?s.lines.splice(a+1,0,n):s.lines.push(n)}function Cr(s,e){if(!s||typeof s!="string")return s;let t=Wi(s),r=!1;for(let i of t.media)if(Xi(i)==="audio")for(let n of ra(i,"opus"))na(i,n,e),r=!0;return r?Yi(t):s}var sa=/^(rtx|red|ulpfec|flexfec-03|telephone-event|CN)$/i;function aa(s){let e=[];for(let t of s.lines){let r=t.match(/^a=rtpmap:(\d+)\s+([^/]+)\//);r&&!sa.test(r[2])&&e.push(r[1])}return e}function oa(s,e){for(let t of aa(s))for(let r of e){let i=`a=rtcp-fb:${t} ${r}`;if(s.lines.includes(i))continue;let n=-1;for(let a=0;ai.startsWith("a=extmap:")&&i.includes(e)))return;let t=0,r=-1;for(let i=0;ii.startsWith("a=mid:")),r===-1&&(r=s.lines.length-1)),s.lines.splice(r+1,0,`a=extmap:${t+1} ${e}`)}function Qi(s,e){if(!s||typeof s!="string"||!e)return s;let t=Wi(s),r=!1;for(let i of t.media){let n=Xi(i),a=n==="video"?e.video:n==="audio"?e.audio:null;a&&(Array.isArray(a.rtcpFb)&&(oa(i,a.rtcpFb),r=!0),a.twcc&&e.twccUri&&(ca(i,e.twccUri),r=!0))}return r?Yi(t):s}function Ji(s){try{if(Ue||!s||typeof s.setCodecPreferences!="function"||!st.preferRed)return!1;let e=typeof RTCRtpSender<"u"&&RTCRtpSender.getCapabilities?RTCRtpSender.getCapabilities("audio"):null;if(!e||!Array.isArray(e.codecs))return!1;let t=o=>/red$/i.test(o.mimeType),r=o=>/opus$/i.test(o.mimeType);if(!e.codecs.some(t))return!1;let i=e.codecs.filter(t),n=e.codecs.filter(r),a=e.codecs.filter(o=>!t(o)&&!r(o));return s.setCodecPreferences([...i,...n,...a]),!0}catch{return!1}}async function Zi(s,e={}){try{if(Ue||!s||typeof s.getParameters!="function")return!1;let t={...st.sender,...e},r=s.getParameters();(!r.encodings||r.encodings.length===0)&&(r.encodings=[{}]);for(let i of r.encodings)i.maxBitrate=t.maxBitrate,i.priority=t.priority,i.networkPriority=t.networkPriority;return await s.setParameters(r),!0}catch{return!1}}var en={VP9:0,AV1:1,H264:2,VP8:3};function tn(s){return(String(s||"").split("/")[1]||"").toUpperCase()}function la(s){let e=t=>{let r=tn(t.mimeType);return Object.prototype.hasOwnProperty.call(en,r)?en[r]:99};return s.map((t,r)=>({c:t,i:r})).sort((t,r)=>e(t.c)-e(r.c)||t.i-r.i).map(t=>t.c)}function rn(s){if(!s||!Array.isArray(s.codecs))return null;let e=new Set(s.codecs.map(t=>tn(t.mimeType)));for(let t of Re.codecPreferenceOrder)if(e.has(t))return t;return null}function nn(){return typeof RTCRtpSender<"u"&&RTCRtpSender.getCapabilities?RTCRtpSender.getCapabilities("video"):null}function sn(s){try{if(Ue||!s||typeof s.setCodecPreferences!="function")return!1;let e=nn();return!e||!Array.isArray(e.codecs)?!1:(s.setCodecPreferences(la(e.codecs)),rn(e))}catch{return!1}}function da(s){return s==="VP9"?{scalabilityMode:Re.vp9.preferredScalabilityMode,maxBitrate:15e5,degradationPreference:Re.vp9.degradationPreference}:s==="AV1"?{scalabilityMode:Re.av1.scalabilityMode,maxBitrate:Re.av1.maxBitrate,degradationPreference:Re.av1.degradationPreference}:{scalabilityMode:void 0,maxBitrate:15e5,degradationPreference:"balanced"}}async function an(s,e={}){try{if(Ue||!s||typeof s.getParameters!="function")return!1;let t=rn(nn())||"VP8",r={...da(t),...e},i=s.getParameters();(!i.encodings||i.encodings.length===0)&&(i.encodings=[{}]);let n=i.encodings.length>1;if(n)for(let a of i.encodings)a.networkPriority=Re.networkPriority;else{let a=i.encodings[0];a.maxBitrate=r.maxBitrate,a.networkPriority=Re.networkPriority,r.scalabilityMode&&(a.scalabilityMode=r.scalabilityMode)}r.degradationPreference&&(i.degradationPreference=r.degradationPreference);try{return await s.setParameters(i),!0}catch{if(!n&&r.scalabilityMode){delete i.encodings[0].scalabilityMode;try{return await s.setParameters(i),!0}catch{return!1}}return!1}}catch{return!1}}function on(s,e={}){let t=null,r=null,i=null;for(let S of s)!S||typeof S.type!="string"||(S.type==="outbound-rtp"&&!S.isRemote?(!t||S.kind==="video")&&(t=S):S.type==="remote-inbound-rtp"?(!r||S.kind==="video")&&(r=S):S.type==="candidate-pair"&&(S.nominated||S.selected||S.state==="succeeded")&&(!i||S.nominated)&&(i=S));let n=Number(t?.packetsSent??0),a=Number(r?.packetsLost??0),o=n-(e.packetsSent??n),c=a-(e.packetsLost??a),d=o+c,h=d>0?Math.min(1,Math.max(0,c/d)):0,u=i?.currentRoundTripTime??r?.roundTripTime??0,m=Number(u)*1e3,y=Number(r?.jitter??0)*1e3,b=i?.availableOutgoingBitrate!=null?Number(i.availableOutgoingBitrate):null,p=t?.qualityLimitationReason??"none";return{lossPct:h,rttMs:m,jitterMs:y,availableOutgoingBitrate:b,qualityLimitationReason:p,counters:{packetsSent:n,packetsLost:a},hasData:!!(t&&(r||i))}}function cn(s){if(!s||!s.hasData)return null;let e=s.lossPct,t=s.rttMs;return e<.03&&t<150?"excellent":e<.07&&t<250?"good":e<.15&&t<400?"fair":"poor"}function ua(s,e,t=Tr){let{targetBitrate:r,ceilingBitrate:i,scaleResolutionDownBy:n,goodTicks:a}=e,o=!1,c="steady";if(s.qualityLimitationReason==="cpu"){let d=Math.min(4,+(n*t.cpuScaleStep).toFixed(3));d!==n&&(n=d,o=!0),a=0,c="cpu"}else if(s.lossPct>t.loss.highPct||s.rttMs>t.rtt.highMs){let d=Math.max(t.minVideoBitrate,Math.round(r*(1-t.stepDownPct)));d!==r&&(r=d,o=!0),a=0,c="backoff"}else if(s.lossPct=t.recoverStableTicks){let d=Math.min(i,Math.round(r*(1+t.stepUpPct)));d!==r&&(r=d,o=!0,c="rampup"),a=0}}else a=0;return{targetBitrate:r,scaleResolutionDownBy:n,goodTicks:a,changed:o,reason:c}}var Nt=class{constructor(e,t={}){this.pc=e,this.getVideoSender=t.getVideoSender||(()=>null),this.onQuality=t.onQuality||(()=>{}),this.cfg=t.cfg||Tr,this._timer=null,this._prevCounters={},this._lastQuality=void 0,this.state={targetBitrate:t.ceilingBitrate||15e5,ceilingBitrate:t.ceilingBitrate||15e5,scaleResolutionDownBy:1,goodTicks:0}}start(){this._timer||(this._timer=setInterval(()=>{this._tick().catch(()=>{})},this.cfg.intervalMs))}stop(){this._timer&&(clearInterval(this._timer),this._timer=null)}async _tick(){if(!this.pc||typeof this.pc.getStats!="function")return;let e=await this.pc.getStats(),t=typeof e.values=="function"?Array.from(e.values()):e,r=on(t,this._prevCounters);this._prevCounters=r.counters;let i=cn(r);if(i&&i!==this._lastQuality){this._lastQuality=i;try{this.onQuality(i,r)}catch{}}if(!r.hasData)return;let n=ua(r,this.state,this.cfg);this.state={targetBitrate:n.targetBitrate,ceilingBitrate:this.state.ceilingBitrate,scaleResolutionDownBy:n.scaleResolutionDownBy,goodTicks:n.goodTicks},n.changed&&await this._applyToVideoSender()}async _applyToVideoSender(){if(Ue)return;let e=this.getVideoSender();if(!(!e||typeof e.getParameters!="function"))try{let t=e.getParameters();if((!t.encodings||t.encodings.length===0)&&(t.encodings=[{}]),t.encodings.length===1)t.encodings[0].maxBitrate=this.state.targetBitrate,t.encodings[0].scaleResolutionDownBy=this.state.scaleResolutionDownBy;else{let r=t.encodings[t.encodings.length-1];r.maxBitrate=this.state.targetBitrate}await e.setParameters(t)}catch{}}};var ha="SecureBit-DR-Root-v1",fa="SecureBit-DR-Message-v1",pa="SecureBit-DR-Init-v1",ya=Uint8Array.of(1),ga=Uint8Array.of(2),Ut=new TextEncoder,ma=new TextDecoder,Ot=Object.freeze({MAX_SKIP_PER_CHAIN:512,MAX_SKIPPED_KEYS:1024,SKIPPED_KEY_TTL_MS:300*1e3});function ln(s){let e="",t=new Uint8Array(s);for(let r=0;r{o&&o.apply(),this._receivingChainKey&&this._receivingChainKey!==y&&q(this._receivingChainKey);for(let b of a)q(b);this._receivingChainKey=y,this._receiveCount=r+1,this._remotePublicKeyB64=h;for(let{id:b,key:p}of n)this._rememberSkipped(b,p);q(m)},discard:()=>{o&&o.discard();for(let{key:b}of n)q(b);for(let b of a)q(b);q(y),q(m)}}}async _collectSkipped(e,t,r,i){if(rOt.MAX_SKIP_PER_CHAIN)throw new Error(`DoubleRatchet: refusing to skip ${r-t} messages (limit ${Ot.MAX_SKIP_PER_CHAIN})`);let n=[],a=e;for(let o=t;o=Ot.MAX_SKIPPED_KEYS;){let r=this._skipped.keys().next().value,i=this._skipped.get(r);this._skipped.delete(r),i&&q(i.key)}this._skipped.set(e,{key:t,storedAt:Date.now()})}_pruneSkipped(){let e=Date.now()-Ot.SKIPPED_KEY_TTL_MS;for(let[t,r]of this._skipped)r.storedAt{q(this._rootKey),q(i.nextRoot),this._sendingChainKey&&q(this._sendingChainKey),this._rootKey=o.nextRoot,this._sendingChainKey=o.chainKey,this._selfKeyPair=n,this._remotePublicKey=t,this._remotePublicKeyB64=e,this._previousSendCount=this._sendCount,this._sendCount=0},discard:()=>{q(i.nextRoot),q(i.chainKey),q(o.nextRoot),q(o.chainKey)}}}destroy(){q(this._rootKey),q(this._sendingChainKey),q(this._receivingChainKey);for(let e of this._skipped.values())q(e.key);this._skipped.clear(),this._rootKey=null,this._sendingChainKey=null,this._receivingChainKey=null,this._selfKeyPair=null,this._remotePublicKey=null,this._remotePublicKeyB64=null,this._initialised=!1}};var j=Object.freeze({MAX_PAYLOAD_BYTES:512,MAX_CANDIDATES:8,MIN_UFRAG:4,MAX_UFRAG:64,MIN_PWD:22,MAX_PWD:64,FINGERPRINT_BYTES:32,COMMITMENT_BYTES:16,BINDING_BYTES:8,MAX_LIFETIME_MINUTES:60,MAX_EXT_BYTES:255,SURPLUS_CANDIDATE_BYTES:48,CLOCK_SKEW_MS:12e4}),pn=Date.UTC(2024,0,1),Sa=16777215,de=Object.freeze({OFFER:0,ANSWER:1}),yn=Object.freeze(["actpass","active","passive"]),Lr=Object.freeze([262144,1073741823,65536,null]),gn=3,St=Object.freeze({MAX_MESSAGE_SIZE:1}),Se=Object.freeze({HOST_V4:0,HOST_MDNS:1,SRFLX_V4:2,RELAY_V4:3,HOST_V6:4,SRFLX_V6:5,RELAY_V6:6}),mn=Object.freeze({0:4,1:16,2:4,3:4,4:16,5:16,6:16}),at=Object.freeze({0:"host",1:"host",2:"srflx",3:"relay",4:"host",5:"srflx",6:"relay"}),Ir=Object.freeze({0:"v4",1:"mdns",2:"v4",3:"v4",4:"v6",5:"v6",6:"v6"}),Dr=Object.freeze([null,"passive","active","so"]),ba=Object.freeze({host:126,srflx:100,relay:0}),Vt=/^[A-Za-z0-9+/]+$/,Rr=class extends Error{constructor(e,t="malformed"){super(e),this.name="DescriptorError",this.code=t}},P=(s,e)=>{throw new Rr(s,e)},_a=/^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\.local$/i,wa=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;function Sn(s){let e=wa.exec(s);if(!e)return null;let t=new Uint8Array(4);for(let r=0;r<4;r++){let i=Number(e[r+1]);if(!Number.isInteger(i)||i<0||i>255)return null;t[r]=i}return t}function Ea(s){if(!/^[0-9a-fA-F:.]+$/.test(s)||s.length>45)return null;let e=s,t=null,r=e.lastIndexOf(":");if(e.includes(".")){if(t=Sn(e.slice(r+1)),!t)return null;e=e.slice(0,r+1)+"0:0"}let i=e.split("::");if(i.length>2)return null;let n=h=>h===""?[]:h.split(":").map(u=>u.length===0||u.length>4?NaN:parseInt(u,16)),a=n(i[0]),o=i.length===2?n(i[1]):[];if([...a,...o].some(h=>!Number.isInteger(h)||h<0||h>65535))return null;let c;if(i.length===2){let h=8-a.length-o.length;if(h<1)return null;c=[...a,...new Array(h).fill(0),...o]}else c=a;if(c.length!==8)return null;let d=new Uint8Array(16);return c.forEach((h,u)=>{d[u*2]=h>>8,d[u*2+1]=h&255}),t&&d.set(t,12),d}function va(s){let e=_a.exec(s);if(!e)return null;let t=(e[1]+e[2]+e[3]+e[4]+e[5]).toLowerCase(),r=new Uint8Array(16);for(let i=0;i<16;i++)r[i]=parseInt(t.substr(i*2,2),16);return r}function Ta(s){return typeof s!="string"&&P("SDP must be a string"),s.length>64*1024&&P("SDP is too large"),s.split(/\r\n|\n/).filter(e=>e.length>0)}function gt(s,e){let t=`a=${e}:`;for(let r of s)if(r.startsWith(t))return r.slice(t.length).trim();return null}function bn(s){let e=Ta(s),t=gt(e,"ice-ufrag"),r=gt(e,"ice-pwd");(!t||!r)&&P("SDP is missing ICE credentials");let i=gt(e,"fingerprint");i||P("SDP is missing a DTLS fingerprint");let[n,a]=i.split(/\s+/);(!n||n.toLowerCase()!=="sha-256")&&P(`unsupported DTLS fingerprint algorithm: ${String(n).slice(0,16)}`);let o=String(a).split(":");o.length!==j.FINGERPRINT_BYTES&&P("DTLS fingerprint has the wrong length");let c=new Uint8Array(j.FINGERPRINT_BYTES);o.forEach((b,p)=>{/^[0-9a-fA-F]{2}$/.test(b)||P("DTLS fingerprint is not hex"),c[p]=parseInt(b,16)});let d=gt(e,"setup")||"actpass",h=yn.indexOf(d);h<0&&P(`unsupported DTLS setup role: ${d.slice(0,16)}`);let u=gt(e,"max-message-size"),m=u===null?65536:Number(u);(!Number.isInteger(m)||m<0)&&P("invalid a=max-message-size");let y=[];for(let b of e){if(!b.startsWith("a=candidate:"))continue;let p=b.slice(12).split(/\s+/);if(p.length<8||p[6]!=="typ"||p[1]!=="1")continue;let S=p[2].toLowerCase(),w=Number(p[3]),M=p[4],F=Number(p[5]),k=p[7];if(!Number.isInteger(F)||F<1||F>65535)continue;let E=0;if(S==="tcp"){let T=p.indexOf("tcptype"),Y=T>=0?Dr.indexOf(p[T+1]):-1;if(Y<=0)continue;E=Y}else if(S!=="udp")continue;let _=null,A=null,x=va(M);if(x&&k==="host")_=Se.HOST_MDNS,A=x;else{let T=Sn(M),Y=T?null:Ea(M),B=T||Y;if(!B)continue;if(k==="host")_=T?Se.HOST_V4:Se.HOST_V6;else if(k==="srflx"||k==="prflx")_=T?Se.SRFLX_V4:Se.SRFLX_V6;else if(k==="relay")_=T?Se.RELAY_V4:Se.RELAY_V6;else continue;A=B}y.push({kind:_,tcptype:E,addr:A,port:F,priority:Number.isFinite(w)?w:0})}return{ufrag:t,pwd:r,fingerprint:c,setup:h,maxMessageSize:m,candidates:y}}function hn(s){return 1+mn[s.kind]+2}var Ca=s=>s.tcptype!==2&&s.tcptype!==3;function Pr(s,{maxCandidates:e=j.MAX_CANDIDATES,maxBytes:t=j.SURPLUS_CANDIDATE_BYTES,keepMdns:r=!0,maxRelays:i=2}={}){let n=s.filter(S=>r||S.kind!==Se.HOST_MDNS),a=[],o=new Set;for(let S of n){let w=`${S.kind}:${S.tcptype}:${Array.from(S.addr).join(".")}:${S.port}`;o.has(w)||(o.add(w),a.push(S))}let c=(S,w)=>(w.priority||0)-(S.priority||0),d=S=>`${Ir[S.kind]}/${at[S.kind]}/${S.tcptype===0?"udp":"tcp"}`,h=new Map;for(let S of[...a].sort(c)){if(!Ca(S))continue;let w=d(S);h.has(w)||h.set(w,[]),h.get(w).push(S)}let u=[],m=new Set,y=0,b=0,p=S=>{u.push(S),m.add(S),y+=hn(S),at[S.kind]==="relay"&&b++};for(let S of h.values())p(S[0]);for(let S of[...a].sort(c))if(!m.has(S)){if(u.length>=e)break;y+hn(S)>t||at[S.kind]==="relay"&&b>=i||p(S)}return u.sort(c)}var bt=class{constructor(){this.b=[]}u8(e){this.b.push(e&255)}u16(e){this.b.push(e>>8&255,e&255)}u24(e){this.b.push(e>>16&255,e>>8&255,e&255)}u32(e){this.b.push(e>>>24&255,e>>>16&255,e>>>8&255,e&255)}bytes(e){for(let t of e)this.b.push(t&255)}ascii(e){for(let t=0;t2147483647)&&P("max-message-size must be an integer between 1024 and 2^31-1");let e=[],t=Lr.indexOf(s);if(t<0){t=gn;let r=new bt;r.u32(s),e.push({type:St.MAX_MESSAGE_SIZE,value:r.done()})}return{mmsIndex:t,records:e}}function _n(s){let{type:e,bindingTag:t=null,expiresAtMs:r,sdpFields:i,commitment:n=null}=s;e!==de.OFFER&&e!==de.ANSWER&&P("invalid descriptor type"),e===de.ANSWER?(!(t instanceof Uint8Array)||t.length!==j.BINDING_BYTES)&&P("answer needs an 8-byte binding tag"):t!==null&&P("offers do not carry a binding tag"),n!==null&&(!(n instanceof Uint8Array)||n.length!==j.COMMITMENT_BYTES)&&P("commitment must be 16 bytes");let{ufrag:a,pwd:o,fingerprint:c,setup:d,maxMessageSize:h,candidates:u}=i;(a.lengthj.MAX_UFRAG||!Vt.test(a))&&P("invalid ice-ufrag"),(o.lengthj.MAX_PWD||!Vt.test(o))&&P("invalid ice-pwd"),u.length>j.MAX_CANDIDATES&&P("too many candidates");let m=Math.ceil((r-pn)/6e4);(!Number.isInteger(m)||m<0||m>Sa)&&P("expiry out of range");let{mmsIndex:y,records:b}=ka(h),p=new bt;for(let k of b)k.value.length>255&&P("extension value is too long"),p.u8(k.type),p.u8(k.value.length),p.bytes(k.value);let S=p.done();S.length>j.MAX_EXT_BYTES&&P("extension area is too long");let w=e&3|(d&3)<<2|(y&3)<<4|(n?64:0)|(S.length?128:0),M=new bt;M.u8(2),M.u8(w),M.u24(m),e===de.ANSWER&&M.bytes(t),M.bytes(c),M.u8(a.length),M.ascii(a),M.u8(o.length),M.ascii(o),M.u8(u.length);for(let k of u)M.u8((k.kind&15)<<4|k.tcptype&15),M.bytes(k.addr),M.u16(k.port);n&&M.bytes(n),S.length&&(M.u8(S.length),M.bytes(S));let F=M.done();return F.length>j.MAX_PAYLOAD_BYTES&&P("descriptor exceeds the payload limit"),F}var _t=class{constructor(e){this.buf=e,this.i=0}need(e){this.i+e>this.buf.length&&P("descriptor is truncated")}u8(){return this.need(1),this.buf[this.i++]}u16(){this.need(2);let e=this.buf[this.i]<<8|this.buf[this.i+1];return this.i+=2,e}u24(){this.need(3);let e=this.buf[this.i]<<16|this.buf[this.i+1]<<8|this.buf[this.i+2];return this.i+=3,e}u32(){this.need(4);let e=(this.buf[this.i]<<24>>>0)+(this.buf[this.i+1]<<16)+(this.buf[this.i+2]<<8)+this.buf[this.i+3];return this.i+=4,e>>>0}bytes(e){return this.need(e),this.buf.slice(this.i,this.i+=e)}ascii(e){this.need(e);let t="";for(let r=0;r126)&&P("non-printable byte in a text field"),t+=String.fromCharCode(i)}return this.i+=e,t}get rest(){return this.buf.length-this.i}};function Aa(s){let e=new _t(s),t=new Map,r=-1;for(;e.rest>0;){let i=e.u8(),n=e.u8(),a=e.bytes(n);if(i<=r&&P("extension records must be in ascending type order without duplicates"),r=i,i===St.MAX_MESSAGE_SIZE){n!==4&&P("extension 0x01 must be 4 bytes");let o=new _t(a).u32();(o<1024||o>2147483647)&&P("extension 0x01 value is out of range"),Lr.includes(o)&&P("extension 0x01 duplicates a value the flags already encode"),t.set(i,o)}else P(`unknown extension type 0x${i.toString(16).padStart(2,"0")}`,"unknown_extension")}return t}function Fr(s,{nowMs:e=Date.now()}={}){s instanceof Uint8Array||P("descriptor must be a Uint8Array"),s.length===0&&P("descriptor is empty"),s.length>j.MAX_PAYLOAD_BYTES&&P("descriptor exceeds the payload limit");let t=new _t(s),r=t.u8();r!==2&&P(`unsupported descriptor version 0x${r.toString(16)}`,"version");let i=t.u8(),n=i&3;n!==de.OFFER&&n!==de.ANSWER&&P("reserved descriptor type");let a=i>>2&3;a>2&&P("reserved DTLS setup role");let o=i>>4&3,c=(i&64)!==0,d=(i&128)!==0,h=t.u24(),u=pn+h*6e4;if(e-j.CLOCK_SKEW_MS>u){let A=Math.round((e-u)/6e4);P(`this code expired ${A} minute(s) ago. If it was just created, this device's clock or time zone is probably wrong \u2014 check the date and time settings.`,"expired")}u-e>j.MAX_LIFETIME_MINUTES*6e4+j.CLOCK_SKEW_MS&&P("descriptor lifetime is implausibly long","lifetime");let m=n===de.ANSWER?t.bytes(j.BINDING_BYTES):null,y=t.bytes(j.FINGERPRINT_BYTES),b=t.u8();(bj.MAX_UFRAG)&&P("ice-ufrag length out of range");let p=t.ascii(b);Vt.test(p)||P("ice-ufrag contains characters outside the ICE alphabet");let S=t.u8();(Sj.MAX_PWD)&&P("ice-pwd length out of range");let w=t.ascii(S);Vt.test(w)||P("ice-pwd contains characters outside the ICE alphabet");let M=t.u8();M>j.MAX_CANDIDATES&&P("too many candidates");let F=[];for(let A=0;A>4&15,Y=x&15,B=mn[T];B===void 0&&P(`reserved candidate kind ${T}`),Y>=Dr.length&&P("reserved TCP candidate type");let R=t.bytes(B),ue=t.u16();ue<1&&P("candidate port must be non-zero"),F.push({kind:T,tcptype:Y,addr:R,port:ue})}let k=null;c&&(k=t.bytes(j.COMMITMENT_BYTES));let E=new Map;if(d){let A=t.u8();A===0&&P("extension area is flagged but empty"),E=Aa(t.bytes(A))}t.rest!==0&&P(`${t.rest} trailing byte(s) after the descriptor`);let _;return o===gn?(E.has(St.MAX_MESSAGE_SIZE)||P("flags promise an explicit max-message-size but no extension carries it"),_=E.get(St.MAX_MESSAGE_SIZE)):(E.has(St.MAX_MESSAGE_SIZE)&&P("extension 0x01 present but the flags do not select it"),_=Lr[o]),{version:r,type:n,setup:a,maxMessageSize:_,expiresAtMs:u,bindingTag:m,fingerprint:y,ufrag:p,pwd:w,candidates:F,commitment:k,extensions:E}}var wn=s=>s.toString(16).padStart(2,"0");function fn(s,e){switch(s){case Se.HOST_MDNS:{let t=Array.from(e,wn).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}.local`}case Se.HOST_V4:case Se.SRFLX_V4:case Se.RELAY_V4:return`${e[0]}.${e[1]}.${e[2]}.${e[3]}`;default:{let t=[];for(let r=0;r<16;r+=2)t.push((e[r]<<8|e[r+1]).toString(16));return t.join(":")}}}function Kr(s,{sessionId:e="1"}={}){let t=s.type===de.OFFER,r={relay:0,srflx:1,host:2},i=s.candidates.filter(u=>u.kind!==Se.HOST_MDNS&&u.tcptype===0).sort((u,m)=>r[at[u.kind]]-r[at[m.kind]])[0],n=i&&Ir[i.kind]==="v6",a=i?i.port:9,o=i?`c=IN IP${n?"6":"4"} ${fn(i.kind,i.addr)}`:"c=IN IP4 0.0.0.0",c=["v=0",`o=- ${e} 2 IN IP4 127.0.0.1`,"s=-","t=0 0","a=group:BUNDLE 0","a=msid-semantic: WMS",`m=application ${a} UDP/DTLS/SCTP webrtc-datachannel`,o,"a=ice-ufrag:"+s.ufrag,"a=ice-pwd:"+s.pwd,"a=fingerprint:sha-256 "+Array.from(s.fingerprint,u=>wn(u).toUpperCase()).join(":"),"a=setup:"+yn[s.setup],"a=mid:0","a=sctp-port:5000","a=max-message-size:"+s.maxMessageSize],d=s.candidates.map((u,m)=>{let y=at[u.kind],b=u.tcptype===0?"udp":"tcp",p=Math.max(0,65535-m),S=ba[y]*16777216+p*256+255,M=`a=candidate:${String(u.kind*4+u.tcptype+1)} 1 ${b} ${S} ${fn(u.kind,u.addr)} ${u.port} typ ${y}`;return y!=="host"&&(M+=Ir[u.kind]==="v6"?" raddr :: rport 0":" raddr 0.0.0.0 rport 0"),b==="tcp"&&(M+=` tcptype ${Dr[u.tcptype]}`),M});d.push("a=end-of-candidates");let h=c.indexOf(o)+1;return c.splice(h,0,...d),{type:t?"offer":"answer",sdp:c.join(`\r `)+`\r -`}}var Nr=new TextEncoder;function Bt(...s){let e=s.reduce((i,n)=>i+n.length,0),t=new Uint8Array(e),r=0;for(let i of s)t.set(i,r),r+=i.length;return t}async function Or(s,e){return(await s(Bt(Nr.encode("sbq2/bind\0"),e))).slice(0,j.BINDING_BYTES)}async function Ht(s,e){return(await s(Bt(Nr.encode("sbq2/blob\0"),e))).slice(0,j.COMMITMENT_BYTES)}function En(s,e,t,r){let i=n=>{let a=new Uint8Array(4);return new DataView(a.buffer).setUint32(0,n.length),Bt(a,n)};return Bt(Nr.encode("sbq2/sas/v1\0"),i(s),i(e),i(t),i(r))}var mt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function xa(s){let e="";for(let t=0;t>2],e+=mt[(r&3)<<4|(i??0)>>4],i===void 0||(e+=mt[(i&15)<<2|(n??0)>>6],n===void 0))break;e+=mt[n&63]}return e}function Ia(s){typeof s!="string"&&P("payload must be a string");let e=s.replace(/\s+/g,"");e.length>Math.ceil(j.MAX_PAYLOAD_BYTES*4/3)+4&&P("payload is too long"),/^[A-Za-z0-9_-]*$/.test(e)||P("payload contains characters outside base64url"),e.length%4===1&&P("payload has an impossible length");let t=new Uint8Array(Math.floor(e.length*3/4)),r=0,i=0,n=0;for(let a of e)i=i<<6|mt.indexOf(a),n+=6,n>=8&&(n-=8,t[r++]=i>>n&255);return i&(1<{throw new zr(s,e)};function Cn({role:s,ecdhSpki:e,ecdsaSpki:t}){s!==ve.OFFER&&s!==ve.ANSWER&&he("invalid role");for(let[a,o]of[["ecdh",e],["ecdsa",t]])o instanceof Uint8Array||he(`${a} SPKI must be a Uint8Array`),(o.lengthWe.MAX_SPKI)&&he(`${a} SPKI length out of range`);let r=new Uint8Array(4+e.length+2+t.length),i=new DataView(r.buffer),n=0;return r[n++]=Tn,r[n++]=s,i.setUint16(n,e.length),n+=2,r.set(e,n),n+=e.length,i.setUint16(n,t.length),n+=2,r.set(t,n),r}function kn(s){s instanceof Uint8Array||he("key blob must be a Uint8Array"),s.length===0&&he("key blob is empty"),s.length>We.MAX_BLOB_BYTES&&he("key blob exceeds the size limit");let e=new DataView(s.buffer,s.byteOffset,s.byteLength),t=0,r=u=>{t+u>s.length&&he("key blob is truncated")};r(1);let i=s[t++];i!==Tn&&he(`unsupported key blob version 0x${i.toString(16)}`,"version"),r(1);let n=s[t++];n!==ve.OFFER&&n!==ve.ANSWER&&he("reserved key blob role"),r(2);let a=e.getUint16(t);t+=2,(aWe.MAX_SPKI)&&he("ECDH SPKI length out of range"),r(a);let o=s.slice(t,t+a);t+=a,r(2);let c=e.getUint16(t);t+=2,(cWe.MAX_SPKI)&&he("ECDSA SPKI length out of range"),r(c);let d=s.slice(t,t+c);return t+=c,t!==s.length&&he(`${s.length-t} trailing byte(s) after the key blob`),{version:i,role:n,ecdhSpki:o,ecdsaSpki:d}}function An({offerDescriptor:s,answerDescriptor:e,offerBlob:t,answerBlob:r}){for(let[i,n]of Object.entries({offerDescriptor:s,answerDescriptor:e,offerBlob:t,answerBlob:r}))(!(n instanceof Uint8Array)||n.length===0)&&he(`transcript component ${i} is missing`);return En(s,e,t,r)}async function xn(s,e){let t=await s.digest("SHA-512",e);return Array.from(new Uint8Array(t))}var In=new TextEncoder;function Vr(s){let e=In.encode("sbq2/proof/v1\0"),t=new Uint8Array(e.length+s.length);return t.set(e,0),t.set(s,e.length),t}async function Rn(s,{ecdhPrivateKey:e,peerEcdhPublicKey:t,transcript:r,digits:i=7}){let n=await s.deriveBits({name:"ECDH",public:t},e,256),a=null;try{a=await s.importKey("raw",n,"HKDF",!1,["deriveBits"]);let o=new Uint8Array(await s.digest("SHA-256",r)),c=await s.deriveBits({name:"HKDF",hash:"SHA-256",salt:o,info:In.encode("sbq2-sas-v1")},a,64),d=new DataView(c),u=(d.getUint32(0)^d.getUint32(4))>>>0,h=10**i;return String(u%h).padStart(i,"0")}finally{try{new Uint8Array(n).fill(0)}catch{}}}async function Mn(s,e,t){(!(t instanceof Uint8Array)||t.length!==j.COMMITMENT_BYTES)&&he("descriptor carried no usable commitment","commitment_missing");let i=await Ht(async a=>new Uint8Array(await s.digest("SHA-256",a)),e);i.length!==t.length&&he("commitment length mismatch","commitment_mismatch");let n=0;for(let a=0;a({...c}))}},this._emitGlobalEvents=o.emitGlobalEvents!==!1,this._ipLeakWarningShown=!1,this._initializeSecureLogging(),this._setupOwnLogger(),this._setupProductionLogging(),this._storeImportantMethods(),this._setupSecureGlobalAPI(),!window.EnhancedSecureCryptoUtils)throw new Error("EnhancedSecureCryptoUtils is not loaded. Please ensure the module is loaded first.");this.getSecurityData=()=>this.lastSecurityCalculation?{level:this.lastSecurityCalculation.level,score:this.lastSecurityCalculation.score,timestamp:this.lastSecurityCalculation.timestamp}:null,this._secureLog("info","\u{1F512} Enhanced WebRTC Manager initialized with secure API"),this.sessionConstraints=null,this.peerConnection=null,this.dataChannel=null,this.onMessage=e,this.onStatusChange=t,this.onKeyExchange=r,this.onVerificationStateChange=a,this.onVerificationRequired=i,this.onAnswerError=n,this.isInitiator=!1,this.connectionAttempts=0,this.maxConnectionAttempts=s.LIMITS.MAX_CONNECTION_ATTEMPTS;try{this._initializeMutexSystem()}catch(c){throw this._secureLog("error","\u274C Failed to initialize mutex system",{errorType:c.constructor.name}),new Error("Critical: Mutex system initialization failed")}if(!this._validateMutexSystem())throw this._secureLog("error","\u274C Mutex system validation failed after initialization"),new Error("Critical: Mutex system validation failed");if(typeof window<"u"&&this._secureLog("info","\u{1F512} Emergency mutex handlers will be available through secure API"),this._secureLog("info","\u{1F512} Enhanced Mutex system fully initialized and validated"),this.heartbeatInterval=null,this.messageQueue=[],this._reconnect={phase:"idle",attempts:0,startedAt:0,graceTimer:null,retryTimer:null,restartTimer:null,inFlightAt:0,barrenFailures:0,pendingRole:null},this._lastInboundAt=0,this._livenessProbeAt=0,this._livenessTimer=null,this._heartbeatTimer=null,this.ecdhKeyPair=null,this.ecdsaKeyPair=null,this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this.verificationCode=null,this.pendingSASCode=null,this.isVerified=!1,this.sasValidationAttempts=0,this.processedMessageIds=new Set,this.localVerificationConfirmed=!1,this.remoteVerificationConfirmed=!1,this.bothVerificationsConfirmed=!1,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.strictDTLSValidation=!0,this.ephemeralKeyPairs=new Map,this.sessionStartTime=Date.now(),this.messageCounter=0,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.sessionSalt=null,this._pendingOfferContext=null,this.replayWindowSize=64,this.replayWindow=new Set,this.maxSequenceGap=100,this.replayProtectionEnabled=!0,this.sessionId=null,this._handshakeMode=null,this._sbq2=null,this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(c=>c.toString(16).padStart(2,"0")).join(""),this.peerPublicKey=null,this._ratchet=null,this._peerSupportsRatchet=!1,this.rateLimiterId=null,this.intentionalDisconnect=!1,this._sessionAlive=!0,this._fileTransferInitRetryTimers=new Set,this._peerDisconnectCleanupTimer=null,this._logCleanupInterval=null,this.lastCleanupTime=Date.now(),this._resetNotificationFlags(),this.verificationInitiationSent=!1,this.disconnectNotificationSent=!1,this.reconnectionFailedNotificationSent=!1,this.peerDisconnectNotificationSent=!1,this.connectionClosedNotificationSent=!1,this.fakeTrafficDisabledNotificationSent=!1,this.advancedFeaturesDisabledNotificationSent=!1,this.securityUpgradeNotificationSent=!1,this.lastSecurityUpgradeStage=null,this.securityCalculationNotificationSent=!1,this.lastSecurityCalculationLevel=null,this.fileTransferSystem=null,this.onFileProgress=null,this._ivTrackingSystem={usedIVs:new Set,ivHistory:new Map,collisionCount:0,maxIVHistorySize:1e4,maxSessionIVs:1e3,entropyValidation:{minEntropy:3,entropyTests:0,entropyFailures:0},rngValidation:{testsPerformed:0,weakRngDetected:!1,lastValidation:0},sessionIVs:new Map,emergencyMode:!1},this._lastIVCleanupTime=null,this._secureErrorHandler={errorCategories:{CRYPTOGRAPHIC:"cryptographic",NETWORK:"network",VALIDATION:"validation",SYSTEM:"system",UNKNOWN:"unknown"},errorMappings:new Map,errorCounts:new Map,lastErrorTime:0,errorThreshold:10,isInErrorMode:!1},this._secureMemoryManager={sensitiveData:new WeakMap,cleanupQueue:[],isCleaning:!1,cleanupInterval:null,memoryStats:{totalCleanups:0,failedCleanups:0,lastCleanup:0}},this.onFileReceived=null,this.onFileError=null,this.onCallStateChanged=null,this.callState={active:!1,phase:"idle",withVideo:!1,micEnabled:!0,cameraEnabled:!1,remoteHasVideo:!1,callId:null,quality:null,groupCallId:null,error:null},this.localMediaStream=null,this.remoteMediaStream=null,this._pendingCallOffer=null,this._callMakingOffer=!1,this._callAudioSender=null,this._callVideoSender=null,this._callFacingMode="user",this._adaptationController=null,this._callGroupContext=null,this._externalMediaStream=null,this._callStateListeners=new Set,this.keyRotationInterval=null,this.lastKeyRotation=Date.now(),this.currentKeyVersion=0,this.keyVersions=new Map,this.oldKeys=new Map,this.maxOldKeys=s.LIMITS.MAX_OLD_KEYS,this.peerConnection=null,this.dataChannel=null,this.securityFeatures={hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0,hasNestedEncryption:!0,hasPacketPadding:!0,hasPacketReordering:!0,hasAntiFingerprinting:!0,hasFakeTraffic:!0,hasDecoyChannels:!0,hasMessageChunking:!0},this._secureLog("info","\u{1F512} Enhanced WebRTC Manager initialized with tiered security"),this._secureLog("info","\u{1F512} Configuration loaded from constructor parameters",{fakeTraffic:this._config.fakeTraffic.enabled,decoyChannels:this._config.decoyChannels.enabled,packetPadding:this._config.packetPadding.enabled,antiFingerprinting:this._config.antiFingerprinting.enabled}),this.sessionMode="ratchet",this._hardenDebugModeReferences(),this._initializeUnifiedScheduler(),this._syncSecurityFeaturesWithTariff(),!this._validateCryptographicSecurity())throw this._secureLog("error","\u{1F6A8} CRITICAL: Cryptographic security validation failed after tariff sync"),new Error("Critical cryptographic features are missing after tariff synchronization");this.nestedEncryptionKey=null,this.paddingConfig={enabled:this._config.packetPadding.enabled,minPadding:this._config.packetPadding.minPadding,maxPadding:this._config.packetPadding.maxPadding,useRandomPadding:this._config.packetPadding.useRandomPadding,preserveMessageSize:this._config.packetPadding.preserveMessageSize},this.fakeTrafficConfig={enabled:this._config.fakeTraffic?.enabled||!1,minInterval:this._config.fakeTraffic?.minInterval||15e3,maxInterval:this._config.fakeTraffic?.maxInterval||3e4,minSize:this._config.fakeTraffic?.minSize||64,maxSize:this._config.fakeTraffic?.maxSize||1024,patterns:this._config.fakeTraffic?.patterns||["heartbeat","status","ping"],randomDecoyIntervals:this._config.fakeTraffic?.randomDecoyIntervals||!0},this.fakeTrafficTimer=null,this.lastFakeTraffic=0,this.chunkingConfig={enabled:!1,maxChunkSize:s.SIZES.CHUNK_SIZE_MAX,minDelay:s.SIZES.CHUNK_DELAY_MIN,maxDelay:s.SIZES.CHUNK_DELAY_MAX,useRandomDelays:!0,addChunkHeaders:!0},this.chunkQueue=[],this.chunkingInProgress=!1,this.decoyChannels=new Map,this.decoyChannelConfig={enabled:this._config.decoyChannels.enabled,maxDecoyChannels:this._config.decoyChannels.maxDecoyChannels,decoyChannelNames:this._config.decoyChannels.decoyChannelNames,sendDecoyData:this._config.decoyChannels.sendDecoyData,randomDecoyIntervals:this._config.decoyChannels.randomDecoyIntervals},this.decoyTimers=new Map,this.reorderingConfig={enabled:!1,maxOutOfOrder:s.LIMITS.MAX_OUT_OF_ORDER_PACKETS,reorderTimeout:s.TIMEOUTS.REORDER_TIMEOUT,useSequenceNumbers:!0,useTimestamps:!0},this.packetBuffer=new Map,this.lastProcessedSequence=-1,this.antiFingerprintingConfig={enabled:this._config.antiFingerprinting.enabled,randomizeTiming:this._config.antiFingerprinting.randomizeTiming,randomizeSizes:this._config.antiFingerprinting.randomizeSizes,addNoise:this._config.antiFingerprinting.addNoise,maskPatterns:this._config.antiFingerprinting.maskPatterns,useRandomHeaders:this._config.antiFingerprinting.useRandomHeaders},this.fingerprintMask=this.generateFingerprintMask(),this.rateLimiterId=`webrtc_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,this.startPeriodicCleanup(),this.initializeEnhancedSecurity(),this._keyOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null},this._cryptoOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null},this._connectionOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null},this._keySystemState={isInitializing:!1,isRotating:!1,isDestroying:!1,lastOperation:null,lastOperationTime:Date.now()},this._operationCounters={keyOperations:0,cryptoOperations:0,connectionOperations:0}}_createMessageAAD(e,t=null,r=!1){try{let i={sessionId:this.currentSession?.sessionId||this.sessionId||"unknown",keyFingerprint:this.keyFingerprint||"unknown",sequenceNumber:this._generateNextSequenceNumber(),messageType:e,timestamp:Date.now(),connectionId:this.connectionId||"unknown",isFileMessage:r};return t&&typeof t=="object"&&(t.fileId&&(i.fileId=t.fileId),t.chunkIndex!==void 0&&(i.chunkIndex=t.chunkIndex),t.totalChunks!==void 0&&(i.totalChunks=t.totalChunks)),JSON.stringify(i)}catch(i){return this._secureLog("error","\u274C Failed to create message AAD",{errorType:i.constructor.name,message:i.message,messageType:e}),JSON.stringify({sessionId:"unknown",keyFingerprint:"unknown",sequenceNumber:Date.now(),messageType:e,timestamp:Date.now(),connectionId:"unknown",isFileMessage:r})}}_generateNextSequenceNumber(){let e=this.sequenceNumber++;return this.sequenceNumber>Number.MAX_SAFE_INTEGER-1e3&&(this.sequenceNumber=0,this.expectedSequenceNumber=0,this.replayWindow.clear(),this._secureLog("warn","\u26A0\uFE0F Sequence number reset due to overflow",{timestamp:Date.now()})),e}async _createSafeLogHash(e,t="unknown"){try{let r;if(e instanceof ArrayBuffer)r=new Uint8Array(e);else if(e instanceof Uint8Array)r=e;else if(e instanceof CryptoKey){let a=`${e.type}_${e.algorithm?.name||"unknown"}_${e.extractable}`;r=new TextEncoder().encode(a)}else if(typeof e=="string")r=new TextEncoder().encode(e);else if(typeof e=="object"&&e!==null){let a={type:e.kty||"unknown",use:e.use||"unknown"};r=new TextEncoder().encode(JSON.stringify(a))}else r=new TextEncoder().encode(String(e));let i=await crypto.subtle.digest("SHA-256",r),n=new Uint8Array(i);return Array.from(n.slice(0,4)).map(a=>a.toString(16).padStart(2,"0")).join("")}catch{return"hash_error"}}async _asyncSleep(e){return new Promise(t=>setTimeout(t,e))}async _scheduleAsyncCleanup(e,t=0){return new Promise(r=>{setTimeout(async()=>{try{await e(),r(!0)}catch(i){this._secureLog("error","Async cleanup failed",{errorType:i?.constructor?.name||"Unknown"}),r(!1)}},t)})}async _batchAsyncOperation(e,t=10,r=5){let i=[];for(let n=0;n{let i=` +`}}var Nr=new TextEncoder;function Bt(...s){let e=s.reduce((i,n)=>i+n.length,0),t=new Uint8Array(e),r=0;for(let i of s)t.set(i,r),r+=i.length;return t}async function Or(s,e){return(await s(Bt(Nr.encode("sbq2/bind\0"),e))).slice(0,j.BINDING_BYTES)}async function Ht(s,e){return(await s(Bt(Nr.encode("sbq2/blob\0"),e))).slice(0,j.COMMITMENT_BYTES)}function En(s,e,t,r){let i=n=>{let a=new Uint8Array(4);return new DataView(a.buffer).setUint32(0,n.length),Bt(a,n)};return Bt(Nr.encode("sbq2/sas/v1\0"),i(s),i(e),i(t),i(r))}var mt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function xa(s){let e="";for(let t=0;t>2],e+=mt[(r&3)<<4|(i??0)>>4],i===void 0||(e+=mt[(i&15)<<2|(n??0)>>6],n===void 0))break;e+=mt[n&63]}return e}function Ia(s){typeof s!="string"&&P("payload must be a string");let e=s.replace(/\s+/g,"");e.length>Math.ceil(j.MAX_PAYLOAD_BYTES*4/3)+4&&P("payload is too long"),/^[A-Za-z0-9_-]*$/.test(e)||P("payload contains characters outside base64url"),e.length%4===1&&P("payload has an impossible length");let t=new Uint8Array(Math.floor(e.length*3/4)),r=0,i=0,n=0;for(let a of e)i=i<<6|mt.indexOf(a),n+=6,n>=8&&(n-=8,t[r++]=i>>n&255);return i&(1<{throw new zr(s,e)};function Cn({role:s,ecdhSpki:e,ecdsaSpki:t}){s!==ve.OFFER&&s!==ve.ANSWER&&he("invalid role");for(let[a,o]of[["ecdh",e],["ecdsa",t]])o instanceof Uint8Array||he(`${a} SPKI must be a Uint8Array`),(o.lengthWe.MAX_SPKI)&&he(`${a} SPKI length out of range`);let r=new Uint8Array(4+e.length+2+t.length),i=new DataView(r.buffer),n=0;return r[n++]=Tn,r[n++]=s,i.setUint16(n,e.length),n+=2,r.set(e,n),n+=e.length,i.setUint16(n,t.length),n+=2,r.set(t,n),r}function kn(s){s instanceof Uint8Array||he("key blob must be a Uint8Array"),s.length===0&&he("key blob is empty"),s.length>We.MAX_BLOB_BYTES&&he("key blob exceeds the size limit");let e=new DataView(s.buffer,s.byteOffset,s.byteLength),t=0,r=h=>{t+h>s.length&&he("key blob is truncated")};r(1);let i=s[t++];i!==Tn&&he(`unsupported key blob version 0x${i.toString(16)}`,"version"),r(1);let n=s[t++];n!==ve.OFFER&&n!==ve.ANSWER&&he("reserved key blob role"),r(2);let a=e.getUint16(t);t+=2,(aWe.MAX_SPKI)&&he("ECDH SPKI length out of range"),r(a);let o=s.slice(t,t+a);t+=a,r(2);let c=e.getUint16(t);t+=2,(cWe.MAX_SPKI)&&he("ECDSA SPKI length out of range"),r(c);let d=s.slice(t,t+c);return t+=c,t!==s.length&&he(`${s.length-t} trailing byte(s) after the key blob`),{version:i,role:n,ecdhSpki:o,ecdsaSpki:d}}function An({offerDescriptor:s,answerDescriptor:e,offerBlob:t,answerBlob:r}){for(let[i,n]of Object.entries({offerDescriptor:s,answerDescriptor:e,offerBlob:t,answerBlob:r}))(!(n instanceof Uint8Array)||n.length===0)&&he(`transcript component ${i} is missing`);return En(s,e,t,r)}async function xn(s,e){let t=await s.digest("SHA-512",e);return Array.from(new Uint8Array(t))}var In=new TextEncoder;function Vr(s){let e=In.encode("sbq2/proof/v1\0"),t=new Uint8Array(e.length+s.length);return t.set(e,0),t.set(s,e.length),t}async function Rn(s,{ecdhPrivateKey:e,peerEcdhPublicKey:t,transcript:r,digits:i=7}){let n=await s.deriveBits({name:"ECDH",public:t},e,256),a=null;try{a=await s.importKey("raw",n,"HKDF",!1,["deriveBits"]);let o=new Uint8Array(await s.digest("SHA-256",r)),c=await s.deriveBits({name:"HKDF",hash:"SHA-256",salt:o,info:In.encode("sbq2-sas-v1")},a,64),d=new DataView(c),h=(d.getUint32(0)^d.getUint32(4))>>>0,u=10**i;return String(h%u).padStart(i,"0")}finally{try{new Uint8Array(n).fill(0)}catch{}}}async function Mn(s,e,t){(!(t instanceof Uint8Array)||t.length!==j.COMMITMENT_BYTES)&&he("descriptor carried no usable commitment","commitment_missing");let i=await Ht(async a=>new Uint8Array(await s.digest("SHA-256",a)),e);i.length!==t.length&&he("commitment length mismatch","commitment_mismatch");let n=0;for(let a=0;a({...c}))}},this._emitGlobalEvents=o.emitGlobalEvents!==!1,this._ipLeakWarningShown=!1,this._initializeSecureLogging(),this._setupOwnLogger(),this._setupProductionLogging(),this._storeImportantMethods(),this._setupSecureGlobalAPI(),!window.EnhancedSecureCryptoUtils)throw new Error("EnhancedSecureCryptoUtils is not loaded. Please ensure the module is loaded first.");this.getSecurityData=()=>this.lastSecurityCalculation?{level:this.lastSecurityCalculation.level,score:this.lastSecurityCalculation.score,timestamp:this.lastSecurityCalculation.timestamp}:null,this._secureLog("info","\u{1F512} Enhanced WebRTC Manager initialized with secure API"),this.sessionConstraints=null,this.peerConnection=null,this.dataChannel=null,this.onMessage=e,this.onStatusChange=t,this.onKeyExchange=r,this.onVerificationStateChange=a,this.onVerificationRequired=i,this.onAnswerError=n,this.isInitiator=!1,this.connectionAttempts=0,this.maxConnectionAttempts=s.LIMITS.MAX_CONNECTION_ATTEMPTS;try{this._initializeMutexSystem()}catch(c){throw this._secureLog("error","\u274C Failed to initialize mutex system",{errorType:c.constructor.name}),new Error("Critical: Mutex system initialization failed")}if(!this._validateMutexSystem())throw this._secureLog("error","\u274C Mutex system validation failed after initialization"),new Error("Critical: Mutex system validation failed");if(typeof window<"u"&&this._secureLog("info","\u{1F512} Emergency mutex handlers will be available through secure API"),this._secureLog("info","\u{1F512} Enhanced Mutex system fully initialized and validated"),this.heartbeatInterval=null,this.messageQueue=[],this._reconnect={phase:"idle",attempts:0,startedAt:0,graceTimer:null,retryTimer:null,restartTimer:null,inFlightAt:0,barrenFailures:0,pendingRole:null},this._lastInboundAt=0,this._livenessProbeAt=0,this._livenessTimer=null,this._heartbeatTimer=null,this.ecdhKeyPair=null,this.ecdsaKeyPair=null,this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this.verificationCode=null,this.pendingSASCode=null,this.isVerified=!1,this.sasValidationAttempts=0,this.processedMessageIds=new Set,this.localVerificationConfirmed=!1,this.remoteVerificationConfirmed=!1,this.bothVerificationsConfirmed=!1,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.strictDTLSValidation=!0,this.ephemeralKeyPairs=new Map,this.sessionStartTime=Date.now(),this.messageCounter=0,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.sessionSalt=null,this._pendingOfferContext=null,this.replayWindowSize=64,this.replayWindow=new Set,this.maxSequenceGap=100,this.replayProtectionEnabled=!0,this.sessionId=null,this._handshakeMode=null,this._sbq2=null,this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(c=>c.toString(16).padStart(2,"0")).join(""),this.peerPublicKey=null,this._ratchet=null,this._peerSupportsRatchet=!1,this.rateLimiterId=null,this.intentionalDisconnect=!1,this._sessionAlive=!0,this._fileTransferInitRetryTimers=new Set,this._peerDisconnectCleanupTimer=null,this._logCleanupInterval=null,this.lastCleanupTime=Date.now(),this._resetNotificationFlags(),this.verificationInitiationSent=!1,this.disconnectNotificationSent=!1,this.reconnectionFailedNotificationSent=!1,this.peerDisconnectNotificationSent=!1,this.connectionClosedNotificationSent=!1,this.fakeTrafficDisabledNotificationSent=!1,this.advancedFeaturesDisabledNotificationSent=!1,this.securityUpgradeNotificationSent=!1,this.lastSecurityUpgradeStage=null,this.securityCalculationNotificationSent=!1,this.lastSecurityCalculationLevel=null,this.fileTransferSystem=null,this.onFileProgress=null,this._ivTrackingSystem={usedIVs:new Set,ivHistory:new Map,collisionCount:0,maxIVHistorySize:1e4,maxSessionIVs:1e3,entropyValidation:{minEntropy:3,entropyTests:0,entropyFailures:0},rngValidation:{testsPerformed:0,weakRngDetected:!1,lastValidation:0},sessionIVs:new Map,emergencyMode:!1},this._lastIVCleanupTime=null,this._secureErrorHandler={errorCategories:{CRYPTOGRAPHIC:"cryptographic",NETWORK:"network",VALIDATION:"validation",SYSTEM:"system",UNKNOWN:"unknown"},errorMappings:new Map,errorCounts:new Map,lastErrorTime:0,errorThreshold:10,isInErrorMode:!1},this._secureMemoryManager={sensitiveData:new WeakMap,cleanupQueue:[],isCleaning:!1,cleanupInterval:null,memoryStats:{totalCleanups:0,failedCleanups:0,lastCleanup:0}},this.onFileReceived=null,this.onFileError=null,this.onCallStateChanged=null,this.callState={active:!1,phase:"idle",withVideo:!1,micEnabled:!0,cameraEnabled:!1,remoteHasVideo:!1,callId:null,quality:null,groupCallId:null,error:null},this.localMediaStream=null,this.remoteMediaStream=null,this._pendingCallOffer=null,this._callMakingOffer=!1,this._callAudioSender=null,this._callVideoSender=null,this._callFacingMode="user",this._adaptationController=null,this._callGroupContext=null,this._externalMediaStream=null,this._callStateListeners=new Set,this.keyRotationInterval=null,this.lastKeyRotation=Date.now(),this.currentKeyVersion=0,this.keyVersions=new Map,this.oldKeys=new Map,this.maxOldKeys=s.LIMITS.MAX_OLD_KEYS,this.peerConnection=null,this.dataChannel=null,this.securityFeatures={hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0,hasNestedEncryption:!0,hasPacketPadding:!0,hasPacketReordering:!0,hasAntiFingerprinting:!0,hasFakeTraffic:!0,hasDecoyChannels:!0,hasMessageChunking:!0},this._secureLog("info","\u{1F512} Enhanced WebRTC Manager initialized with tiered security"),this._secureLog("info","\u{1F512} Configuration loaded from constructor parameters",{fakeTraffic:this._config.fakeTraffic.enabled,decoyChannels:this._config.decoyChannels.enabled,packetPadding:this._config.packetPadding.enabled,antiFingerprinting:this._config.antiFingerprinting.enabled}),this.sessionMode="ratchet",this._hardenDebugModeReferences(),this._initializeUnifiedScheduler(),this._syncSecurityFeaturesWithTariff(),!this._validateCryptographicSecurity())throw this._secureLog("error","\u{1F6A8} CRITICAL: Cryptographic security validation failed after tariff sync"),new Error("Critical cryptographic features are missing after tariff synchronization");this.nestedEncryptionKey=null,this.paddingConfig={enabled:this._config.packetPadding.enabled,minPadding:this._config.packetPadding.minPadding,maxPadding:this._config.packetPadding.maxPadding,useRandomPadding:this._config.packetPadding.useRandomPadding,preserveMessageSize:this._config.packetPadding.preserveMessageSize},this.fakeTrafficConfig={enabled:this._config.fakeTraffic?.enabled||!1,minInterval:this._config.fakeTraffic?.minInterval||15e3,maxInterval:this._config.fakeTraffic?.maxInterval||3e4,minSize:this._config.fakeTraffic?.minSize||64,maxSize:this._config.fakeTraffic?.maxSize||1024,patterns:this._config.fakeTraffic?.patterns||["heartbeat","status","ping"],randomDecoyIntervals:this._config.fakeTraffic?.randomDecoyIntervals||!0},this.fakeTrafficTimer=null,this.lastFakeTraffic=0,this.chunkingConfig={enabled:!1,maxChunkSize:s.SIZES.CHUNK_SIZE_MAX,minDelay:s.SIZES.CHUNK_DELAY_MIN,maxDelay:s.SIZES.CHUNK_DELAY_MAX,useRandomDelays:!0,addChunkHeaders:!0},this.chunkQueue=[],this.chunkingInProgress=!1,this.decoyChannels=new Map,this.decoyChannelConfig={enabled:this._config.decoyChannels.enabled,maxDecoyChannels:this._config.decoyChannels.maxDecoyChannels,decoyChannelNames:this._config.decoyChannels.decoyChannelNames,sendDecoyData:this._config.decoyChannels.sendDecoyData,randomDecoyIntervals:this._config.decoyChannels.randomDecoyIntervals},this.decoyTimers=new Map,this.reorderingConfig={enabled:!1,maxOutOfOrder:s.LIMITS.MAX_OUT_OF_ORDER_PACKETS,reorderTimeout:s.TIMEOUTS.REORDER_TIMEOUT,useSequenceNumbers:!0,useTimestamps:!0},this.packetBuffer=new Map,this.lastProcessedSequence=-1,this.antiFingerprintingConfig={enabled:this._config.antiFingerprinting.enabled,randomizeTiming:this._config.antiFingerprinting.randomizeTiming,randomizeSizes:this._config.antiFingerprinting.randomizeSizes,addNoise:this._config.antiFingerprinting.addNoise,maskPatterns:this._config.antiFingerprinting.maskPatterns,useRandomHeaders:this._config.antiFingerprinting.useRandomHeaders},this.fingerprintMask=this.generateFingerprintMask(),this.rateLimiterId=`webrtc_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,this.startPeriodicCleanup(),this.initializeEnhancedSecurity(),this._keyOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null},this._cryptoOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null},this._connectionOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null},this._keySystemState={isInitializing:!1,isRotating:!1,isDestroying:!1,lastOperation:null,lastOperationTime:Date.now()},this._operationCounters={keyOperations:0,cryptoOperations:0,connectionOperations:0}}_createMessageAAD(e,t=null,r=!1){try{let i={sessionId:this.currentSession?.sessionId||this.sessionId||"unknown",keyFingerprint:this.keyFingerprint||"unknown",sequenceNumber:this._generateNextSequenceNumber(),messageType:e,timestamp:Date.now(),connectionId:this.connectionId||"unknown",isFileMessage:r};return t&&typeof t=="object"&&(t.fileId&&(i.fileId=t.fileId),t.chunkIndex!==void 0&&(i.chunkIndex=t.chunkIndex),t.totalChunks!==void 0&&(i.totalChunks=t.totalChunks)),JSON.stringify(i)}catch(i){return this._secureLog("error","\u274C Failed to create message AAD",{errorType:i.constructor.name,message:i.message,messageType:e}),JSON.stringify({sessionId:"unknown",keyFingerprint:"unknown",sequenceNumber:Date.now(),messageType:e,timestamp:Date.now(),connectionId:"unknown",isFileMessage:r})}}_generateNextSequenceNumber(){let e=this.sequenceNumber++;return this.sequenceNumber>Number.MAX_SAFE_INTEGER-1e3&&(this.sequenceNumber=0,this.expectedSequenceNumber=0,this.replayWindow.clear(),this._secureLog("warn","\u26A0\uFE0F Sequence number reset due to overflow",{timestamp:Date.now()})),e}async _createSafeLogHash(e,t="unknown"){try{let r;if(e instanceof ArrayBuffer)r=new Uint8Array(e);else if(e instanceof Uint8Array)r=e;else if(e instanceof CryptoKey){let a=`${e.type}_${e.algorithm?.name||"unknown"}_${e.extractable}`;r=new TextEncoder().encode(a)}else if(typeof e=="string")r=new TextEncoder().encode(e);else if(typeof e=="object"&&e!==null){let a={type:e.kty||"unknown",use:e.use||"unknown"};r=new TextEncoder().encode(JSON.stringify(a))}else r=new TextEncoder().encode(String(e));let i=await crypto.subtle.digest("SHA-256",r),n=new Uint8Array(i);return Array.from(n.slice(0,4)).map(a=>a.toString(16).padStart(2,"0")).join("")}catch{return"hash_error"}}async _asyncSleep(e){return new Promise(t=>setTimeout(t,e))}async _scheduleAsyncCleanup(e,t=0){return new Promise(r=>{setTimeout(async()=>{try{await e(),r(!0)}catch(i){this._secureLog("error","Async cleanup failed",{errorType:i?.constructor?.name||"Unknown"}),r(!1)}},t)})}async _batchAsyncOperation(e,t=10,r=5){let i=[];for(let n=0;n{let i=` self.onmessage = function(e) { const { type, data } = e.data; @@ -39,10 +39,10 @@ Please wait for real-time cryptographic verification to complete.`,"sec.verifica self.postMessage({ success: false, error: error.message }); } }; - `,n=new Blob([i],{type:"application/javascript"}),a=new Worker(URL.createObjectURL(n)),o=setTimeout(()=>{a.terminate(),r(new Error("Worker cleanup timeout"))},5e3);a.onmessage=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),c.data.success?t(c.data):r(new Error(c.data.error))},a.onerror=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),r(c)},a.postMessage(e)})}async _cleanupInMainThread(e){let{type:t,data:r}=e;switch(t){case"cleanup_arrays":let i=0,n=100;for(;ic++),await this._asyncSleep(1);return{success:!0,cleaned:c};default:return{success:!0,message:"Unknown cleanup type"}}}_initializeMutexSystem(){this._keyOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._cryptoOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._connectionOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._keySystemState={isInitializing:!1,isRotating:!1,isDestroying:!1,lastOperation:null,lastOperationTime:Date.now(),operationId:null,concurrentOperations:0,maxConcurrentOperations:1},this._operationCounters={keyOperations:0,cryptoOperations:0,connectionOperations:0,totalOperations:0,failedOperations:0},this._secureLog("info","\u{1F512} Enhanced mutex system initialized with atomic protection",{mutexes:["keyOperation","cryptoOperation","connectionOperation"],timestamp:Date.now(),features:["atomic_operations","race_condition_protection","enhanced_state_tracking"]})}_hardenDebugModeReferences(){this._secureLog("info","\u{1F512} XSS Hardening: Debug mode references already replaced")}_initializeUnifiedScheduler(){this._maintenanceScheduler=setInterval(()=>{this._executeMaintenanceCycle()},3e5),this._secureLog("info","\u{1F527} Unified maintenance scheduler initialized (5-minute cycle)"),this._activeTimers=new Set([this._maintenanceScheduler])}_trackActiveTimer(e){return e&&(this._activeTimers||(this._activeTimers=new Set),this._activeTimers.add(e),e)}_untrackActiveTimer(e){e&&this._activeTimers&&this._activeTimers.delete(e)}_setSASMaterialReady(e,t){this._sasLocalFingerprint=e,this._sasRemoteFingerprint=t}_isVerificationReady(){let e=!!(this.peerConnection?.localDescription&&this.peerConnection?.remoteDescription),t=this.dataChannel?.readyState==="open",r=typeof this.verificationCode=="string"&&this.verificationCode.trim().length>0,i=typeof this._sasLocalFingerprint=="string"&&this._sasLocalFingerprint.trim().length>0&&typeof this._sasRemoteFingerprint=="string"&&this._sasRemoteFingerprint.trim().length>0;return e&&t&&r&&i}_notifyVerificationReadyIfPossible(){return this._isVerificationReady()?(this._verificationUiOpened||(this._verificationUiOpened=!0,this.onStatusChange?.("verifying"),this.onVerificationRequired?.(this.verificationCode)),!0):!1}_countIceCandidatesInSDP(e){return typeof e!="string"?0:(e.match(/^a=candidate:/gm)||[]).length}_summarizeIceCandidatesInSDP(e){let t={total:0,host:0,srflx:0,relay:0,prflx:0,unknown:0};if(typeof e!="string")return t;for(let r of e.match(/^a=candidate:.*$/gm)||[]){t.total+=1;let n=r.match(/\btyp\s+(host|srflx|relay|prflx)\b/i)?.[1]?.toLowerCase();n&&Object.prototype.hasOwnProperty.call(t,n)?t[n]+=1:t.unknown+=1}return t}_describeIceCandidatesInSDP(e){return typeof e!="string"?[]:(e.match(/^a=candidate:.*$/gm)||[]).map(t=>{let r=t.slice(12).trim().split(/\s+/),i=r.findIndex(u=>u.toLowerCase()==="typ"),n=r[4]||"",a=r[5]||"",o=i>=0&&r[i+1]||"unknown",c=(r[2]||"unknown").toLowerCase(),d="unknown";return/\.local$/i.test(n)?d="mdns":/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(n)?d="private-ipv4":/^\d{1,3}(\.\d{1,3}){3}$/.test(n)?d="public-ipv4":n.includes(":")&&(d="ipv6"),{candidateType:o,protocol:c,addressKind:d,portPresent:!!a,tcpType:(()=>{let u=r.findIndex(h=>h.toLowerCase()==="tcptype");return u>=0&&r[u+1]||null})()}})}_logIceCandidateDiagnostics(e,t,r={}){let i=this._summarizeIceCandidatesInSDP(t),n=this._describeIceCandidatesInSDP(t);return console.info(`[SecureBit ICE] ${e}`,{candidateSummary:i,candidateDetails:n,candidateDetailsJson:JSON.stringify(n),...r}),{candidateSummary:i,candidateDetails:n}}_hasOnlyMdnsHostCandidates(e){let t=this._summarizeIceCandidatesInSDP(e),r=this._describeIceCandidatesInSDP(e);return t.total>0&&t.srflx===0&&t.relay===0&&t.prflx===0&&r.every(i=>i.candidateType==="host"&&i.addressKind==="mdns")}_warnIfRemoteCandidatesNeedRelay(e,t){if(!this._hasOnlyMdnsHostCandidates(t))return!1;let r=e==="answer"?"Connection warning: the response contains only browser-masked mDNS host candidates and no server-reflexive or TURN relay candidates. This network/browser combination may not connect until TURN is configured.":"Connection warning: the invitation contains only browser-masked mDNS host candidates and no server-reflexive or TURN relay candidates. This network/browser combination may not connect until TURN is configured.";return this._secureLog("warn","Remote ICE candidates require TURN or usable non-mDNS candidates",{context:e,candidateSummary:this._summarizeIceCandidatesInSDP(t),candidateDetails:this._describeIceCandidatesInSDP(t)}),this.deliverMessageToUI(r,"system"),!0}async _collectIceFailureDiagnostics(){if(!this.peerConnection?.getStats)return null;try{let e=await this.peerConnection.getStats(),t=new Map,r=[];return e.forEach(i=>{(i.type==="local-candidate"||i.type==="remote-candidate")&&t.set(i.id,{type:i.type,candidateType:i.candidateType,protocol:i.protocol,address:i.address||i.ip||null,port:i.port||null,networkType:i.networkType||null})}),e.forEach(i=>{i.type==="candidate-pair"&&r.push({state:i.state,nominated:!!i.nominated,writable:!!i.writable,bytesSent:i.bytesSent||0,bytesReceived:i.bytesReceived||0,currentRoundTripTime:i.currentRoundTripTime??null,local:t.get(i.localCandidateId)||null,remote:t.get(i.remoteCandidateId)||null})}),{pairCount:r.length,states:r.reduce((i,n)=>(i[n.state||"unknown"]=(i[n.state||"unknown"]||0)+1,i),{}),pairs:r}}catch(e){return{error:e?.message||"Failed to collect ICE diagnostics"}}}_storePendingOfferContext(){this._pendingOfferContext={sessionSalt:Array.isArray(this.sessionSalt)?[...this.sessionSalt]:null,sessionId:this.sessionId||null,connectionId:this.connectionId||null,keyFingerprint:this.keyFingerprint||null,createdAt:Date.now()}}_restorePendingOfferContextIfNeeded(){if(Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64)return!0;let t=this._pendingOfferContext?.sessionSalt;return!Array.isArray(t)||t.length!==64?!1:(this.sessionSalt=[...t],!this.sessionId&&this._pendingOfferContext.sessionId&&(this.sessionId=this._pendingOfferContext.sessionId),!this.connectionId&&this._pendingOfferContext.connectionId&&(this.connectionId=this._pendingOfferContext.connectionId),!this.keyFingerprint&&this._pendingOfferContext.keyFingerprint&&(this.keyFingerprint=this._pendingOfferContext.keyFingerprint),this._secureLog("warn","Restored pending offer context before applying answer",{pendingContextAgeMs:Date.now()-(this._pendingOfferContext.createdAt||Date.now())}),!0)}_clearPendingOfferContext(){this._pendingOfferContext?.sessionSalt&&this._secureWipeMemory(this._pendingOfferContext.sessionSalt,"pendingOfferContext.sessionSalt"),this._pendingOfferContext=null}_executeMaintenanceCycle(){try{this._secureLog("info","\u{1F527} Starting maintenance cycle"),this._cleanupLogs(),this._auditLoggingSystemSecurity(),this._verifyAPIIntegrity(),this._validateCryptographicSecurity(),this._syncSecurityFeaturesWithTariff(),this._cleanupResources(),this._enforceResourceLimits(),this.isConnected&&this.isVerified&&this._monitorKeySecurity(),this._debugMode&&this._monitorGlobalExposure(),this._secureLog("info","\u{1F527} Maintenance cycle completed successfully")}catch(e){this._secureLog("error","\u274C Maintenance cycle failed",{errorType:e?.constructor?.name||"Unknown",message:e?.message||"Unknown error"}),this._emergencyCleanup().catch(t=>{this._secureLog("error","Emergency cleanup failed",{errorType:t?.constructor?.name||"Unknown"})})}}_enforceResourceLimits(){let e=[];this._logCounts.size>this._resourceLimits.maxLogEntries&&e.push("log_entries"),this.messageQueue.length>this._resourceLimits.maxMessageQueue&&e.push("message_queue"),this._ivTrackingSystem&&this._ivTrackingSystem.ivHistory.size>this._resourceLimits.maxIVHistory&&e.push("iv_history"),this.processedMessageIds.size>this._resourceLimits.maxProcessedMessageIds&&e.push("processed_message_ids"),this.decoyChannels.size>this._resourceLimits.maxDecoyChannels&&e.push("decoy_channels"),this._fakeTrafficMessages&&this._fakeTrafficMessages.length>this._resourceLimits.maxFakeTrafficMessages&&e.push("fake_traffic_messages"),this.chunkQueue.length>this._resourceLimits.maxChunkQueue&&e.push("chunk_queue"),this.packetBuffer&&this.packetBuffer.size>this._resourceLimits.maxPacketBuffer&&e.push("packet_buffer"),e.length>0&&(this._secureLog("warn","\u26A0\uFE0F Resource limit violations detected",{violations:e}),this._emergencyCleanup().catch(t=>{this._secureLog("error","Emergency cleanup failed",{errorType:t?.constructor?.name||"Unknown"})}))}async _emergencyCleanup(){this._secureLog("warn","\u{1F6A8} EMERGENCY: Resource limits exceeded, performing emergency cleanup");try{if(this._logCounts.clear(),this._secureLog("info","\u{1F9F9} Emergency: All logs cleared"),this.messageQueue.length=0,this._secureLog("info","\u{1F9F9} Emergency: Message queue cleared"),this._ivTrackingSystem&&(this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","\u{1F9F9} Enhanced Emergency: IV tracking system cleared")),this.processedMessageIds.clear(),this._secureLog("info","\u{1F9F9} Emergency: Processed message IDs cleared"),this.decoyChannels){for(let[e,t]of this.decoyTimers)t&&clearTimeout(t);this.decoyChannels.clear(),this.decoyTimers.clear(),this._secureLog("info","\u{1F9F9} Enhanced Emergency: Decoy channels cleared")}this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null),this._fakeTrafficMessages&&(this._fakeTrafficMessages.length=0,this._secureLog("info","\u{1F9F9} Enhanced Emergency: Fake traffic messages cleared")),this.chunkQueue.length=0,this._secureLog("info","\u{1F9F9} Emergency: Chunk queue cleared"),this.packetBuffer&&(this.packetBuffer.clear(),this._secureLog("info","\u{1F9F9} Emergency: Packet buffer cleared")),this._secureMemoryManager.isCleaning=!0,this._secureMemoryManager.cleanupQueue.length=0,this._secureMemoryManager.memoryStats.lastCleanup=Date.now(),await this._scheduleAsyncCleanup(async()=>{this._secureLog("info","\u{1F9F9} Enhanced Emergency: Starting natural memory cleanup");for(let e=0;e<3;e++)this._secureLog("info",`\u{1F9F9} Enhanced Emergency: Cleanup cycle ${e+1}/3`),await this._performNaturalCleanup();this._secureLog("info","\u{1F9F9} Enhanced Emergency: Natural cleanup completed")},0),this._secureMemoryManager.isCleaning=!1,this._secureLog("info","\u2705 Enhanced emergency cleanup completed successfully")}catch(e){this._secureLog("error","\u274C Enhanced emergency cleanup failed",{errorType:e?.constructor?.name||"Unknown",message:e?.message||"Unknown error"}),this._secureMemoryManager.isCleaning=!1}}_validateEmergencyCleanup(e){let t={messageQueueSize:this.messageQueue.length,processedIdsSize:this.processedMessageIds.size,packetBufferSize:this.packetBuffer?this.packetBuffer.size:0,ivTrackingSize:this._ivTrackingSystem?this._ivTrackingSystem.usedIVs.size:0,decoyChannelsSize:this.decoyChannels?this.decoyChannels.size:0};return{messageQueueCleared:t.messageQueueSize===0,processedIdsCleared:t.processedIdsSize===0,packetBufferCleared:t.packetBufferSize===0,ivTrackingCleared:t.ivTrackingSize===0,decoyChannelsCleared:t.decoyChannelsSize===0,allCleared:t.messageQueueSize===0&&t.processedIdsSize===0&&t.packetBufferSize===0&&t.ivTrackingSize===0&&t.decoyChannelsSize===0}}_cleanupResources(){let e=Date.now();this.processedMessageIds.size>this._emergencyThresholds.processedMessageIds&&(this.processedMessageIds.clear(),this._secureLog("info","\u{1F9F9} Old processed message IDs cleared")),this._ivTrackingSystem&&this._cleanupOldIVs(),this.cleanupOldKeys(),window.EnhancedSecureCryptoUtils&&window.EnhancedSecureCryptoUtils.rateLimiter&&window.EnhancedSecureCryptoUtils.rateLimiter.cleanup(),this._secureLog("info","\u{1F9F9} Resource cleanup completed")}_monitorKeySecurity(){this._keyStorageStats.activeKeys>10&&this._secureLog("warn","\u26A0\uFE0F High number of active keys detected. Consider rotation.")}_sendHeartbeat(e=!1){try{return this.dataChannel&&this.dataChannel.readyState==="open"?(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.HEARTBEAT,ack:e,timestamp:Date.now()})),this._heartbeatConfig.lastHeartbeat=Date.now(),this._secureLog("debug",e?"\u{1F493} Heartbeat ack sent":"\u{1F493} Heartbeat sent"),!0):!1}catch(t){return this._secureLog("error","\u274C Heartbeat failed:",{errorType:t?.constructor?.name||"Unknown",message:t?.message||"Unknown error"}),!1}}_validateInputData(e,t="unknown"){let r={isValid:!1,sanitizedData:null,errors:[],warnings:[]};try{if(e==null)return r.errors.push("Data cannot be null or undefined"),r;if(typeof e=="string")return e.length>this._inputValidationLimits.maxStringLength?(r.errors.push(`String too long: ${e.length} > ${this._inputValidationLimits.maxStringLength}`),r):(r.sanitizedData=this._sanitizeInputString(e),r.isValid=!0,r);if(typeof e=="object"){let i=new WeakSet,n=(o,c="")=>{if(!(o===null||typeof o!="object")){if(i.has(o)){r.errors.push(`Circular reference detected at path: ${c}`);return}if(i.add(o),c.split(".").length>this._inputValidationLimits.maxObjectDepth){r.errors.push(`Object too deep: ${c.split(".").length} > ${this._inputValidationLimits.maxObjectDepth}`);return}if(Array.isArray(o)&&o.length>this._inputValidationLimits.maxArrayLength){r.errors.push(`Array too long: ${o.length} > ${this._inputValidationLimits.maxArrayLength}`);return}for(let d in o)o.hasOwnProperty(d)&&n(o[d],c?`${c}.${d}`:d)}};if(n(e),r.errors.length>0)return r;let a=this._calculateObjectSize(e);return a>this._inputValidationLimits.maxMessageSize?(r.errors.push(`Object too large: ${a} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),r):(r.sanitizedData=this._sanitizeInputObject(e),r.isValid=!0,r)}return e instanceof ArrayBuffer?e.byteLength>this._inputValidationLimits.maxMessageSize?(r.errors.push(`ArrayBuffer too large: ${e.byteLength} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),r):(r.sanitizedData=e,r.isValid=!0,r):(r.errors.push(`Unsupported data type: ${typeof e}`),r)}catch(i){return r.errors.push(`Validation error: ${i.message}`),this._secureLog("error","\u274C Input validation failed",{context:t,errorType:i?.constructor?.name||"Unknown",message:i?.message||"Unknown error"}),r}}_calculateObjectSize(e){try{let t=JSON.stringify(e);return new TextEncoder().encode(t).length}catch{return 1024*1024}}_sanitizeInputString(e){return typeof e!="string"||(e=e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g,""),e=e.replace(/\r\n?/g,` + `,n=new Blob([i],{type:"application/javascript"}),a=new Worker(URL.createObjectURL(n)),o=setTimeout(()=>{a.terminate(),r(new Error("Worker cleanup timeout"))},5e3);a.onmessage=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),c.data.success?t(c.data):r(new Error(c.data.error))},a.onerror=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),r(c)},a.postMessage(e)})}async _cleanupInMainThread(e){let{type:t,data:r}=e;switch(t){case"cleanup_arrays":let i=0,n=100;for(;ic++),await this._asyncSleep(1);return{success:!0,cleaned:c};default:return{success:!0,message:"Unknown cleanup type"}}}_initializeMutexSystem(){this._keyOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._cryptoOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._connectionOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._keySystemState={isInitializing:!1,isRotating:!1,isDestroying:!1,lastOperation:null,lastOperationTime:Date.now(),operationId:null,concurrentOperations:0,maxConcurrentOperations:1},this._operationCounters={keyOperations:0,cryptoOperations:0,connectionOperations:0,totalOperations:0,failedOperations:0},this._secureLog("info","\u{1F512} Enhanced mutex system initialized with atomic protection",{mutexes:["keyOperation","cryptoOperation","connectionOperation"],timestamp:Date.now(),features:["atomic_operations","race_condition_protection","enhanced_state_tracking"]})}_hardenDebugModeReferences(){this._secureLog("info","\u{1F512} XSS Hardening: Debug mode references already replaced")}_initializeUnifiedScheduler(){this._maintenanceScheduler=setInterval(()=>{this._executeMaintenanceCycle()},3e5),this._secureLog("info","\u{1F527} Unified maintenance scheduler initialized (5-minute cycle)"),this._activeTimers=new Set([this._maintenanceScheduler])}_trackActiveTimer(e){return e&&(this._activeTimers||(this._activeTimers=new Set),this._activeTimers.add(e),e)}_untrackActiveTimer(e){e&&this._activeTimers&&this._activeTimers.delete(e)}_setSASMaterialReady(e,t){this._sasLocalFingerprint=e,this._sasRemoteFingerprint=t}_isVerificationReady(){let e=!!(this.peerConnection?.localDescription&&this.peerConnection?.remoteDescription),t=this.dataChannel?.readyState==="open",r=typeof this.verificationCode=="string"&&this.verificationCode.trim().length>0,i=typeof this._sasLocalFingerprint=="string"&&this._sasLocalFingerprint.trim().length>0&&typeof this._sasRemoteFingerprint=="string"&&this._sasRemoteFingerprint.trim().length>0;return e&&t&&r&&i}_notifyVerificationReadyIfPossible(){return this._isVerificationReady()?(this._verificationUiOpened||(this._verificationUiOpened=!0,this.onStatusChange?.("verifying"),this.onVerificationRequired?.(this.verificationCode)),!0):!1}_countIceCandidatesInSDP(e){return typeof e!="string"?0:(e.match(/^a=candidate:/gm)||[]).length}_summarizeIceCandidatesInSDP(e){let t={total:0,host:0,srflx:0,relay:0,prflx:0,unknown:0};if(typeof e!="string")return t;for(let r of e.match(/^a=candidate:.*$/gm)||[]){t.total+=1;let n=r.match(/\btyp\s+(host|srflx|relay|prflx)\b/i)?.[1]?.toLowerCase();n&&Object.prototype.hasOwnProperty.call(t,n)?t[n]+=1:t.unknown+=1}return t}_describeIceCandidatesInSDP(e){return typeof e!="string"?[]:(e.match(/^a=candidate:.*$/gm)||[]).map(t=>{let r=t.slice(12).trim().split(/\s+/),i=r.findIndex(h=>h.toLowerCase()==="typ"),n=r[4]||"",a=r[5]||"",o=i>=0&&r[i+1]||"unknown",c=(r[2]||"unknown").toLowerCase(),d="unknown";return/\.local$/i.test(n)?d="mdns":/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(n)?d="private-ipv4":/^\d{1,3}(\.\d{1,3}){3}$/.test(n)?d="public-ipv4":n.includes(":")&&(d="ipv6"),{candidateType:o,protocol:c,addressKind:d,portPresent:!!a,tcpType:(()=>{let h=r.findIndex(u=>u.toLowerCase()==="tcptype");return h>=0&&r[h+1]||null})()}})}_logIceCandidateDiagnostics(e,t,r={}){let i=this._summarizeIceCandidatesInSDP(t),n=this._describeIceCandidatesInSDP(t);return console.info(`[SecureBit ICE] ${e}`,{candidateSummary:i,candidateDetails:n,candidateDetailsJson:JSON.stringify(n),...r}),{candidateSummary:i,candidateDetails:n}}_hasOnlyMdnsHostCandidates(e){let t=this._summarizeIceCandidatesInSDP(e),r=this._describeIceCandidatesInSDP(e);return t.total>0&&t.srflx===0&&t.relay===0&&t.prflx===0&&r.every(i=>i.candidateType==="host"&&i.addressKind==="mdns")}_warnIfRemoteCandidatesNeedRelay(e,t){if(!this._hasOnlyMdnsHostCandidates(t))return!1;let r=e==="answer"?"Connection warning: the response contains only browser-masked mDNS host candidates and no server-reflexive or TURN relay candidates. This network/browser combination may not connect until TURN is configured.":"Connection warning: the invitation contains only browser-masked mDNS host candidates and no server-reflexive or TURN relay candidates. This network/browser combination may not connect until TURN is configured.";return this._secureLog("warn","Remote ICE candidates require TURN or usable non-mDNS candidates",{context:e,candidateSummary:this._summarizeIceCandidatesInSDP(t),candidateDetails:this._describeIceCandidatesInSDP(t)}),this.deliverMessageToUI(r,"system"),!0}async _collectIceFailureDiagnostics(){if(!this.peerConnection?.getStats)return null;try{let e=await this.peerConnection.getStats(),t=new Map,r=[];return e.forEach(i=>{(i.type==="local-candidate"||i.type==="remote-candidate")&&t.set(i.id,{type:i.type,candidateType:i.candidateType,protocol:i.protocol,address:i.address||i.ip||null,port:i.port||null,networkType:i.networkType||null})}),e.forEach(i=>{i.type==="candidate-pair"&&r.push({state:i.state,nominated:!!i.nominated,writable:!!i.writable,bytesSent:i.bytesSent||0,bytesReceived:i.bytesReceived||0,currentRoundTripTime:i.currentRoundTripTime??null,local:t.get(i.localCandidateId)||null,remote:t.get(i.remoteCandidateId)||null})}),{pairCount:r.length,states:r.reduce((i,n)=>(i[n.state||"unknown"]=(i[n.state||"unknown"]||0)+1,i),{}),pairs:r}}catch(e){return{error:e?.message||"Failed to collect ICE diagnostics"}}}_storePendingOfferContext(){this._pendingOfferContext={sessionSalt:Array.isArray(this.sessionSalt)?[...this.sessionSalt]:null,sessionId:this.sessionId||null,connectionId:this.connectionId||null,keyFingerprint:this.keyFingerprint||null,createdAt:Date.now()}}_restorePendingOfferContextIfNeeded(){if(Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64)return!0;let t=this._pendingOfferContext?.sessionSalt;return!Array.isArray(t)||t.length!==64?!1:(this.sessionSalt=[...t],!this.sessionId&&this._pendingOfferContext.sessionId&&(this.sessionId=this._pendingOfferContext.sessionId),!this.connectionId&&this._pendingOfferContext.connectionId&&(this.connectionId=this._pendingOfferContext.connectionId),!this.keyFingerprint&&this._pendingOfferContext.keyFingerprint&&(this.keyFingerprint=this._pendingOfferContext.keyFingerprint),this._secureLog("warn","Restored pending offer context before applying answer",{pendingContextAgeMs:Date.now()-(this._pendingOfferContext.createdAt||Date.now())}),!0)}_clearPendingOfferContext(){this._pendingOfferContext?.sessionSalt&&this._secureWipeMemory(this._pendingOfferContext.sessionSalt,"pendingOfferContext.sessionSalt"),this._pendingOfferContext=null}_executeMaintenanceCycle(){try{this._secureLog("info","\u{1F527} Starting maintenance cycle"),this._cleanupLogs(),this._auditLoggingSystemSecurity(),this._verifyAPIIntegrity(),this._validateCryptographicSecurity(),this._syncSecurityFeaturesWithTariff(),this._cleanupResources(),this._enforceResourceLimits(),this.isConnected&&this.isVerified&&this._monitorKeySecurity(),this._debugMode&&this._monitorGlobalExposure(),this._secureLog("info","\u{1F527} Maintenance cycle completed successfully")}catch(e){this._secureLog("error","\u274C Maintenance cycle failed",{errorType:e?.constructor?.name||"Unknown",message:e?.message||"Unknown error"}),this._emergencyCleanup().catch(t=>{this._secureLog("error","Emergency cleanup failed",{errorType:t?.constructor?.name||"Unknown"})})}}_enforceResourceLimits(){let e=[];this._logCounts.size>this._resourceLimits.maxLogEntries&&e.push("log_entries"),this.messageQueue.length>this._resourceLimits.maxMessageQueue&&e.push("message_queue"),this._ivTrackingSystem&&this._ivTrackingSystem.ivHistory.size>this._resourceLimits.maxIVHistory&&e.push("iv_history"),this.processedMessageIds.size>this._resourceLimits.maxProcessedMessageIds&&e.push("processed_message_ids"),this.decoyChannels.size>this._resourceLimits.maxDecoyChannels&&e.push("decoy_channels"),this._fakeTrafficMessages&&this._fakeTrafficMessages.length>this._resourceLimits.maxFakeTrafficMessages&&e.push("fake_traffic_messages"),this.chunkQueue.length>this._resourceLimits.maxChunkQueue&&e.push("chunk_queue"),this.packetBuffer&&this.packetBuffer.size>this._resourceLimits.maxPacketBuffer&&e.push("packet_buffer"),e.length>0&&(this._secureLog("warn","\u26A0\uFE0F Resource limit violations detected",{violations:e}),this._emergencyCleanup().catch(t=>{this._secureLog("error","Emergency cleanup failed",{errorType:t?.constructor?.name||"Unknown"})}))}async _emergencyCleanup(){this._secureLog("warn","\u{1F6A8} EMERGENCY: Resource limits exceeded, performing emergency cleanup");try{if(this._logCounts.clear(),this._secureLog("info","\u{1F9F9} Emergency: All logs cleared"),this.messageQueue.length=0,this._secureLog("info","\u{1F9F9} Emergency: Message queue cleared"),this._ivTrackingSystem&&(this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","\u{1F9F9} Enhanced Emergency: IV tracking system cleared")),this.processedMessageIds.clear(),this._secureLog("info","\u{1F9F9} Emergency: Processed message IDs cleared"),this.decoyChannels){for(let[e,t]of this.decoyTimers)t&&clearTimeout(t);this.decoyChannels.clear(),this.decoyTimers.clear(),this._secureLog("info","\u{1F9F9} Enhanced Emergency: Decoy channels cleared")}this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null),this._fakeTrafficMessages&&(this._fakeTrafficMessages.length=0,this._secureLog("info","\u{1F9F9} Enhanced Emergency: Fake traffic messages cleared")),this.chunkQueue.length=0,this._secureLog("info","\u{1F9F9} Emergency: Chunk queue cleared"),this.packetBuffer&&(this.packetBuffer.clear(),this._secureLog("info","\u{1F9F9} Emergency: Packet buffer cleared")),this._secureMemoryManager.isCleaning=!0,this._secureMemoryManager.cleanupQueue.length=0,this._secureMemoryManager.memoryStats.lastCleanup=Date.now(),await this._scheduleAsyncCleanup(async()=>{this._secureLog("info","\u{1F9F9} Enhanced Emergency: Starting natural memory cleanup");for(let e=0;e<3;e++)this._secureLog("info",`\u{1F9F9} Enhanced Emergency: Cleanup cycle ${e+1}/3`),await this._performNaturalCleanup();this._secureLog("info","\u{1F9F9} Enhanced Emergency: Natural cleanup completed")},0),this._secureMemoryManager.isCleaning=!1,this._secureLog("info","\u2705 Enhanced emergency cleanup completed successfully")}catch(e){this._secureLog("error","\u274C Enhanced emergency cleanup failed",{errorType:e?.constructor?.name||"Unknown",message:e?.message||"Unknown error"}),this._secureMemoryManager.isCleaning=!1}}_validateEmergencyCleanup(e){let t={messageQueueSize:this.messageQueue.length,processedIdsSize:this.processedMessageIds.size,packetBufferSize:this.packetBuffer?this.packetBuffer.size:0,ivTrackingSize:this._ivTrackingSystem?this._ivTrackingSystem.usedIVs.size:0,decoyChannelsSize:this.decoyChannels?this.decoyChannels.size:0};return{messageQueueCleared:t.messageQueueSize===0,processedIdsCleared:t.processedIdsSize===0,packetBufferCleared:t.packetBufferSize===0,ivTrackingCleared:t.ivTrackingSize===0,decoyChannelsCleared:t.decoyChannelsSize===0,allCleared:t.messageQueueSize===0&&t.processedIdsSize===0&&t.packetBufferSize===0&&t.ivTrackingSize===0&&t.decoyChannelsSize===0}}_cleanupResources(){let e=Date.now();this.processedMessageIds.size>this._emergencyThresholds.processedMessageIds&&(this.processedMessageIds.clear(),this._secureLog("info","\u{1F9F9} Old processed message IDs cleared")),this._ivTrackingSystem&&this._cleanupOldIVs(),this.cleanupOldKeys(),window.EnhancedSecureCryptoUtils&&window.EnhancedSecureCryptoUtils.rateLimiter&&window.EnhancedSecureCryptoUtils.rateLimiter.cleanup(),this._secureLog("info","\u{1F9F9} Resource cleanup completed")}_monitorKeySecurity(){this._keyStorageStats.activeKeys>10&&this._secureLog("warn","\u26A0\uFE0F High number of active keys detected. Consider rotation.")}_sendHeartbeat(e=!1){try{return this.dataChannel&&this.dataChannel.readyState==="open"?(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.HEARTBEAT,ack:e,timestamp:Date.now()})),this._heartbeatConfig.lastHeartbeat=Date.now(),this._secureLog("debug",e?"\u{1F493} Heartbeat ack sent":"\u{1F493} Heartbeat sent"),!0):!1}catch(t){return this._secureLog("error","\u274C Heartbeat failed:",{errorType:t?.constructor?.name||"Unknown",message:t?.message||"Unknown error"}),!1}}_validateInputData(e,t="unknown"){let r={isValid:!1,sanitizedData:null,errors:[],warnings:[]};try{if(e==null)return r.errors.push("Data cannot be null or undefined"),r;if(typeof e=="string")return e.length>this._inputValidationLimits.maxStringLength?(r.errors.push(`String too long: ${e.length} > ${this._inputValidationLimits.maxStringLength}`),r):(r.sanitizedData=this._sanitizeInputString(e),r.isValid=!0,r);if(typeof e=="object"){let i=new WeakSet,n=(o,c="")=>{if(!(o===null||typeof o!="object")){if(i.has(o)){r.errors.push(`Circular reference detected at path: ${c}`);return}if(i.add(o),c.split(".").length>this._inputValidationLimits.maxObjectDepth){r.errors.push(`Object too deep: ${c.split(".").length} > ${this._inputValidationLimits.maxObjectDepth}`);return}if(Array.isArray(o)&&o.length>this._inputValidationLimits.maxArrayLength){r.errors.push(`Array too long: ${o.length} > ${this._inputValidationLimits.maxArrayLength}`);return}for(let d in o)o.hasOwnProperty(d)&&n(o[d],c?`${c}.${d}`:d)}};if(n(e),r.errors.length>0)return r;let a=this._calculateObjectSize(e);return a>this._inputValidationLimits.maxMessageSize?(r.errors.push(`Object too large: ${a} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),r):(r.sanitizedData=this._sanitizeInputObject(e),r.isValid=!0,r)}return e instanceof ArrayBuffer?e.byteLength>this._inputValidationLimits.maxMessageSize?(r.errors.push(`ArrayBuffer too large: ${e.byteLength} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),r):(r.sanitizedData=e,r.isValid=!0,r):(r.errors.push(`Unsupported data type: ${typeof e}`),r)}catch(i){return r.errors.push(`Validation error: ${i.message}`),this._secureLog("error","\u274C Input validation failed",{context:t,errorType:i?.constructor?.name||"Unknown",message:i?.message||"Unknown error"}),r}}_calculateObjectSize(e){try{let t=JSON.stringify(e);return new TextEncoder().encode(t).length}catch{return 1024*1024}}_sanitizeInputString(e){return typeof e!="string"||(e=e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g,""),e=e.replace(/\r\n?/g,` `),e=e.replace(/\n{3,}/g,` -`),e=e.trim()),e}_sanitizeInputObject(e){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(r=>this._sanitizeInputObject(r));let t={};for(let r in e)if(e.hasOwnProperty(r)){let i=e[r];typeof i=="string"?t[r]=this._sanitizeInputString(i):typeof i=="object"?t[r]=this._sanitizeInputObject(i):t[r]=i}return t}_checkRateLimit(e="message"){let t=Date.now();return this._rateLimiter||(this._rateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._rateLimiter.lastReset>6e4&&(this._rateLimiter.messageCount=0,this._rateLimiter.lastReset=t),t-this._rateLimiter.lastBurstReset>1e3&&(this._rateLimiter.burstCount=0,this._rateLimiter.lastBurstReset=t),this._rateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Rate limit burst exceeded",{context:e}),!1):this._rateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Rate limit exceeded",{context:e}),!1):(this._rateLimiter.messageCount++,this._rateLimiter.burstCount++,!0)}_checkInboundRateLimit(e="incoming_message"){let t=Date.now();return this._inboundRateLimiter||(this._inboundRateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._inboundRateLimiter.lastReset>6e4&&(this._inboundRateLimiter.messageCount=0,this._inboundRateLimiter.lastReset=t),t-this._inboundRateLimiter.lastBurstReset>1e3&&(this._inboundRateLimiter.burstCount=0,this._inboundRateLimiter.lastBurstReset=t),this._inboundRateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Inbound message burst limit exceeded; dropping message",{context:e}),!1):this._inboundRateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Inbound message rate limit exceeded; dropping message",{context:e}),!1):(this._inboundRateLimiter.messageCount++,this._inboundRateLimiter.burstCount++,!0)}_initializeSecureKeyStorage(){this._masterKeyManager=new jt,this._secureKeyStorage=new Gt(this._masterKeyManager),this._keyStorageStats={totalKeys:0,activeKeys:0,lastAccess:null,lastRotation:null},this._secureLog("info","\u{1F510} Enhanced secure key storage initialized")}setMasterKeyPasswordCallback(e){this._masterKeyManager&&this._masterKeyManager.setPasswordRequiredCallback(e)}setMasterKeySessionExpiredCallback(e){this._masterKeyManager&&this._masterKeyManager.setSessionExpiredCallback(e)}lockMasterKey(){this._masterKeyManager&&this._masterKeyManager.lock()}isMasterKeyUnlocked(){return this._masterKeyManager?this._masterKeyManager.isUnlocked():!1}getMasterKeySessionStatus(){return this._masterKeyManager?this._masterKeyManager.getSessionStatus():null}async _ensureFileTransferReady(){try{if(this.fileTransferSystem)return!0;if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.isVerified)throw new Error("Connection not verified");this.initializeFileTransfer();let e=0,t=50;for(;!this.fileTransferSystem&&esetTimeout(r,100)),e++;if(!this.fileTransferSystem)throw new Error("File transfer system initialization timeout");return!0}catch(e){return this._secureLog("error","\u274C _ensureFileTransferReady failed",{errorType:e?.constructor?.name||"Unknown",hasMessage:!!e?.message}),!1}}_getSecureKey(e){return this._secureKeyStorage.retrieveKey(e)}async _setSecureKey(e,t){if(!(t instanceof CryptoKey))return this._secureLog("error","\u274C Attempt to store non-CryptoKey"),!1;let r=await this._secureKeyStorage.storeKey(e,t,{version:this.currentKeyVersion,type:t.algorithm.name});return r&&this._secureLog("info",`\u{1F511} Key ${e} stored securely with encryption`),r}_validateKeyValue(e){return e instanceof CryptoKey&&e.algorithm&&e.usages&&e.usages.length>0}_secureWipeKeys(){this._secureKeyStorage.secureWipeAll(),this._masterKeyManager&&this._masterKeyManager.lock(),this._secureLog("info","\u{1F9F9} All keys securely wiped and encrypted storage cleared")}_validateKeyStorage(){return this._secureKeyStorage instanceof Gt}_getKeyStorageStats(){let e=this._secureKeyStorage.getStorageStats();return{totalKeysCount:e.totalKeys,activeKeysCount:e.totalKeys,hasLastAccess:e.metadata.some(t=>t.lastAccessed),hasLastRotation:!!this._keyStorageStats.lastRotation,storageType:"SecureKeyStorage",timestamp:Date.now()}}_rotateKeys(){let e=Array.from(this._secureKeyStorage.keys());this._secureKeyStorage.clear(),this._keyStorageStats.lastRotation=Date.now(),this._keyStorageStats.activeKeys=0,this._secureLog("info",`\u{1F504} Key rotation completed. ${e.length} keys rotated`)}_emergencyKeyWipe(){this._secureWipeKeys(),this._secureLog("error","\u{1F6A8} EMERGENCY: All keys wiped due to security threat")}_startKeySecurityMonitoring(){this._secureLog("info","\u{1F527} Key security monitoring moved to unified scheduler")}_validateKeyConstantTime(e){let t=0;try{let r=e instanceof CryptoKey;t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.algorithm);t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.type);t+=r?1:0}catch{t+=0}try{let r=e&&e.extractable!==void 0;t+=r?1:0}catch{t+=0}return t===4}_validateKeyPairConstantTime(e){if(!e||typeof e!="object")return!1;let t=this._validateKeyConstantTime(e.privateKey),r=this._validateKeyConstantTime(e.publicKey);return t&&r}_initializeSecureLogging(){this._logLevels={error:0,warn:1,info:2,debug:3,trace:4},this._currentLogLevel=this._isProductionMode?this._logLevels.error:this._logLevels.info,this._logCounts=new Map,this._maxLogCount=this._isProductionMode?5:50,this._resourceLimits={maxLogEntries:this._isProductionMode?100:1e3,maxMessageQueue:1e3,maxIVHistory:1e4,maxProcessedMessageIds:5e3,maxDecoyChannels:100,maxFakeTrafficMessages:500,maxChunkQueue:200,maxPacketBuffer:1e3},this._emergencyThresholds={logEntries:this._resourceLimits.maxLogEntries*.8,messageQueue:this._resourceLimits.maxMessageQueue*.8,ivHistory:this._resourceLimits.maxIVHistory*.8,processedMessageIds:this._resourceLimits.maxProcessedMessageIds*.8},this._inputValidationLimits={maxStringLength:1e5,maxObjectDepth:10,maxArrayLength:1e3,maxMessageSize:1024*1024,maxConcurrentMessages:10,rateLimitMessagesPerMinute:60,rateLimitBurstSize:10},this._absoluteBlacklist=new Set(["encryptionKey","macKey","metadataKey","privateKey","publicKey","ecdhKeyPair","ecdsaKeyPair","peerPublicKey","nestedEncryptionKey","verificationCode","sessionSalt","keyFingerprint","sessionId","authChallenge","authProof","authToken","sessionToken","password","token","secret","credential","signature","apiKey","accessKey","secretKey","privateKey","hash","digest","nonce","iv","cipher","seed","entropy","random","salt","fingerprint","jwt","bearer","refreshToken","accessToken","fileHash","fileSignature","transferKey","chunkKey"]),this._safeFieldsWhitelist=new Set(["timestamp","type","status","state","level","isConnected","isVerified","isInitiator","version","count","total","active","inactive","success","failure","readyState","connectionState","iceConnectionState","activeFeaturesCount","totalFeatures","stage","errorType","errorCode","phase","attempt"]),this._initializeLogSecurityMonitoring(),this._secureLog("info",`\u{1F527} Enhanced secure logging initialized (Production: ${this._isProductionMode})`)}_initializeLogSecurityMonitoring(){this._logSecurityViolations=0,this._maxLogSecurityViolations=3}_auditLoggingSystemSecurity(){let e=0;for(let[r,i]of this._logCounts.entries())i>this._maxLogCount*2&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Excessive log count detected: ${r}`));let t=Array.from(this._logCounts.keys());for(let r of t)this._containsSensitiveContent(r)&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Sensitive content in log key: ${r}`));this._logSecurityViolations+=e,this._logSecurityViolations>=this._maxLogSecurityViolations&&(this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Logging system disabled due to security violations"))}_secureLogShim(...e){try{if(!Array.isArray(e)||e.length===0)return;let t=e[0],r=e.slice(1);if(r.length===0){this._secureLog("info",String(t||""));return}if(r.length===1){this._secureLog("info",String(t||""),r[0]);return}this._secureLog("info",String(t||""),{additionalArgs:r,argCount:r.length})}catch{try{this._originalConsole?.log&&this._originalConsole.log(...e)}catch{}}}_setupOwnLogger(){this.logger={log:(e,t)=>this._secureLog("info",e,t),info:(e,t)=>this._secureLog("info",e,t),warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:(e,t)=>this._secureLog("debug",e,t)},s.DEBUG_MODE?this._secureLog("info","\u{1F512} Own logger created - development mode"):this._secureLog("info","\u{1F512} Own logger created - production mode")}_setupProductionLogging(){this._isProductionMode&&(this.logger={log:()=>{},info:()=>{},warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:()=>{}},this._secureLog("info","Production logging mode activated"))}_secureLog(e,t,r=null){if(r&&!this._auditLogMessage(t,r)){this._originalConsole?.error?.("SECURITY: Logging blocked due to potential data leakage");return}if(this._logLevels[e]>this._currentLogLevel)return;let i=`${e}:${t.substring(0,50)}`,n=this._logCounts.get(i)||0;if(n>=this._maxLogCount)return;this._logCounts.set(i,n+1);let a=null;if(r&&(a=this._sanitizeLogData(r),this._containsSensitiveContent(JSON.stringify(a)))){this._originalConsole?.error?.("ECURITY: Sanitized data still contains sensitive content - blocking log");return}if(this._isProductionMode){if(e==="error"){let c=this._sanitizeString(t);this._originalConsole?.error?.(c)}return}let o=this._originalConsole?.[e]||this._originalConsole?.log;a?o(t,a):o(t)}_sanitizeLogData(e){if(typeof e=="string")return this._sanitizeString(e);if(!e||typeof e!="object")return e;let t={};for(let[i,n]of Object.entries(e)){let a=i.toLowerCase(),o=["key","secret","token","password","credential","auth","fingerprint","salt","signature","private","encryption","mac","metadata","session","jwt","bearer","hash","digest","nonce","iv","cipher","seed","entropy"];if(this._absoluteBlacklist.has(i)||o.some(d=>a.includes(d))){t[i]="[SENSITIVE_DATA_BLOCKED]";continue}if(this._safeFieldsWhitelist.has(i)){typeof n=="string"?t[i]=this._sanitizeString(n):t[i]=n;continue}if(typeof n=="boolean"||typeof n=="number")t[i]=n;else if(typeof n=="string")t[i]=this._sanitizeString(n);else if(n instanceof ArrayBuffer||n instanceof Uint8Array)t[i]=`[${n.constructor.name}( bytes)]`;else if(n&&typeof n=="object")try{t[i]=this._sanitizeLogData(n)}catch{t[i]="[RECURSIVE_SANITIZATION_FAILED]"}else t[i]=`[${typeof n}]`}let r=JSON.stringify(t);return this._containsSensitiveContent(r)?{error:"SANITIZATION_FAILED_SENSITIVE_CONTENT_DETECTED"}:t}_sanitizeString(e){if(typeof e!="string"||e.length===0)return e;let t=[/[a-f0-9]{16,}/i,/[a-f0-9]{8,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[A-Za-z0-9+/]{12,}/,/[A-Za-z0-9+/=]{10,}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/[A-Z2-7]{12,}/,/[A-Za-z0-9\-_]{16,}/,/[A-Za-z0-9\.\-_]{16,}/,/\b[A-Za-z0-9]{12,}\b/,/\b[A-Za-z0-9]{8,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/END\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i,/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/,/\b\d{3}-\d{2}-\d{4}\b/,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/,/(fingerprint|hash|digest|signature)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(encryption|mac|metadata)[\s]*key[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(session|auth|jwt|bearer)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i];for(let r of t)if(r.test(e))return"[SENSITIVE_DATA_REDACTED]";return this._hasHighEntropy(e)?"[HIGH_ENTROPY_DATA_REDACTED]":this._hasSuspiciousDistribution(e)?"[SUSPICIOUS_DATA_REDACTED]":e.length>50?e.substring(0,20)+"...[TRUNCATED]":e}_containsSensitiveContent(e){return typeof e!="string"?!1:[/[a-f0-9]{16,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/\b[A-Za-z0-9]{12,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i].some(r=>r.test(e))||this._hasHighEntropy(e)||this._hasSuspiciousDistribution(e)}_hasHighEntropy(e){if(e.length<8)return!1;let t={};for(let n of e)t[n]=(t[n]||0)+1;let r=e.length,i=0;for(let n of Object.values(t)){let a=n/r;i-=a*Math.log2(a)}return i>4.5}_hasSuspiciousDistribution(e){return e.length<8?!1:(e.match(/[a-f0-9]/gi)||[]).length>=e.length*.8||(e.match(/[A-Za-z0-9+/=]/g)||[]).length>=e.length*.9||new Set(e).size/e.length>.8&&e.length>16}_detectProductionMode(){return typeof process<"u"&&!0||!this._debugMode||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")}_setupSecureGlobalAPI(){this._secureLog("info","Starting secure global API setup");let e={};typeof this.sendMessage=="function"&&(e.sendMessage=this.sendMessage.bind(this)),e.getConnectionStatus=()=>({isConnected:this.isConnected?this.isConnected():!1,isVerified:this.isVerified||!1,connectionState:this.peerConnection?.connectionState||"disconnected"}),e.getSecurityStatus=()=>({securityLevel:"maximum",stage:"initialized",activeFeaturesCount:Object.values(this.securityFeatures||{}).filter(Boolean).length}),typeof this.sendFile=="function"&&(e.sendFile=this.sendFile.bind(this)),e.getFileTransferStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),typeof this.disconnect=="function"&&(e.disconnect=this.disconnect.bind(this));let t={...e,getConfiguration:()=>({fakeTraffic:this._config.fakeTraffic.enabled,decoyChannels:this._config.decoyChannels.enabled,packetPadding:this._config.packetPadding.enabled,antiFingerprinting:this._config.antiFingerprinting.enabled}),emergency:{}};typeof this._emergencyUnlockAllMutexes=="function"&&(t.emergency.unlockAllMutexes=this._emergencyUnlockAllMutexes.bind(this)),typeof this._emergencyRecoverMutexSystem=="function"&&(t.emergency.recoverMutexSystem=this._emergencyRecoverMutexSystem.bind(this)),typeof this._emergencyDisableLogging=="function"&&(t.emergency.disableLogging=this._emergencyDisableLogging.bind(this)),typeof this._resetLoggingSystem=="function"&&(t.emergency.resetLogging=this._resetLoggingSystem.bind(this)),t.getFileTransferSystemStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),this._secureLog("info","API methods available",{sendMessage:!!e.sendMessage,getConnectionStatus:!!e.getConnectionStatus,getSecurityStatus:!!e.getSecurityStatus,sendFile:!!e.sendFile,getFileTransferStatus:!!e.getFileTransferStatus,disconnect:!!e.disconnect,getConfiguration:!!t.getConfiguration,emergencyMethods:Object.keys(t.emergency).length}),Object.freeze(t),Object.freeze(t.emergency),this._createProtectedGlobalAPI(t),this._setupMinimalGlobalProtection(),this._secureLog("info","Secure global API setup completed successfully")}_createProtectedGlobalAPI(e){this._secureLog("info","Creating protected global API"),window.secureBitChat?this._secureLog("warn","\u26A0\uFE0F Global API already exists, skipping setup"):this._exportAPI(e)}_exportAPI(e){this._secureLog("info","Exporting API to window.secureBitChat"),!this._importantMethods||!this._importantMethods.defineProperty?(this._secureLog("error","\u274C Important methods not available for API export, using fallback"),Object.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0})):this._importantMethods.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0}),this._secureLog("info","\u{1F512} Secure API exported to window.secureBitChat")}_setupMinimalGlobalProtection(){this._protectGlobalAPI(),this._secureLog("info","\u{1F512} Minimal global protection activated")}_storeImportantMethods(){this._importantMethods={defineProperty:Object.defineProperty,getOwnPropertyDescriptor:Object.getOwnPropertyDescriptor,freeze:Object.freeze,consoleLog:console.log,consoleError:console.error,consoleWarn:console.warn},this._secureLog("info","\u{1F512} Important methods stored locally",{defineProperty:!!this._importantMethods.defineProperty,getOwnPropertyDescriptor:!!this._importantMethods.getOwnPropertyDescriptor,freeze:!!this._importantMethods.freeze})}_setupSimpleProtection(){this._secureLog("info","\u{1F512} Simple protection activated - no monitoring")}_preventGlobalExposure(){this._secureLog("info","\u{1F512} No global exposure prevention - using secure API export only")}_verifyAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C SECURITY ALERT: Secure API has been removed!"),!1;let t=["sendMessage","getConnectionStatus","disconnect"].filter(r=>typeof window.secureBitChat[r]!="function");return t.length>0?(this._secureLog("error","\u274C SECURITY ALERT: API tampering detected, missing methods:",{errorType:t?.constructor?.name||"Unknown"}),!1):!0}catch(e){return this._secureLog("error","\u274C SECURITY ALERT: API integrity check failed:",{errorType:e?.constructor?.name||"Unknown"}),!1}}_auditGlobalExposure(){return this._secureLog("info","\u{1F512} Global exposure check completed at initialization"),[]}_startSecurityAudit(){this._secureLog("info","\u{1F512} Security audit completed at initialization - no periodic monitoring")}_protectGlobalAPI(){if(!window.secureBitChat){this._secureLog("warn","\u26A0\uFE0F Global API not found during protection setup");return}try{this._validateAPIIntegrityOnce()&&this._secureLog("info","\u{1F512} Global API protection verified")}catch(e){this._secureLog("error","\u274C Failed to verify global API protection",{errorType:e.constructor.name,errorMessage:e.message})}}_validateAPIIntegrityOnce(){try{if(!this._importantMethods||!this._importantMethods.getOwnPropertyDescriptor){let e=Object.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}else{let e=this._importantMethods.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}return this._secureLog("info","\u2705 API integrity validated"),!0}catch(e){return this._secureLog("error","\u274C API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_secureWipeMemory(e,t="unknown"){if(e)try{e instanceof ArrayBuffer?this._secureWipeArrayBuffer(e,t):e instanceof Uint8Array?this._secureWipeUint8Array(e,t):Array.isArray(e)?this._secureWipeArray(e,t):typeof e=="string"?this._secureWipeString(e,t):e instanceof CryptoKey?this._secureWipeCryptoKey(e,t):typeof e=="object"&&this._secureWipeObject(e,t),this._secureMemoryManager.memoryStats.totalCleanups++}catch(r){this._secureMemoryManager.memoryStats.failedCleanups++,this._secureLog("error","\u274C Secure memory wipe failed",{context:t,errorType:r.constructor.name,errorMessage:r.message})}}_secureWipeArrayBuffer(e,t){if(!(!e||e.byteLength===0))try{let r=new Uint8Array(e);crypto.getRandomValues(r),r.fill(0),r.fill(255),r.fill(0),this._secureLog("debug","\u{1F512} ArrayBuffer securely wiped",{context:t,size:e.byteLength})}catch(r){this._secureLog("error","\u274C Failed to wipe ArrayBuffer",{context:t,errorType:r.constructor.name})}}_secureWipeUint8Array(e,t){if(!(!e||e.length===0))try{crypto.getRandomValues(e),e.fill(0),e.fill(255),e.fill(0),this._secureLog("debug","\u{1F512} Uint8Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe Uint8Array",{context:t,errorType:r.constructor.name})}}_secureWipeArray(e,t){if(!(!Array.isArray(e)||e.length===0))try{e.forEach((r,i)=>{r!=null&&this._secureWipeMemory(r,`${t}[${i}]`)}),e.fill(null),this._secureLog("debug","\u{1F512} Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe array",{context:t,errorType:r.constructor.name})}}_secureWipeString(e,t){return this._secureLog("debug","String secret cannot be wiped in JS (immutable) \u2014 reference dropped only",{context:t,length:e?e.length:0}),!1}_secureWipeCryptoKey(e,t){return!e||!(e instanceof CryptoKey)||(this._secureLog("debug","CryptoKey cannot be wiped from JS \u2014 handle dropped, material is non-extractable",{context:t,type:e.type,extractable:e.extractable}),e.extractable&&this._secureLog("error","Extractable key reached the wipe path \u2014 material may persist in memory",{context:t})),!1}_secureWipeObject(e,t){if(!(!e||typeof e!="object"))try{for(let[r,i]of Object.entries(e))i!=null&&this._secureWipeMemory(i,`${t}.${r}`),e[r]=null;this._secureLog("debug","\u{1F512} Object securely wiped",{context:t,properties:Object.keys(e).length})}catch(r){this._secureLog("error","\u274C Failed to wipe object",{context:t,errorType:r.constructor.name})}}_secureCleanupCryptographicMaterials(){try{if(this.ecdhKeyPair&&(this._secureWipeMemory(this.ecdhKeyPair,"ecdhKeyPair"),this.ecdhKeyPair=null),this.ecdsaKeyPair&&(this._secureWipeMemory(this.ecdsaKeyPair,"ecdsaKeyPair"),this.ecdsaKeyPair=null),this.encryptionKey&&(this._secureWipeMemory(this.encryptionKey,"encryptionKey"),this.encryptionKey=null),this.macKey&&(this._secureWipeMemory(this.macKey,"macKey"),this.macKey=null),this.metadataKey&&(this._secureWipeMemory(this.metadataKey,"metadataKey"),this.metadataKey=null),this.nestedEncryptionKey&&(this._secureWipeMemory(this.nestedEncryptionKey,"nestedEncryptionKey"),this.nestedEncryptionKey=null),this.sessionSalt&&(this._secureWipeMemory(this.sessionSalt,"sessionSalt"),this.sessionSalt=null),this.sessionId&&(this._secureWipeMemory(this.sessionId,"sessionId"),this.sessionId=null),this.verificationCode&&(this._secureWipeMemory(this.verificationCode,"verificationCode"),this.verificationCode=null),this.peerPublicKey&&(this._secureWipeMemory(this.peerPublicKey,"peerPublicKey"),this.peerPublicKey=null),this.keyFingerprint&&(this._secureWipeMemory(this.keyFingerprint,"keyFingerprint"),this.keyFingerprint=null),this.connectionId&&(this._secureWipeMemory(this.connectionId,"connectionId"),this.connectionId=null),this._clearPendingOfferContext(),this._ratchet){try{this._ratchet.destroy()}catch{}this._ratchet=null}this._peerSupportsRatchet=!1,this._secureLog("info","\u{1F512} Cryptographic materials securely cleaned up")}catch(e){this._secureLog("error","\u274C Failed to cleanup cryptographic materials",{errorType:e.constructor.name,errorMessage:e.message})}}async _forceGarbageCollection(){try{await this._performNaturalCleanup(),this._secureLog("debug","\u{1F512} Natural memory cleanup performed")}catch(e){this._secureLog("error","\u274C Failed to perform natural cleanup",{errorType:e.constructor.name})}}async _performPeriodicMemoryCleanup(){try{this._secureMemoryManager.isCleaning=!0;let e=this.sessionMode==="ratchet"&&this.isConnected&&this.dataChannel&&this.dataChannel.readyState==="open",t=this._pendingOfferContext?Date.now()-(this._pendingOfferContext.createdAt||0):1/0,r=!!this._pendingOfferContext&&Array.isArray(this._pendingOfferContext.sessionSalt)&&this._pendingOfferContext.sessionSalt.length===64&&t100&&this.messageQueue.splice(0,this.messageQueue.length-50).forEach((a,o)=>{this._secureWipeMemory(a,`periodicCleanup[${o}]`)}),this.processedMessageIds&&this.processedMessageIds.size>1e3&&this.processedMessageIds.clear(),await this._forceGarbageCollection(),this._secureLog("debug","\u{1F512} Periodic memory cleanup completed")}catch(e){this._secureLog("error","\u274C Error during periodic memory cleanup",{errorType:e.constructor.name,errorMessage:e.message})}finally{this._secureMemoryManager.isCleaning=!1}}_createSecureErrorMessage(e,t="unknown"){try{let r=this._categorizeError(e),i=this._getSafeErrorMessage(r,t);return this._secureLog("error","Internal error occurred",{category:r,context:t,errorType:e?.constructor?.name||"Unknown",timestamp:Date.now()}),this._trackErrorFrequency(r),i}catch(r){return this._secureLog("error","Error handling failed",{originalError:e?.message||"Unknown",handlingError:r.message}),"An unexpected error occurred"}}_categorizeError(e){if(!e||!e.message)return this._secureErrorHandler.errorCategories.UNKNOWN;let t=e.message.toLowerCase();return t.includes("crypto")||t.includes("key")||t.includes("encrypt")||t.includes("decrypt")||t.includes("sign")||t.includes("verify")||t.includes("ecdh")||t.includes("ecdsa")?this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC:t.includes("network")||t.includes("connection")||t.includes("timeout")||t.includes("webrtc")||t.includes("peer")?this._secureErrorHandler.errorCategories.NETWORK:t.includes("invalid")||t.includes("validation")||t.includes("format")||t.includes("type")?this._secureErrorHandler.errorCategories.VALIDATION:t.includes("system")||t.includes("internal")||t.includes("memory")||t.includes("resource")?this._secureErrorHandler.errorCategories.SYSTEM:this._secureErrorHandler.errorCategories.UNKNOWN}_getSafeErrorMessage(e,t){let r={[this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC]:{key_generation:"Security initialization failed",key_import:"Security verification failed",key_derivation:"Security setup failed",encryption:"Message security failed",decryption:"Message verification failed",signature:"Authentication failed",default:"Security operation failed"},[this._secureErrorHandler.errorCategories.NETWORK]:{connection:"Connection failed",timeout:"Connection timeout",peer:"Peer connection failed",webrtc:"Communication failed",default:"Network operation failed"},[this._secureErrorHandler.errorCategories.VALIDATION]:{format:"Invalid data format",type:"Invalid data type",structure:"Invalid data structure",default:"Validation failed"},[this._secureErrorHandler.errorCategories.SYSTEM]:{memory:"System resource error",resource:"System resource unavailable",internal:"Internal system error",default:"System operation failed"},[this._secureErrorHandler.errorCategories.UNKNOWN]:{default:"An unexpected error occurred"}},i=r[e]||r[this._secureErrorHandler.errorCategories.UNKNOWN],n="default";return t.includes("key")||t.includes("crypto")?n=e===this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC?"key_generation":"default":t.includes("connection")||t.includes("peer")?n=e===this._secureErrorHandler.errorCategories.NETWORK?"connection":"default":(t.includes("validation")||t.includes("format"))&&(n=e===this._secureErrorHandler.errorCategories.VALIDATION?"format":"default"),i[n]||i.default}_trackErrorFrequency(e){let t=Date.now();t-this._secureErrorHandler.lastErrorTime>6e4&&this._secureErrorHandler.errorCounts.clear();let r=this._secureErrorHandler.errorCounts.get(e)||0;this._secureErrorHandler.errorCounts.set(e,r+1),this._secureErrorHandler.lastErrorTime=t;let i=Array.from(this._secureErrorHandler.errorCounts.values()).reduce((n,a)=>n+a,0);i>this._secureErrorHandler.errorThreshold&&(this._secureErrorHandler.isInErrorMode=!0,this._secureLog("warn","\u26A0\uFE0F High error frequency detected - entering error mode",{totalErrors:i,threshold:this._secureErrorHandler.errorThreshold}))}_throwSecureError(e,t="unknown"){let r=this._createSecureErrorMessage(e,t);throw new Error(r)}_getErrorHandlingStats(){return{errorCounts:Object.fromEntries(this._secureErrorHandler.errorCounts),isInErrorMode:this._secureErrorHandler.isInErrorMode,lastErrorTime:this._secureErrorHandler.lastErrorTime,errorThreshold:this._secureErrorHandler.errorThreshold}}_resetErrorHandlingSystem(){this._secureErrorHandler.errorCounts.clear(),this._secureErrorHandler.isInErrorMode=!1,this._secureErrorHandler.lastErrorTime=0,this._secureLog("info","\u{1F504} Error handling system reset")}_getMemoryManagementStats(){return{totalCleanups:this._secureMemoryManager.memoryStats.totalCleanups,failedCleanups:this._secureMemoryManager.memoryStats.failedCleanups,lastCleanup:this._secureMemoryManager.memoryStats.lastCleanup,isCleaning:this._secureMemoryManager.isCleaning,queueLength:this._secureMemoryManager.cleanupQueue.length}}_validateAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C Global API not found during integrity validation"),!1;let e=["sendMessage","getConnectionStatus","getSecurityStatus","sendFile","disconnect"],t=e.filter(a=>!window.secureBitChat[a]||typeof window.secureBitChat[a]!="function");if(t.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - missing methods",{missingMethods:t}),!1;let r={test:!0},n=e.map(a=>{try{return window.secureBitChat[a].bind(r)}catch{return null}}).filter(a=>a===null);if(n.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - method binding issues",{unboundMethods:n.length}),!1;try{let a="_integrity_test_"+Date.now();return Object.defineProperty(window.secureBitChat,a,{value:"test",writable:!0,configurable:!0}),this._secureLog("error","\u274C Global API integrity validation failed - API is mutable"),delete window.secureBitChat[a],!1}catch{this._secureLog("debug","\u2705 Global API immutability verified")}return this._secureLog("info","\u2705 Global API integrity validation passed"),!0}catch(e){return this._secureLog("error","\u274C Global API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_validateCryptographicSecurity(){let e=["hasRateLimiting"],t=e.filter(n=>!this.securityFeatures[n]);t.length>0&&(this._secureLog("error","\u{1F6A8} CRITICAL: Missing critical rate limiting feature",{missing:t,currentFeatures:this.securityFeatures,action:"Rate limiting will be forced enabled"}),t.forEach(n=>{this.securityFeatures[n]=!0,this._secureLog("warn",`\u26A0\uFE0F Forced enable critical: ${n} = true`)}));let r=Object.keys(this.securityFeatures).filter(n=>this.securityFeatures[n]),i=["hasEncryption","hasECDH","hasECDSA"].filter(n=>this.securityFeatures[n]);return this._secureLog("info","\u2705 Cryptographic security validation passed",{criticalFeatures:e.length,availableFeatures:r.length,encryptionFeatures:i.length,totalSecurityFeatures:r.length,note:"Encryption features will be enabled after key generation",currentState:{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasRateLimiting:this.securityFeatures.hasRateLimiting}}),!0}_syncSecurityFeaturesWithTariff(){this._secureLog("info","\u2705 All security features enabled by default - no payment required"),["hasEncryption","hasECDH","hasECDSA","hasMutualAuth","hasMetadataProtection","hasEnhancedReplayProtection","hasNonExtractableKeys","hasRateLimiting","hasEnhancedValidation","hasPFS","hasNestedEncryption","hasPacketPadding","hasPacketReordering","hasAntiFingerprinting","hasFakeTraffic","hasDecoyChannels","hasMessageChunking"].forEach(t=>{this.securityFeatures[t]=!0}),this._secureLog("info","\u2705 All security features enabled by default",{enabledFeatures:Object.keys(this.securityFeatures).filter(t=>this.securityFeatures[t]).length,totalFeatures:Object.keys(this.securityFeatures).length})}_emergencyShutdown(e="Security breach"){this._secureLog("error","\u274C EMERGENCY SHUTDOWN: ${reason}");try{this.encryptionKey=null,this.macKey=null,this.metadataKey=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.messageQueue=[],this.processedMessageIds.clear(),this.packetBuffer.clear(),this.onStatusChange&&this.onStatusChange("security_breach"),this._secureLog("info","\u{1F512} Emergency shutdown completed")}catch(t){this._secureLog("error","\u274C Error during emergency shutdown:",{errorType:t?.constructor?.name||"Unknown"})}}_finalizeSecureInitialization(){if(this._startKeySecurityMonitoring(),!this._verifyAPIIntegrity()){this._secureLog("error","\u274C Security initialization failed");return}this._startSecurityMonitoring(),this._logCleanupInterval=this._trackActiveTimer(setInterval(()=>{this._cleanupLogs()},3e5)),this._secureLog("info","\u2705 Secure WebRTC Manager initialization completed"),this._secureLog("info","\u{1F512} Global exposure protection: Monitoring only, no automatic removal")}_startSecurityMonitoring(){this._secureLog("info","\u{1F527} Security monitoring moved to unified scheduler")}_validateConnection(e=!0){let t=this.dataChannel&&this.dataChannel.readyState==="open",r=this.isVerified,i=t&&r;if(!i&&e){if(!t)throw new Error("Data channel not ready");if(!r)throw new Error("Connection not verified")}return i}_enforceVerificationGate(e="unknown",t=!0){if(!this.isVerified){let r=`SECURITY VIOLATION: ${e} blocked - connection not cryptographically verified`;if(this._secureLog("error",r,{operation:e,isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey),timestamp:Date.now()}),t)throw new Error(r);return!1}return!0}_setVerifiedStatus(e,t="unknown",r=null){if(e){if(!this.encryptionKey||!this.macKey)throw new Error("Cannot set verified=true without encryption keys");if(!t||t==="unknown")throw new Error("Cannot set verified=true without specifying verification method");if(t.includes("SAS")&&!this.localVerificationConfirmed)throw this._secureLog("error","Blocked verified transition without local SAS confirmation",{verificationMethod:t,localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed}),new Error("Cannot set verified=true without local SAS confirmation");this._secureLog("info","Connection verified through cryptographic verification",{verificationMethod:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,keyFingerprint:this.keyFingerprint,timestamp:Date.now(),verificationData:r?"provided":"none"})}this.isVerified=e,e?this.onStatusChange("connected"):this.onStatusChange("disconnected")}markGroupLinkVerified(e="group_roster_signature"){let t=this._sbq2;if(!this._isSbq2()||!t||!t.completed||!t.proofVerified||!t.keysDerived)throw new Error("Group link cannot be released: the in-band handshake has not completed");if(!this.encryptionKey||!this.macKey)throw new Error("Group link cannot be released: session keys are missing");if(this.isVerified)return!0;this.localVerificationConfirmed=!0,this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this._setVerifiedStatus(!0,"GROUP_ROSTER_SIGNATURE",{reason:e,timestamp:Date.now()}),this._enforceVerificationGate("group_link_release",!1),this.onStatusChange?.("verified");try{this.processMessageQueue()}catch{}return!0}_createFileMessageAAD(e,t=null){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in _createFileMessageAAD. Manager may not be fully initialized.");return this._createMessageAAD(e,t,!0)}_validateFileMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);if(Date.now()-r.timestamp>18e5)throw new Error("AAD timestamp too old - possible replay attack");return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}_validateIncomingSequenceNumber(e,t="unknown"){try{if(!this.replayProtectionEnabled)return!0;if(typeof e!="number"||!Number.isFinite(e))return this._secureLog("warn","Missing or non-numeric sequence number - rejecting",{receivedType:typeof e,context:t,timestamp:Date.now()}),!1;if(ethis.expectedSequenceNumber+this.maxSequenceGap)return this._secureLog("warn","Sequence number gap too large - possible DoS attack",{received:e,expected:this.expectedSequenceNumber,gap:e-this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.has(e))return this._secureLog("warn","Duplicate sequence number detected - replay attack",{received:e,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.add(e),this.replayWindow.size>this.replayWindowSize){let r=Math.min(...this.replayWindow);this.replayWindow.delete(r)}if(e===this.expectedSequenceNumber)for(this.expectedSequenceNumber++;this.replayWindow.has(this.expectedSequenceNumber-this.replayWindowSize-1);)this.replayWindow.delete(this.expectedSequenceNumber-this.replayWindowSize-1);return this._secureLog("debug","Sequence number validation successful",{received:e,expected:this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!0}catch(r){return this._secureLog("error","Sequence number validation failed",{error:r.message,context:t,timestamp:Date.now()}),!1}}_validateMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(!this._validateIncomingSequenceNumber(r.sequenceNumber,r.messageType))throw new Error("Sequence number validation failed - possible replay or DoS attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}getAntiReplayStatus(){let e={replayProtectionEnabled:this.replayProtectionEnabled,replayWindowSize:this.replayWindowSize,currentReplayWindowSize:this.replayWindow.size,sequenceNumber:this.sequenceNumber,expectedSequenceNumber:this.expectedSequenceNumber,maxSequenceGap:this.maxSequenceGap,replayWindowEntries:Array.from(this.replayWindow).sort((t,r)=>t-r)};return this._secureLog("info","Anti-replay status retrieved",e),e}configureAntiReplayProtection(e){try{if(e.windowSize!==void 0){if(e.windowSize<16||e.windowSize>1024)throw new Error("Replay window size must be between 16 and 1024");this.replayWindowSize=e.windowSize}if(e.maxGap!==void 0){if(e.maxGap<10||e.maxGap>1e3)throw new Error("Max sequence gap must be between 10 and 1000");this.maxSequenceGap=e.maxGap}return e.enabled!==void 0&&(this.replayProtectionEnabled=e.enabled),this._secureLog("info","Anti-replay protection configured",e),!0}catch(t){return this._secureLog("error","Failed to configure anti-replay protection",{error:t.message}),!1}}async getRealSecurityLevel(){try{let e={ecdhKeyExchange:!!this.ecdhKeyPair,ecdsaSignatures:!!this.ecdsaKeyPair,aesEncryption:!!this.encryptionKey,messageIntegrity:!!this.hmacKey,replayProtection:this.replayProtectionEnabled,dtlsFingerprint:!!(this.expectedDTLSFingerprint&&this._peerDTLSFingerprint),sasCode:!!this.verificationCode&&this.localVerificationConfirmed===!0,metadataProtection:!0,trafficObfuscation:!0,perfectForwardSecrecy:this.isRatchetActive?.()===!0,rateLimiter:!0,connectionId:this.connectionId,keyFingerprint:this.keyFingerprint,currentSecurityLevel:"maximum",timestamp:Date.now()},t=await this.calculateAndReportSecurityLevel();return t?{...t,...e}:{...e,level:"INITIALIZING",score:0,isRealData:!1}}catch(e){throw this._secureLog("error","Failed to calculate real security level",{error:e.message}),e}}_extractDTLSFingerprintFromSDP(e){try{if(!e||typeof e!="string")throw new Error("Invalid SDP provided");let t=/a=fingerprint:([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/g,r=[],i;for(;(i=t.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()});if(r.length===0){let a=/fingerprint\s*=\s*([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/gi;for(;(i=a.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()})}if(r.length===0)throw this._secureLog("warn","No DTLS fingerprints found in SDP - this may be normal for some WebRTC implementations",{sdpLength:e.length,sdpPreview:e.substring(0,200)+"..."}),new Error("No DTLS fingerprints found in SDP");return[...r].sort((a,o)=>{let c=a.algorithm==="sha-256",d=o.algorithm==="sha-256";if(c!==d)return c?-1:1;let u=a.algorithm.localeCompare(o.algorithm);return u!==0?u:a.fingerprint.localeCompare(o.fingerprint)})[0].fingerprint}catch(t){throw this._secureLog("error","Failed to extract DTLS fingerprint from SDP",{error:t.message,sdpLength:e?.length||0}),new Error(`DTLS fingerprint extraction failed: ${t.message}`)}}async _validateDTLSFingerprint(e,t,r="unknown"){try{if(!e||!t)throw new Error("Missing fingerprint for validation");let i=e.toLowerCase().replace(/:/g,""),n=t.toLowerCase().replace(/:/g,"");if(i!==n)throw this._secureLog("error","DTLS fingerprint mismatch - possible MITM attack",{context:r,timestamp:Date.now()}),new Error(`DTLS fingerprint mismatch - possible MITM attack in ${r}`);return this._secureLog("info","DTLS fingerprint validation successful",{context:r,timestamp:Date.now()}),!0}catch(i){throw this._secureLog("error","DTLS fingerprint validation failed",{error:i.message,context:r}),i}}async _computeSAS(e,t,r){try{if(!e){let b=[];throw e||b.push("keyMaterialRaw"),new Error(`Missing required parameters for SAS computation: ${b.join(", ")}`)}let i=new TextEncoder,n=(b,w)=>{if(typeof b!="string"||b.trim().length===0)throw new Error(`Security error: ${w} must be a non-empty DTLS fingerprint string for SAS computation`);return b.trim().toLowerCase()},a=n(t,"localFP"),o=n(r,"remoteFP"),c=i.encode("webrtc-sas|"+[a,o].sort().join("|")),d;if(e instanceof ArrayBuffer)d=e;else if(e instanceof Uint8Array)d=e.buffer;else if(typeof e=="string"){let b=e.replace(/:/g,"").replace(/\s/g,""),w=new Uint8Array(b.length/2);for(let M=0;M>>0,g=String(S%1e7).padStart(7,"0");return this._secureLog("info","SAS code computed successfully",{localFP:a.substring(0,16)+"...",remoteFP:o.substring(0,16)+"...",sasLength:g.length,timestamp:Date.now()}),g}catch(i){throw this._secureLog("error","SAS computation failed",{error:i.message,keyMaterialType:typeof e,hasLocalFP:!!t,hasRemoteFP:!!r,timestamp:Date.now()}),new Error(`SAS computation failed: ${i.message}`)}}_dispatchAppEvent(e){if(!this._emitGlobalEvents)return!1;try{return document.dispatchEvent(e)}catch{return!1}}_isSbq2(){return this._handshakeMode==="sbq2"}_latchHandshakeMode(e){if(this._handshakeMode&&this._handshakeMode!==e)throw new Error(`handshake format cannot change mid-session (${this._handshakeMode} -> ${e})`);this._handshakeMode=e}_sbq2State(){return this._sbq2||(this._sbq2={role:null,localDescriptor:null,remoteDescriptor:null,localBlob:null,remoteBlob:null,remoteCommitment:null,transcript:null,peerEcdhKey:null,peerEcdsaKey:null,blobSent:!1,proofSent:!1,proofVerified:!1,keysDerived:!1,pendingProof:null,completed:!1,timer:null,startedAt:0}),this._sbq2}_sbq2Abort(e,t){let r=this._sbq2;r?.timer&&(clearTimeout(r.timer),r.timer=null),this._secureLog("error","SBQ2 handshake aborted",{code:e});try{this.deliverMessageToUI(t,"system")}catch{}try{this.onStatusChange?.("failed")}catch{}try{this.disconnect()}catch{}}async _exportSpki(e){return new Uint8Array(await crypto.subtle.exportKey("spki",e))}async _sbq2BuildLocalBlob(e){if(!this.ecdhKeyPair?.publicKey||!this.ecdsaKeyPair?.publicKey)throw new Error("SBQ2: key pairs are not ready");let t=Cn({role:e,ecdhSpki:await this._exportSpki(this.ecdhKeyPair.publicKey),ecdsaSpki:await this._exportSpki(this.ecdsaKeyPair.publicKey)}),i=await Ht(async a=>new Uint8Array(await crypto.subtle.digest("SHA-256",a)),t),n=this._sbq2State();return n.role=e,n.localBlob=t,{blob:t,commitment:i}}async _sbq2BuildDescriptor(e,{bindingTag:t=null,lifetimeMs:r=600*1e3}={}){let i=this.peerConnection?.localDescription?.sdp;if(!i)throw new Error("SBQ2: no local description to encode");let n=e===de.OFFER?ve.OFFER:ve.ANSWER,{commitment:a}=await this._sbq2BuildLocalBlob(n),o=bn(i),c=_n({type:e,expiresAtMs:Date.now()+r,sdpFields:{...o,candidates:Pr(o.candidates)},commitment:a,...e===de.ANSWER?{bindingTag:t}:{}}),d=this._sbq2State();return d.localDescriptor=c,this._secureLog("info","SBQ2 descriptor built",{type:e===de.OFFER?"offer":"answer",bytes:c.length,candidates:Pr(o.candidates).length}),{bytes:c,text:vn(c)}}_sbq2AdoptRemoteDescriptor(e,t){let r=Fr(e);if(r.type!==t)throw new Error(`expected an ${t===de.OFFER?"invitation":"answer"}, got the other kind`);if(!r.commitment)throw new Error("the invitation carries no key commitment");let i=this._sbq2State();return i.remoteDescriptor=e,i.remoteCommitment=r.commitment,r}async _runSbq2KeyExchange(){let e=this._sbq2State();if(!(e.completed||e.blobSent)){if(e.startedAt=Date.now(),!e.localBlob||!e.localDescriptor||!e.remoteDescriptor||!e.remoteCommitment){this._sbq2Abort("incomplete_state","The secure handshake could not start because the connection setup is incomplete. Please start a new invitation.");return}e.timer=setTimeout(()=>{e.completed||this._sbq2Abort("timeout","The other side did not complete the secure handshake in time. Please try connecting again.")},s.SBQ2_KEY_EXCHANGE_TIMEOUT_MS);try{this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_BLOB,v:2,blob:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(e.localBlob.buffer.slice(e.localBlob.byteOffset,e.localBlob.byteOffset+e.localBlob.byteLength))})),e.blobSent=!0,this._secureLog("info","SBQ2 key blob sent",{bytes:e.localBlob.length})}catch{this._sbq2Abort("blob_send_failed","The secure handshake could not be sent. Please try connecting again.")}}}async _sbq2HandleHandshakeFrame(e){let t=s.MESSAGE_TYPES,r=this._sbq2State();if(!this._isSbq2()){this._secureLog("error","Rejected SBQ2 handshake frame on a non-SBQ2 session",{messageType:e?.type});return}try{if(e.type===t.KEY_BLOB){if(r.remoteBlob){this._sbq2Abort("duplicate_blob","The secure handshake was sent twice. The connection has been closed for safety.");return}let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.blob||"")));await Mn(crypto.subtle,i,r.remoteCommitment);let n=kn(i),a=r.role===ve.OFFER?ve.ANSWER:ve.OFFER;if(n.role!==a){this._sbq2Abort("role_mismatch","The other side sent the wrong kind of handshake. The connection has been closed for safety.");return}r.remoteBlob=i,r.peerEcdhKey=await crypto.subtle.importKey("spki",n.ecdhSpki,{name:"ECDH",namedCurve:"P-384"},!1,[]),r.peerEcdsaKey=await crypto.subtle.importKey("spki",n.ecdsaSpki,{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),await this._sbq2CompleteExchange();return}if(e.type===t.KEY_PROOF){let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.sig||"")));if(!r.transcript||!r.peerEcdsaKey){r.pendingProof=i;return}await this._sbq2VerifyProof(i);return}}catch(i){let n=i?.code||"handshake_failed",a=n==="commitment_mismatch"?"The key material does not match the invitation you scanned. This can mean someone tampered with the connection, so it has been closed.":"The secure handshake failed. The connection has been closed for safety.";this._sbq2Abort(n,a)}}async _sbq2CompleteExchange(){let e=this._sbq2State();if(e.keysDerived||!e.remoteBlob||!e.localBlob)return;this._peerSupportsRatchet=!0;let t=e.role===ve.OFFER;e.transcript=An({offerDescriptor:t?e.localDescriptor:e.remoteDescriptor,answerDescriptor:t?e.remoteDescriptor:e.localDescriptor,offerBlob:t?e.localBlob:e.remoteBlob,answerBlob:t?e.remoteBlob:e.localBlob}),this.sessionSalt=await xn(crypto.subtle,e.transcript),this.peerPublicKey=e.peerEcdhKey,this.peerECDHPublicKey=e.peerEcdhKey;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,e.peerEcdhKey,this.sessionSalt);await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),await this._initializeRatchet(r,t),e.keysDerived=!0;let i=new Uint8Array(await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},this.ecdsaKeyPair.privateKey,Vr(e.transcript)));if(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_PROOF,sig:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(i.buffer)})),e.proofSent=!0,e.pendingProof){let n=e.pendingProof;e.pendingProof=null,await this._sbq2VerifyProof(n)}}async _sbq2VerifyProof(e){let t=this._sbq2State();if(t.proofVerified)return;if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},t.peerEcdsaKey,e,Vr(t.transcript))){this._sbq2Abort("bad_proof","The other side could not prove it owns its identity key. The connection has been closed for safety.");return}t.proofVerified=!0,this.verificationCode=await Rn(crypto.subtle,{ecdhPrivateKey:this.ecdhKeyPair.privateKey,peerEcdhPublicKey:t.peerEcdhKey,transcript:t.transcript});let i=this.expectedDTLSFingerprint,n=this._peerDTLSFingerprint;i&&n&&this._setSASMaterialReady(i,n),t.completed=!0,t.timer&&(clearTimeout(t.timer),t.timer=null),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this._secureLog("info","SBQ2 in-band key exchange complete",{elapsedMs:Date.now()-t.startedAt,ratchetActive:this.isRatchetActive?.()===!0});try{this.onKeyExchange?.(this.keyFingerprint)}catch{}this._notifyVerificationReadyIfPossible(),this.initiateVerification()}_decodeKeyFingerprint(e){try{if(!e||typeof e!="string")throw new Error("Invalid hex string provided");return window.EnhancedSecureCryptoUtils.hexToUint8Array(e)}catch(t){throw this._secureLog("error","Key fingerprint decoding failed",{error:t.message,inputType:typeof e,inputLength:e?.length||0}),new Error(`Key fingerprint decoding failed: ${t.message}`)}}_emergencyWipeOnFingerprintMismatch(e="DTLS fingerprint mismatch"){try{this._secureLog("error","\u{1F6A8} EMERGENCY: Initiating security wipe due to fingerprint mismatch",{reason:e,timestamp:Date.now()}),this._secureWipeKeys(),this._secureWipeMemory(this.encryptionKey,"emergency_wipe"),this._secureWipeMemory(this.macKey,"emergency_wipe"),this._secureWipeMemory(this.metadataKey,"emergency_wipe"),this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this.isVerified=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.disconnect(),this.deliverMessageToUI("\u{1F6A8} SECURITY BREACH: Connection terminated due to fingerprint mismatch. Possible MITM attack detected!","system")}catch(t){this._secureLog("error","Failed to perform emergency wipe",{error:t.message})}}getCurrentDTLSFingerprint(){try{if(!this.expectedDTLSFingerprint)throw new Error("No DTLS fingerprint available - connection not established");return this.expectedDTLSFingerprint}catch(e){throw this._secureLog("error","Failed to get current DTLS fingerprint",{error:e.message}),e}}disableStrictDTLSValidation(){this.strictDTLSValidation=!1,this._secureLog("warn","\u26A0\uFE0F Strict DTLS validation disabled - security reduced",{timestamp:Date.now()}),this.deliverMessageToUI("\u26A0\uFE0F DTLS validation disabled for debugging","system")}enableStrictDTLSValidation(){this.strictDTLSValidation=!0,this._secureLog("info","\u2705 Strict DTLS validation re-enabled",{timestamp:Date.now()}),this.deliverMessageToUI("\u2705 DTLS validation re-enabled","system")}async _initializeRatchet(e,t){let r=e?.ratchetRoot;if(!r)return!1;if(!this._peerSupportsRatchet)return this._secureLog("warn","Peer did not advertise Double Ratchet \u2014 falling back to static session keys",{localVersion:s.RATCHET_VERSION}),window.EnhancedSecureCryptoUtils.zeroizeBuffer(r),!1;try{let i=this.peerPublicKey||this.peerECDHPublicKey;if(!i||!this.ecdhKeyPair?.privateKey)throw new Error("handshake ECDH keys unavailable");let n=new zt;return await n.init({sharedSecret:r,sessionSalt:new Uint8Array(this.sessionSalt||[]),selfPrivateKey:this.ecdhKeyPair.privateKey,remotePublicKey:i,isInitiator:t}),this._ratchet=n,this.securityFeatures.hasPFS=!0,this._secureLog("info","\u{1F510} Double Ratchet active \u2014 per-message forward secrecy enabled",{role:t?"initiator":"responder"}),!0}catch(i){return this._ratchet=null,this.securityFeatures.hasPFS=!1,this._secureLog("error","Double Ratchet initialisation failed \u2014 continuing with static session keys",{errorType:i?.constructor?.name||"Unknown"}),!1}finally{window.EnhancedSecureCryptoUtils.zeroizeBuffer(r)}}isRatchetActive(){return!!this._ratchet?.isInitialised}async _generateEphemeralECDHKeys(){try{this._secureLog("info","\u{1F511} Generating ephemeral ECDH keys for PFS",{sessionStartTime:this.sessionStartTime,timestamp:Date.now()});let e=await window.EnhancedSecureCryptoUtils.generateECDHKeyPair();if(!e||!this._validateKeyPairConstantTime(e))throw new Error("Ephemeral ECDH key pair validation failed");let t=this.currentSession?.sessionId||`session_${Date.now()}`;return this.ephemeralKeyPairs.set(t,{keyPair:e,timestamp:Date.now(),sessionId:t}),this._secureLog("info","\u2705 Ephemeral ECDH keys generated for PFS",{timestamp:Date.now()}),e}catch(e){throw this._secureLog("error","\u274C Failed to generate ephemeral ECDH keys",{error:e.message}),new Error(`Ephemeral key generation failed: ${e.message}`)}}async _hardWipeOldKeys(){try{this._secureLog("info","\u{1F9F9} Performing hard wipe of old keys for PFS",{oldKeysCount:this.oldKeys.size,timestamp:Date.now()});for(let[e,t]of this.oldKeys.entries())t.encryptionKey&&this._secureWipeMemory(t.encryptionKey,"pfs_key_wipe"),t.macKey&&this._secureWipeMemory(t.macKey,"pfs_key_wipe"),t.metadataKey&&this._secureWipeMemory(t.metadataKey,"pfs_key_wipe"),t.encryptionKey=null,t.macKey=null,t.metadataKey=null,t.keyFingerprint=null;this.oldKeys.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Hard wipe of old keys completed for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to perform hard wipe of old keys",{error:e.message})}}async _wipeEphemeralKeys(){try{this._secureLog("info","\u{1F9F9} Wiping ephemeral keys for PFS",{ephemeralKeysCount:this.ephemeralKeyPairs.size,timestamp:Date.now()});for(let[e,t]of this.ephemeralKeyPairs.entries())t.keyPair?.privateKey&&this._secureWipeMemory(t.keyPair.privateKey,"ephemeral_key_wipe"),t.keyPair?.publicKey&&this._secureWipeMemory(t.keyPair.publicKey,"ephemeral_key_wipe"),t.keyPair=null,t.timestamp=null,t.sessionId=null;this.ephemeralKeyPairs.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Ephemeral keys wiped for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to wipe ephemeral keys",{error:e.message})}}async _encryptFileMessage(e,t){try{if(!this.encryptionKey)throw new Error("No encryption key available for file message");let r=typeof e=="string"?e:JSON.stringify(e),n={type:"encrypted_file_message",encryptedData:await window.EnhancedSecureCryptoUtils.encryptDataWithAAD(r,this.encryptionKey,t),aad:t,timestamp:Date.now(),keyFingerprint:this.keyFingerprint};return JSON.stringify(n)}catch(r){throw this._secureLog("error","Failed to encrypt file message",{error:r.message}),new Error(`File message encryption failed: ${r.message}`)}}async _decryptFileMessage(e){try{let t=JSON.parse(e);if(t.type!=="encrypted_file_message")throw new Error("Invalid encrypted file message type");if(t.keyFingerprint!==this.keyFingerprint)throw new Error("Key fingerprint mismatch in encrypted file message");let r=this._validateMessageAAD(t.aad,"file_message");if(!this.encryptionKey)throw new Error("No encryption key available for file message decryption");return{decryptedData:await window.EnhancedSecureCryptoUtils.decryptDataWithAAD(t.encryptedData,this.encryptionKey,t.aad),aad:r}}catch(t){throw this._secureLog("error","Failed to decrypt file message",{error:t.message}),new Error(`File message decryption failed: ${t.message}`)}}_validateEncryptionKeys(e=!0){let t=!!(this.encryptionKey&&this.macKey&&this.metadataKey);if(!t&&e)throw new Error("Encryption keys not initialized");return t}async _tryReinitializeEncryptionKeys(){try{if(this.encryptionKey&&this.macKey&&this.metadataKey)return!0;let e=!!(this.ecdhKeyPair?.privateKey&&(this.peerPublicKey||this.peerECDHPublicKey)),t=this.peerPublicKey||this.peerECDHPublicKey;if(!e||!t||!this.sessionSalt)return!1;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,t,this.sessionSalt);return await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),!!(this.encryptionKey&&this.macKey&&this.metadataKey)}catch(e){return this._secureLog("error","Failed to reinitialize encryption keys",{error:e.message}),!1}}_isFileMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type&&t.type.startsWith("file_")}catch{return!1}return typeof e=="object"&&e.type?e.type.startsWith("file_"):!1}_isSystemMessage(e){let t=[s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.SECURITY_UPGRADE,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY];if(typeof e=="string")try{let r=JSON.parse(e);return t.includes(r.type)}catch{return!1}return typeof e=="object"&&e.type?t.includes(e.type):!1}_isFakeMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type===s.MESSAGE_TYPES.FAKE||t.isFakeTraffic===!0}catch{return!1}return typeof e=="object"&&e!==null?e.type===s.MESSAGE_TYPES.FAKE||e.isFakeTraffic===!0:!1}_withErrorHandling(e,t,r=null){try{return e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}async _withAsyncErrorHandling(e,t,r=null){try{return await e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}_getMessageType(e){if(typeof e=="string")try{return JSON.parse(e).type||null}catch{return null}return typeof e=="object"&&e!==null&&e.type||null}_resetNotificationFlags(){this.lastSecurityLevelNotification=null,this.verificationNotificationSent=!1,this.verificationInitiationSent=!1,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.disconnectNotificationSent=!1,this.reconnectionFailedNotificationSent=!1,this.peerDisconnectNotificationSent=!1,this.connectionClosedNotificationSent=!1,this.fakeTrafficDisabledNotificationSent=!1,this.advancedFeaturesDisabledNotificationSent=!1,this.securityUpgradeNotificationSent=!1,this.lastSecurityUpgradeStage=null,this.securityCalculationNotificationSent=!1,this.lastSecurityCalculationLevel=null}_isFilteredMessage(e){return Object.values(s.FILTERED_RESULTS).includes(e)}_cleanupLogs(){this._logCounts.size>500&&(this._logCounts.clear(),this._secureLog("debug","\u{1F9F9} Log counts cleared due to size limit"));let e=Date.now(),t=3e5,r=0;for(let[i,n]of this._logCounts.entries())n>10&&r++;r>20&&(this._logCounts.clear(),this._secureLog("warn","\u{1F6A8} Emergency log cleanup due to suspicious patterns")),this._logSecurityViolations>0&&r<5&&(this._logSecurityViolations=Math.max(0,this._logSecurityViolations-1)),(!this._lastIVCleanupTime||Date.now()-this._lastIVCleanupTime>3e5)&&(this._cleanupOldIVs(),this._lastIVCleanupTime=Date.now()),(!this._secureMemoryManager.memoryStats.lastCleanup||Date.now()-this._secureMemoryManager.memoryStats.lastCleanup>6e5)&&(this._performPeriodicMemoryCleanup().catch(i=>{this._secureLog("error","Periodic cleanup failed",{errorType:i?.constructor?.name||"Unknown"})}),this._secureMemoryManager.memoryStats.lastCleanup=Date.now())}_getLoggingStats(){let e={isProductionMode:this._isProductionMode,debugMode:this._debugMode,currentLogLevel:this._currentLogLevel,logCountsSize:this._logCounts.size,maxLogCount:this._maxLogCount,securityViolations:this._logSecurityViolations||0,maxSecurityViolations:this._maxLogSecurityViolations||3,systemStatus:this._currentLogLevel===-1?"DISABLED":"ACTIVE"},t={};for(let[r,i]of Object.entries(e))typeof i=="string"&&this._containsSensitiveContent(i)?t[r]="[SENSITIVE_DATA_REDACTED]":t[r]=i;return t}async _emergencyDisableLogging(){this._currentLogLevel=-1,this._logCounts.clear(),this._logSecurityViolations&&(this._logSecurityViolations=0),this._secureLog=()=>{arguments[0]==="error"&&this._originalConsole?.error&&this._originalConsole.error("\u{1F6A8} SECURITY: Logging system disabled - potential data exposure prevented")},this._originalSanitizeString=this._sanitizeString,this._originalSanitizeLogData=this._sanitizeLogData,this._originalAuditLogMessage=this._auditLogMessage,this._originalContainsSensitiveContent=this._containsSensitiveContent,this._sanitizeString=()=>"[LOGGING_DISABLED]",this._sanitizeLogData=()=>({error:"LOGGING_DISABLED"}),this._auditLogMessage=()=>!1,this._containsSensitiveContent=()=>!0,await this._performNaturalCleanup(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Secure logging system disabled due to potential data exposure")}_resetLoggingSystem(){this._secureLog("info","\u{1F527} Resetting logging system after emergency shutdown"),this._sanitizeString=this._originalSanitizeString||(e=>e),this._sanitizeLogData=this._originalSanitizeLogData||(e=>e),this._auditLogMessage=this._originalAuditLogMessage||(()=>!0),this._containsSensitiveContent=this._originalContainsSensitiveContent||(()=>!1),this._logSecurityViolations=0,this._secureLog("info","\u2705 Logging system reset successfully")}_auditLogMessage(e,t){if(!t||typeof t!="object")return!0;let r=JSON.stringify(t);if(this._containsSensitiveContent(e))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log message"),!1;if(this._containsSensitiveContent(r))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log data"),!1;let i=["secret","token","password","credential","auth","fingerprint","salt","signature","private_key","api_key","private","encryption","mac","metadata","session","jwt","bearer","key","hash","digest","nonce","iv","cipher"],n=r.toLowerCase();for(let a of i)if(n.includes(a)&&!this._safeFieldsWhitelist.has(a))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: Dangerous pattern detected in log: ${a}`),!1;for(let[a,o]of Object.entries(t))if(typeof o=="string"&&this._hasHighEntropy(o))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: High entropy value detected in log field: ${a}`),!1;return!0}initializeFileTransfer(){try{if(this._sessionAlive===!1)return;if(this._secureLog("info","\u{1F527} Initializing Enhanced Secure File Transfer system..."),this.fileTransferSystem){this._secureLog("info","\u2705 File transfer system already initialized");return}if(!!!(this.dataChannel&&this.dataChannel.readyState==="open")){if(this._secureLog("warn","\u26A0\uFE0F Data channel not open, deferring file transfer initialization"),this.dataChannel){let i=()=>{this._secureLog("info","\u{1F504} DataChannel opened, initializing file transfer..."),this.initializeFileTransfer()};this.dataChannel.addEventListener("open",i,{once:!0})}return}if(!this.isVerified){this._secureLog("warn","\u26A0\uFE0F Connection not verified yet, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(500);return}if(this.fileTransferSystem&&(this._secureLog("info","\u{1F9F9} Cleaning up existing file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),!this.encryptionKey||!this.macKey){this._secureLog("warn","\u26A0\uFE0F Encryption keys not ready, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(1e3);return}let t=i=>{try{this._secureLog("info","\u{1F3C1} Sender transfer summary",{summary:i}),this.onFileProgress&&this.onFileProgress({type:"complete",...i})}catch(n){this._secureLog("warn","\u26A0\uFE0F onComplete handler failed:",{details:n.message})}};this.fileTransferSystem=new je(this,this.onFileProgress||null,t,this.onFileError||null,this.onFileReceived||null,this.onIncomingFileRequest||null),this._fileTransferActive=!0,this._secureLog("info","\u2705 Enhanced Secure File Transfer system initialized successfully");let r=this.fileTransferSystem.getSystemStatus();this._secureLog("info","\u{1F50D} File transfer system status after init",{status:r})}catch(e){this._secureLog("error","\u274C Failed to initialize file transfer system",{errorType:e.constructor.name}),this.fileTransferSystem=null,this._fileTransferActive=!1}}_scheduleFileTransferInitRetry(e){if(this._sessionAlive===!1)return null;this._fileTransferInitRetryTimers||(this._fileTransferInitRetryTimers=new Set);let t=this._trackActiveTimer(setTimeout(()=>{this._fileTransferInitRetryTimers.delete(t),this._untrackActiveTimer(t),this._sessionAlive!==!1&&this.initializeFileTransfer()},e));return this._fileTransferInitRetryTimers.add(t),t}async initializeEnhancedSecurity(){try{await this.generateNestedEncryptionKey(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration()}catch(e){this._secureLog("error","\u274C Failed to initialize enhanced security",{errorType:e.constructor.name})}}getSafeRandomInt(e,t){if(!Number.isInteger(e)||!Number.isInteger(t))throw new Error("getSafeRandomInt requires integer min and max");if(e>=t)throw new Error("min must be less than max");let r=t-e+1,i=Math.ceil(Math.log2(r)),n=Math.ceil(i/8),a=(1<=r);return e+o}getSafeRandomFloat(e,t,r=1e3){if(typeof e!="number"||typeof t!="number")throw new Error("getSafeRandomFloat requires numeric min and max");if(e>=t)throw new Error("minFloat must be less than maxFloat");let i=this.getSafeRandomInt(0,r),n=(t-e)/r;return e+i*n}generateFingerprintMask(){return{timingOffset:this.getSafeRandomInt(0,1500),sizeVariation:this.getSafeRandomFloat(.75,1.25,1e3),noisePattern:Array.from(crypto.getRandomValues(new Uint8Array(64))),headerVariations:["X-Client-Version","X-Session-ID","X-Request-ID","X-Timestamp","X-Signature","X-Secure","X-Encrypted","X-Protected","X-Safe","X-Anonymous","X-Private"],noiseIntensity:this.getSafeRandomInt(50,150),sizeMultiplier:this.getSafeRandomFloat(.75,1.25,1e3),timingVariation:this.getSafeRandomInt(100,1100)}}configureSecurityForSession(){this._secureLog("info","\u{1F527} Configuring security - all features enabled by default"),this.sessionConstraints={},Object.keys(this.securityFeatures).forEach(e=>{this.sessionConstraints[e]=!0}),this.applySessionConstraints(),this._secureLog("info","\u2705 Security configured - all features enabled",{constraints:this.sessionConstraints}),this._validateCryptographicSecurity()||(this._secureLog("error","\u{1F6A8} CRITICAL: Cryptographic security validation failed after session configuration"),this.onStatusChange&&this.onStatusChange("security_breach",{type:"crypto_security_failure",message:"Cryptographic security validation failed after session configuration"})),this.notifySecurityLevel(),setTimeout(()=>{this.calculateAndReportSecurityLevel()},s.TIMEOUTS.SECURITY_CALC_DELAY)}applySessionConstraints(){this.sessionConstraints&&(Object.keys(this.sessionConstraints).forEach(e=>{switch(this.securityFeatures[e]=!0,e){case"hasFakeTraffic":this.fakeTrafficConfig.enabled=!0,this.isConnected()&&this.startFakeTrafficGeneration();break;case"hasDecoyChannels":this.decoyChannelConfig.enabled=!0,this.isConnected()&&this.initializeDecoyChannels();break;case"hasPacketReordering":this.reorderingConfig.enabled=!0;break;case"hasAntiFingerprinting":this.antiFingerprintingConfig.enabled=!0;break;case"hasMessageChunking":this.chunkingConfig.enabled=!0;break}}),this._secureLog("info","\u2705 All security features enabled by default",{constraints:this.sessionConstraints,currentFeatures:this.securityFeatures}))}_sanitizeIncomingChatMessage(e){return typeof e!="string"?e:window.EnhancedSecureCryptoUtils.sanitizeMessage(e)}deliverMessageToUI(e,t="received",r=null){try{if(this._secureLog("debug","\u{1F4E4} deliverMessageToUI called",{message:e,type:t,messageType:typeof e,hasOnMessage:!!this.onMessage}),typeof e=="object"&&e.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(e.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI: ${e.type}`);return}if(typeof e=="string"&&e.trim().startsWith("{"))try{let n=JSON.parse(e);if(n.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(n.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI (string): ${n.type}`);return}}catch{}let i=t==="received"?this._sanitizeIncomingChatMessage(e):e;if(this.onMessage){let n=r&&typeof this._sanitizeMessageMeta=="function"?this._sanitizeMessageMeta(r):null;this._secureLog("debug","\u{1F4E4} Calling this.onMessage callback",{message:i,type:t}),this.onMessage(i,t,n||void 0)}else this._secureLog("warn","\u26A0\uFE0F this.onMessage callback is null or undefined")}catch(i){this._secureLog("error","\u274C Failed to deliver message to UI:",{errorType:i?.constructor?.name||"Unknown"})}}notifySecurityLevel(){if(this.lastSecurityLevelNotification==="maximum")return;if(this.lastSecurityLevelNotification="maximum",this.onMessage&&this.deliverMessageToUI("\u{1F6E1}\uFE0F Maximum Security Active - All features enabled","system"),this.onMessage){let t=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r.replace("has","").replace(/([A-Z])/g," $1").trim().toLowerCase()).slice(0,5);this.deliverMessageToUI(`\u{1F527} Active: ${t.join(", ")}...`,"system")}}cleanupDecoyChannels(){for(let[e,t]of this.decoyTimers.entries())clearTimeout(t);this.decoyTimers.clear();for(let[e,t]of this.decoyChannels.entries())t.readyState==="open"&&t.close();this.decoyChannels.clear(),this._secureLog("info","\u{1F9F9} Decoy channels cleaned up")}async generateNestedEncryptionKey(){try{this.nestedEncryptionKey=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(e){throw this._secureLog("error","\u274C Failed to generate nested encryption key:",{errorType:e?.constructor?.name||"Unknown"}),e}}async applyNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;try{let t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"nestedEncryption"),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this.nestedEncryptionKey,e),i=new Uint8Array(s.SIZES.NESTED_ENCRYPTION_IV_SIZE+r.byteLength);return i.set(t,0),i.set(new Uint8Array(r),s.SIZES.NESTED_ENCRYPTION_IV_SIZE),this._secureLog("debug","\u2705 Nested encryption applied with secure IV",{ivSize:t.length,dataSize:e.byteLength,encryptedSize:r.byteLength}),i.buffer}catch(t){return this._secureLog("error","\u274C Nested encryption failed:",{errorType:t?.constructor?.name||"Unknown",errorMessage:t?.message||"Unknown error"}),t.message.includes("emergency mode")&&(this.securityFeatures.hasNestedEncryption=!1,this._secureLog("warn","\u26A0\uFE0F Nested encryption disabled due to IV emergency mode")),e}}async removeNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;if(!(e instanceof ArrayBuffer)||e.byteLengtht.length-4?(this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid packet padding size, skipping removal"),e):t.slice(4,4+i).buffer}catch(t){return this._debugMode&&this._secureLog("error","\u274C Packet padding removal failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}startFakeTrafficGeneration(){if(!this.fakeTrafficConfig.enabled||!this.isConnected())return;if(this.fakeTrafficTimer){this._secureLog("warn","\u26A0\uFE0F Fake traffic generation already running");return}let e=async()=>{if(!this.isConnected()){this.stopFakeTrafficGeneration();return}try{let n=this.generateFakeMessage();await this.sendFakeMessage(n);let a=this.fakeTrafficConfig.randomDecoyIntervals?this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minInterval,Math.min(this.fakeTrafficConfig.maxInterval,6e4)):this.fakeTrafficConfig.minInterval,o=Math.max(a,s.TIMEOUTS.FAKE_TRAFFIC_MIN_INTERVAL);this.fakeTrafficTimer=setTimeout(e,o)}catch(n){this._debugMode&&this._secureLog("error","\u274C Fake traffic generation failed:",{errorType:n?.constructor?.name||"Unknown"}),this.stopFakeTrafficGeneration()}},t=s.TIMEOUTS.DECOY_INITIAL_DELAY,r=Math.min(this.fakeTrafficConfig.maxInterval,3e4),i=this.getUnbiasedRandomInRange(t,r);this.fakeTrafficTimer=setTimeout(e,i)}stopFakeTrafficGeneration(){this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null)}generateFakeMessage(){let e=this.getUnbiasedRandomInRange(0,this.fakeTrafficConfig.patterns.length-1),t=this.fakeTrafficConfig.patterns[e],r=this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minSize,this.fakeTrafficConfig.maxSize),i=crypto.getRandomValues(new Uint8Array(r));return{type:s.MESSAGE_TYPES.FAKE,pattern:t,data:Array.from(i).map(n=>n.toString(16).padStart(2,"0")).join(""),timestamp:Date.now(),size:r,isFakeTraffic:!0,source:"fake_traffic_generator",fakeId:crypto.getRandomValues(new Uint32Array(1))[0].toString(36)}}emergencyDisableAdvancedFeatures(){this._secureLog("error","\u{1F6A8} Emergency disabling advanced security features due to errors"),this.securityFeatures.hasNestedEncryption=!1,this.securityFeatures.hasPacketReordering=!1,this.securityFeatures.hasAntiFingerprinting=!1,this.reorderingConfig.enabled=!1,this.antiFingerprintingConfig.enabled=!1,this.packetBuffer.clear(),this.emergencyDisableFakeTraffic(),this._secureLog("info","\u2705 Advanced features disabled, keeping basic encryption"),this.advancedFeaturesDisabledNotificationSent||(this.advancedFeaturesDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Advanced security features temporarily disabled due to compatibility issues","system"))}async sendFakeMessage(e){if(this._validateConnection(!1))try{this._secureLog("debug","\u{1F3AD} Sending fake message",{hasPattern:!!e.pattern,sizeRange:e.size>100?"large":"small"});let t=JSON.stringify({...e,type:s.MESSAGE_TYPES.FAKE,isFakeTraffic:!0,timestamp:Date.now()}),r=new TextEncoder().encode(t),i=await this.applySecurityLayers(r,!0);this.dataChannel.send(i),this._secureLog("debug","\u{1F3AD} Fake message sent successfully",{pattern:e.pattern})}catch(t){this._secureLog("error","\u274C Failed to send fake message",{error:t.message})}}checkFakeTrafficStatus(){let e={fakeTrafficEnabled:this.securityFeatures.hasFakeTraffic,fakeTrafficConfigEnabled:this.fakeTrafficConfig.enabled,timerActive:!!this.fakeTrafficTimer,patterns:this.fakeTrafficConfig.patterns,intervals:{min:this.fakeTrafficConfig.minInterval,max:this.fakeTrafficConfig.maxInterval}};return this._debugMode&&this._secureLog("info","\u{1F3AD} Fake Traffic Status",{status:e}),e}emergencyDisableFakeTraffic(){this._debugMode&&this._secureLog("error","\u{1F6A8} Emergency disabling fake traffic"),this.securityFeatures.hasFakeTraffic=!1,this.fakeTrafficConfig.enabled=!1,this.stopFakeTrafficGeneration(),this._debugMode&&this._secureLog("info","\u2705 Fake traffic disabled"),this.fakeTrafficDisabledNotificationSent||(this.fakeTrafficDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Fake traffic emergency disabled","system"))}async _applySecurityLayersWithoutMutex(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayersWithoutMutex:",{errorType:r?.constructor?.name||"Unknown"}),e}}async processChunkedMessage(e){try{if(!this.chunkingConfig.addChunkHeaders)return this.processMessage(e);let t=new Uint8Array(e);if(t.length<16)return this.processMessage(e);let r=new DataView(t.buffer,0,16),i=r.getUint32(0,!1),n=r.getUint32(4,!1),a=r.getUint32(8,!1),o=r.getUint32(12,!1),c=t.slice(16,16+o);this.chunkQueue[i]||(this.chunkQueue[i]={chunks:new Array(a),received:0,timestamp:Date.now()});let d=this.chunkQueue[i];if(d.chunks[n]=c,d.received++,this._secureLog("debug",`\u{1F4E6} Received chunk ${n+1}/${a} for message ${i}`),d.received===a){let u=d.chunks.reduce((p,S)=>p+S.length,0),h=new Uint8Array(u),m=0;for(let p of d.chunks)h.set(p,m),m+=p.length;await this.processMessage(h.buffer),delete this.chunkQueue[i],this._secureLog("info",`\u{1F4E6} Chunked message ${i} reassembled and processed`)}}catch(t){this._secureLog("error","\u274C Chunked message processing failed:",{errorType:t?.constructor?.name||"Unknown"})}}initializeDecoyChannels(){if(!(!this.decoyChannelConfig.enabled||!this.peerConnection)){if(this.decoyChannels.size>0){this._secureLog("warn","\u26A0\uFE0F Decoy channels already initialized, skipping...");return}try{let e=Math.min(this.decoyChannelConfig.maxDecoyChannels,this.decoyChannelConfig.decoyChannelNames.length);for(let t=0;t.5,maxRetransmits:Math.floor(Math.random()*3)});this.setupDecoyChannel(i,r),this.decoyChannels.set(r,i)}this._debugMode&&this._secureLog("info",`\u{1F3AD} Initialized ${e} decoy channels`)}catch(e){this._debugMode&&this._secureLog("error","\u274C Failed to initialize decoy channels:",{errorType:e?.constructor?.name||"Unknown"})}}}setupDecoyChannel(e,t){e.onopen=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" opened`),this.startDecoyTraffic(e,t)},e.onmessage=r=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Received decoy message on "${t}": ${r.data?.length||"undefined"} bytes`)},e.onclose=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" closed`),this.stopDecoyTraffic(t)},e.onerror=r=>{this._debugMode&&this._secureLog("error",`\u274C Decoy channel "${t}" error`,{error:r.message})}}startDecoyTraffic(e,t){let r=async()=>{if(e.readyState==="open")try{let n=this.generateDecoyData(t);e.send(n);let a=this.decoyChannelConfig.randomDecoyIntervals?Math.random()*15e3+1e4:2e4;this.decoyTimers.set(t,setTimeout(()=>r(),a))}catch(n){this._debugMode&&this._secureLog("error",`\u274C Failed to send decoy data on "${t}"`,{error:n.message})}},i=Math.random()*1e4+5e3;this.decoyTimers.set(t,setTimeout(()=>r(),i))}stopDecoyTraffic(e){let t=this.decoyTimers.get(e);t&&(clearTimeout(t),this.decoyTimers.delete(e))}generateDecoyData(e){let t={sync:()=>JSON.stringify({type:"sync",timestamp:Date.now(),sequence:Math.floor(Math.random()*1e3),data:Array.from(crypto.getRandomValues(new Uint8Array(32))).map(r=>r.toString(16).padStart(2,"0")).join("")}),status:()=>JSON.stringify({type:"status",status:["online","away","busy"][Math.floor(Math.random()*3)],uptime:Math.floor(Math.random()*3600),data:Array.from(crypto.getRandomValues(new Uint8Array(16))).map(r=>r.toString(16).padStart(2,"0")).join("")}),heartbeat:()=>JSON.stringify({type:"heartbeat",timestamp:Date.now(),data:Array.from(crypto.getRandomValues(new Uint8Array(24))).map(r=>r.toString(16).padStart(2,"0")).join("")}),metrics:()=>JSON.stringify({type:"metrics",cpu:Math.random()*100,memory:Math.random()*100,network:Math.random()*1e3,data:Array.from(crypto.getRandomValues(new Uint8Array(20))).map(r=>r.toString(16).padStart(2,"0")).join("")}),debug:()=>JSON.stringify({type:"debug",level:["info","warn","error"][Math.floor(Math.random()*3)],message:"Debug message",data:Array.from(crypto.getRandomValues(new Uint8Array(28))).map(r=>r.toString(16).padStart(2,"0")).join("")})};return t[e]?t[e]():Array.from(crypto.getRandomValues(new Uint8Array(64))).map(r=>r.toString(16).padStart(2,"0")).join("")}addReorderingHeaders(e){if(!this.reorderingConfig.enabled)return e;try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8,i=new ArrayBuffer(r),n=new DataView(i);this.reorderingConfig.useSequenceNumbers&&n.setUint32(0,this.sequenceNumber++,!1),this.reorderingConfig.useTimestamps&&n.setUint32(4,Date.now(),!1),n.setUint32(this.reorderingConfig.useTimestamps?8:4,t.length,!1);let a=new Uint8Array(r+t.length);return a.set(new Uint8Array(i),0),a.set(t,r),a.buffer}catch(t){return this._secureLog("error","\u274C Failed to add reordering headers:",{errorType:t?.constructor?.name||"Unknown"}),e}}async processReorderedPacket(e){if(!this.reorderingConfig.enabled)return this.processMessage(e);try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8;if(t.lengtht.length-r||o<=0)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid reordered packet data size, processing directly"),this.processMessage(e);let c=t.slice(r,r+o);try{let d=new TextDecoder().decode(c),u=JSON.parse(d);if(u.type==="fake"||u.isFakeTraffic===!0){this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Reordered fake message: ${u.pattern||"unknown"}`);return}}catch{}this.packetBuffer.set(n,{data:c.buffer,timestamp:a||Date.now()}),await this.processOrderedPackets()}catch(t){return this._secureLog("error","\u274C Failed to process reordered packet:",{errorType:t?.constructor?.name||"Unknown"}),this.processMessage(e)}}async processOrderedPackets(){let e=Date.now(),t=this.reorderingConfig.reorderTimeout;for(;;){let r=this.lastProcessedSequence+1,i=this.packetBuffer.get(r);if(i){try{let n=new TextDecoder().decode(i.data),a=JSON.parse(n);if(a.type==="fake"||a.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Ordered fake message: ${a.pattern||"unknown"}`),this.packetBuffer.delete(r),this.lastProcessedSequence=r;continue}}catch{}await this.processMessage(i.data),this.packetBuffer.delete(r),this.lastProcessedSequence=r}else{let n=this.findOldestPacket();if(n&&e-n.timestamp>t){this._secureLog("warn","\u26A0\uFE0F Packet ${oldestPacket.sequence} timed out, processing out of order");try{let a=new TextDecoder().decode(n.data),o=JSON.parse(a);if(o.type==="fake"||o.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Timed out fake message: ${o.pattern||"unknown"}`),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence;continue}}catch{}await this.processMessage(n.data),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence}else break}}this.cleanupOldPackets(e,t)}findOldestPacket(){let e=null;for(let[t,r]of this.packetBuffer.entries())(!e||r.timestampt&&(this._secureLog("warn","\u26A0\uFE0F \u{1F5D1}\uFE0F Removing timed out packet ${sequence}"),this.packetBuffer.delete(r))}applyAntiFingerprinting(e){if(!this.antiFingerprintingConfig.enabled)return e;try{let t=e;return this.antiFingerprintingConfig.addNoise&&(t=this.addNoise(t)),this.antiFingerprintingConfig.randomizeSizes&&(t=this.randomizeSize(t)),this.antiFingerprintingConfig.maskPatterns&&(t=this.maskPatterns(t)),this.antiFingerprintingConfig.useRandomHeaders&&(t=this.addRandomHeaders(t)),t}catch(t){return this._secureLog("error","\u274C Anti-fingerprinting failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}addNoise(e){let t=new Uint8Array(e),r=this.getUnbiasedRandomInRange(8,40),i=crypto.getRandomValues(new Uint8Array(r)),n=new Uint8Array(t.length+r);return n.set(t,0),n.set(i,t.length),n.buffer}randomizeSize(e){let t=new Uint8Array(e),r=this.fingerprintMask.sizeVariation,i=Math.floor(t.length*r);if(i>t.length){let n=crypto.getRandomValues(new Uint8Array(i-t.length)),a=new Uint8Array(i);return a.set(t,0),a.set(n,t.length),a.buffer}else if(i=256-256%this.fingerprintMask.headerVariations.length);let d=this.fingerprintMask.headerVariations[c%this.fingerprintMask.headerVariations.length],u;do u=crypto.getRandomValues(new Uint8Array(1))[0];while(u>=256-256%16);let h=crypto.getRandomValues(new Uint8Array(u%16+4)),m=new DataView(n.buffer,a);m.setUint32(0,h.length+8,!1),m.setUint32(4,this.hashString(d),!1),n.set(h,a+8);let p=this.calculateChecksum(n.slice(a,a+8+h.length));new DataView(n.buffer,a+8+h.length).setUint32(0,p,!1),a+=8+h.length+4}return n.set(t,a),n.buffer}hashString(e){let t=0;for(let r=0;r50)try{if(/^[A-Za-z0-9+/=]+$/.test(r.trim())&&(this._debugMode&&this._secureLog("debug","\u{1F513} Applying standard decryption..."),r=await window.EnhancedSecureCryptoUtils.decryptData(r,this.encryptionKey),this._debugMode&&this._secureLog("debug","\u2705 Standard decryption successful"),typeof r=="string")){try{let n=JSON.parse(r);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Legacy fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}r=new TextEncoder().encode(r).buffer}}catch(i){return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Standard decryption failed:",{details:i.message}),e}if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&r.byteLength>12)try{if(r=await this.removeNestedEncryption(r),r instanceof ArrayBuffer)try{let i=new TextDecoder().decode(r),n=JSON.parse(i);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Nested fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Nested decryption failed - skipping this layer:",{details:i.message})}if(this.securityFeatures.hasPacketReordering&&this.reorderingConfig.enabled&&r instanceof ArrayBuffer)try{let i=this.reorderingConfig.useTimestamps?12:8;if(r.byteLength>i)return await this.processReorderedPacket(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Reordering processing failed - using direct processing:",{details:i.message})}if(this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer)try{r=this.removePacketPadding(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Padding removal failed:",{details:i.message})}if(this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer)try{r=this.removeAntiFingerprinting(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Anti-fingerprinting removal failed:",{details:i.message})}if(r instanceof ArrayBuffer&&(r=new TextDecoder().decode(r)),typeof r=="string")try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Final check fake message: ${i.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}return r}catch(t){return this._secureLog("error","\u274C Critical error in removeSecurityLayers:",{errorType:t?.constructor?.name||"Unknown"}),e}}removeAntiFingerprinting(e){return e}async applySecurityLayers(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:r?.constructor?.name||"Unknown"}),e}}_sanitizeMessageMeta(e){if(!e||typeof e!="object")return null;let t={};if(typeof e.mid=="string"&&e.mid.length>0&&e.mid.length<=64&&(t.mid=e.mid.replace(/[^A-Za-z0-9_-]/g,"").slice(0,64)),e.code===!0&&(t.code=!0),e.once===!0&&(t.once=!0),Number.isFinite(e.onceTtl)){let r=Math.floor(e.onceTtl);r>=1&&r<=3600&&(t.onceTtl=r)}if(Number.isFinite(e.ttl)){let r=Math.floor(e.ttl);r>=5&&r<=86400&&(t.ttl=r)}return Object.keys(t).length?t:null}sendMessageDelete(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_DELETE,messageId:e.slice(0,64)})}sendDeliveryReceipt(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_RECEIPT,messageId:e.slice(0,64)})}async sendMessage(e,t=null){let r=this._validateInputData(e,"sendMessage");if(!r.isValid){let i=`Input validation failed: ${r.errors.join(", ")}`;throw this._secureLog("error","\u274C Input validation failed in sendMessage",{errors:r.errors,dataType:typeof e,dataLength:e?.length||e?.byteLength||0}),new Error(i)}if(!this._checkRateLimit("sendMessage"))throw new Error("Rate limit exceeded for message sending");if(this._enforceVerificationGate("sendMessage"),!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not ready");try{if(this.encryptionKey&&this.macKey&&this.metadataKey||await this._tryReinitializeEncryptionKeys(),this._secureLog("debug","sendMessage called",{hasDataChannel:!!this.dataChannel,dataChannelReady:this.dataChannel?.readyState==="open",isInitiator:this.isInitiator,isVerified:this.isVerified,connectionReady:this.peerConnection?.connectionState==="connected"}),this._secureLog("debug","\u{1F50D} sendMessage DEBUG",{dataType:typeof r.sanitizedData,isString:typeof r.sanitizedData=="string",isArrayBuffer:r.sanitizedData instanceof ArrayBuffer,dataLength:r.sanitizedData?.length||r.sanitizedData?.byteLength||0}),typeof r.sanitizedData=="string")try{let n=JSON.parse(r.sanitizedData);if(n.type&&n.type.startsWith("file_")){this._secureLog("debug","\u{1F4C1} File message detected - applying full encryption with AAD",{type:n.type});let a=this._createFileMessageAAD(n.type,n.data),o=await this._encryptFileMessage(r.sanitizedData,a);return this.dataChannel.send(o),!0}}catch{}if(typeof r.sanitizedData=="string"){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available. Manager may not be fully initialized.");let n=this._createMessageAAD("message",{content:r.sanitizedData}),a={type:"message",data:r.sanitizedData,timestamp:Date.now(),aad:n};return t&&typeof t=="object"&&(a.meta=this._sanitizeMessageMeta(t)),await this.sendSecureMessage(a)}this._secureLog("debug","\u{1F510} Applying security layers to non-string data");let i=await this._applySecurityLayersWithLimitedMutex(r.sanitizedData,!1);return this.dataChannel.send(i),!0}catch(i){throw this._secureLog("error","\u274C Failed to send message",{error:i.message,errorType:i.constructor.name}),i}}async _applySecurityLayersWithLimitedMutex(e,t=!1){return this._withMutex("cryptoOperation",async r=>{try{let i=e;return t?(this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&i instanceof ArrayBuffer&&(i=await this.applyNestedEncryption(i)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&i instanceof ArrayBuffer&&(i=this.applyPacketReordering(i)),this.securityFeatures.hasPacketPadding&&i instanceof ArrayBuffer&&(i=this.applyPacketPadding(i)),this.securityFeatures.hasAntiFingerprinting&&i instanceof ArrayBuffer&&(i=this.applyAntiFingerprinting(i)),this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i)}catch(i){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:i?.constructor?.name||"Unknown"}),e}},3e3)}async sendSystemMessage(e){if(e.type==="verification_request"||e.type==="verification_response"||e.type==="verification_required"||this._enforceVerificationGate("sendSystemMessage",!1),!this.dataChannel||this.dataChannel.readyState!=="open")return this._secureLog("warn","\u26A0\uFE0F Cannot send system message - data channel not ready"),!1;try{let r=JSON.stringify({type:e.type,data:e,timestamp:Date.now()});return this._secureLog("debug","\u{1F527} Sending system message",{type:e.type}),this.dataChannel.send(r),!0}catch(r){return this._secureLog("error","\u274C Failed to send system message:",{errorType:r?.constructor?.name||"Unknown"}),!1}}async processMessage(e){try{if(this._noteInboundActivity?.(),this._secureLog("debug","\uFFFD\uFFFD Processing message",{dataType:typeof e,isArrayBuffer:e instanceof ArrayBuffer,hasData:!!(e?.length||e?.byteLength)}),typeof e=="string")try{let i=JSON.parse(e),n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(i.type==="encrypted_file_message"){this._secureLog("debug","\u{1F4C1} Encrypted file message detected in processMessage");try{let{decryptedData:a,aad:o}=await this._decryptFileMessage(e),c=JSON.parse(a);if(this._secureLog("debug","\u{1F4C1} File message decrypted successfully",{type:c.type,aadMessageType:o.messageType}),this.fileTransferSystem&&typeof this.fileTransferSystem.handleFileMessage=="function"){await this.fileTransferSystem.handleFileMessage(c);return}}catch(a){this._secureLog("error","\u274C Failed to decrypt file message",{error:a.message});return}}if(i.type&&n.includes(i.type)){this._secureLog("warn","\u26A0\uFE0F Unencrypted file message detected - this should not happen in secure mode",{type:i.type}),this._secureLog("error","\u274C Dropping unencrypted file message for security",{type:i.type});return}if(i.type==="enhanced_message"){if(this._secureLog("debug","\u{1F510} Enhanced message detected in processMessage"),!this._checkInboundRateLimit("processMessage:enhanced_message"))return;try{let a=await window.EnhancedSecureCryptoUtils.decryptMessage(i.data,this.encryptionKey,this.macKey,this.metadataKey),o=JSON.parse(a.data);if(a.metadata&&a.metadata.sequenceNumber!==void 0&&!this._validateIncomingSequenceNumber(a.metadata.sequenceNumber,"enhanced_message")){this._secureLog("warn","\u26A0\uFE0F Enhanced message sequence number validation failed - possible replay attack",{received:a.metadata.sequenceNumber,expected:this.expectedSequenceNumber});return}o.type==="message"&&this.onMessage&&o.data&&this.deliverMessageToUI(o.data,"received",o.meta);return}catch(a){this._secureLog("error","\u274C Failed to decrypt enhanced message",{error:a.message});return}}if(i.type===s.MESSAGE_TYPES.MESSAGE){this._secureLog("error","Rejected unencrypted frame in processMessage",{messageType:"message"});return}if(i.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(i.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:i.type});return}let a=s.MESSAGE_TYPES;if(i.type===a.MESSAGE_DELETE){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelete?.(o.slice(0,64))}catch{}return}if(i.type===a.MESSAGE_RECEIPT){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelivered?.(o.slice(0,64))}catch{}return}if([a.CALL_OFFER,a.CALL_ANSWER,a.CALL_ICE,a.CALL_DECLINE,a.CALL_END].includes(i.type)){try{await this._handleCallSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C Call signal handling failed",{errorType:o?.constructor?.name})}return}if([a.ICE_RESTART_OFFER,a.ICE_RESTART_ANSWER,a.ICE_RESTART_REQUEST].includes(i.type)){try{await this._handleIceRestartSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:o?.constructor?.name})}return}return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn","\u{1F3AD} Fake message blocked in processMessage",{pattern:i.pattern});return}}catch{this._secureLog("error","Rejected malformed (non-JSON) frame in processMessage",{dataLength:typeof e=="string"?e.length:0});return}let t=await this._processEncryptedDataWithLimitedMutex(e);if(t==="FAKE_MESSAGE_FILTERED"||t==="FILE_MESSAGE_FILTERED"||t==="SYSTEM_MESSAGE_FILTERED")return;if(!t){this._secureLog("warn","\u26A0\uFE0F No data returned from removeSecurityLayers");return}let r;if(typeof t=="string")try{let i=JSON.parse(t);if(i.type&&fileMessageTypes.includes(i.type)){this._secureLog("debug","\u{1F4C1} File message detected after decryption",{type:i.type}),this.fileTransferSystem&&await this.fileTransferSystem.handleFileMessage(i);return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Post-decryption fake message blocked: ${i.pattern}`);return}i.type==="message"&&i.data?r=i.data:r=t}catch{r=t}else if(t instanceof ArrayBuffer)r=new TextDecoder().decode(t);else if(t&&typeof t=="object"&&t.message)r=t.message;else{this._secureLog("warn","\u26A0\uFE0F Unexpected data type after processing:",{details:typeof t});return}if(r&&r.trim().startsWith("{"))try{let i=JSON.parse(r);if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Final fake message check blocked: ${i.pattern}`);return}let n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error","heartbeat","verification","verification_response","peer_disconnect","key_rotation_signal","key_rotation_ready","security_upgrade","ice_restart_offer","ice_restart_answer","ice_restart_request"];if(i.type&&n.includes(i.type)){this._secureLog("warn",`\u{1F4C1} Final system/file message check blocked: ${i.type}`);return}}catch{}r&&this._secureLog("error","Rejected unauthenticated payload at the end of processMessage",{messageLength:typeof r=="string"?r.length:0})}catch(t){this._secureLog("error","\u274C Failed to process message:",{errorType:t?.constructor?.name||"Unknown"})}}async _processEncryptedDataWithLimitedMutex(e){return this._withMutex("cryptoOperation",async t=>{this._secureLog("debug","\u{1F510} Processing encrypted data with limited mutex",{operationId:t,dataType:typeof e});try{return await this.removeSecurityLayers(e)}catch(r){return this._secureLog("error","\u274C Error processing encrypted data",{operationId:t,errorType:r.constructor.name}),e}},2e3)}notifySecurityUpdate(){try{this._secureLog("debug","\u{1F512} Notifying about security level update",{isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasLastCalculation:!!this.lastSecurityCalculation}),this._dispatchAppEvent?.(new CustomEvent("security-level-updated",{detail:{timestamp:Date.now(),manager:"webrtc",webrtcManager:this,isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),lastCalculation:this.lastSecurityCalculation}})),setTimeout(()=>{},100),this.lastSecurityCalculation&&this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:this.lastSecurityCalculation,webrtcManager:this,timestamp:Date.now()}}))}catch(e){this._secureLog("error","\u274C Error in notifySecurityUpdate",{error:e.message})}}handleSystemMessage(e){switch(this._secureLog("debug","\u{1F527} Handling system message:",{type:e.type}),e.type){case"heartbeat":this.handleHeartbeat(e);break;case"verification":this.handleVerificationRequest(e.data);break;case"verification_response":this.handleVerificationResponse(e.data);break;case"sas_code":this.handleSASCode(e.data);break;case"verification_confirmed":this.handleVerificationConfirmed(e.data);break;case"verification_both_confirmed":this.handleVerificationBothConfirmed(e.data);break;case"peer_disconnect":this.handlePeerDisconnectNotification(e);break;case"key_rotation_signal":this._secureLog("debug","\u{1F504} Key rotation signal received (ignored for stability)");break;case"key_rotation_ready":this._secureLog("debug","\u{1F504} Key rotation ready signal received (ignored for stability)");break;case"security_upgrade":this._secureLog("debug","\u{1F512} Security upgrade notification received:",{type:e.type});break;default:this._secureLog("debug","\u{1F527} Unknown system message type:",{type:e.type})}}enableStage2Security(){this.sessionConstraints?.hasPacketReordering&&(this.securityFeatures.hasPacketReordering=!0,this.reorderingConfig.enabled=!0),this.sessionConstraints?.hasAntiFingerprinting&&(this.securityFeatures.hasAntiFingerprinting=!0,this.antiFingerprintingConfig.enabled=!0,this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!0),this.notifySecurityUpgrade(2),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage3Security(){this._secureLog("info","\u{1F512} Enabling Stage 3 features (traffic obfuscation)"),this.sessionConstraints?.hasMessageChunking&&(this.securityFeatures.hasMessageChunking=!0,this.chunkingConfig.enabled=!0),this.sessionConstraints?.hasFakeTraffic&&(this.securityFeatures.hasFakeTraffic=!0,this.fakeTrafficConfig.enabled=!0,this.startFakeTrafficGeneration()),this.notifySecurityUpgrade(3),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage4Security(){if(this._secureLog("info","\u{1F512} Enabling Stage 4 features (maximum safety)"),this.sessionConstraints?.hasDecoyChannels&&this.isConnected()&&this.isVerified){this.securityFeatures.hasDecoyChannels=!0,this.decoyChannelConfig.enabled=!0;try{this.initializeDecoyChannels()}catch(e){this._secureLog("warn","\u26A0\uFE0F Decoy channels initialization failed:",{details:e.message}),this.securityFeatures.hasDecoyChannels=!1,this.decoyChannelConfig.enabled=!1}}this.sessionConstraints?.hasAntiFingerprinting&&(this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!1),this.notifySecurityUpgrade(4),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}forceSecurityUpdate(){setTimeout(()=>{this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate()},100)}getSecurityStatus(){let e=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r);return{stage:4,securityLevel:"maximum",activeFeatures:e,totalFeatures:Object.keys(this.securityFeatures).length,activeFeaturesCount:e.length,activeFeaturesNames:e,sessionConstraints:this.sessionConstraints}}notifySecurityUpgrade(e){let t={1:"Basic Enhanced",2:"Medium Security",3:"High Security",4:"Maximum Security"},r=`\u{1F512} Security upgraded to Stage ${e}: ${t[e]}`;if((!this.securityUpgradeNotificationSent||this.lastSecurityUpgradeStage!==e)&&(this.securityUpgradeNotificationSent=!0,this.lastSecurityUpgradeStage=e,this.onMessage&&this.deliverMessageToUI(r,"system")),this.dataChannel&&this.dataChannel.readyState==="open")try{let n={type:"security_upgrade",stage:e,stageName:t[e],message:r,timestamp:Date.now()};this._secureLog("debug","\u{1F512} Sending security upgrade notification to peer:",{type:n.type,stage:n.stage}),this.dataChannel.send(JSON.stringify(n))}catch(n){this._secureLog("warn","\u26A0\uFE0F Failed to send security upgrade notification to peer:",{details:n.message})}let i=this.getSecurityStatus()}async calculateAndReportSecurityLevel(){try{if(!window.EnhancedSecureCryptoUtils)return this._secureLog("warn","\u26A0\uFE0F EnhancedSecureCryptoUtils not available for security calculation"),null;if(!this.isConnected()||!this.isVerified||!this.encryptionKey||!this.macKey)return this._secureLog("debug","\u26A0\uFE0F WebRTC not ready for security calculation",{connected:this.isConnected(),verified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey}),null;this._secureLog("debug","\u{1F50D} Calculating real security level",{managerState:"ready",hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey)});let e=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this);if(this._secureLog("info","Real security level calculated",{hasSecurityLevel:!!e.level,scoreRange:e.score>80?"high":e.score>50?"medium":"low",checksRatio:`${e.passedChecks}/${e.totalChecks}`,isRealCalculation:e.isRealData}),this.lastSecurityCalculation=e,this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:e,webrtcManager:this,timestamp:Date.now(),source:"calculateAndReportSecurityLevel"}})),e.isRealData&&this.onMessage&&(!this.securityCalculationNotificationSent||this.lastSecurityCalculationLevel!==e.level)){this.securityCalculationNotificationSent=!0,this.lastSecurityCalculationLevel=e.level;let t=`Security Level: ${e.level} (${e.score}%) - ${e.passedChecks}/${e.totalChecks} checks passed`;this.deliverMessageToUI(t,"system")}return e}catch(e){return this._secureLog("error","Failed to calculate real security level",{errorType:e.constructor.name}),null}}async autoEnableSecurityFeatures(){this._secureLog("info","Starting graduated security activation - all features enabled");let e=()=>this.isConnected()&&this.isVerified&&this.connectionAttempts===0&&this.messageQueue.length===0&&this.peerConnection?.connectionState==="connected";await this.calculateAndReportSecurityLevel(),this.notifySecurityUpgrade(1),setTimeout(async()=>{e()&&(this.enableStage2Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage3Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage4Security(),await this.calculateAndReportSecurityLevel())},2e4))},15e3))},1e4)}async establishConnection(){try{await this.initializeEnhancedSecurity(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels()}catch(e){throw this._secureLog("error","\u274C Failed to establish enhanced connection:",{errorType:e?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),e}}_clearVerificationStates(){try{this.localVerificationConfirmed=!1,this.remoteVerificationConfirmed=!1,this.bothVerificationsConfirmed=!1,this.isVerified=!1,this.verificationCode=null,this.pendingSASCode=null,this.sasValidationAttempts=0,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.keyFingerprint=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.connectionId=null,this.processedMessageIds.clear(),this.verificationNotificationSent=!1,this.verificationInitiationSent=!1}catch(e){this._secureLog("error","\u274C Error clearing verification states:",{errorType:e?.constructor?.name||"Unknown"})}}startPeriodicCleanup(){this._secureLog("info","\u{1F527} Periodic cleanup moved to unified scheduler")}async calculateSecurityLevel(){return await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this)}shouldRotateKeys(){return!this.isConnected()||!this.isVerified?!1:Date.now()-this.lastKeyRotation>this.keyRotationInterval||this.messageCounter%100===0}async rotateKeys(){return this._withMutex("keyOperation",async e=>{if(this._secureLog("info","\u{1F504} Starting key rotation with mutex",{operationId:e}),!this.isConnected()||!this.isVerified)return this._secureLog("warn"," Key rotation aborted - connection not ready",{operationId:e,isConnected:this.isConnected(),isVerified:this.isVerified}),!1;if(this._keySystemState.isRotating)return this._secureLog("warn"," Key rotation already in progress",{operationId:e}),!1;try{this._keySystemState.isRotating=!0,this._keySystemState.lastOperation="rotation",this._keySystemState.lastOperationTime=Date.now();let t={type:"key_rotation_signal",newVersion:this.currentKeyVersion+1,timestamp:Date.now(),operationId:e};if(this.dataChannel&&this.dataChannel.readyState==="open")this.dataChannel.send(JSON.stringify(t));else throw new Error("Data channel not ready for key rotation");return this._hardWipeOldKeys(),new Promise(r=>{this.pendingRotation={newVersion:this.currentKeyVersion+1,operationId:e,resolve:r,timeout:setTimeout(()=>{this._secureLog("error"," Key rotation timeout",{operationId:e}),this._keySystemState.isRotating=!1,this.pendingRotation=null,r(!1)},1e4)}})}catch(t){return this._secureLog("error"," Key rotation failed in critical section",{operationId:e,errorType:t.constructor.name}),this._keySystemState.isRotating=!1,!1}},1e4)}cleanupOldKeys(){let e=Date.now(),t=s.LIMITS.MAX_KEY_AGE,r=0;for(let[i,n]of this.oldKeys.entries())e-n.timestamp>t&&(n.encryptionKey&&this._secureWipeMemory(n.encryptionKey,"pfs_cleanup_wipe"),n.macKey&&this._secureWipeMemory(n.macKey,"pfs_cleanup_wipe"),n.metadataKey&&this._secureWipeMemory(n.metadataKey,"pfs_cleanup_wipe"),n.encryptionKey=null,n.macKey=null,n.metadataKey=null,n.keyFingerprint=null,this.oldKeys.delete(i),r++,this._secureLog("info","\u{1F9F9} Old PFS keys hard wiped and cleaned up",{version:i,age:Math.round((e-n.timestamp)/1e3)+"s",timestamp:Date.now()}));r>0&&this._secureLog("info",`PFS cleanup completed: ${r} keys hard wiped`,{timestamp:Date.now()})}getKeysForVersion(e){let t=this.oldKeys.get(e);return t&&t.encryptionKey&&t.macKey&&t.metadataKey?{encryptionKey:t.encryptionKey,macKey:t.macKey,metadataKey:t.metadataKey}:e===this.currentKeyVersion&&this.encryptionKey&&this.macKey&&this.metadataKey?{encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey}:(window.EnhancedSecureCryptoUtils.secureLog.log("error","No valid keys found for version",{requestedVersion:e,currentVersion:this.currentKeyVersion,availableVersions:Array.from(this.oldKeys.keys())}),null)}_hasTurnServer(){return(this._config.webrtc.iceServers||[]).some(e=>(Array.isArray(e.urls)?e.urls:[e.urls]).some(r=>typeof r=="string"&&r.toLowerCase().startsWith("turn:")))}_buildPeerConnectionConfig(){let e=this._isRelayOnlyMode(),t={iceServers:this._config.webrtc.iceServers,iceCandidatePoolSize:10,bundlePolicy:"balanced"};return e&&(t.iceTransportPolicy="relay"),t}_summarizeIceServerConfig(e=[]){let t={serverCount:0,stun:0,turn:0,turns:0,hasCredentials:!1};for(let r of e||[]){t.serverCount+=1,(r?.username||r?.credential)&&(t.hasCredentials=!0);let i=Array.isArray(r?.urls)?r.urls:[r?.urls];for(let n of i){let a=String(n||"").toLowerCase();a.startsWith("stun:")&&(t.stun+=1),a.startsWith("turn:")&&(t.turn+=1),a.startsWith("turns:")&&(t.turns+=1)}}return t}_isRelayOnlyMode(){return this._config.webrtc.privacyMode==="relay-only"}_setRelayOnlyMode(e){let t=e===!0;this._config.webrtc.privacyMode=t?"relay-only":"standard",this._config.webrtc.relayOnly=t}_warnIfTurnMissing(){if(this._ipLeakWarningShown)return;this._ipLeakWarningShown=!0;let e=this._isRelayOnlyMode(),t=this._hasTurnServer(),r=null;e&&!t?r="Privacy mode is relay-only, but no TURN server is configured. Relay-only mode cannot connect until TURN is configured; STUN alone does not hide IP addresses.":!e&&!t?r="Privacy warning: relay-only mode is disabled and no TURN server is configured. Direct WebRTC connections may expose host or server-reflexive IP addresses; STUN alone does not provide IP protection.":e||(r="Privacy warning: relay-only mode is disabled. Direct WebRTC connectivity may expose host or server-reflexive IP addresses even when TURN is available."),r&&this.deliverMessageToUI(r,"system")}createPeerConnection(){this._sessionAlive=!0;let e=this._buildPeerConnectionConfig();this._warnIfTurnMissing(),console.info("[SecureBit ICE] peer connection config",this._summarizeIceServerConfig(e.iceServers)),this.peerConnection=new RTCPeerConnection(e),this._callAudioSender=null,this._callVideoSender=null,this.peerConnection.onconnectionstatechange=()=>{let t=this.peerConnection.connectionState;console.info("[SecureBit ICE] connection state changed",{connectionState:t,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState}),t==="connected"&&!this.isVerified?this._notifyVerificationReadyIfPossible():t==="connected"&&this.isVerified?this._onPathRecovered()||this.onStatusChange("connected"):t==="disconnected"?this.intentionalDisconnect?(this.onStatusChange("disconnected"),setTimeout(()=>this.disconnect(),100)):this.isVerified?this._onPathDegraded("ice_disconnected"):console.warn(`[SecureBit ICE] State is ${t} but not verified yet. Keeping session open for manual exchange.`):t==="closed"?(this._resetReconnectState(),this.onStatusChange("disconnected"),this._clearVerificationStates(),this.intentionalDisconnect&&setTimeout(()=>this.disconnect(),100)):t==="failed"?(this._collectIceFailureDiagnostics().then(r=>{console.warn("[SecureBit ICE] failure diagnostics",r),this._noteIceFailureDiagnostics(r)}),this.isVerified?this._onPathLost("ice_failed"):console.warn("[SecureBit ICE] State is failed but not verified yet. Keeping session open for manual exchange.")):this.isReconnecting()&&(t==="connecting"||t==="new")||this.onStatusChange(t)},this.peerConnection.oniceconnectionstatechange=()=>{console.info("[SecureBit ICE] ICE connection state changed",{connectionState:this.peerConnection.connectionState,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState})},this.peerConnection.onicecandidateerror=t=>{console.warn("[SecureBit ICE] ICE candidate error",{url:t.url,errorCode:t.errorCode,errorText:t.errorText})},this.peerConnection.ontrack=t=>{try{this._refreshRemoteStream()}catch(r){this._secureLog("warn","\u26A0\uFE0F ontrack handling failed",{errorType:r?.constructor?.name})}},this.peerConnection.ondatachannel=t=>{t.channel.label==="securechat"?(this.dataChannel=t.channel,this.setupDataChannel(t.channel)):t.channel.label==="heartbeat"&&(this.heartbeatChannel=t.channel)}}setupDataChannel(e){this.dataChannel=e;let t=!1,r=async()=>{if(!t){t=!0;try{this.dataChannel&&typeof this.dataChannel.bufferedAmountLowThreshold=="number"&&(this.dataChannel.bufferedAmountLowThreshold=1024*1024)}catch{}if(this._handshakeMode==="sbq2")try{await this._runSbq2KeyExchange()}catch(i){this._secureLog("error","SBQ2 key exchange failed to start",{errorType:i?.constructor?.name||"Unknown"}),this._sbq2Abort("start_failed","The secure handshake could not be started. Please try connecting again.");return}try{await this.establishConnection(),this.initializeFileTransfer()}catch(i){this._secureLog("error","Error in establishConnection:",{errorType:i?.constructor?.name||"Unknown"})}if(this.pendingSASCode&&this.dataChannel&&this.dataChannel.readyState==="open")try{let i={type:"sas_code",data:{code:this.pendingSASCode,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(i)),this.pendingSASCode=null}catch{}else this.pendingSASCode;this.isVerified?(this.onStatusChange("connected"),this.processMessageQueue(),setTimeout(async()=>{await this.calculateAndReportSecurityLevel(),this.autoEnableSecurityFeatures(),this.notifySecurityUpdate()},500)):(this._notifyVerificationReadyIfPossible(),this.initiateVerification()),this.startHeartbeat()}};this.dataChannel.onopen=r,this.dataChannel.readyState==="open"&&Promise.resolve().then(()=>r()).catch(i=>{this._secureLog("error","Deferred data channel open handling failed",{errorType:i?.constructor?.name||"Unknown"})}),this.dataChannel.onclose=()=>{this._resetReconnectState?.(),this._teardownRecoveryLifecycleListeners?.(),this.intentionalDisconnect?(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed","system"))):(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed. Check connection status.","system"))),this._wipeEphemeralKeys(),this.stopHeartbeat(),this.isVerified=!1},this.dataChannel.onmessage=async i=>{try{if(this._noteInboundActivity?.(),typeof i.data=="string")try{let n=JSON.parse(i.data),a=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(n.type&&a.includes(n.type)){if(!this._enforceVerificationGate("file_message_receive",!1)){this._secureLog("error","Dropped file message received before verification",{messageType:n.type});return}if(!this.fileTransferSystem)try{if(this.isVerified&&this.dataChannel&&this.dataChannel.readyState==="open"){this.initializeFileTransfer();let o=0,c=30;for(;!this.fileTransferSystem&&osetTimeout(d,100)),o++}}catch(o){this._secureLog("error","Failed to initialize file transfer system for receiver:",{errorType:o?.constructor?.name||"Unknown"})}if(this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}this._secureLog("warn","\u26A0\uFE0F File transfer system not ready, attempting lazy init...");try{if(await this._ensureFileTransferReady(),this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}}catch(o){this._secureLog("error","Lazy init of file transfer failed:",{errorType:o?.message||o?.constructor?.name||"Unknown"})}this._secureLog("error","No file transfer system available for:",{errorType:n.type?.constructor?.name||"Unknown"});return}if(n.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(n.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:n.type});return}let o=s.MESSAGE_TYPES;if(n.type===o.MESSAGE_DELETE){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelete?.(c.slice(0,64))}catch{}return}if(n.type===o.MESSAGE_RECEIPT){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelivered?.(c.slice(0,64))}catch{}return}if([o.CALL_OFFER,o.CALL_ANSWER,o.CALL_ICE,o.CALL_DECLINE,o.CALL_END].includes(n.type)){try{await this._handleCallSignal(n.type,n.data||{})}catch{}return}if([o.ICE_RESTART_OFFER,o.ICE_RESTART_ANSWER,o.ICE_RESTART_REQUEST].includes(n.type)){try{await this._handleIceRestartSignal(n.type,n.data||{})}catch(c){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:c?.constructor?.name})}return}return}if(n.type===s.MESSAGE_TYPES.KEY_BLOB||n.type===s.MESSAGE_TYPES.KEY_PROOF){await this._sbq2HandleHandshakeFrame(n);return}if(n.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","sas_code","peer_disconnect","security_upgrade"].includes(n.type)){this.handleSystemMessage(n);return}if(n.type===s.MESSAGE_TYPES.RATCHET_MESSAGE){await this._processRatchetMessage(n);return}if(n.type==="enhanced_message"&&n.data){await this._processEnhancedMessageWithoutMutex(n);return}this._secureLog("error","Rejected unencrypted frame on the chat channel",{messageType:typeof n.type=="string"?n.type.slice(0,32):typeof n.type});return}catch{this._secureLog("error","Rejected malformed (non-JSON) frame on the chat channel",{dataLength:typeof i.data=="string"?i.data.length:0});return}else i.data instanceof ArrayBuffer&&await this._processBinaryDataWithoutMutex(i.data)}catch(n){this._secureLog("error","Failed to process message in onmessage:",{errorType:n?.constructor?.name||"Unknown"})}}}async _processBinaryDataWithoutMutex(e){try{if(!this._checkInboundRateLimit("binary_message"))return;let t=e;if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&t instanceof ArrayBuffer&&t.byteLength>12)try{t=await this.removeNestedEncryption(t)}catch{this._secureLog("warn","Nested decryption failed, continuing with original data")}if(this.securityFeatures.hasPacketPadding&&t instanceof ArrayBuffer)try{t=this.removePacketPadding(t)}catch{this._secureLog("warn","Packet padding removal failed, continuing with original data")}if(this.securityFeatures.hasAntiFingerprinting&&t instanceof ArrayBuffer)try{t=this.removeAntiFingerprinting(t)}catch{this._secureLog("warn","Anti-fingerprinting removal failed, continuing with original data")}if(t instanceof ArrayBuffer){let r=new TextDecoder().decode(t);try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return}catch{}this._secureLog("error","Rejected unauthenticated binary frame on the chat channel",{byteLength:e?.byteLength||0})}}catch(t){this._secureLog("error","Error processing binary data:",{errorType:t?.constructor?.name||"Unknown"})}}async _processRatchetMessage(e){try{if(!this._checkInboundRateLimit("ratchet_message"))return;if(!this.isRatchetActive()){this._secureLog("error","Received a ratchet message but no ratchet is active");return}if(typeof e?.h!="string"||typeof e?.c!="string"){this._secureLog("error","Malformed ratchet message frame");return}let t=await this._ratchet.decrypt(e.h,e.c);try{let r=JSON.parse(t);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.deliverMessageToUI(t,"received")}catch(t){this._secureLog("error","Failed to decrypt ratchet message",{errorType:t?.constructor?.name||"Unknown"})}}async _processEnhancedMessageWithoutMutex(e){try{if(!this._checkInboundRateLimit("enhanced_message"))return;if(!this.encryptionKey||!this.macKey||!this.metadataKey){this._secureLog("error","Missing encryption keys for enhanced message");return}let t=await window.EnhancedSecureCryptoUtils.decryptMessage(e.data,this.encryptionKey,this.macKey,this.metadataKey);if(!this._validateIncomingSequenceNumber(t?.sequenceNumber,"enhanced_message")){this._secureLog("error","Rejected chat message failing anti-replay validation",{messageId:t?.messageId?"present":"absent"});return}if(t&&t.message){try{let r=JSON.parse(t.message);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.onMessage&&this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.onMessage&&this.deliverMessageToUI(t.message,"received")}else this._secureLog("warn","No message content in decrypted result")}catch(t){this._secureLog("error","Error processing enhanced message:",{errorType:t?.constructor?.name||"Unknown"})}}_generateOperationId(){return`op_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async _acquireMutex(e,t,r=5e3){let i=`_${e}Mutex`,n=this[i];if(!n)throw this._secureLog("error",`Unknown mutex: ${e}`,{mutexPropertyName:i,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex: ${e}. Available: ${this._getAvailableMutexes().join(", ")}`);if(!t||typeof t!="string")throw new Error("Invalid operation ID for mutex acquisition");return new Promise((a,o)=>{(()=>{if(n.lockId===t){this._secureLog("warn",`Mutex '${e}' already locked by same operation`,{operationId:t}),a();return}if(!n.locked)n.locked=!0,n.lockId=t,n.lockTime=Date.now(),this._secureLog("debug",`Mutex '${e}' acquired atomically`,{operationId:t,lockTime:n.lockTime}),n.lockTimeout=setTimeout(()=>{this._handleMutexTimeout(e,t,r)},r),a();else{let d={resolve:a,reject:o,operationId:t,timestamp:Date.now(),timeout:setTimeout(()=>{let u=n.queue.findIndex(h=>h.operationId===t);u!==-1&&(n.queue.splice(u,1),o(new Error(`Mutex acquisition timeout for '${e}'`)))},r)};n.queue.push(d),this._secureLog("debug",`Operation queued for mutex '${e}'`,{operationId:t,queueLength:n.queue.length,currentLockId:n.lockId})}})()})}_releaseMutex(e,t){if(!e||typeof e!="string")throw new Error("Invalid mutex name provided for release");if(!t||typeof t!="string")throw new Error("Invalid operation ID provided for mutex release");let r=`_${e}Mutex`,i=this[r];if(!i)throw this._secureLog("error",`Unknown mutex for release: ${e}`,{mutexPropertyName:r,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex for release: ${e}`);if(i.lockId!==t)throw this._secureLog("error","CRITICAL: Invalid mutex release attempt - potential race condition",{mutexName:e,expectedLockId:i.lockId,providedOperationId:t,mutexState:{locked:i.locked,lockTime:i.lockTime,queueLength:i.queue.length}}),new Error(`Invalid mutex release attempt for '${e}': expected '${i.lockId}', got '${t}'`);if(!i.locked)throw this._secureLog("error","CRITICAL: Attempting to release unlocked mutex",{mutexName:e,operationId:t,mutexState:{locked:i.locked,lockId:i.lockId,lockTime:i.lockTime}}),new Error(`Attempting to release unlocked mutex: ${e}`);try{i.lockTimeout&&(clearTimeout(i.lockTimeout),i.lockTimeout=null);let n=i.lockTime?Date.now()-i.lockTime:0;i.locked=!1,i.lockId=null,i.lockTime=null,this._secureLog("debug",`Mutex released successfully: ${e}`,{operationId:t,lockDuration:n,queueLength:i.queue.length}),this._processNextInQueue(e)}catch(n){throw this._secureLog("error","Error during mutex release queue processing",{mutexName:e,operationId:t,errorType:n.constructor.name,errorMessage:n.message}),i.locked=!1,i.lockId=null,i.lockTime=null,i.lockTimeout=null,n}}_processNextInQueue(e){let t=this[`_${e}Mutex`];if(!t){this._secureLog("error",`Mutex not found for queue processing: ${e}`);return}if(t.queue.length===0)return;if(t.locked){this._secureLog("warn",`Mutex '${e}' is still locked, skipping queue processing`,{lockId:t.lockId,queueLength:t.queue.length});return}let r=t.queue.shift();if(!r){this._secureLog("warn",`Empty queue item for mutex '${e}'`);return}if(!r.operationId||!r.resolve||!r.reject){this._secureLog("error",`Invalid queue item structure for mutex '${e}'`,{hasOperationId:!!r.operationId,hasResolve:!!r.resolve,hasReject:!!r.reject});return}try{r.timeout&&clearTimeout(r.timeout),this._secureLog("debug",`Processing next operation in queue for mutex '${e}'`,{operationId:r.operationId,queueRemaining:t.queue.length,timestamp:Date.now()}),setTimeout(async()=>{try{await this._acquireMutex(e,r.operationId,5e3),this._secureLog("debug",`Queued operation acquired mutex '${e}'`,{operationId:r.operationId,acquisitionTime:Date.now()}),r.resolve()}catch(i){this._secureLog("error",`Queued operation failed to acquire mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message,timestamp:Date.now()}),r.reject(new Error(`Queue processing failed for '${e}': ${i.message}`)),setTimeout(()=>{this._processNextInQueue(e)},50)}},10)}catch(i){this._secureLog("error",`Critical error during queue processing for mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message});try{r.reject(new Error(`Queue processing critical error: ${i.message}`))}catch(n){this._secureLog("error","Failed to reject queue item",{originalError:i.message,rejectError:n.message})}setTimeout(()=>{this._processNextInQueue(e)},100)}}_getAvailableMutexes(){let e=[],t=Object.getOwnPropertyNames(this);for(let r of t)if(r.endsWith("Mutex")&&r.startsWith("_")){let i=r.slice(1,-5);e.push(i)}return e}async _withMutex(e,t,r=5e3){let i=this._generateOperationId();if(!this._validateMutexSystem())throw this._secureLog("error","Mutex system not properly initialized",{operationId:i,mutexName:e}),new Error("Mutex system not properly initialized. Call _initializeMutexSystem() first.");let n=this[`_${e}Mutex`];if(!n)throw new Error(`Mutex '${e}' not found`);let a=!1;try{await this._acquireMutex(e,i,r),a=!0;let o=`${e}Operations`;this._operationCounters&&this._operationCounters[o]!==void 0&&this._operationCounters[o]++;let c=await t(i);return c===void 0&&t.name!=="cleanup"&&this._secureLog("warn","Mutex operation returned undefined result",{operationId:i,mutexName:e,operationName:t.name}),c}catch(o){throw this._secureLog("error","Error in mutex operation",{operationId:i,mutexName:e,errorType:o.constructor.name,errorMessage:o.message,mutexAcquired:a,mutexState:n?{locked:n.locked,lockId:n.lockId,queueLength:n.queue.length}:"null"}),e==="keyOperation"&&this._handleKeyOperationError(o,i),(o.message.includes("timeout")||o.message.includes("race condition"))&&this._emergencyUnlockAllMutexes("errorHandler"),o}finally{if(a)try{await this._releaseMutex(e,i),n.locked&&n.lockId===i&&(this._secureLog("error","Mutex release verification failed",{operationId:i,mutexName:e}),n.locked=!1,n.lockId=null,n.lockTimeout=null)}catch(o){this._secureLog("error","Error releasing mutex in finally block",{operationId:i,mutexName:e,releaseErrorType:o.constructor.name,releaseErrorMessage:o.message}),n.locked=!1,n.lockId=null,n.lockTimeout=null}}}_validateMutexSystem(){let e=["keyOperation","cryptoOperation","connectionOperation"];for(let t of e){let r=`_${t}Mutex`,i=this[r];if(!i||typeof i!="object")return this._secureLog("error",`Missing or invalid mutex: ${t}`,{mutexPropertyName:r,mutexType:typeof i}),!1;let n=["locked","queue","lockId","lockTimeout"];for(let a of n)if(!(a in i))return this._secureLog("error",`Mutex ${t} missing property: ${a}`),!1}return!0}_emergencyRecoverMutexSystem(){this._secureLog("warn","Emergency mutex system recovery initiated");try{if(this._emergencyUnlockAllMutexes("emergencyRecovery"),this._initializeMutexSystem(),!this._validateMutexSystem())throw new Error("Mutex system validation failed after recovery");return this._secureLog("info","Mutex system recovered successfully with validation"),!0}catch(e){this._secureLog("error","Failed to recover mutex system",{errorType:e.constructor.name,errorMessage:e.message});try{return this._initializeMutexSystem(),this._secureLog("warn","Forced mutex system re-initialization completed"),!0}catch(t){return this._secureLog("error","CRITICAL: Forced re-initialization also failed",{originalError:e.message,reinitError:t.message}),!1}}}async _generateEncryptionKeys(){return this._withMutex("keyOperation",async e=>{this._secureLog("info","Generating encryption keys with atomic mutex",{operationId:e});let t=this._keySystemState;if(t.isInitializing){this._secureLog("warn","Key generation already in progress, waiting for completion",{operationId:e,lastOperation:t.lastOperation,lastOperationTime:t.lastOperationTime});let r=0,i=50;for(;t.isInitializing&&rsetTimeout(n,100)),r++;if(t.isInitializing)throw new Error("Key generation timeout - operation still in progress after 5 seconds")}try{t.isInitializing=!0,t.lastOperation="generation",t.lastOperationTime=Date.now(),t.operationId=e,this._secureLog("debug","Atomic key generation state set",{operationId:e,timestamp:t.lastOperationTime});let r=null,i=null;try{if(r=await this._generateEphemeralECDHKeys(),!r||!r.privateKey||!r.publicKey)throw new Error("Ephemeral ECDH key pair validation failed");if(!this._validateKeyPairConstantTime(r))throw new Error("Ephemeral ECDH keys are not valid CryptoKey instances");this._secureLog("debug","Ephemeral ECDH keys generated and validated for PFS",{operationId:e,privateKeyType:r.privateKey.algorithm?.name,publicKeyType:r.publicKey.algorithm?.name,isEphemeral:!0})}catch(n){this._secureLog("error","Ephemeral ECDH key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ephemeral_ecdh_key_generation")}try{if(i=await window.EnhancedSecureCryptoUtils.generateECDSAKeyPair(),!i||!i.privateKey||!i.publicKey)throw new Error("ECDSA key pair validation failed");if(!this._validateKeyPairConstantTime(i))throw new Error("ECDSA keys are not valid CryptoKey instances");this._secureLog("debug","ECDSA keys generated and validated",{operationId:e,privateKeyType:i.privateKey.algorithm?.name,publicKeyType:i.publicKey.algorithm?.name})}catch(n){this._secureLog("error","ECDSA key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ecdsa_key_generation")}if(!r||!i)throw new Error("One or both key pairs failed to generate");return this._enableSecurityFeaturesAfterKeyGeneration(r,i),this._secureLog("info","Encryption keys generated successfully with atomic protection",{operationId:e,hasECDHKeys:!!(r?.privateKey&&r?.publicKey),hasECDSAKeys:!!(i?.privateKey&&i?.publicKey),generationTime:Date.now()-t.lastOperationTime}),{ecdhKeyPair:r,ecdsaKeyPair:i}}catch(r){throw this._secureLog("error","Key generation failed, resetting state",{operationId:e,errorType:r.constructor.name}),r}finally{t.isInitializing=!1,t.operationId=null,this._secureLog("debug","Key generation state reset",{operationId:e})}})}_enableSecurityFeaturesAfterKeyGeneration(e,t){try{e&&e.privateKey&&e.publicKey&&(this.securityFeatures.hasEncryption=!0,this.securityFeatures.hasECDH=!0,this._secureLog("info","ECDH encryption features enabled")),t&&t.privateKey&&t.publicKey&&(this.securityFeatures.hasECDSA=!0,this._secureLog("info","ECDSA signature features enabled")),this.securityFeatures.hasEncryption&&(this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasNonExtractableKeys=!0,this._secureLog("info","Additional encryption-dependent features enabled")),e&&this.ephemeralKeyPairs.size>0&&(this.securityFeatures.hasPFS=!0,this._secureLog("info","Perfect Forward Secrecy enabled with ephemeral keys")),this._secureLog("info","Security features updated after key generation",{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasMetadataProtection:this.securityFeatures.hasMetadataProtection,hasEnhancedReplayProtection:this.securityFeatures.hasEnhancedReplayProtection,hasNonExtractableKeys:this.securityFeatures.hasNonExtractableKeys,hasPFS:this.securityFeatures.hasPFS})}catch(r){this._secureLog("error","Failed to enable security features after key generation",{errorType:r.constructor.name,errorMessage:r.message})}}_emergencyUnlockAllMutexes(e="unknown"){let t=["keyOperation","cryptoOperation","connectionOperation","emergencyRecovery","systemShutdown","errorHandler"];if(!t.includes(e))throw this._secureLog("error","UNAUTHORIZED emergency mutex unlock attempt",{callerContext:e,authorizedCallers:t,timestamp:Date.now()}),new Error(`Unauthorized emergency mutex unlock attempt by: ${e}`);let r=["keyOperation","cryptoOperation","connectionOperation"];this._secureLog("error","EMERGENCY: Unlocking all mutexes with authorization and state cleanup",{callerContext:e,timestamp:Date.now()});let i=0,n=0;if(r.forEach(a=>{let o=this[`_${a}Mutex`];if(o)try{o.lockTimeout&&clearTimeout(o.lockTimeout);let c={locked:o.locked,lockId:o.lockId,lockTime:o.lockTime,queueLength:o.queue.length};o.locked=!1,o.lockId=null,o.lockTimeout=null,o.lockTime=null;let d=0;o.queue.forEach(u=>{try{u.reject&&typeof u.reject=="function"&&(u.reject(new Error(`Emergency mutex unlock for ${a} by ${e}`)),d++)}catch(h){this._secureLog("warn","Failed to reject queue item during emergency unlock",{mutexName:a,errorType:h.constructor.name})}}),o.queue=[],i++,this._secureLog("debug",`Emergency unlocked mutex: ${a}`,{previousState:c,queueRejectCount:d,callerContext:e})}catch(c){n++,this._secureLog("error",`Error during emergency unlock of mutex: ${a}`,{errorType:c.constructor.name,errorMessage:c.message,callerContext:e})}}),this._keySystemState)try{let a={...this._keySystemState};this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null,this._keySystemState.concurrentOperations=0,this._secureLog("debug","Emergency reset key system state",{previousState:a,callerContext:e})}catch(a){this._secureLog("error","Error resetting key system state during emergency unlock",{errorType:a.constructor.name,errorMessage:a.message,callerContext:e})}this._secureLog("info","Emergency mutex unlock completed",{callerContext:e,unlockedCount:i,errorCount:n,totalMutexes:r.length,timestamp:Date.now()}),setTimeout(()=>{this._validateMutexSystemAfterEmergencyUnlock()},100)}_handleKeyOperationError(e,t){this._secureLog("error","Key operation error detected, initiating recovery",{operationId:t,errorType:e.constructor.name,errorMessage:e.message}),this._keySystemState&&(this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null),this.ecdhKeyPair=null,this.ecdsaKeyPair=null,this.encryptionKey=null,this.macKey=null,this.metadataKey=null,(e.message.includes("timeout")||e.message.includes("race condition"))&&(this._secureLog("warn","Race condition or timeout detected, triggering emergency recovery"),this._emergencyRecoverMutexSystem())}_generateSecureIV(e=12,t="general"){if(this._ivTrackingSystem.emergencyMode)throw this._secureLog("error","CRITICAL: IV generation blocked - emergency mode active due to IV reuse"),new Error("IV generation blocked - emergency mode active");let r=0,i=100;for(;ro.toString(16).padStart(2,"0")).join("");if(this._ivTrackingSystem.usedIVs.has(a)){if(this._ivTrackingSystem.collisionCount++,this._secureLog("error","CRITICAL: IV reuse detected!",{context:t,attempt:r,collisionCount:this._ivTrackingSystem.collisionCount,ivString:a.substring(0,16)+"..."}),this._ivTrackingSystem.collisionCount>5)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to excessive IV reuse"),new Error("Emergency mode: Excessive IV reuse detected");continue}if(!this._validateIVEntropy(n)){if(this._ivTrackingSystem.entropyValidation.entropyFailures++,this._secureLog("warn","Low entropy IV detected",{context:t,attempt:r,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures}),this._ivTrackingSystem.entropyValidation.entropyFailures>10)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to low entropy IVs"),new Error("Emergency mode: Low entropy IVs detected");continue}return this._ivTrackingSystem.usedIVs.add(a),this._ivTrackingSystem.ivHistory.set(a,{timestamp:Date.now(),context:t,attempt:r}),this.sessionId&&(this._ivTrackingSystem.sessionIVs.has(this.sessionId)||this._ivTrackingSystem.sessionIVs.set(this.sessionId,new Set),this._ivTrackingSystem.sessionIVs.get(this.sessionId).add(a)),this._validateRNGQuality(),this._secureLog("debug","Secure IV generated",{context:t,attempt:r,ivSize:e,totalIVs:this._ivTrackingSystem.usedIVs.size}),n}throw this._secureLog("error",`Failed to generate unique IV after ${i} attempts`,{context:t,totalIVs:this._ivTrackingSystem.usedIVs.size}),new Error(`Failed to generate unique IV after ${i} attempts`)}_validateIVEntropy(e){this._ivTrackingSystem.entropyValidation.entropyTests++;let t=new Array(256).fill(0);for(let S=0;S0){let g=t[S]/n;i-=g*Math.log2(g)}r.shannon=i;let o=Math.max(...t)/n;r.min=-Math.log2(o);let c=0;for(let S=0;S<256;S++)if(t[S]>0){let g=t[S]/n;c+=g*g}r.collision=-Math.log2(c);let d=Array.from(e).map(S=>String.fromCharCode(S)).join(""),u=this._estimateCompressedLength(d);r.compression=(1-u/n)*8,r.quantum=this._calculateQuantumResistantEntropy(e);let h=this._detectAdvancedSuspiciousPatterns(e),m=this._ivTrackingSystem.entropyValidation.minEntropy,p=r.shannon>=m&&r.min>=m*.8&&r.collision>=m*.9&&r.compression>=m*.7&&r.quantum>=m*.6&&!h;return p||this._secureLog("warn","Enhanced IV entropy validation failed",{shannon:r.shannon.toFixed(2),min:r.min.toFixed(2),collision:r.collision.toFixed(2),compression:r.compression.toFixed(2),quantum:r.quantum.toFixed(2),minThreshold:m,hasSuspiciousPatterns:h}),p}_estimateCompressedLength(e){let t=0,r=0;for(;ri&&(i=o,n=r-a)}i>=3?(t+=3,r+=i):(t+=1,r+=1)}return t}_calculateQuantumResistantEntropy(e){let t=0;this._detectQuantumVulnerablePatterns(e)&&(t-=2);let i=this._analyzeBitDistribution(e);t+=i.score;let n=this._detectPeriodicity(e);return t-=n*.5,Math.max(0,Math.min(8,t))}_detectQuantumVulnerablePatterns(e){let t=[[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,1,0,1,0,1,0,1],[1,0,1,0,1,0,1,0]];for(let r of t)for(let i=0;i<=e.length-r.length;i++){let n=!0;for(let a=0;a>>0).toString(2).split("1").length-1;let i=(r-t)/r,n=t/r,a=Math.abs(.5-n);return{score:Math.max(0,8-a*16),zeroRatio:i,oneRatio:n,deviation:a}}_detectPeriodicity(e){if(e.length<16)return 0;let t=0;for(let r=2;r<=e.length/2;r++){let i=0,n=0;for(let a=0;a0){let a=i/n;t=Math.max(t,a)}}return t}_detectAdvancedSuspiciousPatterns(e){let t=[[0,1,2,3,4,5,6,7],[255,254,253,252,251,250,249,248],[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,255,0,255,0,255,0,255],[255,0,255,0,255,0,255,0]];for(let n of t)for(let a=0;a<=e.length-n.length;a++){let o=!0;for(let c=0;cn<3).length>e.length*.3}_calculateLocalEntropy(e){let r=[];for(let i=0;i<=e.length-8;i++){let n=e.slice(i,i+8),a={};for(let c of n)a[c]=(a[c]||0)+1;let o=0;for(let c of Object.values(a)){let d=c/8;o-=d*Math.log2(d)}r.push(o)}return r}_detectSuspiciousIVPatterns(e){let t=e.every(n=>n===0),r=e.every(n=>n===255);if(t||r)return!0;let i=0;for(let n=1;n=3)return!0;for(let n=2;n<=Math.floor(e.length/2);n++)for(let a=0;a<=e.length-n*2;a++){let o=e.slice(a,a+n),c=e.slice(a+n,a+n*2);if(o.every((d,u)=>d===c[u]))return!0}return!1}async _cleanupOldIVs(){let e=Date.now(),t=18e5,r=0,i=[];if(this._ivTrackingSystem.ivHistory.size>this._ivTrackingSystem.maxIVHistorySize){let n=Array.from(this._ivTrackingSystem.ivHistory.entries()),a=n.slice(0,n.length-this._ivTrackingSystem.maxIVHistorySize);for(let[o]of a)i.push(o),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0)}for(let[n,a]of this._ivTrackingSystem.ivHistory.entries())e-a.timestamp>t&&(i.push(n),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0));i.length>0&&this._processCleanupBatch(i);for(let[n,a]of this._ivTrackingSystem.sessionIVs.entries())if(a.size>this._ivTrackingSystem.maxSessionIVs){let o=Array.from(a),c=o.slice(0,o.length-this._ivTrackingSystem.maxSessionIVs);for(let d of c)a.delete(d),this._ivTrackingSystem.usedIVs.delete(d),this._ivTrackingSystem.ivHistory.delete(d),r++}r>50&&await this._performNaturalCleanup(),r>0&&this._secureLog("debug",`Enhanced cleanup: ${r} old IVs removed`,{cleanedCount:r,remainingIVs:this._ivTrackingSystem.usedIVs.size,remainingHistory:this._ivTrackingSystem.ivHistory.size,memoryPressure:this._calculateMemoryPressure()})}_processCleanupBatch(e){for(let t of e)this._ivTrackingSystem.usedIVs.delete(t),this._ivTrackingSystem.ivHistory.delete(t)}_calculateMemoryPressure(){let e=this._ivTrackingSystem.usedIVs.size,t=this._resourceLimits.maxIVHistory;return Math.min(100,Math.floor(e/t*100))}_getIVTrackingStats(){return{totalIVs:this._ivTrackingSystem.usedIVs.size,collisionCount:this._ivTrackingSystem.collisionCount,entropyTests:this._ivTrackingSystem.entropyValidation.entropyTests,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures,rngTests:this._ivTrackingSystem.rngValidation.testsPerformed,weakRngDetected:this._ivTrackingSystem.rngValidation.weakRngDetected,emergencyMode:this._ivTrackingSystem.emergencyMode,sessionCount:this._ivTrackingSystem.sessionIVs.size,lastCleanup:this._lastIVCleanupTime||0}}_resetIVTrackingSystem(){this._secureLog("warn","Resetting IV tracking system"),this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.entropyValidation.entropyTests=0,this._ivTrackingSystem.entropyValidation.entropyFailures=0,this._ivTrackingSystem.rngValidation.testsPerformed=0,this._ivTrackingSystem.rngValidation.weakRngDetected=!1,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","IV tracking system reset completed")}_validateRNGQuality(){let e=Date.now();if(this._ivTrackingSystem.rngValidation.testsPerformed%1e3===0)try{let t=[];for(let n=0;n<100;n++)t.push(crypto.getRandomValues(new Uint8Array(12)));let r=t.map(n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("")),i=new Set(r);i.size<95&&(this._ivTrackingSystem.rngValidation.weakRngDetected=!0,this._secureLog("error","CRITICAL: Weak RNG detected in validation test",{uniqueIVs:i.size,totalTests:t.length})),this._ivTrackingSystem.rngValidation.lastValidation=e}catch(t){this._secureLog("error","RNG validation failed",{errorType:t.constructor.name})}this._ivTrackingSystem.rngValidation.testsPerformed++}_handleMutexTimeout(e,t,r){let i=this[`_${e}Mutex`];if(!i){this._secureLog("error",`Mutex '${e}' not found during timeout handling`);return}if(i.lockId!==t){this._secureLog("warn",`Timeout for different operation ID on mutex '${e}'`,{expectedOperationId:t,actualLockId:i.lockId,locked:i.locked});return}if(!i.locked){this._secureLog("warn",`Timeout for already unlocked mutex '${e}'`,{operationId:t});return}try{let n=i.lockTime?Date.now()-i.lockTime:0;this._secureLog("warn",`Mutex '${e}' auto-released due to timeout`,{operationId:t,lockDuration:n,timeout:r,queueLength:i.queue.length}),i.locked=!1,i.lockId=null,i.lockTimeout=null,i.lockTime=null,setTimeout(()=>{try{this._processNextInQueue(e)}catch(a){this._secureLog("error",`Error processing queue after timeout for mutex '${e}'`,{errorType:a.constructor.name,errorMessage:a.message})}},10)}catch(n){this._secureLog("error",`Critical error during mutex timeout handling for '${e}'`,{operationId:t,errorType:n.constructor.name,errorMessage:n.message});try{this._emergencyUnlockAllMutexes("timeoutHandler")}catch(a){this._secureLog("error","Emergency unlock failed during timeout handling",{originalError:n.message,emergencyError:a.message})}}}_validateMutexSystemAfterEmergencyUnlock(){let e=["keyOperation","cryptoOperation","connectionOperation"],t=0;this._secureLog("info","Validating mutex system after emergency unlock"),e.forEach(r=>{let i=this[`_${r}Mutex`];if(!i){t++,this._secureLog("error",`Mutex '${r}' not found after emergency unlock`);return}i.locked&&(t++,this._secureLog("error",`Mutex '${r}' still locked after emergency unlock`,{lockId:i.lockId,lockTime:i.lockTime})),i.lockId!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has lock ID after emergency unlock`,{lockId:i.lockId})),i.lockTimeout!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has timeout after emergency unlock`)),i.queue.length>0&&(t++,this._secureLog("error",`Mutex '${r}' still has queue items after emergency unlock`,{queueLength:i.queue.length}))}),this._keySystemState&&(this._keySystemState.isInitializing||this._keySystemState.isRotating||this._keySystemState.isDestroying)&&(t++,this._secureLog("error","Key system state not properly reset after emergency unlock",{isInitializing:this._keySystemState.isInitializing,isRotating:this._keySystemState.isRotating,isDestroying:this._keySystemState.isDestroying})),t===0?this._secureLog("info","Mutex system validation passed after emergency unlock"):(this._secureLog("error","Mutex system validation failed after emergency unlock",{validationErrors:t}),setTimeout(()=>{this._emergencyRecoverMutexSystem()},1e3))}_getMutexSystemDiagnostics(){let e={timestamp:Date.now(),systemValid:this._validateMutexSystem(),mutexes:{},counters:{...this._operationCounters},keySystemState:{...this._keySystemState}};return["keyOperation","cryptoOperation","connectionOperation"].forEach(r=>{let i=`_${r}Mutex`,n=this[i];n?e.mutexes[r]={locked:n.locked,lockId:n.lockId,queueLength:n.queue.length,hasTimeout:!!n.lockTimeout}:e.mutexes[r]={error:"not_found"}}),e}async createSecureOffer(){return this._withMutex("connectionOperation",async e=>{this._secureLog("info","Creating secure offer with mutex",{operationId:e,connectionAttempts:this.connectionAttempts,currentState:this.peerConnection?.connectionState||"none"});try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this.connectionAttempts=0,this.sessionSalt=window.EnhancedSecureCryptoUtils.generateSalt(),this._secureLog("debug","Session salt generated",{operationId:e,saltLength:this.sessionSalt.length,isValidSalt:Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64});let t=await this._generateEncryptionKeys();if(this.ecdhKeyPair=t.ecdhKeyPair,this.ecdsaKeyPair=t.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdhKeyPair?.publicKey)throw new Error("Failed to generate valid ECDH key pair");if(!this.ecdsaKeyPair?.privateKey||!this.ecdsaKeyPair?.publicKey)throw new Error("Failed to generate valid ECDSA key pair");let r=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdhKeyPair.publicKey)),i=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdsaKeyPair.publicKey));if(!r||!i)throw new Error("Failed to generate key fingerprints");this._secureLog("info","Generated unique key pairs for MITM protection",{operationId:e,hasECDHFingerprint:!!r,hasECDSAFingerprint:!!i,fingerprintLength:r.length,timestamp:Date.now()});let n=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),a=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!n||typeof n!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!a||typeof a!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.isInitiator=!0,this.onStatusChange("connecting"),this.createPeerConnection(),this.dataChannel=this.peerConnection.createDataChannel("securechat",{ordered:!0}),this.setupDataChannel(this.dataChannel),this._secureLog("debug","Data channel created",{operationId:e,channelLabel:this.dataChannel.label,channelOrdered:this.dataChannel.ordered});let o=await this.peerConnection.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});await this.peerConnection.setLocalDescription(o);try{let b=this._extractDTLSFingerprintFromSDP(o.sdp);this.expectedDTLSFingerprint=b,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:b,context:"offer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${b}`,"system")}catch(b){this._secureLog("error","Failed to extract DTLS fingerprint from offer",{error:b.message})}let c=Date.now(),d=await this.waitForIceGathering(),u=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),h=u.total;if(!d&&h===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the invitation would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");if(this._secureLog(h>0?"info":"warn","ICE candidates captured for offer export",{candidateSummary:u,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),this._logIceCandidateDiagnostics("offer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),d||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the invitation. Connectivity may still fail on restrictive networks.","system"),h===0&&this.deliverMessageToUI("No ICE candidates were gathered for the invitation yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed",{operationId:e,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState}),this.verificationCode=window.EnhancedSecureCryptoUtils.generateVerificationCode(),!this.verificationCode||this.verificationCode.lengthb.toString(16).padStart(2,"0")).join(""),!this.sessionId||this.sessionId.length!==s.SIZES.SESSION_ID_LENGTH*2)throw new Error("Failed to generate valid session ID");this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(b=>b.toString(16).padStart(2,"0")).join(""),this._storePendingOfferContext();let p={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},S=Date.now(),g={t:"offer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:S,e:n,d:a,sl:this.sessionSalt,si:this.sessionId,ci:this.connectionId,vc:this.verificationCode,ac:m,slv:"MAX",dr:s.RATCHET_VERSION,kf:{e:r.substring(0,12),d:i.substring(0,12)}};try{let b=this.validateEnhancedOfferData(g)}catch(b){throw new Error(`Offer package validation error: ${b.message}`)}if(this._secureLog("info","Enhanced secure offer created successfully",{operationId:e,version:g.version,hasECDSA:!0,hasMutualAuth:!0,hasSessionId:!!g.sessionId,securityLevel:p.level,timestamp:S,capabilitiesCount:10}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"offer",timestamp:S,securityLevel:p.level,operationId:e}})),s.SBQ2_SEND_ENABLED){this._latchHandshakeMode("sbq2");let{text:b}=await this._sbq2BuildDescriptor(de.OFFER);return{t:"offer",sbq2:b}}return this._latchHandshakeMode("sb1"),g}catch(t){throw this._secureLog("error","Enhanced secure offer creation failed in critical section",{operationId:e,errorType:t.constructor.name,errorMessage:t.message,phase:this._determineErrorPhase(t),connectionAttempts:this.connectionAttempts}),this._cleanupFailedOfferCreation(),this.onStatusChange("disconnected"),t}},6e4)}_determineErrorPhase(e){let t=e.message.toLowerCase();return t.includes("rate limit")?"rate_limiting":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("fingerprint")?"fingerprinting":t.includes("export")||t.includes("signature")?"key_export":t.includes("peer connection")?"webrtc_setup":t.includes("offer")||t.includes("sdp")?"sdp_creation":t.includes("verification")?"verification_setup":t.includes("session")?"session_setup":t.includes("validation")?"package_validation":"unknown"}_cleanupFailedOfferCreation(){try{this._secureCleanupCryptographicMaterials(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during offer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed offer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during offer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}_updateSecurityFeatures(e){let t={...this.securityFeatures};try{Object.assign(this.securityFeatures,e),this._secureLog("debug","Security features updated",{updatedCount:Object.keys(e).length,totalFeatures:Object.keys(this.securityFeatures).length})}catch(r){throw this.securityFeatures=t,this._secureLog("error","Security features update failed, rolled back",{errorType:r.constructor.name}),r}}async _createSbq2Answer(e){return this._withMutex("connectionOperation",async t=>{try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this._latchHandshakeMode("sbq2");let r=Ur(String(e.sbq2)),i=this._sbq2AdoptRemoteDescriptor(r,de.OFFER),{sdp:n}=Kr(i);this.isInitiator=!1,this.onStatusChange("connecting");let a=await this._generateEncryptionKeys();if(this.ecdhKeyPair=a.ecdhKeyPair,this.ecdsaKeyPair=a.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdsaKeyPair?.privateKey)throw new Error("Failed to generate valid key pairs");this.createPeerConnection(),this._peerDTLSFingerprint=Array.from(i.fingerprint,d=>d.toString(16).padStart(2,"0").toUpperCase()).join(":"),await this.peerConnection.setRemoteDescription({type:"offer",sdp:n}),await this.peerConnection.setLocalDescription(await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})),this.expectedDTLSFingerprint=this._extractDTLSFingerprintFromSDP(this.peerConnection.localDescription.sdp),await this.waitForIceGathering();let o=async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),{text:c}=await this._sbq2BuildDescriptor(de.ANSWER,{bindingTag:await Or(o,r)});return this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:Date.now(),operationId:t}})),{t:"answer",sbq2:c}}catch(r){throw this._secureLog("error","SBQ2 answer creation failed",{operationId:t,errorType:r?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),r}},6e4)}async createSecureAnswer(e){return e&&typeof e.sbq2=="string"?this._createSbq2Answer(e):this._withMutex("connectionOperation",async t=>{this._secureLog("info","Creating secure answer with mutex",{operationId:t,hasOfferData:!!e,offerType:e?.type,offerVersion:e?.version,offerTimestamp:e?.timestamp});try{if(this._resetNotificationFlags(),this._secureLog("debug","Starting enhanced offer validation",{operationId:t,hasOfferData:!!e,offerType:e?.type,hasECDHKey:!!e?.ecdhPublicKey,hasECDSAKey:!!e?.ecdsaPublicKey,hasSalt:!!e?.salt}),!this.validateEnhancedOfferData(e))throw new Error("Invalid connection data format - failed enhanced validation");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkConnectionRate(this.rateLimiterId))throw new Error("Connection rate limit exceeded. Please wait before trying again.");let r=e.ts||e.timestamp,i=e.v||e.version;if(!r||!i)throw new Error("Missing required security fields in offer data \u2013 possible MITM attack");let n=Date.now()-r,a=18e5;if(n>a)throw this._secureLog("error","Offer data is too old - possible replay attack",{operationId:t,offerAge:Math.round(n/1e3),maxAllowedAge:Math.round(a/1e3),timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Offer data is too old \u2013 possible replay attack"),new Error("Offer data is too old \u2013 possible replay attack");let o=i;if(o!==s.PROTOCOL_VERSION)throw this._secureLog("warn","Protocol version mismatch detected",{operationId:t,expectedVersion:s.PROTOCOL_VERSION,receivedVersion:o}),new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${o}`);if(this.sessionSalt=e.sl||e.salt,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,!Array.isArray(this.sessionSalt))throw new Error("Invalid session salt format - must be array");let c=64;if(this.sessionSalt.length!==c)throw new Error(`Invalid session salt length: expected ${c}, got ${this.sessionSalt.length}`);let d=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);this._secureLog("info","Session salt validated successfully",{operationId:t,saltLength:this.sessionSalt.length,saltFingerprint:d.substring(0,8)});let u=await this._generateEncryptionKeys();if(this.ecdhKeyPair=u.ecdhKeyPair,this.ecdsaKeyPair=u.ecdsaKeyPair,!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw this._secureLog("error","Local ECDH private key is not a CryptoKey",{operationId:t,hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a valid CryptoKey");let h;try{let R=e.d||e.ecdsaPublicKey;h=await crypto.subtle.importKey("spki",new Uint8Array(R.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"])}catch(R){this._throwSecureError(R,"ecdsa_key_import")}let m;try{let R=e.e||e.ecdhPublicKey;m=await window.EnhancedSecureCryptoUtils.importSignedPublicKey(R,h,"ECDH")}catch(R){this._secureLog("error","Failed to import signed ECDH public key",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"ecdh_key_import")}if(!(m instanceof CryptoKey))throw this._secureLog("error","Peer ECDH public key is not a CryptoKey",{operationId:t,publicKeyType:typeof m,publicKeyAlgorithm:m?.algorithm?.name}),new Error("Peer ECDH public key is not a valid CryptoKey");this.peerPublicKey=m;let p;try{this._secureLog("debug","About to call deriveSharedKeys",{operationId:t,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),p=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,m,this.sessionSalt),this._secureLog("debug","deriveSharedKeys completed successfully",{operationId:t,hasMessageKey:!!p.messageKey,hasMacKey:!!p.macKey,hasPfsKey:!!p.pfsKey,hasMetadataKey:!!p.metadataKey,hasFingerprint:!!p.fingerprint})}catch(R){this._secureLog("error","Failed to derive shared keys",{operationId:t,errorType:R.constructor.name,errorMessage:R.message,errorStack:R.stack,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),this._throwSecureError(R,"key_derivation")}if(await this._setEncryptionKeys(p.messageKey,p.macKey,p.metadataKey,p.fingerprint),await this._initializeRatchet(p,!1),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw this._secureLog("error","Invalid key types after derivation",{operationId:t,encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey}),new Error("Invalid key types after derivation");this.verificationCode=e.vc||e.verificationCode||null,this._secureLog("info","Encryption keys derived and set successfully",{operationId:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0});let S;if(e.authChallenge)try{S=await window.EnhancedSecureCryptoUtils.createAuthProof(e.authChallenge,this.ecdsaKeyPair.privateKey,this.ecdsaKeyPair.publicKey)}catch(R){this._secureLog("error","Failed to create authentication proof",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"authentication_proof_creation")}else this._secureLog("warn","No auth challenge in offer - mutual auth disabled",{operationId:t});if(this.isInitiator=!1,this.onStatusChange("connecting"),this.onKeyExchange(this.keyFingerprint),this.createPeerConnection(),this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp)}catch(R){this._secureLog("warn","Could not extract peer DTLS fingerprint from offer",{error:R.message,context:"offer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");try{this._secureLog("debug","Setting remote description from offer",{operationId:t,sdpLength:e.sdp?.length||0}),await this.peerConnection.setRemoteDescription(new RTCSessionDescription({type:"offer",sdp:e.s||e.sdp})),this._logIceCandidateDiagnostics("remote offer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("offer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully",{operationId:t,signalingState:this.peerConnection.signalingState})}catch(R){this._secureLog("error","Failed to set remote description",{error:R.message,operationId:t}),this._throwSecureError(R,"webrtc_remote_description")}this._secureLog("debug","Remote description set successfully",{operationId:t,connectionState:this.peerConnection.connectionState,signalingState:this.peerConnection.signalingState});let g;try{g=await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})}catch(R){this._throwSecureError(R,"webrtc_create_answer")}try{await this.peerConnection.setLocalDescription(g)}catch(R){this._throwSecureError(R,"webrtc_local_description")}try{let R=this._extractDTLSFingerprintFromSDP(g.sdp);this.expectedDTLSFingerprint=R,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:R,context:"answer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${R}`,"system")}catch(R){this._secureLog("error","Failed to extract DTLS fingerprint from answer",{error:R.message})}try{let R=this._extractDTLSFingerprintFromSDP(e.s||e.sdp),ue=this.expectedDTLSFingerprint,K=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(K,ue,R),this._setSASMaterialReady(ue,R)}catch(R){throw this._secureLog("error","SAS computation failed in createSecureAnswer (Answer side)",{errorType:R?.constructor?.name||"Unknown"}),new Error(`SAS computation failed: ${R.message}`)}let b=Date.now(),w=await this.waitForIceGathering(),M=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),F=M.total;if(!w&&F===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the response would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");this._secureLog(F>0?"info":"warn","ICE candidates captured for answer export",{candidateSummary:M,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-b,iceGatheringCompleted:w}),this._logIceCandidateDiagnostics("answer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-b,iceGatheringCompleted:w}),w||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the response. Connectivity may still fail on restrictive networks.","system"),F===0&&this.deliverMessageToUI("No ICE candidates were gathered for the response yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed for answer",{operationId:t,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState});let k=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),E=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!k||typeof k!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!k.keyData||!k.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!k.keyData,hasSignature:!!k.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!E||typeof E!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!E.keyData||!E.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!E.keyData,hasSignature:!!E.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");let _={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},A=Date.now(),x={t:"answer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:A,e:k,d:E,ap:S,slv:"MAX",dr:s.RATCHET_VERSION,sc:{sf:d.substring(0,12),kd:!0,ma:!0}},T=x.s||x.sdp,Y=x.e||x.ecdhPublicKey,B=x.d||x.ecdsaPublicKey;if(!T||!Y||!B)throw new Error("Generated answer package is incomplete");return this._secureLog("info","Enhanced secure answer created successfully",{operationId:t,version:x.version,hasECDSA:!0,hasMutualAuth:!!S,hasSessionConfirmation:!!x.sessionConfirmation,securityLevel:_.level,timestamp:A,processingTime:A-e.timestamp}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:A,securityLevel:_.level,operationId:t}})),setTimeout(async()=>{try{let R=await this.calculateAndReportSecurityLevel();R&&(this.notifySecurityUpdate(),this._secureLog("info","Post-connection security level calculated",{operationId:t,level:R.level}))}catch(R){this._secureLog("error","Error calculating post-connection security",{operationId:t,errorType:R.constructor.name})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(this._secureLog("info","Retrying security calculation",{operationId:t}),await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate(),x}catch(r){throw this._secureLog("error","Enhanced secure answer creation failed in critical section",{operationId:t,errorType:r.constructor.name,errorMessage:r.message,phase:this._determineAnswerErrorPhase(r),offerAge:e?.timestamp?Date.now()-e.timestamp:"unknown"}),this._cleanupFailedAnswerCreation(),this.onStatusChange("disconnected"),this.onAnswerError&&(r.message.includes("too old")||r.message.includes("replay")?this.onAnswerError("replay_attack",r.message):r.message.includes("MITM")||r.message.includes("signature")?this.onAnswerError("security_violation",r.message):r.message.includes("validation")||r.message.includes("format")?this.onAnswerError("invalid_format",r.message):this.onAnswerError("general_error",r.message)),r}},6e4)}_determineAnswerErrorPhase(e){let t=e.message.toLowerCase();return t.includes("validation")||t.includes("format")?"offer_validation":t.includes("rate limit")?"rate_limiting":t.includes("replay")||t.includes("too old")?"replay_protection":t.includes("salt")?"salt_validation":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("import")||t.includes("ecdsa")||t.includes("ecdh")?"key_import":t.includes("signature")||t.includes("mitm")?"signature_verification":t.includes("derive")||t.includes("shared")?"key_derivation":t.includes("auth")||t.includes("proof")?"authentication":t.includes("remote description")||t.includes("local description")?"webrtc_setup":t.includes("answer")||t.includes("sdp")?"sdp_creation":t.includes("export")?"key_export":t.includes("security level")?"security_calculation":"unknown"}_cleanupFailedAnswerCreation(){try{this._clearPendingOfferContext(),this._secureCleanupCryptographicMaterials(),this.currentKeyVersion=0,this.keyVersions.clear(),this.oldKeys.clear(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during answer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed answer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during answer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}async _setEncryptionKeys(e,t,r,i){return this._withMutex("keyOperation",async n=>{if(this._secureLog("info","Setting encryption keys with mutex",{operationId:n}),!(e instanceof CryptoKey)||!(t instanceof CryptoKey)||!(r instanceof CryptoKey))throw new Error("Invalid key types provided");if(!i||typeof i!="string")throw new Error("Invalid key fingerprint provided");let a={encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey,keyFingerprint:this.keyFingerprint};try{return this.encryptionKey=e,this.macKey=t,this.metadataKey=r,this.keyFingerprint=i,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._secureLog("info","Encryption keys set successfully",{operationId:n,hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasFingerprint:!!this.keyFingerprint}),!0}catch(o){throw this.encryptionKey=a.encryptionKey,this.macKey=a.macKey,this.metadataKey=a.metadataKey,this.keyFingerprint=a.keyFingerprint,this._secureLog("error","Key setting failed, rolled back",{operationId:n,errorType:o.constructor.name}),o}})}async _handleSbq2Answer(e){if(!this._isSbq2())throw new Error("Received a new-format response to an old-format invitation. Please start a new invitation.");let t=this._sbq2State(),r=Ur(String(e.sbq2)),i=Fr(r);if(i.type!==de.ANSWER)throw new Error("That code is an invitation, not a response to one.");if(!i.commitment)throw new Error("The response carries no key commitment");let a=await Or(async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),t.localDescriptor),o=0;for(let d=0;dd.toString(16).padStart(2,"0").toUpperCase()).join(":");let{sdp:c}=Kr(i);await this.peerConnection.setRemoteDescription({type:"answer",sdp:c}),this._secureLog("info","SBQ2 answer accepted; awaiting in-band key exchange",{bytes:r.length})}async handleSecureAnswer(e){if(e&&typeof e.sbq2=="string")return this._handleSbq2Answer(e);try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid answer data structure",{hasAnswerData:!!e,answerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Answer data must be a non-null object");let t=e.t==="answer"&&e.s,r=e.type==="enhanced_secure_answer"&&e.sdp;if(!t&&!r)throw this._secureLog("error","CRITICAL: Invalid answer format",{type:e.type||e.t,hasSdp:!!(e.sdp||e.s)}),new Error("CRITICAL SECURITY FAILURE: Invalid answer format - hard abort required");let i=e.v||e.version;if(i!==s.PROTOCOL_VERSION)throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${i||"unknown"}`);let n=e.ecdhPublicKey||e.e,a=e.ecdsaPublicKey||e.d;if(!n||typeof n!="object"||Array.isArray(n))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure in answer",{hasEcdhKey:!!n,ecdhKeyType:typeof n,isArray:Array.isArray(n),availableKeys:Object.keys(e)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDH public key structure");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature in answer",{hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!a||typeof a!="object"||Array.isArray(a))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure in answer",{hasEcdsaKey:!!a,ecdsaKeyType:typeof a,isArray:Array.isArray(a)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDSA public key structure");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature in answer",{hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");let o=e.ts||e.timestamp,c=e.v||e.version;if(!o||!c)throw new Error("Missing required fields in response data \u2013 possible MITM attack");if(e.sessionId&&this.sessionId&&e.sessionId!==this.sessionId)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Session ID mismatch detected - possible MITM attack",{}),new Error("Session ID mismatch \u2013 possible MITM attack");let d=Date.now()-e.timestamp;if(d>36e5)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Answer data is too old - possible replay attack",{answerAge:d,timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Response data is too old \u2013 possible replay attack"),new Error("Response data is too old \u2013 possible replay attack");i!==s.PROTOCOL_VERSION&&window.EnhancedSecureCryptoUtils.secureLog.log("warn","Incompatible protocol version in answer",{expectedVersion:s.PROTOCOL_VERSION,receivedVersion:i});let u=await crypto.subtle.importKey("spki",new Uint8Array(a.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),h=await window.EnhancedSecureCryptoUtils.importPublicKeyFromSignedPackage(n,u);if(this._restorePendingOfferContextIfNeeded(),!this.sessionSalt||this.sessionSalt.length!==64)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid session salt detected - possible session hijacking",{saltLength:this.sessionSalt?this.sessionSalt.length:0}),new Error("Missing pending offer context. Apply the response in the original creator window that generated the invitation.");let m=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);if(window.EnhancedSecureCryptoUtils.secureLog.log("info","Session salt integrity verified",{saltFingerprint:m.substring(0,8)}),!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Local ECDH private key is not a CryptoKey in handleSecureAnswer",{hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a CryptoKey");if(!(h instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Peer ECDH public key is not a CryptoKey in handleSecureAnswer",{publicKeyType:typeof h,publicKeyAlgorithm:h?.algorithm?.name}),new Error("Peer ECDH public key is not a CryptoKey");this.peerPublicKey=h,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,this.connectionId||(this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(g=>g.toString(16).padStart(2,"0")).join(""));let p=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,h,this.sessionSalt);if(this.encryptionKey=p.messageKey,this.macKey=p.macKey,this.metadataKey=p.metadataKey,this.keyFingerprint=p.fingerprint,await this._initializeRatchet(p,!0),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid key types after derivation in handleSecureAnswer",{encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey,encryptionKeyAlgorithm:this.encryptionKey?.algorithm?.name,macKeyAlgorithm:this.macKey?.algorithm?.name,metadataKeyAlgorithm:this.metadataKey?.algorithm?.name}),new Error("Invalid key types after export");this._secureLog("info","Encryption keys set in handleSecureAnswer",{hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasPFS=!0,this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0}),this.onKeyExchange(this.keyFingerprint);try{let g=this._extractDTLSFingerprintFromSDP(e.sdp||e.s),b=this.expectedDTLSFingerprint,w=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(w,b,g),this._setSASMaterialReady(b,g),this.pendingSASCode=this.verificationCode,this._secureLog("info","SAS verification code generated for MITM protection (Offer side)",{sasCode:this.verificationCode,localFP:b.substring(0,16)+"...",remoteFP:g.substring(0,16)+"...",timestamp:Date.now()})}catch(g){this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{errorType:g?.constructor?.name||"Unknown"}),this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{error:g.message,stack:g.stack,timestamp:Date.now()})}if(this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp||e.s)}catch(g){this._secureLog("warn","Could not extract peer DTLS fingerprint from answer",{error:g.message,context:"answer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");let S=e.sdp||e.s;if(this.peerConnection?.signalingState!=="have-local-offer"){this._secureLog("warn","Ignoring answer outside have-local-offer state",{signalingState:this.peerConnection?.signalingState||"unknown"});return}this._secureLog("debug","Setting remote description from answer",{sdpLength:S?.length||0,usingCompactSDP:!e.sdp&&!!e.s}),await this.peerConnection.setRemoteDescription({type:"answer",sdp:S}),this._logIceCandidateDiagnostics("remote answer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("answer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully from answer",{signalingState:this.peerConnection.signalingState}),setTimeout(async()=>{try{await this.calculateAndReportSecurityLevel()&&this.notifySecurityUpdate()}catch(g){this._secureLog("error","Error calculating security after connection:",{errorType:g?.constructor?.name||"Unknown"})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate()}catch(t){throw this._secureLog("error","Enhanced secure answer handling failed",{errorType:t.constructor.name}),this.onStatusChange("failed"),this.onAnswerError&&(t.message.includes("too old")||t.message.includes("\u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0441\u0442\u0430\u0440\u044B\u0435")?this.onAnswerError("replay_attack",t.message):t.message.includes("MITM")||t.message.includes("signature")||t.message.includes("\u043F\u043E\u0434\u043F\u0438\u0441\u044C")?this.onAnswerError("security_violation",t.message):this.onAnswerError("general_error",t.message)),t}}initiateVerification(){this.isInitiator?this.verificationInitiationSent||(this.verificationInitiationSent=!0,this.deliverMessageToUI("CRITICAL: Compare verification code with peer out-of-band (voice/video/in-person) to prevent MITM attack!","system"),this.deliverMessageToUI(`Your verification code: ${this.verificationCode}`,"system"),this.deliverMessageToUI("Ask peer to confirm this exact code before allowing traffic!","system")):this.deliverMessageToUI("Waiting for verification code from peer...","system")}_validateSASCode(e){if(!e||typeof e!="string"||!this.verificationCode||typeof this.verificationCode!="string")return!1;let t=e.replace(/[-\s]/g,"").toUpperCase(),r=this.verificationCode.replace(/[-\s]/g,"").toUpperCase();return t.length!==r.length?!1:window.EnhancedSecureCryptoUtils.constantTimeCompare(t,r)}confirmVerification(e){try{if(!this._validateSASCode(e))throw this.sasValidationAttempts=(this.sasValidationAttempts||0)+1,this._secureLog("warn","SAS validation failed: user entered incorrect code",{attempts:this.sasValidationAttempts,maxAttempts:s.MAX_SAS_ATTEMPTS}),this.sasValidationAttempts>=s.MAX_SAS_ATTEMPTS?(this.deliverMessageToUI("Verification failed 3 times. Session reset for safety.","system"),this.disconnect(),new Error("SAS_MAX_ATTEMPTS")):new Error("SAS_MISMATCH");this.localVerificationConfirmed=!0,this.sasValidationAttempts=0;let t={type:"verification_confirmed",data:{timestamp:Date.now(),verificationMethod:"MANUAL_SAS_ENTRY",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(t)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed(),this.deliverMessageToUI("Code verified locally. Waiting for peer confirmation...","system"),this.processMessageQueue()}catch(t){throw t.message==="SAS_MISMATCH"?this.deliverMessageToUI("Verification failed: the code you entered is incorrect.","system"):t.message!=="SAS_MAX_ATTEMPTS"&&(this._secureLog("error","SAS verification failed:",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("SAS verification failed","system")),t}}_checkBothVerificationsConfirmed(){if(this.localVerificationConfirmed&&this.remoteVerificationConfirmed&&!this.bothVerificationsConfirmed){this.bothVerificationsConfirmed=!0;let e={type:"verification_both_confirmed",data:{timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_COMPLETE"}};this.dataChannel.send(JSON.stringify(e)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{try{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")}catch(t){this._secureLog("error","Verified transition rejected - aborting session",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("Verification could not be completed safely. Connection aborted.","system"),this.disconnect()}},2e3)}}handleVerificationConfirmed(e){this.remoteVerificationConfirmed=!0,this.deliverMessageToUI("Peer confirmed the verification code. Waiting for your confirmation...","system"),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed()}handleVerificationBothConfirmed(e){if(!this.bothVerificationsConfirmed){if(!this.localVerificationConfirmed){this._secureLog("error","Peer claimed mutual SAS confirmation before local confirmation - possible MITM attack",{localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,timestamp:Date.now()}),this.deliverMessageToUI("Verification protocol violation: peer claimed confirmation before you verified the code. Connection aborted for safety.","system"),this.disconnect();return}this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")},2e3)}}handleVerificationRequest(e){if(this._validateSASCode(e?.code)){let t={type:"verification_response",data:{ok:!0,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTED"}};this.dataChannel.send(JSON.stringify(t)),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI("SAS verification successful! MITM protection confirmed. Channel is now secure!","system")),this.processMessageQueue()}else{let t={type:"verification_response",data:{ok:!1,timestamp:Date.now(),reason:"code_mismatch"}};this.dataChannel.send(JSON.stringify(t)),this._secureLog("error","SAS verification failed - possible MITM attack",{receivedCodeLength:typeof e?.code=="string"?e.code.length:0,timestamp:Date.now()}),this.deliverMessageToUI("SAS verification failed! Possible MITM attack detected. Connection aborted for safety!","system"),this.disconnect()}}handleSASCode(e){if(!e?.code||typeof e.code!="string"){this._secureLog("warn","Invalid SAS announcement received from peer");return}if(!this.verificationCode){this._secureLog("error","Received peer SAS announcement before local SAS was derived - refusing to adopt it",{timestamp:Date.now()}),this.deliverMessageToUI("Verification failed: no locally derived code to compare against. Connection aborted for safety.","system"),this.disconnect();return}if(!this._validateSASCode(e.code)){this._secureLog("error","Peer-announced SAS does not match locally computed SAS"),this.deliverMessageToUI("Version or SAS mismatch detected. Connection aborted for safety.","system"),this.disconnect();return}this._notifyVerificationReadyIfPossible(),this._secureLog("info","Peer SAS announcement matched locally derived code",{timestamp:Date.now()})}handleVerificationResponse(e){e.ok===!0?(this._secureLog("info","Mutual SAS verification completed - MITM protection active",{verificationMethod:e.verificationMethod||"SAS",securityLevel:e.securityLevel||"MITM_PROTECTED",timestamp:Date.now()}),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI(" Mutual SAS verification complete! MITM protection active. Channel is now secure!","system")),this.processMessageQueue()):(this._secureLog("error","Peer SAS verification failed - connection not secure",{responseData:e,timestamp:Date.now()}),this.deliverMessageToUI("Peer verification failed! Connection not secure!","system"),this.disconnect())}validateOfferData(e){return e&&e.type==="enhanced_secure_offer"&&e.sdp&&e.publicKey&&e.salt&&e.verificationCode&&Array.isArray(e.publicKey)&&Array.isArray(e.salt)&&e.salt.length===32}validateEnhancedOfferData(e){try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid offer data structure",{hasOfferData:!!e,offerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Offer data must be a non-null object");let t=e.v===s.PROTOCOL_VERSION&&e.e&&e.d,r=e.version===s.PROTOCOL_VERSION&&e.ecdhPublicKey&&e.ecdsaPublicKey;if(!(t?["offer"].includes(e.t):["enhanced_secure_offer","secure_offer"].includes(e.type)))throw new Error("Invalid offer type");if(t){let a=["e","d","sl","vc","si","ci","ac","slv"];for(let c of a)if(!e[c])throw new Error(`Missing required v4.1 compact field: ${c}`);if(!e.e||typeof e.e!="object"||Array.isArray(e.e))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure");if(!e.d||typeof e.d!="object"||Array.isArray(e.d))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure");if(!Array.isArray(e.sl)||e.sl.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");if(typeof e.vc!="string"||e.vc.length<6)throw new Error("Invalid verification code format");if(!["MAX","HIGH","MED","LOW"].includes(e.slv))throw new Error("Invalid security level");let o=Date.now()-e.ts;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");this._secureLog("info","v4.1 compact offer validation passed",{version:e.v,hasECDH:!!e.e,hasECDSA:!!e.d,hasSalt:!!e.sl,hasVerificationCode:!!e.vc,securityLevel:e.slv,offerAge:Math.round(o/1e3)+"s"})}else if(r){let a=["ecdhPublicKey","ecdsaPublicKey","salt","verificationCode","authChallenge","timestamp","version","securityLevel"];for(let c of a)if(!e[c])throw new Error(`Missing v4.1 field: ${c}`);if(!Array.isArray(e.salt)||e.salt.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");let o=Date.now()-e.timestamp;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");if(!e.ecdhPublicKey||typeof e.ecdhPublicKey!="object"||Array.isArray(e.ecdhPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure",{hasEcdhKey:!!e.ecdhPublicKey,ecdhKeyType:typeof e.ecdhPublicKey,isArray:Array.isArray(e.ecdhPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure - hard abort required");if(!e.ecdsaPublicKey||typeof e.ecdsaPublicKey!="object"||Array.isArray(e.ecdsaPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure",{hasEcdsaKey:!!e.ecdsaPublicKey,ecdsaKeyType:typeof e.ecdsaPublicKey,isArray:Array.isArray(e.ecdsaPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure - hard abort required");if(!e.ecdhPublicKey.keyData||!e.ecdhPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature",{hasKeyData:!!e.ecdhPublicKey.keyData,hasSignature:!!e.ecdhPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!e.ecdsaPublicKey.keyData||!e.ecdsaPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature",{hasKeyData:!!e.ecdsaPublicKey.keyData,hasSignature:!!e.ecdsaPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");if(typeof e.verificationCode!="string"||e.verificationCode.length<6)throw new Error("Invalid SAS verification code format - MITM protection required");this._secureLog("info","v4.1 offer validation passed",{version:e.version,hasSecurityLevel:!!e.securityLevel?.level,offerAge:Math.round(o/1e3)+"s"})}else{let a=e.v||e.version||"unknown";throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${a}`)}let n=t?e.s:e.sdp;if(typeof n!="string"||!n.includes("v=0"))throw new Error("Invalid SDP structure");return!0}catch(t){throw this._secureLog("error","CRITICAL: Security validation failed - hard abort required",{error:t.message,errorType:t.constructor.name,timestamp:Date.now()}),new Error(`CRITICAL SECURITY VALIDATION FAILURE: ${t.message}`)}}async sendSecureMessage(e){let t=this._validateInputData(e,"sendSecureMessage");if(!t.isValid){let r=`Input validation failed: ${t.errors.join(", ")}`;throw this._secureLog("error","Input validation failed in sendSecureMessage",{errors:t.errors,messageType:typeof e}),new Error(r)}if(!this._checkRateLimit("sendSecureMessage"))throw new Error("Rate limit exceeded for secure message sending");if(this._enforceVerificationGate("sendSecureMessage"),!this.isConnected())throw t.sanitizedData&&typeof t.sanitizedData=="object"&&t.sanitizedData.type&&t.sanitizedData.type.startsWith("file_")?new Error("Connection not ready for file transfer. Please ensure the connection is established and verified."):(this.messageQueue.push(t.sanitizedData),new Error("Connection not ready. Message queued for sending."));return this._withMutex("cryptoOperation",async r=>{if(!this.isConnected()||!this.isVerified)throw new Error("Connection lost during message preparation");if(!this.encryptionKey||!this.macKey||!this.metadataKey)throw new Error("Encryption keys not initialized");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkMessageRate(this.rateLimiterId))throw new Error("Message rate limit exceeded (60 messages per minute)");try{let i=typeof t.sanitizedData=="string"?t.sanitizedData:JSON.stringify(t.sanitizedData),n=window.EnhancedSecureCryptoUtils.sanitizeMessage(i),a=`msg_${Date.now()}_${this.messageCounter++}`;if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in sendSecureMessage. Manager may not be fully initialized.");let o=e.aad||this._createMessageAAD("enhanced_message",{content:n}),c;if(this._ratchet?.canEncrypt){let{header:d,ciphertext:u}=await this._ratchet.encrypt(n);c={type:s.MESSAGE_TYPES.RATCHET_MESSAGE,h:d,c:u,version:"5.0"}}else c={type:"enhanced_message",data:await window.EnhancedSecureCryptoUtils.encryptMessage(n,this.encryptionKey,this.macKey,this.metadataKey,a,JSON.parse(o).sequenceNumber),keyVersion:this.currentKeyVersion,version:"4.0"};this.dataChannel.send(JSON.stringify(c)),typeof t.sanitizedData=="string"&&this.deliverMessageToUI(t.sanitizedData,"sent"),this._secureLog("debug","Secure message sent successfully",{operationId:r,messageLength:n.length,keyVersion:this.currentKeyVersion})}catch(i){throw this._secureLog("error","Secure message sending failed",{operationId:r,errorType:i.constructor.name}),i.message.includes("Session expired")?new Error("Session expired. Please enter your password to unlock."):i.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):i.message.includes("Connection lost")?new Error("Connection lost. Please check your Internet connection."):i.message.includes("Rate limit exceeded")?new Error("Message rate limit exceeded. Please wait before sending another message."):i}},2e3)}processMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected()&&this.isVerified;){let e=this.messageQueue.shift();this.sendSecureMessage(e).catch(console.error)}}startHeartbeat(){this._heartbeatConfig={enabled:!0,interval:s.TIMEOUTS.HEARTBEAT_INTERVAL,lastHeartbeat:0},this.stopHeartbeat(!0),this._heartbeatTimer=setInterval(()=>{this._heartbeatConfig?.enabled&&this.dataChannel?.readyState==="open"&&this._sendHeartbeat()},s.TIMEOUTS.HEARTBEAT_INTERVAL),this._trackActiveTimer(this._heartbeatTimer),this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!1,this._startLivenessWatchdog(),this._setupRecoveryLifecycleListeners(),this._secureLog("info","\u{1F504} Liveness watchdog started",{heartbeatMs:s.TIMEOUTS.HEARTBEAT_INTERVAL,probeAfterMs:s.TIMEOUTS.LIVENESS_PROBE_AFTER,probeTimeoutMs:s.TIMEOUTS.LIVENESS_PROBE_TIMEOUT})}stopHeartbeat(e=!1){!e&&this._heartbeatConfig&&(this._heartbeatConfig.enabled=!1),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._activeTimers?.delete(this._heartbeatTimer),this._heartbeatTimer=null),e||this._stopLivenessWatchdog()}handleHeartbeat(e){this._lastInboundAt=Date.now(),this._livenessProbeAt=0;let t=e?.ack===!0||e?.data?.ack===!0;t||this._sendHeartbeat(!0),this._secureLog("debug",t?"\u{1F493} Heartbeat ack received":"\u{1F493} Heartbeat probe received")}_noteInboundActivity(){this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!0}_startLivenessWatchdog(){this._stopLivenessWatchdog(),this._livenessTimer=setInterval(()=>{try{this._checkLiveness()}catch(e){this._secureLog("error","\u274C Liveness check failed",{errorType:e?.constructor?.name||"Unknown"})}},s.TIMEOUTS.LIVENESS_CHECK_INTERVAL),this._trackActiveTimer(this._livenessTimer)}_stopLivenessWatchdog(){this._livenessTimer&&(clearInterval(this._livenessTimer),this._activeTimers?.delete(this._livenessTimer),this._livenessTimer=null)}_checkLiveness(){if(!this.isVerified||this._reconnect.phase!=="idle"||this.dataChannel?.readyState!=="open"||!this._lastInboundAt||!this._livenessArmed)return;let e=s.TIMEOUTS,t=Date.now();if(this.peerConnection?.connectionState==="connected"){this._livenessProbeAt=0;return}if(this._livenessProbeAt){if(t-this._livenessProbeAt"u"||this._recoveryLifecycleBound||(this._recoveryLifecycleBound=!0,this._onDeviceOnline=()=>{this.isVerified&&(this.isReconnecting()?(this._secureLog("info","\u{1F504} Device back online \u2014 retrying immediately"),this._attemptIceRestart()):this._checkLiveness())},this._onVisibilityRestored=()=>{typeof document>"u"||document.visibilityState!=="visible"||this.isVerified&&(this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._reconnect.phase==="idle"&&this.dataChannel?.readyState==="open"&&(this._livenessProbeAt=Date.now(),this._sendHeartbeat(!1),this._secureLog("info","\u{1F504} returned to foreground, probing peer")))},window.addEventListener("online",this._onDeviceOnline),typeof document<"u"&&document.addEventListener("visibilitychange",this._onVisibilityRestored))}_teardownRecoveryLifecycleListeners(){!this._recoveryLifecycleBound||typeof window>"u"||(this._recoveryLifecycleBound=!1,this._onDeviceOnline&&window.removeEventListener("online",this._onDeviceOnline),this._onVisibilityRestored&&typeof document<"u"&&document.removeEventListener("visibilitychange",this._onVisibilityRestored),this._onDeviceOnline=null,this._onVisibilityRestored=null)}_resetReconnectState(){let e=this._reconnect;e&&(e.graceTimer&&(clearTimeout(e.graceTimer),this._activeTimers?.delete(e.graceTimer)),e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer)),e.restartTimer&&(clearTimeout(e.restartTimer),this._activeTimers?.delete(e.restartTimer)),e.graceTimer=null,e.retryTimer=null,e.restartTimer=null,e.phase="idle",e.attempts=0,e.startedAt=0,e.inFlightAt=0,e.barrenFailures=0,e.pendingRole=null)}_onPathDegraded(e="ice_disconnected"){this.isVerified&&this._reconnect.phase==="idle"&&(this._reconnect.phase="grace",this._reconnect.startedAt=Date.now(),this._secureLog("info","\u{1F504} path degraded, holding grace window",{reason:e}),this.onStatusChange("reconnecting"),this._reconnect.graceTimer=setTimeout(()=>{if(this._reconnect.graceTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},s.TIMEOUTS.ICE_DISCONNECT_GRACE),this._trackActiveTimer(this._reconnect.graceTimer))}_onPathLost(e="ice_failed"){this.isVerified&&(this._reconnect.phase==="restarting"||this._reconnect.phase==="exhausted"||(this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.graceTimer&&(clearTimeout(this._reconnect.graceTimer),this._activeTimers?.delete(this._reconnect.graceTimer),this._reconnect.graceTimer=null),this._secureLog("info","\u{1F504} path lost, restarting ICE",{reason:e}),this._attemptIceRestart()))}_noteIceFailureDiagnostics(e){if(this.isReconnecting()&&e){if(e.pairCount>0){this._reconnect.barrenFailures=0;return}this._reconnect.barrenFailures=(this._reconnect.barrenFailures||0)+1,!(this._reconnect.barrenFailuress.TIMEOUTS.RECONNECT_MAX_DURATION){this._giveUpAutoReconnect("timeout");return}if(e.inFlightAt&&Date.now()-e.inFlightAt=2&&r>s.TIMEOUTS.RECOVERY_SILENCE_LIMIT){this._secureLog("warn","\u26A0\uFE0F nothing has reached us since the drop \u2014 the channel cannot carry a renegotiation",{silentForMs:r,attempts:e.attempts}),this._giveUpAutoReconnect("no_signalling_path");return}e.phase="restarting",e.attempts+=1,e.inFlightAt=Date.now(),this._secureLog("info","\u{1F504} ICE restart attempt",{attempt:e.attempts,role:this.isInitiator?"offerer":"answerer"});try{this.isInitiator?await this._sendIceRestartOffer():await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_REQUEST,timestamp:Date.now()})}catch(i){this._secureLog("warn","\u26A0\uFE0F ICE restart attempt failed to send",{errorType:i?.constructor?.name||"Unknown"})}this._scheduleReconnectRetry()}_scheduleReconnectRetry(){let e=this._reconnect;e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer));let t=s.RECONNECT_BACKOFF,r=t[Math.min(Math.max(e.attempts-1,0),t.length-1)];e.retryTimer=setTimeout(()=>{if(e.retryTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},r),this._trackActiveTimer(e.retryTimer)}_applyCurrentIceServers(e){try{if(!e||typeof e.getConfiguration!="function"||typeof e.setConfiguration!="function")return;let t=this._config?.webrtc?.iceServers;if(!Array.isArray(t)||t.length===0)return;e.setConfiguration({...e.getConfiguration(),iceServers:t})}catch(t){this._secureLog("warn","Could not refresh ICE servers before restart",{errorType:t?.constructor?.name||"Unknown"})}}async _sendIceRestartOffer(){let e=this.peerConnection;if(!e)return;if(this._applyCurrentIceServers(e),e.signalingState==="have-local-offer")try{await e.setLocalDescription({type:"rollback"})}catch{}let t=await e.createOffer({iceRestart:!0});await e.setLocalDescription(t),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_OFFER,sdp:e.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart offer sent")}_currentRemoteDtlsFingerprint(){let e=this.peerConnection?.currentRemoteDescription?.sdp||this.peerConnection?.remoteDescription?.sdp;if(!e)return null;try{return this._extractDTLSFingerprintFromSDP(e)}catch{return null}}async _assertSameRemoteIdentity(e,t){let r=this._currentRemoteDtlsFingerprint();if(!r)throw new Error(`Cannot verify peer identity for ${t}`);let i=this._extractDTLSFingerprintFromSDP(e);await this._validateDTLSFingerprint(i,r,t)}async _handleIceRestartSignal(e,t){let r=s.MESSAGE_TYPES,i=this.peerConnection;if(i)switch(this._noteInboundActivity(),e){case r.ICE_RESTART_REQUEST:{if(!this.isInitiator)return;this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this._reconnect.phase="restarting",this.onStatusChange("reconnecting")),await this._sendIceRestartOffer();return}case r.ICE_RESTART_OFFER:{if(!t.sdp)return;await this._assertSameRemoteIdentity(t.sdp,"ice_restart_offer"),this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.phase="restarting",this._applyCurrentIceServers(i),await i.setRemoteDescription({type:"offer",sdp:t.sdp});let n=await i.createAnswer();await i.setLocalDescription(n),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:r.ICE_RESTART_ANSWER,sdp:i.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart answer sent");return}case r.ICE_RESTART_ANSWER:{if(!t.sdp)return;if(i.signalingState!=="have-local-offer"){this._secureLog("warn","\u26A0\uFE0F Ignoring restart answer in unexpected state",{signalingState:i.signalingState});return}await this._assertSameRemoteIdentity(t.sdp,"ice_restart_answer"),await i.setRemoteDescription({type:"answer",sdp:t.sdp}),this._reconnect.inFlightAt=0,this._secureLog("debug","\u{1F504} ICE restart answer applied");return}default:}}_giveUpAutoReconnect(e){this._resetReconnectState(),this._reconnect.phase="exhausted",this._teardownRecoveryLifecycleListeners?.(),this._secureLog("warn","\u26A0\uFE0F automatic reconnection exhausted \u2014 ending session",{reason:e}),this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Could not restore the connection. This chat is being closed and its data wiped \u2014 start a new one to continue.","system")),this.onStatusChange("recovery_failed"),this._clearVerificationStates()}_stopAllTimers(){this._secureLog("info","Stopping all timers and cleanup scheduler"),this._maintenanceScheduler&&(clearInterval(this._maintenanceScheduler),this._maintenanceScheduler=null),this.stopHeartbeat?.(),this._resetReconnectState?.(),this._activeTimers&&(this._activeTimers.forEach(e=>{e&&(clearInterval(e),clearTimeout(e))}),this._activeTimers.clear()),this._fileTransferInitRetryTimers&&this._fileTransferInitRetryTimers.clear(),this._logCleanupInterval=null,this._secureLog("info","All timers stopped successfully")}waitForIceGathering(e=s.TIMEOUTS.ICE_GATHERING_TIMEOUT,t=s.TIMEOUTS.ICE_GATHERING_HARD_TIMEOUT){return new Promise(r=>{let i=this.peerConnection;if(!i){r(!1);return}if(i.iceGatheringState==="complete"){r(!0);return}let n=!1,a=null,o=null,c=()=>{try{let h=this.peerConnection?.localDescription?.sdp;return h?this._summarizeIceCandidatesInSDP(h).total>0:!1}catch{return!1}},d=h=>{if(!n){n=!0,a&&(clearTimeout(a),this._untrackActiveTimer?.(a)),o&&(clearTimeout(o),this._untrackActiveTimer?.(o));try{i.removeEventListener("icegatheringstatechange",u)}catch{}r(h)}},u=()=>{this.peerConnection?.iceGatheringState==="complete"&&d(!0)};i.addEventListener("icegatheringstatechange",u),a=setTimeout(()=>{c()&&d(!1)},e),this._trackActiveTimer?.(a),o=setTimeout(()=>d(!1),Math.max(t,e)),this._trackActiveTimer?.(o)})}retryConnection(){this._secureLog("info","Retrying connection",{attempt:this.connectionAttempts,maxAttempts:this.maxConnectionAttempts}),this.onStatusChange("retrying")}isConnected(){let e=!!this.dataChannel,r=this.dataChannel?.readyState==="open",i=this.isVerified,n=this.peerConnection?.connectionState;return this.dataChannel&&this.dataChannel.readyState==="open"&&this.isVerified}getConnectionInfo(){return{fingerprint:this.keyFingerprint,isConnected:this.isConnected(),isVerified:this.isVerified,connectionState:this.peerConnection?.connectionState,iceConnectionState:this.peerConnection?.iceConnectionState,verificationCode:this.verificationCode}}handleUnexpectedDisconnect(){this.sendDisconnectNotification(),this.isVerified=!1,this.disconnectNotificationSent||(this.disconnectNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Connection lost. Attempting to reconnect...","system")),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"connection_lost",timestamp:Date.now()}}))}sendDisconnectNotification(){try{if(this.dataChannel&&this.dataChannel.readyState==="open"){let e={type:"peer_disconnect",timestamp:Date.now(),reason:this.intentionalDisconnect?"user_disconnect":"connection_lost"};for(let t=0;t<3;t++)try{this.dataChannel.send(JSON.stringify(e)),window.EnhancedSecureCryptoUtils.secureLog.log("info","Disconnect notification sent",{reason:e.reason,attempt:t+1});break}catch(r){t===2&&window.EnhancedSecureCryptoUtils.secureLog.log("error","Failed to send disconnect notification",{error:r.message})}}}catch(e){window.EnhancedSecureCryptoUtils.secureLog.log("error","Could not send disconnect notification",{error:e.message})}}attemptReconnection(){return!this.isVerified||this.dataChannel?.readyState!=="open"?(this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Unable to reconnect. A new connection is required.","system")),!1):(this._resetReconnectState(),this.reconnectionFailedNotificationSent=!1,this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting"),this._attemptIceRestart(),!0)}handlePeerDisconnectNotification(e){let t=e.reason||"unknown",r=t==="user_disconnect"?"manually disconnected.":"connection lost.";this.peerDisconnectNotificationSent||(this.peerDisconnectNotificationSent=!0,this.deliverMessageToUI(`Peer ${r}`,"system")),this.onStatusChange("peer_disconnected"),this.intentionalDisconnect=!1,this.isVerified=!1,this.stopHeartbeat(),this.onKeyExchange(""),this.onVerificationRequired(""),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:t,timestamp:Date.now()}})),this._peerDisconnectCleanupTimer||(this._peerDisconnectCleanupTimer=this._trackActiveTimer(setTimeout(()=>{let i=this._peerDisconnectCleanupTimer;this._peerDisconnectCleanupTimer=null,this._untrackActiveTimer(i),this._sessionAlive!==!1&&this.disconnect()},2e3))),window.EnhancedSecureCryptoUtils.secureLog.log("info","Peer disconnect notification processed",{reason:t})}disconnect(){try{this._sessionAlive=!1;try{this._stopAdaptation?.()}catch{}try{this._stopLocalMediaPermanently?.()}catch{}this._callAudioSender=null,this._callVideoSender=null,this._callGroupContext=null,this._externalMediaStream=null,this._callStateListeners?.clear?.(),this.intentionalDisconnect=!0,window.EnhancedSecureCryptoUtils.secureLog.log("info","Starting intentional disconnect"),this.sendDisconnectNotification(),this._teardownRecoveryLifecycleListeners?.(),this._stopAllTimers(),this._peerDisconnectCleanupTimer=null,this.stopHeartbeat(),this.stopFakeTrafficGeneration();for(let e of this.decoyTimers.entries())clearTimeout(e[1]);this.decoyTimers.clear(),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null);for(let e of this.decoyChannels.values())e.readyState==="open"&&e.close();this.decoyChannels.clear(),this.heartbeatChannel&&(this.heartbeatChannel.close(),this.heartbeatChannel=null),this.isVerified=!1,this.processedMessageIds.clear(),this.messageCounter=0,this.packetBuffer.clear(),this.chunkQueue=[],this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this._secureCleanupCryptographicMaterials(),this.keyVersions.clear(),this.oldKeys.clear(),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.replayWindow.clear(),this._clearVerificationStates(),this.securityFeatures={hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0},this.dataChannel&&(this.dataChannel.close(),this.dataChannel.onopen=null,this.dataChannel.onclose=null,this.dataChannel.onmessage=null,this.dataChannel.onerror=null,this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection.onconnectionstatechange=null,this.peerConnection.ondatachannel=null,this.peerConnection=null),this.messageQueue&&this.messageQueue.length>0&&(this.messageQueue.forEach((e,t)=>{this._secureWipeMemory(e,`messageQueue[${t}]`)}),this.messageQueue=[]),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during disconnect",{errorType:e?.constructor?.name||"Unknown"})}),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"user_disconnect",timestamp:Date.now()}})),this._dispatchAppEvent?.(new CustomEvent("connection-cleaned",{detail:{timestamp:Date.now(),reason:"user_cleanup"}})),this.onStatusChange("disconnected"),this.onKeyExchange(""),this.onVerificationRequired(""),this._secureLog("info","Connection securely cleaned up with complete memory wipe")}catch(e){this._secureLog("error","\u274C Error during enhanced disconnect:",{errorType:e?.constructor?.name||"Unknown"})}finally{this.intentionalDisconnect=!1}}async sendFile(e,t={}){if(this._enforceVerificationGate("sendFile"),!this.isConnected())throw new Error("Connection not ready for file transfer. Please ensure the connection is established.");if(!this.fileTransferSystem&&(this.initializeFileTransfer(),await new Promise(r=>setTimeout(r,500)),!this.fileTransferSystem))throw new Error("File transfer system could not be initialized. Please try reconnecting.");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready. Please wait for connection to be fully established.");try{return await this.fileTransferSystem.sendFile(e,t)}catch(r){throw this._secureLog("error","File transfer error:",{errorType:r?.constructor?.name||"Unknown"}),r.message.includes("Connection not ready")?new Error("Connection not ready for file transfer. Check connection status."):r.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):r.message.includes("Transfer timeout")?new Error("File transfer timeout. Check connection and try again."):r}}getFileTransfers(){if(!this.fileTransferSystem)return{sending:[],receiving:[]};try{let e=[],t=[];return typeof this.fileTransferSystem.getActiveTransfers=="function"?e=this.fileTransferSystem.getActiveTransfers():this._secureLog("warn","getActiveTransfers method not available in file transfer system"),typeof this.fileTransferSystem.getReceivingTransfers=="function"?t=this.fileTransferSystem.getReceivingTransfers():this._secureLog("warn","getReceivingTransfers method not available in file transfer system"),{sending:e||[],receiving:t||[]}}catch(e){return this._secureLog("error","Error getting file transfers:",{errorType:e?.constructor?.name||"Unknown"}),{sending:[],receiving:[]}}}getFileTransferStatus(){if(!this.fileTransferSystem)return{initialized:!1,status:"not_initialized",message:"File transfer system not initialized"};let e=this.fileTransferSystem.getActiveTransfers(),t=this.fileTransferSystem.getReceivingTransfers();return{initialized:!0,status:"ready",activeTransfers:e.length,receivingTransfers:t.length,totalTransfers:e.length+t.length}}cancelFileTransfer(e){return this.fileTransferSystem?this.fileTransferSystem.cancelTransfer(e):!1}cleanupFileTransferSystem(){return this.fileTransferSystem?(this._secureLog("info","\u{1F9F9} Force cleaning up file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,!0):!1}reinitializeFileTransfer(){try{return this.fileTransferSystem&&this.fileTransferSystem.cleanup(),this.initializeFileTransfer(),!0}catch(e){return this._secureLog("error","Failed to reinitialize file transfer system:",{errorType:e?.constructor?.name||"Unknown"}),!1}}setFileTransferCallbacks(e,t,r,i=null){this.onFileProgress=e,this.onFileReceived=t,this.onFileError=r,this.onIncomingFileRequest=i,this.fileTransferSystem&&(this.fileTransferSystem.onProgress=e,this.fileTransferSystem.onFileReceived=t,this.fileTransferSystem.onError=r,this.fileTransferSystem.onIncomingFileRequest=i)}getPendingIncomingFiles(){return this.fileTransferSystem?this.fileTransferSystem.getPendingIncomingTransfers():[]}async acceptIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.acceptIncomingFile(e):!1}async rejectIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.rejectIncomingFile(e):!1}async getReceivedFileObjectURL(e){return this.fileTransferSystem?this.fileTransferSystem.getObjectURL(e):null}revokeReceivedFileObjectURL(e){this.fileTransferSystem&&this.fileTransferSystem.revokeObjectURL(e)}async handleSessionActivation(e){try{this.currentSession=e;let t=!!(this.encryptionKey&&this.macKey);e.sessionId&&this.onStatusChange("connected"),setTimeout(()=>{try{this.initializeFileTransfer()}catch(i){this._secureLog("warn","File transfer initialization failed during session activation:",{details:i.message})}},1e3),this.fileTransferSystem&&this.isConnected()&&typeof this.fileTransferSystem.onSessionUpdate=="function"&&this.fileTransferSystem.onSessionUpdate({keyFingerprint:this.keyFingerprint,sessionSalt:this.sessionSalt,hasMacKey:!!this.macKey})}catch(t){this._secureLog("error","Failed to handle session activation:",{errorType:t?.constructor?.name||"Unknown"})}}checkFileTransferReadiness(){let e={hasFileTransferSystem:!!this.fileTransferSystem,hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,ready:!1};return e.ready=e.hasFileTransferSystem&&e.hasDataChannel&&e.dataChannelState==="open"&&e.isConnected&&e.isVerified,e}forceReinitializeFileTransfer(){try{return this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),setTimeout(()=>{this.initializeFileTransfer()},500),!0}catch(e){return this._secureLog("error","Failed to force reinitialize file transfer:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferDiagnostics(){let e={timestamp:new Date().toISOString(),webrtcManager:{hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,isInitiator:this.isInitiator,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,hasSessionSalt:!!this.sessionSalt},fileTransferSystem:null,globalState:{fileTransferActive:this._fileTransferActive||!1,hasFileTransferSystem:!!this.fileTransferSystem,fileTransferSystemType:this.fileTransferSystem?"EnhancedSecureFileTransfer":"none"}};if(this.fileTransferSystem)try{e.fileTransferSystem=this.fileTransferSystem.getSystemStatus()}catch(t){e.fileTransferSystem={error:t.message}}return e}getSupportedFileTypes(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getSupportedFileTypes()}catch(e){return{error:e.message}}}validateFile(e){if(!this.fileTransferSystem)return{isValid:!1,errors:["File transfer system not initialized"],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"};try{return this.fileTransferSystem.validateFile(e)}catch(t){return{isValid:!1,errors:[t.message],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"}}}getFileTypeInfo(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getFileTypeInfo()}catch(e){return{error:e.message}}}async forceInitializeFileTransfer(e={}){let t=new AbortController,{signal:r=t.signal,timeout:i=6e3}=e;r&&r!==t.signal&&r.addEventListener("abort",()=>t.abort());try{if(!this.isVerified)throw new Error("Connection not verified");if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready");this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this.initializeFileTransfer();let n=0,a=50,o=100,c=a*o,d=new Promise((u,h)=>{let m=()=>{if(t.signal.aborted){h(new Error("Operation cancelled"));return}if(this.fileTransferSystem){u(!0);return}if(n>=a){h(new Error(`Initialization timeout after ${c}ms`));return}n++,setTimeout(m,o)};m()});if(await Promise.race([d,new Promise((u,h)=>setTimeout(()=>h(new Error(`Global timeout after ${i}ms`)),i))]),this.fileTransferSystem)return!0;throw new Error("Force initialization timeout")}catch(n){return n.name==="AbortError"||n.message.includes("cancelled")?(this._secureLog("info","File transfer initialization cancelled by user"),{cancelled:!0}):(this._secureLog("error","Force file transfer initialization failed:",{errorType:n?.constructor?.name||"Unknown",message:n.message,attempts}),{error:n.message,attempts})}}cancelFileTransferInitialization(){try{return this.fileTransferSystem?(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,this._fileTransferActive=!1,this._secureLog("info","File transfer initialization cancelled"),!0):!1}catch(e){return this._secureLog("error","Failed to cancel file transfer initialization:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferSystemStatus(){if(!this.fileTransferSystem)return{available:!1,status:"not_initialized"};try{let e=this.fileTransferSystem.getSystemStatus();return{available:!0,status:e.status||"unknown",activeTransfers:e.activeTransfers||0,receivingTransfers:e.receivingTransfers||0,systemType:"EnhancedSecureFileTransfer"}}catch(e){return this._secureLog("error","Failed to get file transfer system status:",{errorType:e?.constructor?.name||"Unknown"}),{available:!1,status:"error",error:e.message}}}_validateNestedEncryptionSecurity(){if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey)try{let e=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest1"),t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest2");return e.every((i,n)=>i===t[n])?(this._secureLog("error","CRITICAL: Nested encryption security validation failed - IVs are identical!"),!1):this._getIVTrackingStats().totalIVs<2?(this._secureLog("error","CRITICAL: IV tracking system not working properly"),!1):(this._secureLog("info","Nested encryption security validation passed - secure IV generation working"),!0)}catch(e){return this._secureLog("error","CRITICAL: Nested encryption security validation failed:",{errorType:e.constructor.name,errorMessage:e.message}),!1}return!0}getCallState(){return{...this.callState}}addCallStateListener(e){return typeof e!="function"?()=>{}:(this._callStateListeners.add(e),()=>this._callStateListeners.delete(e))}removeCallStateListener(e){this._callStateListeners.delete(e)}setCallGroupContext(e){this._callGroupContext=typeof e=="string"&&e?e:null,this._updateCallState({}),this._callGroupContext&&this._pendingCallOffer&&this.callState.phase==="incoming"&&this.acceptCall().catch(t=>{this._secureLog("warn","\u26A0\uFE0F Failed to answer a group call leg that was already ringing",{errorType:t?.constructor?.name})})}setExternalMediaStream(e){this._externalMediaStream=e||null}_usingExternalMedia(){return!!this._externalMediaStream&&this.localMediaStream===this._externalMediaStream}getRemoteMediaStream(){return this.remoteMediaStream}getLocalMediaStream(){return this.localMediaStream}_refreshRemoteStream(){let e=this.peerConnection;if(!e||typeof e.getReceivers!="function")return;let t=e.getReceivers().map(n=>n.track).filter(n=>n&&(n.kind==="audio"||n.kind==="video")&&n.readyState==="live"),r=this.remoteMediaStream?this.remoteMediaStream.getTracks():[];r.length===t.length&&r.every(n=>t.includes(n))||(this.remoteMediaStream=new MediaStream(t)),this._updateCallState({remoteHasVideo:t.some(n=>n.kind==="video")})}_scheduleRemoteRefresh(){this._refreshRemoteStream(),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},300),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},1200)}_updateCallState(e){this.callState={...this.callState,...e,groupCallId:this._callGroupContext};let t=this.getCallState();t.phase==="active"?this._startAdaptation():t.phase==="idle"&&this._stopAdaptation();try{this.onCallStateChanged?.(t)}catch{}for(let r of this._callStateListeners)try{r(t)}catch{}if(typeof document<"u")try{this._dispatchAppEvent?.(new CustomEvent("securebit-call-state",{detail:{managerId:this._managerId||null,state:t}}))}catch{}}_callCanStart(){let e=typeof this.isConnected=="function"?this.isConnected():!1,t=this.dataChannel&&this.dataChannel.readyState==="open";return!!(e&&t&&this.isVerified&&!this.isReconnecting())}async _sendCallSignal(e,t){return await this.sendSystemMessage({type:e,...t})}_audioConstraints(){return{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}}_videoConstraints(){return{facingMode:this._callFacingMode,width:{ideal:1280},height:{ideal:720}}}async _acquireLocalMedia(e){let t=this._externalMediaStream||await navigator.mediaDevices.getUserMedia({audio:this._audioConstraints(),video:e?this._videoConstraints():!1});this.localMediaStream=t;let r=this.peerConnection,i=t.getAudioTracks()[0]||null,n=t.getVideoTracks()[0]||null;return i&&(this._callAudioSender?await this._callAudioSender.replaceTrack(i):this._callAudioSender=r.addTrack(i,t)),n&&(this._callVideoSender?await this._callVideoSender.replaceTrack(n):this._callVideoSender=r.addTrack(n,t)),this._applyCallCodecPrefs(),t}_stopLocalMediaPermanently(){try{if(this.localMediaStream&&!this._usingExternalMedia())for(let e of this.localMediaStream.getTracks())try{e.stop()}catch{}}catch{}this.localMediaStream=null}_applyCallCodecPrefs(){try{let e=this.peerConnection?.getTransceivers?.()||[],t=e.find(i=>i.sender&&i.sender===this._callAudioSender);t&&Ji(t);let r=e.find(i=>i.sender&&i.sender===this._callVideoSender);r&&sn(r)}catch{}}_mungeCallSdp(e){try{let t=Cr(e,st.opusFmtp);return t=Qi(t,qi),t}catch{return e}}async _setLocalMunged(e){let t=this.peerConnection;try{await t.setLocalDescription({type:e.type,sdp:this._mungeCallSdp(e.sdp)});return}catch{try{await t.setLocalDescription({type:e.type,sdp:Cr(e.sdp,st.opusFmtp)});return}catch{await t.setLocalDescription(e)}}}async _applyCallSenderParams(){try{this._callAudioSender&&await Zi(this._callAudioSender,{}),this._callVideoSender&&await an(this._callVideoSender,{})}catch{}}_startAdaptation(){if(!(this._adaptationController||!this.peerConnection))try{this._adaptationController=new Nt(this.peerConnection,{getVideoSender:()=>this._callVideoSender,ceilingBitrate:15e5,onQuality:e=>{e!==this.callState.quality&&this._updateCallState({quality:e})}}),this._adaptationController.start()}catch{}}_stopAdaptation(){if(this._adaptationController){try{this._adaptationController.stop()}catch{}this._adaptationController=null}}_notifyCallMediaError(e,t){let r=e?.name||"",i=t?"camera/microphone":"microphone",n,a;r==="NotAllowedError"?(a="permission_denied",n=`\u26A0\uFE0F Call not started \u2014 ${i} access is blocked. Allow it for this site in the browser, and enable your browser under System Settings \u2192 Privacy & Security \u2192 ${t?"Camera/Microphone":"Microphone"}, then try again.`):r==="NotFoundError"||r==="OverconstrainedError"?(a="device_not_found",n=`\u26A0\uFE0F Call not started \u2014 no ${i} found on this device.`):r==="NotReadableError"||r==="AbortError"?(a="device_busy",n=`\u26A0\uFE0F Call not started \u2014 your ${i} is in use by another app. Close it and try again.`):(a="media_failed",n=`\u26A0\uFE0F Call not started \u2014 could not access ${i}${r?" ("+r+")":""}.`);try{this.deliverMessageToUI(n,"system")}catch{}return a}async startCall(e=!1){if(!this._callCanStart())throw this._updateCallState({error:"not_verified"}),new Error("Calls require a connected, SAS-verified session.");if(this.callState.active){this._secureLog("warn","\u26A0\uFE0F startCall ignored \u2014 a call is already active");return}let t=crypto?.randomUUID?.()||String(Date.now())+Math.random().toString(36).slice(2);this._updateCallState({active:!0,phase:"outgoing",withVideo:e,callId:t,micEnabled:!0,cameraEnabled:e,remoteHasVideo:!1,error:null});try{await this._acquireLocalMedia(e),this._callMakingOffer=!0;let r=await this.peerConnection.createOffer();await this._setLocalMunged(r),this._callMakingOffer=!1,await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:t,withVideo:e,sdp:this.peerConnection.localDescription.sdp})}catch(r){this._callMakingOffer=!1,this._secureLog("error","\u274C startCall failed",{errorType:r?.constructor?.name});let i=this._notifyCallMediaError(r,e);throw await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:i}),r}}async _onIncomingCallOffer(e){if(this.callState.active&&(this.callState.phase==="active"||this.callState.phase==="connecting")){await this._answerCallOffer(e,!0),e.withVideo&&this._updateCallState({withVideo:!0});return}this._pendingCallOffer=e,this._updateCallState({active:!0,phase:"incoming",withVideo:!!e.withVideo,callId:e.callId,remoteHasVideo:!!e.withVideo,error:null}),this._callGroupContext&&await this.acceptCall()}async _answerCallOffer(e,t=!1){await this.peerConnection.setRemoteDescription({type:"offer",sdp:e.sdp}),t||await this._acquireLocalMedia(!!e.withVideo);let r=await this.peerConnection.createAnswer();await this._setLocalMunged(r),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_ANSWER,{callId:e.callId,sdp:this.peerConnection.localDescription.sdp})}async acceptCall(){let e=this._pendingCallOffer;if(e){this._pendingCallOffer=null,this._updateCallState({phase:"connecting",cameraEnabled:!!e.withVideo});try{await this._answerCallOffer(e,!1),this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(t){this._secureLog("error","\u274C acceptCall failed",{errorType:t?.constructor?.name});let r=this._notifyCallMediaError(t,!!e.withVideo);try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:e.callId})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:r})}}}async declineCall(){let e=this.callState.callId;this._pendingCallOffer=null,await this._sendCallSignal(s.MESSAGE_TYPES.CALL_DECLINE,{callId:e}),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1})}async endCall(e=!0){let t=this.callState.callId;if(e&&t)try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:t})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,micEnabled:!0,cameraEnabled:!1,remoteHasVideo:!1,callId:null,quality:null})}async _teardownCallMedia(){this._stopAdaptation();let e=this.peerConnection;try{if(this.localMediaStream&&!this._usingExternalMedia())for(let t of this.localMediaStream.getTracks())try{t.stop()}catch{}if(e)for(let t of[this._callAudioSender,this._callVideoSender].filter(Boolean))try{await t.replaceTrack(null)}catch{}}catch{}this.localMediaStream=null,this.remoteMediaStream=null,this._callMakingOffer=!1;try{this.peerConnection&&(this.peerConnection.signalingState==="have-local-offer"||this.peerConnection.signalingState==="have-local-pranswer")&&await this.peerConnection.setLocalDescription({type:"rollback"})}catch{}}setMicEnabled(e){this.localMediaStream&&this.localMediaStream.getAudioTracks().forEach(t=>{t.enabled=e}),this._updateCallState({micEnabled:e})}toggleMic(){this.setMicEnabled(!this.callState.micEnabled)}async setCameraEnabled(e){if(!e){this.localMediaStream&&this.localMediaStream.getVideoTracks().forEach(r=>{r.enabled=!1}),this._updateCallState({cameraEnabled:!1});return}let t=this.localMediaStream?.getVideoTracks?.()||[];if(t.length){t.forEach(r=>{r.enabled=!0}),this._updateCallState({cameraEnabled:!0,withVideo:!0});return}await this.upgradeToVideo()}async toggleCamera(){await this.setCameraEnabled(!this.callState.cameraEnabled)}async upgradeToVideo(){if(this.localMediaStream)try{let t=(await navigator.mediaDevices.getUserMedia({video:this._videoConstraints()})).getVideoTracks()[0];if(!t)return;await this.addVideoTrack(t)}catch(e){this._secureLog("error","\u274C upgradeToVideo failed",{errorType:e?.constructor?.name}),this._updateCallState({cameraEnabled:!1,error:"camera_failed"})}}async addVideoTrack(e){!e||!this.localMediaStream||!this.peerConnection||(this.localMediaStream.getVideoTracks().includes(e)||this.localMediaStream.addTrack(e),this._callVideoSender?await this._callVideoSender.replaceTrack(e):this._callVideoSender=this.peerConnection.addTrack(e,this.localMediaStream),this._applyCallCodecPrefs(),this._updateCallState({cameraEnabled:!0,withVideo:!0}),await this._renegotiateCall())}async replaceVideoTrack(e){!e||!this._callVideoSender||await this._callVideoSender.replaceTrack(e)}async switchCamera(){if(!(!this._callVideoSender||!this.localMediaStream)){this._callFacingMode=this._callFacingMode==="user"?"environment":"user";try{let t=(await navigator.mediaDevices.getUserMedia({video:{facingMode:this._callFacingMode}})).getVideoTracks()[0],r=this.localMediaStream.getVideoTracks()[0];if(r){this.localMediaStream.removeTrack(r);try{r.stop()}catch{}}this.localMediaStream.addTrack(t),await this._callVideoSender.replaceTrack(t)}catch(e){this._secureLog("warn","\u26A0\uFE0F switchCamera failed",{errorType:e?.constructor?.name})}}}async _renegotiateCall(){if(!this._callMakingOffer)try{this._callMakingOffer=!0;let e=await this.peerConnection.createOffer();await this._setLocalMunged(e),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:this.callState.callId,withVideo:this.callState.withVideo,sdp:this.peerConnection.localDescription.sdp})}finally{this._callMakingOffer=!1}}async _handleCallSignal(e,t){let r=s.MESSAGE_TYPES;switch(e){case r.CALL_OFFER:{await this._onIncomingCallOffer(t);return}case r.CALL_ANSWER:{try{this.peerConnection.signalingState==="have-local-offer"&&await this.peerConnection.setRemoteDescription({type:"answer",sdp:t.sdp}),this.callState.phase==="outgoing"&&this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(i){this._secureLog("warn","\u26A0\uFE0F Failed to apply call answer",{errorType:i?.constructor?.name})}return}case r.CALL_ICE:{try{t.candidate&&await this.peerConnection.addIceCandidate(t.candidate)}catch{}return}case r.CALL_DECLINE:{await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1,error:"declined"});return}case r.CALL_END:{await this.endCall(!1);return}default:return}}},Gt=class{constructor(e=null){this._keyStore=new WeakMap,this._keyMetadata=new Map,this._keyReferences=new Map,this._masterKeyManager=e||new jt,this._persistentStorage=new Br(this._masterKeyManager),this._setupMasterKeyCallbacks(),setTimeout(()=>{this.validateStorageIntegrity()||this._secureLog("error","CRITICAL: Key storage integrity check failed")},100)}_secureLog(e,t,r={}){try{let i=typeof window<"u"&&window.EnhancedSecureCryptoUtils?.secureLog||null;if(i&&typeof i.log=="function"){i.log(e,`[KeyStorage] ${t}`,r);return}}catch{}e==="error"?console.error(`[KeyStorage] ${t}`):e==="warn"&&console.warn(`[KeyStorage] ${t}`)}_setupMasterKeyCallbacks(){this._masterKeyManager.setPasswordRequiredCallback((e,t)=>{this._secureLog("error","Master key password requested but no password UI is installed",{isRetry:!!e}),t(null)}),this._masterKeyManager.setSessionExpiredCallback(e=>{console.warn(`Master key session expired: ${e}`)}),this._masterKeyManager.setUnlockedCallback(()=>{console.log("Master key unlocked successfully")})}setPasswordCallback(e){this._masterKeyManager.setPasswordRequiredCallback(e)}setSessionExpiredCallback(e){this._masterKeyManager.setSessionExpiredCallback(e)}async _ensureMasterKeyUnlocked(){this._masterKeyManager.isUnlocked()||await this._masterKeyManager.unlock()}async storeKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");try{return t.extractable?(await this._persistentStorage.storeExtractableKey(e,t,r),this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0,encrypted:!0}),!0):(this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!1,persistent:!1,encrypted:!1}),!0)}catch(i){return this._secureLog("error","Failed to store key securely",{errorType:i?.constructor?.name||"Unknown"}),!1}}async retrieveKey(e){try{if(this._keyReferences.has(e)){let r=this._keyMetadata.get(e);return r&&(r.lastAccessed=Date.now()),this._keyReferences.get(e)}let t=await this._persistentStorage.retrieveKey(e);if(t){this._keyReferences.set(e,t);let r=this._keyMetadata.get(e);return this._keyMetadata.set(e,{...r,lastAccessed:Date.now(),restoredFromPersistent:!0}),t}return null}catch(t){return this._secureLog("error","Failed to retrieve key",{errorType:t?.constructor?.name||"Unknown"}),null}}async _encryptKeyData(e){let t=typeof e=="object"?JSON.stringify(e):e,i=new TextEncoder().encode(t);await this._ensureMasterKeyUnlocked();let{encryptedData:n,iv:a}=await this._masterKeyManager.encryptBytes(i),o=new Uint8Array(a.length+n.byteLength);return o.set(a,0),o.set(n,a.length),o}async _decryptKeyData(e){let t=e.slice(0,12),r=e.slice(12);await this._ensureMasterKeyUnlocked();let i=await this._masterKeyManager.decryptBytes(r,t),a=new TextDecoder().decode(i);try{return JSON.parse(a)}catch{return i}}async secureWipe(e){let t=this._keyReferences.get(e);t&&(this._keyStore.delete(t),this._keyReferences.delete(e),this._keyMetadata.delete(e)),await this._performNaturalCleanup()}async secureWipeAll(){try{await this._persistentStorage.clearAll()}catch(e){this._secureLog("error","Failed to clear persistent storage",{errorType:e?.constructor?.name||"Unknown"})}this._keyReferences.clear(),this._keyMetadata.clear(),this._keyStore=new WeakMap,await this._performNaturalCleanup()}validateStorageIntegrity(){let e=[];for(let[t,r]of this._keyMetadata.entries())r.extractable===!0&&r.encrypted!==!0&&e.push({keyId:t,type:"EXTRACTABLE_KEY_NOT_ENCRYPTED",metadata:r}),r.extractable===!1&&r.encrypted===!0&&e.push({keyId:t,type:"NON_EXTRACTABLE_KEY_ENCRYPTED",metadata:r});return e.length>0?(this._secureLog("error","Storage integrity violations detected",{violationCount:e.length}),!1):!0}async getStorageStats(){let e=await this._persistentStorage.getStorageStats();return{totalKeys:this._keyReferences.size,memoryKeys:this._keyReferences.size,persistentKeys:e.persistentKeys,metadata:Array.from(this._keyMetadata.entries()).map(([t,r])=>({id:t,created:r.created,lastAccessed:r.lastAccessed,age:Date.now()-r.created,persistent:r.persistent||!1})),persistent:e}}async listAllKeys(){try{let e=Array.from(this._keyMetadata.entries()).map(([i,n])=>({keyId:i,...n,location:"memory"})),r=(await this._persistentStorage.listStoredKeys()).map(i=>({...i,location:"persistent"}));return{memoryKeys:e,persistentKeys:r,totalCount:e.length+r.length}}catch(e){return this._secureLog("error","Failed to list keys",{errorType:e?.constructor?.name||"Unknown"}),{memoryKeys:[],persistentKeys:[],totalCount:0,error:e.message}}}async deleteKey(e){try{return this._keyReferences.delete(e),this._keyMetadata.delete(e),await this._persistentStorage.deleteKey(e),!0}catch(t){return this._secureLog("error","Failed to delete key",{errorType:t?.constructor?.name||"Unknown"}),!1}}},qt=class{constructor(e="SecureKeyStorage",t=1){this.dbName=e,this.version=t,this.db=null,this.KEYS_STORE="encrypted_keys",this.METADATA_STORE="key_metadata",this.SALT_STORE="master_salt"}async initialize(){return new Promise((e,t)=>{let r=indexedDB.open(this.dbName,this.version);r.onerror=()=>{t(new Error(`Failed to open IndexedDB: ${r.error}`))},r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=i=>{let n=i.target.result;if(!n.objectStoreNames.contains(this.KEYS_STORE)){let a=n.createObjectStore(this.KEYS_STORE,{keyPath:"keyId"});a.createIndex("timestamp","timestamp",{unique:!1}),a.createIndex("algorithm","algorithm",{unique:!1})}if(!n.objectStoreNames.contains(this.METADATA_STORE)){let a=n.createObjectStore(this.METADATA_STORE,{keyPath:"keyId"});a.createIndex("created","created",{unique:!1}),a.createIndex("lastAccessed","lastAccessed",{unique:!1})}n.objectStoreNames.contains(this.SALT_STORE)||n.createObjectStore(this.SALT_STORE,{keyPath:"id"})}})}async storeEncryptedKey(e,t,r,i,n,a,o={}){if(!this.db)throw new Error("Database not initialized");let c=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite"),d={keyId:e,encryptedData:Array.from(new Uint8Array(t)),iv:Array.from(new Uint8Array(r)),algorithm:i,usages:n,type:a},u={keyId:e,...o};return new Promise((h,m)=>{let p=c.objectStore(this.KEYS_STORE).put(d),S=c.objectStore(this.METADATA_STORE).put(u);c.oncomplete=()=>h(),c.onerror=()=>m(new Error(`Failed to store key: ${c.error}`))})}async getEncryptedKey(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.KEYS_STORE],"readonly").objectStore(this.KEYS_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>{let o=a.result;o&&(o.encryptedData=new Uint8Array(o.encryptedData),o.iv=new Uint8Array(o.iv)),i(o)},a.onerror=()=>n(new Error(`Failed to retrieve key: ${a.error}`))})}async updateKeyMetadata(e,t){if(!this.db)throw new Error("Database not initialized");let i=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((n,a)=>{let o=i.get(e);o.onsuccess=()=>{let c=o.result;if(c){Object.assign(c,t);let d=i.put(c);d.onsuccess=()=>n(),d.onerror=()=>a(new Error(`Failed to update metadata: ${d.error}`))}else a(new Error(`Key metadata not found: ${e}`))},o.onerror=()=>a(new Error(`Failed to get metadata: ${o.error}`))})}async getKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>i(a.result||null),a.onerror=()=>n(new Error(`Failed to get metadata: ${a.error}`))})}async putKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.put(e);a.onsuccess=()=>i(),a.onerror=()=>n(new Error(`Failed to store metadata: ${a.error}`))})}async deleteKey(e){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite");return new Promise((r,i)=>{let n=t.objectStore(this.KEYS_STORE).delete(e),a=t.objectStore(this.METADATA_STORE).delete(e);t.oncomplete=()=>r(),t.onerror=()=>i(new Error(`Failed to delete key: ${t.error}`))})}async listKeys(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((r,i)=>{let n=t.getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>i(new Error(`Failed to list keys: ${n.error}`))})}async storeMasterSalt(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.SALT_STORE],"readwrite").objectStore(this.SALT_STORE),i={id:"master_salt",salt:Array.from(new Uint8Array(e))};return new Promise((n,a)=>{let o=r.put(i);o.onsuccess=()=>n(),o.onerror=()=>a(new Error(`Failed to store salt: ${o.error}`))})}async getMasterSalt(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.SALT_STORE],"readonly").objectStore(this.SALT_STORE);return new Promise((r,i)=>{let n=t.get("master_salt");n.onsuccess=()=>{let a=n.result;r(a?new Uint8Array(a.salt):null)},n.onerror=()=>i(new Error(`Failed to retrieve salt: ${n.error}`))})}async clearAll(){if(!this.db)throw new Error("Database not initialized");let e=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE,this.SALT_STORE],"readwrite");return new Promise((t,r)=>{let i=e.objectStore(this.KEYS_STORE).clear(),n=e.objectStore(this.METADATA_STORE).clear(),a=e.objectStore(this.SALT_STORE).clear();e.oncomplete=()=>t(),e.onerror=()=>r(new Error(`Failed to clear database: ${e.error}`))})}close(){this.db&&(this.db.close(),this.db=null)}},Br=class{constructor(e,t=null){this._masterKeyManager=e,this._indexedDB=t||new qt,this._dbInitialized=!1,this._keyCache=new WeakMap,this._keyReferences=new Map}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}async _ensureMasterKeyUnlocked(){typeof this._masterKeyManager.isUnlocked=="function"&&!this._masterKeyManager.isUnlocked()&&await this._masterKeyManager.unlock()}async storeExtractableKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");if(!t.extractable)throw new Error("Key must be extractable for persistent storage");try{await this._ensureDBInitialized();let i=await crypto.subtle.exportKey("jwk",t),{encryptedData:n,iv:a}=await this._encryptKeyData(i),o=await this._encryptMetadata({...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0});await this._indexedDB.storeEncryptedKey(e,n,a,t.algorithm,t.usages,t.type,o);let c=await this._importAsNonExtractable(i,t.algorithm,t.usages);return this._keyReferences.set(e,c),!0}catch(i){throw new Error(`Failed to store extractable key: ${i.message}`)}}async retrieveKey(e){try{if(this._keyReferences.has(e))return this._keyReferences.get(e);await this._ensureDBInitialized();let t=await this._indexedDB.getEncryptedKey(e);if(!t)return null;let r=await this._decryptKeyData(t.encryptedData,t.iv),i=await this._importAsNonExtractable(r,t.algorithm,t.usages);return this._keyReferences.set(e,i),await this._updateEncryptedMetadata(e,{lastAccessed:Date.now()}),i}catch(t){throw new Error(`Failed to retrieve key: ${t.message}`)}}async deleteKey(e){try{return await this._ensureDBInitialized(),await this._indexedDB.deleteKey(e),this._keyReferences.delete(e),!0}catch(t){throw new Error(`Failed to delete key: ${t.message}`)}}async listStoredKeys(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys(),t=[];for(let r of e){let i=await this._readMetadataWithMigration(r);i&&t.push({keyId:r.keyId,...i})}return t}catch(e){throw new Error(`Failed to list keys: ${e.message}`)}}async clearAll(){try{return await this._ensureDBInitialized(),await this._indexedDB.clearAll(),this._keyReferences.clear(),!0}catch(e){throw new Error(`Failed to clear storage: ${e.message}`)}}async _encryptKeyData(e){let t=JSON.stringify(e),r=new TextEncoder().encode(t);return await this._ensureMasterKeyUnlocked(),await this._masterKeyManager.encryptBytes(r)}async _decryptKeyData(e,t){await this._ensureMasterKeyUnlocked();let r=await this._masterKeyManager.decryptBytes(e,t),i=new TextDecoder().decode(r);return JSON.parse(i)}async _encryptMetadata(e){let t=new TextEncoder().encode(JSON.stringify(e));await this._ensureMasterKeyUnlocked();let{encryptedData:r,iv:i}=await this._masterKeyManager.encryptBytes(t);return{metadataVersion:1,encryptedMetadata:Array.from(r),metadataIv:Array.from(i)}}async _decryptMetadataRecord(e){if(!e?.encryptedMetadata||!e?.metadataIv)throw new Error("Encrypted metadata missing");await this._ensureMasterKeyUnlocked();let t=await this._masterKeyManager.decryptBytes(new Uint8Array(e.encryptedMetadata),new Uint8Array(e.metadataIv));return JSON.parse(new TextDecoder().decode(t))}async _readMetadataWithMigration(e){if(!e)return null;if(e.encryptedMetadata)try{return await this._decryptMetadataRecord(e)}catch{return null}let{keyId:t,...r}=e,i={keyId:t,...await this._encryptMetadata(r)};return await this._indexedDB.putKeyMetadataRecord(i),r}async _updateEncryptedMetadata(e,t){let r=await this._indexedDB.getKeyMetadataRecord(e);if(!r)throw new Error(`Key metadata not found: ${e}`);let i=await this._readMetadataWithMigration(r);if(!i)throw new Error(`Key metadata corrupted: ${e}`);await this._indexedDB.putKeyMetadataRecord({keyId:e,...await this._encryptMetadata({...i,...t})})}async _importAsNonExtractable(e,t,r){return await crypto.subtle.importKey("jwk",e,t,!1,r)}async getStorageStats(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys();return{totalKeys:e.length,memoryKeys:this._keyReferences.size,persistentKeys:e.length,lastAccessed:e.reduce((t,r)=>Math.max(t,r.lastAccessed||0),0)}}catch(e){return{totalKeys:0,memoryKeys:this._keyReferences.size,persistentKeys:0,lastAccessed:0,error:e.message}}}},jt=class{constructor(e=null){this._keyHandle=null,this._isUnlocked=!1,this._sessionTimeout=null,this._lastActivity=null,this._sessionTimeoutMs=3600*1e3,this._inactivityTimeoutMs=1800*1e3,this._pbkdf2Iterations=31e4,this._saltSize=32,this._indexedDB=e||new qt,this._dbInitialized=!1,this._onPasswordRequired=null,this._onSessionExpired=null,this._onUnlocked=null}setPasswordRequiredCallback(e){this._onPasswordRequired=e}setSessionExpiredCallback(e){this._onSessionExpired=e}setUnlockedCallback(e){this._onUnlocked=e}_setupEventListeners(){typeof document<"u"&&(document.addEventListener("visibilitychange",()=>{document.hidden?this._handleFocusOut():this._handleFocusIn()}),window.addEventListener("blur",()=>this._handleFocusOut()),window.addEventListener("focus",()=>this._handleFocusIn()),["mousedown","mousemove","keypress","scroll","touchstart"].forEach(e=>{document.addEventListener(e,()=>this._updateActivity(),{passive:!0})}))}_handleFocusOut(){this._isUnlocked&&this._startInactivityTimer(this._inactivityTimeoutMs)}_handleFocusIn(){this._isUnlocked&&this._resetSessionTimer()}_updateActivity(){this._lastActivity=Date.now(),this._isUnlocked&&this._resetSessionTimer()}_startSessionTimer(){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("timeout")},this._sessionTimeoutMs)}_startInactivityTimer(e){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("inactivity")},e)}_resetSessionTimer(){this._isUnlocked&&this._startSessionTimer()}_clearTimers(){this._sessionTimeout&&(clearTimeout(this._sessionTimeout),this._sessionTimeout=null)}_expireSession(e="unknown"){this._isUnlocked&&(this._secureWipeMasterKey(),this._isUnlocked=!1,this._onSessionExpired&&this._onSessionExpired(e))}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}_generateSalt(){return crypto.getRandomValues(new Uint8Array(this._saltSize))}async _getOrCreateSalt(){await this._ensureDBInitialized();let e=await this._indexedDB.getMasterSalt();return e||(e=this._generateSalt(),await this._indexedDB.storeMasterSalt(e)),e}async _deriveKeyFromPassword(e,t){try{let r=await crypto.subtle.importKey("raw",new TextEncoder().encode(e),"PBKDF2",!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:this._pbkdf2Iterations,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,["encrypt","decrypt","wrapKey","unwrapKey"])}catch(r){throw new Error(`Key derivation failed: ${r.message}`)}}async _requestPassword(e=!1){if(!this._onPasswordRequired)throw new Error("Password callback not set");return new Promise((t,r)=>{this._onPasswordRequired(e,i=>{i?t(i):r(new Error("Password not provided"))})})}async unlock(e=null){try{e||(e=await this._requestPassword(!1));let t=await this._getOrCreateSalt();return this._keyHandle=await this._deriveKeyFromPassword(e,t),this._isUnlocked=!0,this._lastActivity=Date.now(),this._startSessionTimer(),e=null,this._onUnlocked&&this._onUnlocked(),{success:!0}}catch(t){throw e=null,t}}lock(){this._expireSession("manual")}async encryptBytes(e){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let t=crypto.getRandomValues(new Uint8Array(12)),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return{encryptedData:new Uint8Array(r),iv:t}}async decryptBytes(e,t){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let r=await crypto.subtle.decrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return new Uint8Array(r)}isUnlocked(){return this._isUnlocked&&this._keyHandle!==null}getSessionStatus(){return{isUnlocked:this._isUnlocked,lastActivity:this._lastActivity,sessionTimeoutMs:this._sessionTimeoutMs,inactivityTimeoutMs:this._inactivityTimeoutMs}}_secureWipeMasterKey(){this._keyHandle&&(this._keyHandle=null),this._clearTimers()}destroy(){this._secureWipeMasterKey(),this._isUnlocked=!1,typeof document<"u"&&(document.removeEventListener("visibilitychange",this._handleFocusOut),window.removeEventListener("blur",this._handleFocusOut),window.removeEventListener("focus",this._handleFocusIn))}};var $n=wi(Pn());var Fn="6.8.14";var Hr=()=>{if(Ke.length<2)return null;let[s,e]=React.useState(!1),t=React.useRef(null),r=typeof window<"u"?window.location.pathname:"/",i=Gi({pathname:r,active:Ge()}),n=i.find(c=>c.isCurrent)||i[0];React.useEffect(()=>{if(!s)return;let c=u=>{t.current&&!t.current.contains(u.target)&&e(!1)},d=u=>{u.key==="Escape"&&e(!1)};return document.addEventListener("pointerdown",c),document.addEventListener("keydown",d),()=>{document.removeEventListener("pointerdown",c),document.removeEventListener("keydown",d)}},[s]);let a=React.createElement("button",{key:"trigger",type:"button",onClick:()=>e(c=>!c),"aria-haspopup":"menu","aria-expanded":s?"true":"false","aria-label":f("language.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"7px 10px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:s?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",fontSize:"12.5px",fontWeight:600,cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"c"},n?n.abbr:""),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:s?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),o=React.createElement("div",{key:"menu",role:"menu",className:"sb-scroll",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:s?"block":"none",minWidth:"170px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",maxHeight:"min(62vh, 420px)",overflowY:"auto",overscrollBehavior:"contain"}},i.map(c=>React.createElement("a",{key:c.code,href:c.href,hrefLang:c.hrefLang,lang:c.hrefLang,dir:c.dir,role:"menuitem","aria-current":c.isCurrent?"page":void 0,onClick:()=>Hi(c.code),style:{display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",fontSize:"13px",fontWeight:c.isCurrent?600:500,color:c.isCurrent?"var(--sb-text-2)":"var(--sb-text-6)",background:c.isCurrent?"rgba(var(--sb-ink), 0.06)":"transparent",textDecoration:"none",whiteSpace:"nowrap"}},[React.createElement("span",{key:"a",style:{fontSize:"11px",fontWeight:700,letterSpacing:"0.4px",color:"var(--sb-text-9)",width:"22px",flex:"none",textAlign:"start"}},c.abbr),React.createElement("span",{key:"n"},c.label)])));return React.createElement("nav",{ref:t,"aria-label":f("language.label"),style:{position:"relative",display:"inline-flex"}},[a,o])};window.LanguageSwitcher=Hr;var ot={system:'',light:'',dark:''},$r=(s,e,t)=>React.createElement("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:t,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",dangerouslySetInnerHTML:{__html:s}}),Gr=()=>{let s=typeof window<"u"?window.SecureBitTheme:null;if(!s)return null;let[e,t]=React.useState(!1),[r,i]=React.useState(()=>s.get()),[n,a]=React.useState(()=>s.resolved()),o=React.useRef(null);React.useEffect(()=>s.subscribe((p,S)=>{i(p),a(S)}),[]),React.useEffect(()=>{if(!e)return;let p=g=>{o.current&&!o.current.contains(g.target)&&t(!1)},S=g=>{g.key==="Escape"&&t(!1)};return document.addEventListener("pointerdown",p),document.addEventListener("keydown",S),()=>{document.removeEventListener("pointerdown",p),document.removeEventListener("keydown",S)}},[e]);let c=[{mode:"system",icon:ot.system,label:f("theme.system")},{mode:"light",icon:ot.light,label:f("theme.light")},{mode:"dark",icon:ot.dark,label:f("theme.dark")}],d=r==="system"?ot.system:n==="light"?ot.light:ot.dark,u=c.find(p=>p.mode===r)||c[0],h=React.createElement("button",{key:"trigger",type:"button",onClick:()=>t(p=>!p),"aria-haspopup":"menu","aria-expanded":e?"true":"false","aria-label":f("theme.label")+": "+u.label,title:f("theme.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"8px 9px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:e?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"i",style:{display:"grid",placeItems:"center"}},$r(d,15,1.9)),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:e?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),m=React.createElement("div",{key:"menu",role:"menu",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:e?"block":"none",minWidth:"158px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))"}},c.map(p=>{let S=p.mode===r;return React.createElement("button",{key:p.mode,type:"button",role:"menuitemradio","aria-checked":S?"true":"false",onClick:()=>{s.set(p.mode),t(!1)},style:{width:"100%",display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",border:"none",fontSize:"13px",fontFamily:"inherit",fontWeight:S?600:500,color:S?"var(--sb-text-2)":"var(--sb-text-6)",background:S?"rgba(var(--sb-ink), 0.06)":"transparent",cursor:"pointer",textAlign:"start",whiteSpace:"nowrap"}},[React.createElement("span",{key:"i",style:{flex:"none",display:"grid",placeItems:"center",width:"16px",color:S?"var(--sb-orange)":"var(--sb-text-9)"}},$r(p.icon,14,1.9)),React.createElement("span",{key:"l",style:{flex:1}},p.label),S&&React.createElement("span",{key:"c",style:{flex:"none",display:"grid",placeItems:"center",color:"var(--sb-orange)"}},$r('',12,2.6))])}));return React.createElement("div",{ref:o,style:{position:"relative",display:"inline-flex"}},[h,m])};window.ThemeSwitcher=Gr;var Ma=`v${Fn}`,La=({status:s,fingerprint:e,verificationCode:t,onDisconnect:r,isConnected:i,securityLevel:n,webrtcManager:a})=>{let[o,c]=React.useState(null),[d,u]=React.useState(0),[h,m]=React.useState(!1),[p,S]=React.useState(0),[g,b]=React.useState("unknown");React.useEffect(()=>{let G=!1,U=0,I=async()=>{let N=Date.now();if(!(N-U<1e4)&&!G){G=!0,U=N;try{if(!a||!i)return;let z=a,W=null;if(typeof z.getRealSecurityLevel=="function"?W=await z.getRealSecurityLevel():typeof z.calculateAndReportSecurityLevel=="function"?W=await z.calculateAndReportSecurityLevel():W=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(z),W&&W.isRealData!==!1){let Z=o?.score||0,be=W.score||0;Z!==be||!o?(c(W),u(N)):window.DEBUG_MODE}}catch{}finally{G=!1}}};if(i&&(I(),!o||o.score<50)){let N=setInterval(()=>{!o||o.score<50?I():clearInterval(N)},5e3);setTimeout(()=>clearInterval(N),3e4)}let D=setInterval(I,3e4);return()=>clearInterval(D)},[a,i]),React.useEffect(()=>{let G=I=>{setTimeout(()=>{u(0)},100)},U=I=>{I.detail&&I.detail.securityData&&(c(I.detail.securityData),u(Date.now()))};return document.addEventListener("security-level-updated",G),document.addEventListener("real-security-calculated",U),window.forceHeaderSecurityUpdate=I=>{I&&window.EnhancedSecureCryptoUtils?window.EnhancedSecureCryptoUtils.calculateSecurityLevel(I).then(D=>{D&&D.isRealData!==!1&&(c(D),u(Date.now()))}).catch(D=>{}):u(0)},()=>{document.removeEventListener("security-level-updated",G),document.removeEventListener("real-security-calculated",U)}},[]),React.useEffect(()=>{m(!0),S(0),b("premium")},[]),React.useEffect(()=>{m(!0),S(0),b("premium")},[]),React.useEffect(()=>{let G=N=>{m(!0),S(0),b("premium")},U=()=>{c(null),u(0),m(!1),S(0),b("unknown")},I=()=>{c(null),u(0)},D=()=>{c(null),u(0),m(!1),S(0),b("unknown")};return document.addEventListener("force-header-update",G),document.addEventListener("peer-disconnect",I),document.addEventListener("connection-cleaned",U),document.addEventListener("disconnected",D),()=>{document.removeEventListener("force-header-update",G),document.removeEventListener("peer-disconnect",I),document.removeEventListener("connection-cleaned",U),document.removeEventListener("disconnected",D)}},[]);let w=async G=>{if(G&&(G.button===2||G.ctrlKey||G.metaKey)&&r&&typeof r=="function"){r();return}G.preventDefault(),G.stopPropagation();let U=null;if(a&&window.EnhancedSecureCryptoUtils)try{U=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(a)}catch{}if(!U&&!o){alert(f("sec.verificationWait"));return}let I=U||o;I||(I={level:"UNKNOWN",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:f("sec.verificationUnavailable"),isRealData:!1,passedChecks:0,totalChecks:0});let D=`REAL-TIME SECURITY VERIFICATION +`),e=e.trim()),e}_sanitizeInputObject(e){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(r=>this._sanitizeInputObject(r));let t={};for(let r in e)if(e.hasOwnProperty(r)){let i=e[r];typeof i=="string"?t[r]=this._sanitizeInputString(i):typeof i=="object"?t[r]=this._sanitizeInputObject(i):t[r]=i}return t}_checkRateLimit(e="message"){let t=Date.now();return this._rateLimiter||(this._rateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._rateLimiter.lastReset>6e4&&(this._rateLimiter.messageCount=0,this._rateLimiter.lastReset=t),t-this._rateLimiter.lastBurstReset>1e3&&(this._rateLimiter.burstCount=0,this._rateLimiter.lastBurstReset=t),this._rateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Rate limit burst exceeded",{context:e}),!1):this._rateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Rate limit exceeded",{context:e}),!1):(this._rateLimiter.messageCount++,this._rateLimiter.burstCount++,!0)}_checkInboundRateLimit(e="incoming_message"){let t=Date.now();return this._inboundRateLimiter||(this._inboundRateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._inboundRateLimiter.lastReset>6e4&&(this._inboundRateLimiter.messageCount=0,this._inboundRateLimiter.lastReset=t),t-this._inboundRateLimiter.lastBurstReset>1e3&&(this._inboundRateLimiter.burstCount=0,this._inboundRateLimiter.lastBurstReset=t),this._inboundRateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Inbound message burst limit exceeded; dropping message",{context:e}),!1):this._inboundRateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Inbound message rate limit exceeded; dropping message",{context:e}),!1):(this._inboundRateLimiter.messageCount++,this._inboundRateLimiter.burstCount++,!0)}_initializeSecureKeyStorage(){this._masterKeyManager=new jt,this._secureKeyStorage=new Gt(this._masterKeyManager),this._keyStorageStats={totalKeys:0,activeKeys:0,lastAccess:null,lastRotation:null},this._secureLog("info","\u{1F510} Enhanced secure key storage initialized")}setMasterKeyPasswordCallback(e){this._masterKeyManager&&this._masterKeyManager.setPasswordRequiredCallback(e)}setMasterKeySessionExpiredCallback(e){this._masterKeyManager&&this._masterKeyManager.setSessionExpiredCallback(e)}lockMasterKey(){this._masterKeyManager&&this._masterKeyManager.lock()}isMasterKeyUnlocked(){return this._masterKeyManager?this._masterKeyManager.isUnlocked():!1}getMasterKeySessionStatus(){return this._masterKeyManager?this._masterKeyManager.getSessionStatus():null}async _ensureFileTransferReady(){try{if(this.fileTransferSystem)return!0;if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.isVerified)throw new Error("Connection not verified");this.initializeFileTransfer();let e=0,t=50;for(;!this.fileTransferSystem&&esetTimeout(r,100)),e++;if(!this.fileTransferSystem)throw new Error("File transfer system initialization timeout");return!0}catch(e){return this._secureLog("error","\u274C _ensureFileTransferReady failed",{errorType:e?.constructor?.name||"Unknown",hasMessage:!!e?.message}),!1}}_getSecureKey(e){return this._secureKeyStorage.retrieveKey(e)}async _setSecureKey(e,t){if(!(t instanceof CryptoKey))return this._secureLog("error","\u274C Attempt to store non-CryptoKey"),!1;let r=await this._secureKeyStorage.storeKey(e,t,{version:this.currentKeyVersion,type:t.algorithm.name});return r&&this._secureLog("info",`\u{1F511} Key ${e} stored securely with encryption`),r}_validateKeyValue(e){return e instanceof CryptoKey&&e.algorithm&&e.usages&&e.usages.length>0}_secureWipeKeys(){this._secureKeyStorage.secureWipeAll(),this._masterKeyManager&&this._masterKeyManager.lock(),this._secureLog("info","\u{1F9F9} All keys securely wiped and encrypted storage cleared")}_validateKeyStorage(){return this._secureKeyStorage instanceof Gt}_getKeyStorageStats(){let e=this._secureKeyStorage.getStorageStats();return{totalKeysCount:e.totalKeys,activeKeysCount:e.totalKeys,hasLastAccess:e.metadata.some(t=>t.lastAccessed),hasLastRotation:!!this._keyStorageStats.lastRotation,storageType:"SecureKeyStorage",timestamp:Date.now()}}_rotateKeys(){let e=Array.from(this._secureKeyStorage.keys());this._secureKeyStorage.clear(),this._keyStorageStats.lastRotation=Date.now(),this._keyStorageStats.activeKeys=0,this._secureLog("info",`\u{1F504} Key rotation completed. ${e.length} keys rotated`)}_emergencyKeyWipe(){this._secureWipeKeys(),this._secureLog("error","\u{1F6A8} EMERGENCY: All keys wiped due to security threat")}_startKeySecurityMonitoring(){this._secureLog("info","\u{1F527} Key security monitoring moved to unified scheduler")}_validateKeyConstantTime(e){let t=0;try{let r=e instanceof CryptoKey;t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.algorithm);t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.type);t+=r?1:0}catch{t+=0}try{let r=e&&e.extractable!==void 0;t+=r?1:0}catch{t+=0}return t===4}_validateKeyPairConstantTime(e){if(!e||typeof e!="object")return!1;let t=this._validateKeyConstantTime(e.privateKey),r=this._validateKeyConstantTime(e.publicKey);return t&&r}_initializeSecureLogging(){this._logLevels={error:0,warn:1,info:2,debug:3,trace:4},this._currentLogLevel=this._isProductionMode?this._logLevels.error:this._logLevels.info,this._logCounts=new Map,this._maxLogCount=this._isProductionMode?5:50,this._resourceLimits={maxLogEntries:this._isProductionMode?100:1e3,maxMessageQueue:1e3,maxIVHistory:1e4,maxProcessedMessageIds:5e3,maxDecoyChannels:100,maxFakeTrafficMessages:500,maxChunkQueue:200,maxPacketBuffer:1e3},this._emergencyThresholds={logEntries:this._resourceLimits.maxLogEntries*.8,messageQueue:this._resourceLimits.maxMessageQueue*.8,ivHistory:this._resourceLimits.maxIVHistory*.8,processedMessageIds:this._resourceLimits.maxProcessedMessageIds*.8},this._inputValidationLimits={maxStringLength:1e5,maxObjectDepth:10,maxArrayLength:1e3,maxMessageSize:1024*1024,maxConcurrentMessages:10,rateLimitMessagesPerMinute:60,rateLimitBurstSize:10},this._absoluteBlacklist=new Set(["encryptionKey","macKey","metadataKey","privateKey","publicKey","ecdhKeyPair","ecdsaKeyPair","peerPublicKey","nestedEncryptionKey","verificationCode","sessionSalt","keyFingerprint","sessionId","authChallenge","authProof","authToken","sessionToken","password","token","secret","credential","signature","apiKey","accessKey","secretKey","privateKey","hash","digest","nonce","iv","cipher","seed","entropy","random","salt","fingerprint","jwt","bearer","refreshToken","accessToken","fileHash","fileSignature","transferKey","chunkKey"]),this._safeFieldsWhitelist=new Set(["timestamp","type","status","state","level","isConnected","isVerified","isInitiator","version","count","total","active","inactive","success","failure","readyState","connectionState","iceConnectionState","activeFeaturesCount","totalFeatures","stage","errorType","errorCode","phase","attempt"]),this._initializeLogSecurityMonitoring(),this._secureLog("info",`\u{1F527} Enhanced secure logging initialized (Production: ${this._isProductionMode})`)}_initializeLogSecurityMonitoring(){this._logSecurityViolations=0,this._maxLogSecurityViolations=3}_auditLoggingSystemSecurity(){let e=0;for(let[r,i]of this._logCounts.entries())i>this._maxLogCount*2&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Excessive log count detected: ${r}`));let t=Array.from(this._logCounts.keys());for(let r of t)this._containsSensitiveContent(r)&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Sensitive content in log key: ${r}`));this._logSecurityViolations+=e,this._logSecurityViolations>=this._maxLogSecurityViolations&&(this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Logging system disabled due to security violations"))}_secureLogShim(...e){try{if(!Array.isArray(e)||e.length===0)return;let t=e[0],r=e.slice(1);if(r.length===0){this._secureLog("info",String(t||""));return}if(r.length===1){this._secureLog("info",String(t||""),r[0]);return}this._secureLog("info",String(t||""),{additionalArgs:r,argCount:r.length})}catch{try{this._originalConsole?.log&&this._originalConsole.log(...e)}catch{}}}_setupOwnLogger(){this.logger={log:(e,t)=>this._secureLog("info",e,t),info:(e,t)=>this._secureLog("info",e,t),warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:(e,t)=>this._secureLog("debug",e,t)},s.DEBUG_MODE?this._secureLog("info","\u{1F512} Own logger created - development mode"):this._secureLog("info","\u{1F512} Own logger created - production mode")}_setupProductionLogging(){this._isProductionMode&&(this.logger={log:()=>{},info:()=>{},warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:()=>{}},this._secureLog("info","Production logging mode activated"))}_secureLog(e,t,r=null){if(r&&!this._auditLogMessage(t,r)){this._originalConsole?.error?.("SECURITY: Logging blocked due to potential data leakage");return}if(this._logLevels[e]>this._currentLogLevel)return;let i=`${e}:${t.substring(0,50)}`,n=this._logCounts.get(i)||0;if(n>=this._maxLogCount)return;this._logCounts.set(i,n+1);let a=null;if(r&&(a=this._sanitizeLogData(r),this._containsSensitiveContent(JSON.stringify(a)))){this._originalConsole?.error?.("ECURITY: Sanitized data still contains sensitive content - blocking log");return}if(this._isProductionMode){if(e==="error"){let c=this._sanitizeString(t);this._originalConsole?.error?.(c)}return}let o=this._originalConsole?.[e]||this._originalConsole?.log;a?o(t,a):o(t)}_sanitizeLogData(e){if(typeof e=="string")return this._sanitizeString(e);if(!e||typeof e!="object")return e;let t={};for(let[i,n]of Object.entries(e)){let a=i.toLowerCase(),o=["key","secret","token","password","credential","auth","fingerprint","salt","signature","private","encryption","mac","metadata","session","jwt","bearer","hash","digest","nonce","iv","cipher","seed","entropy"];if(this._absoluteBlacklist.has(i)||o.some(d=>a.includes(d))){t[i]="[SENSITIVE_DATA_BLOCKED]";continue}if(this._safeFieldsWhitelist.has(i)){typeof n=="string"?t[i]=this._sanitizeString(n):t[i]=n;continue}if(typeof n=="boolean"||typeof n=="number")t[i]=n;else if(typeof n=="string")t[i]=this._sanitizeString(n);else if(n instanceof ArrayBuffer||n instanceof Uint8Array)t[i]=`[${n.constructor.name}( bytes)]`;else if(n&&typeof n=="object")try{t[i]=this._sanitizeLogData(n)}catch{t[i]="[RECURSIVE_SANITIZATION_FAILED]"}else t[i]=`[${typeof n}]`}let r=JSON.stringify(t);return this._containsSensitiveContent(r)?{error:"SANITIZATION_FAILED_SENSITIVE_CONTENT_DETECTED"}:t}_sanitizeString(e){if(typeof e!="string"||e.length===0)return e;let t=[/[a-f0-9]{16,}/i,/[a-f0-9]{8,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[A-Za-z0-9+/]{12,}/,/[A-Za-z0-9+/=]{10,}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/[A-Z2-7]{12,}/,/[A-Za-z0-9\-_]{16,}/,/[A-Za-z0-9\.\-_]{16,}/,/\b[A-Za-z0-9]{12,}\b/,/\b[A-Za-z0-9]{8,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/END\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i,/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/,/\b\d{3}-\d{2}-\d{4}\b/,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/,/(fingerprint|hash|digest|signature)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(encryption|mac|metadata)[\s]*key[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(session|auth|jwt|bearer)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i];for(let r of t)if(r.test(e))return"[SENSITIVE_DATA_REDACTED]";return this._hasHighEntropy(e)?"[HIGH_ENTROPY_DATA_REDACTED]":this._hasSuspiciousDistribution(e)?"[SUSPICIOUS_DATA_REDACTED]":e.length>50?e.substring(0,20)+"...[TRUNCATED]":e}_containsSensitiveContent(e){return typeof e!="string"?!1:[/[a-f0-9]{16,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/\b[A-Za-z0-9]{12,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i].some(r=>r.test(e))||this._hasHighEntropy(e)||this._hasSuspiciousDistribution(e)}_hasHighEntropy(e){if(e.length<8)return!1;let t={};for(let n of e)t[n]=(t[n]||0)+1;let r=e.length,i=0;for(let n of Object.values(t)){let a=n/r;i-=a*Math.log2(a)}return i>4.5}_hasSuspiciousDistribution(e){return e.length<8?!1:(e.match(/[a-f0-9]/gi)||[]).length>=e.length*.8||(e.match(/[A-Za-z0-9+/=]/g)||[]).length>=e.length*.9||new Set(e).size/e.length>.8&&e.length>16}_detectProductionMode(){return typeof process<"u"&&!0||!this._debugMode||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")}_setupSecureGlobalAPI(){this._secureLog("info","Starting secure global API setup");let e={};typeof this.sendMessage=="function"&&(e.sendMessage=this.sendMessage.bind(this)),e.getConnectionStatus=()=>({isConnected:this.isConnected?this.isConnected():!1,isVerified:this.isVerified||!1,connectionState:this.peerConnection?.connectionState||"disconnected"}),e.getSecurityStatus=()=>({securityLevel:"maximum",stage:"initialized",activeFeaturesCount:Object.values(this.securityFeatures||{}).filter(Boolean).length}),typeof this.sendFile=="function"&&(e.sendFile=this.sendFile.bind(this)),e.getFileTransferStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),typeof this.disconnect=="function"&&(e.disconnect=this.disconnect.bind(this));let t={...e,getConfiguration:()=>({fakeTraffic:this._config.fakeTraffic.enabled,decoyChannels:this._config.decoyChannels.enabled,packetPadding:this._config.packetPadding.enabled,antiFingerprinting:this._config.antiFingerprinting.enabled}),emergency:{}};typeof this._emergencyUnlockAllMutexes=="function"&&(t.emergency.unlockAllMutexes=this._emergencyUnlockAllMutexes.bind(this)),typeof this._emergencyRecoverMutexSystem=="function"&&(t.emergency.recoverMutexSystem=this._emergencyRecoverMutexSystem.bind(this)),typeof this._emergencyDisableLogging=="function"&&(t.emergency.disableLogging=this._emergencyDisableLogging.bind(this)),typeof this._resetLoggingSystem=="function"&&(t.emergency.resetLogging=this._resetLoggingSystem.bind(this)),t.getFileTransferSystemStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),this._secureLog("info","API methods available",{sendMessage:!!e.sendMessage,getConnectionStatus:!!e.getConnectionStatus,getSecurityStatus:!!e.getSecurityStatus,sendFile:!!e.sendFile,getFileTransferStatus:!!e.getFileTransferStatus,disconnect:!!e.disconnect,getConfiguration:!!t.getConfiguration,emergencyMethods:Object.keys(t.emergency).length}),Object.freeze(t),Object.freeze(t.emergency),this._createProtectedGlobalAPI(t),this._setupMinimalGlobalProtection(),this._secureLog("info","Secure global API setup completed successfully")}_createProtectedGlobalAPI(e){this._secureLog("info","Creating protected global API"),window.secureBitChat?this._secureLog("warn","\u26A0\uFE0F Global API already exists, skipping setup"):this._exportAPI(e)}_exportAPI(e){this._secureLog("info","Exporting API to window.secureBitChat"),!this._importantMethods||!this._importantMethods.defineProperty?(this._secureLog("error","\u274C Important methods not available for API export, using fallback"),Object.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0})):this._importantMethods.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0}),this._secureLog("info","\u{1F512} Secure API exported to window.secureBitChat")}_setupMinimalGlobalProtection(){this._protectGlobalAPI(),this._secureLog("info","\u{1F512} Minimal global protection activated")}_storeImportantMethods(){this._importantMethods={defineProperty:Object.defineProperty,getOwnPropertyDescriptor:Object.getOwnPropertyDescriptor,freeze:Object.freeze,consoleLog:console.log,consoleError:console.error,consoleWarn:console.warn},this._secureLog("info","\u{1F512} Important methods stored locally",{defineProperty:!!this._importantMethods.defineProperty,getOwnPropertyDescriptor:!!this._importantMethods.getOwnPropertyDescriptor,freeze:!!this._importantMethods.freeze})}_setupSimpleProtection(){this._secureLog("info","\u{1F512} Simple protection activated - no monitoring")}_preventGlobalExposure(){this._secureLog("info","\u{1F512} No global exposure prevention - using secure API export only")}_verifyAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C SECURITY ALERT: Secure API has been removed!"),!1;let t=["sendMessage","getConnectionStatus","disconnect"].filter(r=>typeof window.secureBitChat[r]!="function");return t.length>0?(this._secureLog("error","\u274C SECURITY ALERT: API tampering detected, missing methods:",{errorType:t?.constructor?.name||"Unknown"}),!1):!0}catch(e){return this._secureLog("error","\u274C SECURITY ALERT: API integrity check failed:",{errorType:e?.constructor?.name||"Unknown"}),!1}}_auditGlobalExposure(){return this._secureLog("info","\u{1F512} Global exposure check completed at initialization"),[]}_startSecurityAudit(){this._secureLog("info","\u{1F512} Security audit completed at initialization - no periodic monitoring")}_protectGlobalAPI(){if(!window.secureBitChat){this._secureLog("warn","\u26A0\uFE0F Global API not found during protection setup");return}try{this._validateAPIIntegrityOnce()&&this._secureLog("info","\u{1F512} Global API protection verified")}catch(e){this._secureLog("error","\u274C Failed to verify global API protection",{errorType:e.constructor.name,errorMessage:e.message})}}_validateAPIIntegrityOnce(){try{if(!this._importantMethods||!this._importantMethods.getOwnPropertyDescriptor){let e=Object.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}else{let e=this._importantMethods.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}return this._secureLog("info","\u2705 API integrity validated"),!0}catch(e){return this._secureLog("error","\u274C API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_secureWipeMemory(e,t="unknown"){if(e)try{e instanceof ArrayBuffer?this._secureWipeArrayBuffer(e,t):e instanceof Uint8Array?this._secureWipeUint8Array(e,t):Array.isArray(e)?this._secureWipeArray(e,t):typeof e=="string"?this._secureWipeString(e,t):e instanceof CryptoKey?this._secureWipeCryptoKey(e,t):typeof e=="object"&&this._secureWipeObject(e,t),this._secureMemoryManager.memoryStats.totalCleanups++}catch(r){this._secureMemoryManager.memoryStats.failedCleanups++,this._secureLog("error","\u274C Secure memory wipe failed",{context:t,errorType:r.constructor.name,errorMessage:r.message})}}_secureWipeArrayBuffer(e,t){if(!(!e||e.byteLength===0))try{let r=new Uint8Array(e);crypto.getRandomValues(r),r.fill(0),r.fill(255),r.fill(0),this._secureLog("debug","\u{1F512} ArrayBuffer securely wiped",{context:t,size:e.byteLength})}catch(r){this._secureLog("error","\u274C Failed to wipe ArrayBuffer",{context:t,errorType:r.constructor.name})}}_secureWipeUint8Array(e,t){if(!(!e||e.length===0))try{crypto.getRandomValues(e),e.fill(0),e.fill(255),e.fill(0),this._secureLog("debug","\u{1F512} Uint8Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe Uint8Array",{context:t,errorType:r.constructor.name})}}_secureWipeArray(e,t){if(!(!Array.isArray(e)||e.length===0))try{e.forEach((r,i)=>{r!=null&&this._secureWipeMemory(r,`${t}[${i}]`)}),e.fill(null),this._secureLog("debug","\u{1F512} Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe array",{context:t,errorType:r.constructor.name})}}_secureWipeString(e,t){return this._secureLog("debug","String secret cannot be wiped in JS (immutable) \u2014 reference dropped only",{context:t,length:e?e.length:0}),!1}_secureWipeCryptoKey(e,t){return!e||!(e instanceof CryptoKey)||(this._secureLog("debug","CryptoKey cannot be wiped from JS \u2014 handle dropped, material is non-extractable",{context:t,type:e.type,extractable:e.extractable}),e.extractable&&this._secureLog("error","Extractable key reached the wipe path \u2014 material may persist in memory",{context:t})),!1}_secureWipeObject(e,t){if(!(!e||typeof e!="object"))try{for(let[r,i]of Object.entries(e))i!=null&&this._secureWipeMemory(i,`${t}.${r}`),e[r]=null;this._secureLog("debug","\u{1F512} Object securely wiped",{context:t,properties:Object.keys(e).length})}catch(r){this._secureLog("error","\u274C Failed to wipe object",{context:t,errorType:r.constructor.name})}}_secureCleanupCryptographicMaterials(){try{if(this.ecdhKeyPair&&(this._secureWipeMemory(this.ecdhKeyPair,"ecdhKeyPair"),this.ecdhKeyPair=null),this.ecdsaKeyPair&&(this._secureWipeMemory(this.ecdsaKeyPair,"ecdsaKeyPair"),this.ecdsaKeyPair=null),this.encryptionKey&&(this._secureWipeMemory(this.encryptionKey,"encryptionKey"),this.encryptionKey=null),this.macKey&&(this._secureWipeMemory(this.macKey,"macKey"),this.macKey=null),this.metadataKey&&(this._secureWipeMemory(this.metadataKey,"metadataKey"),this.metadataKey=null),this.nestedEncryptionKey&&(this._secureWipeMemory(this.nestedEncryptionKey,"nestedEncryptionKey"),this.nestedEncryptionKey=null),this.sessionSalt&&(this._secureWipeMemory(this.sessionSalt,"sessionSalt"),this.sessionSalt=null),this.sessionId&&(this._secureWipeMemory(this.sessionId,"sessionId"),this.sessionId=null),this.verificationCode&&(this._secureWipeMemory(this.verificationCode,"verificationCode"),this.verificationCode=null),this.peerPublicKey&&(this._secureWipeMemory(this.peerPublicKey,"peerPublicKey"),this.peerPublicKey=null),this.keyFingerprint&&(this._secureWipeMemory(this.keyFingerprint,"keyFingerprint"),this.keyFingerprint=null),this.connectionId&&(this._secureWipeMemory(this.connectionId,"connectionId"),this.connectionId=null),this._clearPendingOfferContext(),this._ratchet){try{this._ratchet.destroy()}catch{}this._ratchet=null}this._peerSupportsRatchet=!1,this._secureLog("info","\u{1F512} Cryptographic materials securely cleaned up")}catch(e){this._secureLog("error","\u274C Failed to cleanup cryptographic materials",{errorType:e.constructor.name,errorMessage:e.message})}}async _forceGarbageCollection(){try{await this._performNaturalCleanup(),this._secureLog("debug","\u{1F512} Natural memory cleanup performed")}catch(e){this._secureLog("error","\u274C Failed to perform natural cleanup",{errorType:e.constructor.name})}}async _performPeriodicMemoryCleanup(){try{this._secureMemoryManager.isCleaning=!0;let e=this.sessionMode==="ratchet"&&this.isConnected&&this.dataChannel&&this.dataChannel.readyState==="open",t=this._pendingOfferContext?Date.now()-(this._pendingOfferContext.createdAt||0):1/0,r=!!this._pendingOfferContext&&Array.isArray(this._pendingOfferContext.sessionSalt)&&this._pendingOfferContext.sessionSalt.length===64&&t100&&this.messageQueue.splice(0,this.messageQueue.length-50).forEach((a,o)=>{this._secureWipeMemory(a,`periodicCleanup[${o}]`)}),this.processedMessageIds&&this.processedMessageIds.size>1e3&&this.processedMessageIds.clear(),await this._forceGarbageCollection(),this._secureLog("debug","\u{1F512} Periodic memory cleanup completed")}catch(e){this._secureLog("error","\u274C Error during periodic memory cleanup",{errorType:e.constructor.name,errorMessage:e.message})}finally{this._secureMemoryManager.isCleaning=!1}}_createSecureErrorMessage(e,t="unknown"){try{let r=this._categorizeError(e),i=this._getSafeErrorMessage(r,t);return this._secureLog("error","Internal error occurred",{category:r,context:t,errorType:e?.constructor?.name||"Unknown",timestamp:Date.now()}),this._trackErrorFrequency(r),i}catch(r){return this._secureLog("error","Error handling failed",{originalError:e?.message||"Unknown",handlingError:r.message}),"An unexpected error occurred"}}_categorizeError(e){if(!e||!e.message)return this._secureErrorHandler.errorCategories.UNKNOWN;let t=e.message.toLowerCase();return t.includes("crypto")||t.includes("key")||t.includes("encrypt")||t.includes("decrypt")||t.includes("sign")||t.includes("verify")||t.includes("ecdh")||t.includes("ecdsa")?this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC:t.includes("network")||t.includes("connection")||t.includes("timeout")||t.includes("webrtc")||t.includes("peer")?this._secureErrorHandler.errorCategories.NETWORK:t.includes("invalid")||t.includes("validation")||t.includes("format")||t.includes("type")?this._secureErrorHandler.errorCategories.VALIDATION:t.includes("system")||t.includes("internal")||t.includes("memory")||t.includes("resource")?this._secureErrorHandler.errorCategories.SYSTEM:this._secureErrorHandler.errorCategories.UNKNOWN}_getSafeErrorMessage(e,t){let r={[this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC]:{key_generation:"Security initialization failed",key_import:"Security verification failed",key_derivation:"Security setup failed",encryption:"Message security failed",decryption:"Message verification failed",signature:"Authentication failed",default:"Security operation failed"},[this._secureErrorHandler.errorCategories.NETWORK]:{connection:"Connection failed",timeout:"Connection timeout",peer:"Peer connection failed",webrtc:"Communication failed",default:"Network operation failed"},[this._secureErrorHandler.errorCategories.VALIDATION]:{format:"Invalid data format",type:"Invalid data type",structure:"Invalid data structure",default:"Validation failed"},[this._secureErrorHandler.errorCategories.SYSTEM]:{memory:"System resource error",resource:"System resource unavailable",internal:"Internal system error",default:"System operation failed"},[this._secureErrorHandler.errorCategories.UNKNOWN]:{default:"An unexpected error occurred"}},i=r[e]||r[this._secureErrorHandler.errorCategories.UNKNOWN],n="default";return t.includes("key")||t.includes("crypto")?n=e===this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC?"key_generation":"default":t.includes("connection")||t.includes("peer")?n=e===this._secureErrorHandler.errorCategories.NETWORK?"connection":"default":(t.includes("validation")||t.includes("format"))&&(n=e===this._secureErrorHandler.errorCategories.VALIDATION?"format":"default"),i[n]||i.default}_trackErrorFrequency(e){let t=Date.now();t-this._secureErrorHandler.lastErrorTime>6e4&&this._secureErrorHandler.errorCounts.clear();let r=this._secureErrorHandler.errorCounts.get(e)||0;this._secureErrorHandler.errorCounts.set(e,r+1),this._secureErrorHandler.lastErrorTime=t;let i=Array.from(this._secureErrorHandler.errorCounts.values()).reduce((n,a)=>n+a,0);i>this._secureErrorHandler.errorThreshold&&(this._secureErrorHandler.isInErrorMode=!0,this._secureLog("warn","\u26A0\uFE0F High error frequency detected - entering error mode",{totalErrors:i,threshold:this._secureErrorHandler.errorThreshold}))}_throwSecureError(e,t="unknown"){let r=this._createSecureErrorMessage(e,t);throw new Error(r)}_getErrorHandlingStats(){return{errorCounts:Object.fromEntries(this._secureErrorHandler.errorCounts),isInErrorMode:this._secureErrorHandler.isInErrorMode,lastErrorTime:this._secureErrorHandler.lastErrorTime,errorThreshold:this._secureErrorHandler.errorThreshold}}_resetErrorHandlingSystem(){this._secureErrorHandler.errorCounts.clear(),this._secureErrorHandler.isInErrorMode=!1,this._secureErrorHandler.lastErrorTime=0,this._secureLog("info","\u{1F504} Error handling system reset")}_getMemoryManagementStats(){return{totalCleanups:this._secureMemoryManager.memoryStats.totalCleanups,failedCleanups:this._secureMemoryManager.memoryStats.failedCleanups,lastCleanup:this._secureMemoryManager.memoryStats.lastCleanup,isCleaning:this._secureMemoryManager.isCleaning,queueLength:this._secureMemoryManager.cleanupQueue.length}}_validateAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C Global API not found during integrity validation"),!1;let e=["sendMessage","getConnectionStatus","getSecurityStatus","sendFile","disconnect"],t=e.filter(a=>!window.secureBitChat[a]||typeof window.secureBitChat[a]!="function");if(t.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - missing methods",{missingMethods:t}),!1;let r={test:!0},n=e.map(a=>{try{return window.secureBitChat[a].bind(r)}catch{return null}}).filter(a=>a===null);if(n.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - method binding issues",{unboundMethods:n.length}),!1;try{let a="_integrity_test_"+Date.now();return Object.defineProperty(window.secureBitChat,a,{value:"test",writable:!0,configurable:!0}),this._secureLog("error","\u274C Global API integrity validation failed - API is mutable"),delete window.secureBitChat[a],!1}catch{this._secureLog("debug","\u2705 Global API immutability verified")}return this._secureLog("info","\u2705 Global API integrity validation passed"),!0}catch(e){return this._secureLog("error","\u274C Global API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_validateCryptographicSecurity(){let e=["hasRateLimiting"],t=e.filter(n=>!this.securityFeatures[n]);t.length>0&&(this._secureLog("error","\u{1F6A8} CRITICAL: Missing critical rate limiting feature",{missing:t,currentFeatures:this.securityFeatures,action:"Rate limiting will be forced enabled"}),t.forEach(n=>{this.securityFeatures[n]=!0,this._secureLog("warn",`\u26A0\uFE0F Forced enable critical: ${n} = true`)}));let r=Object.keys(this.securityFeatures).filter(n=>this.securityFeatures[n]),i=["hasEncryption","hasECDH","hasECDSA"].filter(n=>this.securityFeatures[n]);return this._secureLog("info","\u2705 Cryptographic security validation passed",{criticalFeatures:e.length,availableFeatures:r.length,encryptionFeatures:i.length,totalSecurityFeatures:r.length,note:"Encryption features will be enabled after key generation",currentState:{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasRateLimiting:this.securityFeatures.hasRateLimiting}}),!0}_syncSecurityFeaturesWithTariff(){this._secureLog("info","\u2705 All security features enabled by default - no payment required"),["hasEncryption","hasECDH","hasECDSA","hasMutualAuth","hasMetadataProtection","hasEnhancedReplayProtection","hasNonExtractableKeys","hasRateLimiting","hasEnhancedValidation","hasPFS","hasNestedEncryption","hasPacketPadding","hasPacketReordering","hasAntiFingerprinting","hasFakeTraffic","hasDecoyChannels","hasMessageChunking"].forEach(t=>{this.securityFeatures[t]=!0}),this._secureLog("info","\u2705 All security features enabled by default",{enabledFeatures:Object.keys(this.securityFeatures).filter(t=>this.securityFeatures[t]).length,totalFeatures:Object.keys(this.securityFeatures).length})}_emergencyShutdown(e="Security breach"){this._secureLog("error","\u274C EMERGENCY SHUTDOWN: ${reason}");try{this.encryptionKey=null,this.macKey=null,this.metadataKey=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.messageQueue=[],this.processedMessageIds.clear(),this.packetBuffer.clear(),this.onStatusChange&&this.onStatusChange("security_breach"),this._secureLog("info","\u{1F512} Emergency shutdown completed")}catch(t){this._secureLog("error","\u274C Error during emergency shutdown:",{errorType:t?.constructor?.name||"Unknown"})}}_finalizeSecureInitialization(){if(this._startKeySecurityMonitoring(),!this._verifyAPIIntegrity()){this._secureLog("error","\u274C Security initialization failed");return}this._startSecurityMonitoring(),this._logCleanupInterval=this._trackActiveTimer(setInterval(()=>{this._cleanupLogs()},3e5)),this._secureLog("info","\u2705 Secure WebRTC Manager initialization completed"),this._secureLog("info","\u{1F512} Global exposure protection: Monitoring only, no automatic removal")}_startSecurityMonitoring(){this._secureLog("info","\u{1F527} Security monitoring moved to unified scheduler")}_validateConnection(e=!0){let t=this.dataChannel&&this.dataChannel.readyState==="open",r=this.isVerified,i=t&&r;if(!i&&e){if(!t)throw new Error("Data channel not ready");if(!r)throw new Error("Connection not verified")}return i}_enforceVerificationGate(e="unknown",t=!0){if(!this.isVerified){let r=`SECURITY VIOLATION: ${e} blocked - connection not cryptographically verified`;if(this._secureLog("error",r,{operation:e,isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey),timestamp:Date.now()}),t)throw new Error(r);return!1}return!0}_setVerifiedStatus(e,t="unknown",r=null){if(e){if(!this.encryptionKey||!this.macKey)throw new Error("Cannot set verified=true without encryption keys");if(!t||t==="unknown")throw new Error("Cannot set verified=true without specifying verification method");if(t.includes("SAS")&&!this.localVerificationConfirmed)throw this._secureLog("error","Blocked verified transition without local SAS confirmation",{verificationMethod:t,localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed}),new Error("Cannot set verified=true without local SAS confirmation");this._secureLog("info","Connection verified through cryptographic verification",{verificationMethod:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,keyFingerprint:this.keyFingerprint,timestamp:Date.now(),verificationData:r?"provided":"none"})}this.isVerified=e,e?this.onStatusChange("connected"):this.onStatusChange("disconnected")}markGroupLinkVerified(e="group_roster_signature"){let t=this._sbq2;if(!this._isSbq2()||!t||!t.completed||!t.proofVerified||!t.keysDerived)throw new Error("Group link cannot be released: the in-band handshake has not completed");if(!this.encryptionKey||!this.macKey)throw new Error("Group link cannot be released: session keys are missing");if(this.isVerified)return!0;this.localVerificationConfirmed=!0,this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this._setVerifiedStatus(!0,"GROUP_ROSTER_SIGNATURE",{reason:e,timestamp:Date.now()}),this._enforceVerificationGate("group_link_release",!1),this.onStatusChange?.("verified");try{this.processMessageQueue()}catch{}return!0}_createFileMessageAAD(e,t=null){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in _createFileMessageAAD. Manager may not be fully initialized.");return this._createMessageAAD(e,t,!0)}_validateFileMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);if(Date.now()-r.timestamp>18e5)throw new Error("AAD timestamp too old - possible replay attack");return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}_validateIncomingSequenceNumber(e,t="unknown"){try{if(!this.replayProtectionEnabled)return!0;if(typeof e!="number"||!Number.isFinite(e))return this._secureLog("warn","Missing or non-numeric sequence number - rejecting",{receivedType:typeof e,context:t,timestamp:Date.now()}),!1;if(ethis.expectedSequenceNumber+this.maxSequenceGap)return this._secureLog("warn","Sequence number gap too large - possible DoS attack",{received:e,expected:this.expectedSequenceNumber,gap:e-this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.has(e))return this._secureLog("warn","Duplicate sequence number detected - replay attack",{received:e,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.add(e),this.replayWindow.size>this.replayWindowSize){let r=Math.min(...this.replayWindow);this.replayWindow.delete(r)}if(e===this.expectedSequenceNumber)for(this.expectedSequenceNumber++;this.replayWindow.has(this.expectedSequenceNumber-this.replayWindowSize-1);)this.replayWindow.delete(this.expectedSequenceNumber-this.replayWindowSize-1);return this._secureLog("debug","Sequence number validation successful",{received:e,expected:this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!0}catch(r){return this._secureLog("error","Sequence number validation failed",{error:r.message,context:t,timestamp:Date.now()}),!1}}_validateMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(!this._validateIncomingSequenceNumber(r.sequenceNumber,r.messageType))throw new Error("Sequence number validation failed - possible replay or DoS attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}getAntiReplayStatus(){let e={replayProtectionEnabled:this.replayProtectionEnabled,replayWindowSize:this.replayWindowSize,currentReplayWindowSize:this.replayWindow.size,sequenceNumber:this.sequenceNumber,expectedSequenceNumber:this.expectedSequenceNumber,maxSequenceGap:this.maxSequenceGap,replayWindowEntries:Array.from(this.replayWindow).sort((t,r)=>t-r)};return this._secureLog("info","Anti-replay status retrieved",e),e}configureAntiReplayProtection(e){try{if(e.windowSize!==void 0){if(e.windowSize<16||e.windowSize>1024)throw new Error("Replay window size must be between 16 and 1024");this.replayWindowSize=e.windowSize}if(e.maxGap!==void 0){if(e.maxGap<10||e.maxGap>1e3)throw new Error("Max sequence gap must be between 10 and 1000");this.maxSequenceGap=e.maxGap}return e.enabled!==void 0&&(this.replayProtectionEnabled=e.enabled),this._secureLog("info","Anti-replay protection configured",e),!0}catch(t){return this._secureLog("error","Failed to configure anti-replay protection",{error:t.message}),!1}}async getRealSecurityLevel(){try{let e={ecdhKeyExchange:!!this.ecdhKeyPair,ecdsaSignatures:!!this.ecdsaKeyPair,aesEncryption:!!this.encryptionKey,messageIntegrity:!!this.hmacKey,replayProtection:this.replayProtectionEnabled,dtlsFingerprint:!!(this.expectedDTLSFingerprint&&this._peerDTLSFingerprint),sasCode:!!this.verificationCode&&this.localVerificationConfirmed===!0,metadataProtection:!0,trafficObfuscation:!0,perfectForwardSecrecy:this.isRatchetActive?.()===!0,rateLimiter:!0,connectionId:this.connectionId,keyFingerprint:this.keyFingerprint,currentSecurityLevel:"maximum",timestamp:Date.now()},t=await this.calculateAndReportSecurityLevel();return t?{...t,...e}:{...e,level:"INITIALIZING",score:0,isRealData:!1}}catch(e){throw this._secureLog("error","Failed to calculate real security level",{error:e.message}),e}}_extractDTLSFingerprintFromSDP(e){try{if(!e||typeof e!="string")throw new Error("Invalid SDP provided");let t=/a=fingerprint:([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/g,r=[],i;for(;(i=t.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()});if(r.length===0){let a=/fingerprint\s*=\s*([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/gi;for(;(i=a.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()})}if(r.length===0)throw this._secureLog("warn","No DTLS fingerprints found in SDP - this may be normal for some WebRTC implementations",{sdpLength:e.length,sdpPreview:e.substring(0,200)+"..."}),new Error("No DTLS fingerprints found in SDP");return[...r].sort((a,o)=>{let c=a.algorithm==="sha-256",d=o.algorithm==="sha-256";if(c!==d)return c?-1:1;let h=a.algorithm.localeCompare(o.algorithm);return h!==0?h:a.fingerprint.localeCompare(o.fingerprint)})[0].fingerprint}catch(t){throw this._secureLog("error","Failed to extract DTLS fingerprint from SDP",{error:t.message,sdpLength:e?.length||0}),new Error(`DTLS fingerprint extraction failed: ${t.message}`)}}async _validateDTLSFingerprint(e,t,r="unknown"){try{if(!e||!t)throw new Error("Missing fingerprint for validation");let i=e.toLowerCase().replace(/:/g,""),n=t.toLowerCase().replace(/:/g,"");if(i!==n)throw this._secureLog("error","DTLS fingerprint mismatch - possible MITM attack",{context:r,timestamp:Date.now()}),new Error(`DTLS fingerprint mismatch - possible MITM attack in ${r}`);return this._secureLog("info","DTLS fingerprint validation successful",{context:r,timestamp:Date.now()}),!0}catch(i){throw this._secureLog("error","DTLS fingerprint validation failed",{error:i.message,context:r}),i}}async _computeSAS(e,t,r){try{if(!e){let S=[];throw e||S.push("keyMaterialRaw"),new Error(`Missing required parameters for SAS computation: ${S.join(", ")}`)}let i=new TextEncoder,n=(S,w)=>{if(typeof S!="string"||S.trim().length===0)throw new Error(`Security error: ${w} must be a non-empty DTLS fingerprint string for SAS computation`);return S.trim().toLowerCase()},a=n(t,"localFP"),o=n(r,"remoteFP"),c=i.encode("webrtc-sas|"+[a,o].sort().join("|")),d;if(e instanceof ArrayBuffer)d=e;else if(e instanceof Uint8Array)d=e.buffer;else if(typeof e=="string"){let S=e.replace(/:/g,"").replace(/\s/g,""),w=new Uint8Array(S.length/2);for(let M=0;M>>0,p=String(b%1e7).padStart(7,"0");return this._secureLog("info","SAS code computed successfully",{localFP:a.substring(0,16)+"...",remoteFP:o.substring(0,16)+"...",sasLength:p.length,timestamp:Date.now()}),p}catch(i){throw this._secureLog("error","SAS computation failed",{error:i.message,keyMaterialType:typeof e,hasLocalFP:!!t,hasRemoteFP:!!r,timestamp:Date.now()}),new Error(`SAS computation failed: ${i.message}`)}}_dispatchAppEvent(e){if(!this._emitGlobalEvents)return!1;try{return document.dispatchEvent(e)}catch{return!1}}_isSbq2(){return this._handshakeMode==="sbq2"}_latchHandshakeMode(e){if(this._handshakeMode&&this._handshakeMode!==e)throw new Error(`handshake format cannot change mid-session (${this._handshakeMode} -> ${e})`);this._handshakeMode=e}_sbq2State(){return this._sbq2||(this._sbq2={role:null,localDescriptor:null,remoteDescriptor:null,localBlob:null,remoteBlob:null,remoteCommitment:null,transcript:null,peerEcdhKey:null,peerEcdsaKey:null,blobSent:!1,proofSent:!1,proofVerified:!1,keysDerived:!1,pendingProof:null,completed:!1,timer:null,startedAt:0}),this._sbq2}_sbq2Abort(e,t){let r=this._sbq2;r?.timer&&(clearTimeout(r.timer),r.timer=null),this._secureLog("error","SBQ2 handshake aborted",{code:e});try{this.deliverMessageToUI(t,"system")}catch{}try{this.onStatusChange?.("failed")}catch{}try{this.disconnect()}catch{}}async _exportSpki(e){return new Uint8Array(await crypto.subtle.exportKey("spki",e))}async _sbq2BuildLocalBlob(e){if(!this.ecdhKeyPair?.publicKey||!this.ecdsaKeyPair?.publicKey)throw new Error("SBQ2: key pairs are not ready");let t=Cn({role:e,ecdhSpki:await this._exportSpki(this.ecdhKeyPair.publicKey),ecdsaSpki:await this._exportSpki(this.ecdsaKeyPair.publicKey)}),i=await Ht(async a=>new Uint8Array(await crypto.subtle.digest("SHA-256",a)),t),n=this._sbq2State();return n.role=e,n.localBlob=t,{blob:t,commitment:i}}async _sbq2BuildDescriptor(e,{bindingTag:t=null,lifetimeMs:r=600*1e3}={}){let i=this.peerConnection?.localDescription?.sdp;if(!i)throw new Error("SBQ2: no local description to encode");let n=e===de.OFFER?ve.OFFER:ve.ANSWER,{commitment:a}=await this._sbq2BuildLocalBlob(n),o=bn(i),c=_n({type:e,expiresAtMs:Date.now()+r,sdpFields:{...o,candidates:Pr(o.candidates)},commitment:a,...e===de.ANSWER?{bindingTag:t}:{}}),d=this._sbq2State();return d.localDescriptor=c,this._secureLog("info","SBQ2 descriptor built",{type:e===de.OFFER?"offer":"answer",bytes:c.length,candidates:Pr(o.candidates).length}),{bytes:c,text:vn(c)}}_sbq2AdoptRemoteDescriptor(e,t){let r=Fr(e);if(r.type!==t)throw new Error(`expected an ${t===de.OFFER?"invitation":"answer"}, got the other kind`);if(!r.commitment)throw new Error("the invitation carries no key commitment");let i=this._sbq2State();return i.remoteDescriptor=e,i.remoteCommitment=r.commitment,r}async _runSbq2KeyExchange(){let e=this._sbq2State();if(!(e.completed||e.blobSent)){if(e.startedAt=Date.now(),!e.localBlob||!e.localDescriptor||!e.remoteDescriptor||!e.remoteCommitment){this._sbq2Abort("incomplete_state","The secure handshake could not start because the connection setup is incomplete. Please start a new invitation.");return}e.timer=setTimeout(()=>{e.completed||this._sbq2Abort("timeout","The other side did not complete the secure handshake in time. Please try connecting again.")},s.SBQ2_KEY_EXCHANGE_TIMEOUT_MS);try{this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_BLOB,v:2,blob:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(e.localBlob.buffer.slice(e.localBlob.byteOffset,e.localBlob.byteOffset+e.localBlob.byteLength))})),e.blobSent=!0,this._secureLog("info","SBQ2 key blob sent",{bytes:e.localBlob.length})}catch{this._sbq2Abort("blob_send_failed","The secure handshake could not be sent. Please try connecting again.")}}}async _sbq2HandleHandshakeFrame(e){let t=s.MESSAGE_TYPES,r=this._sbq2State();if(!this._isSbq2()){this._secureLog("error","Rejected SBQ2 handshake frame on a non-SBQ2 session",{messageType:e?.type});return}try{if(e.type===t.KEY_BLOB){if(r.remoteBlob){this._sbq2Abort("duplicate_blob","The secure handshake was sent twice. The connection has been closed for safety.");return}let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.blob||"")));await Mn(crypto.subtle,i,r.remoteCommitment);let n=kn(i),a=r.role===ve.OFFER?ve.ANSWER:ve.OFFER;if(n.role!==a){this._sbq2Abort("role_mismatch","The other side sent the wrong kind of handshake. The connection has been closed for safety.");return}r.remoteBlob=i,r.peerEcdhKey=await crypto.subtle.importKey("spki",n.ecdhSpki,{name:"ECDH",namedCurve:"P-384"},!1,[]),r.peerEcdsaKey=await crypto.subtle.importKey("spki",n.ecdsaSpki,{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),await this._sbq2CompleteExchange();return}if(e.type===t.KEY_PROOF){let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.sig||"")));if(!r.transcript||!r.peerEcdsaKey){r.pendingProof=i;return}await this._sbq2VerifyProof(i);return}}catch(i){let n=i?.code||"handshake_failed",a=n==="commitment_mismatch"?"The key material does not match the invitation you scanned. This can mean someone tampered with the connection, so it has been closed.":"The secure handshake failed. The connection has been closed for safety.";this._sbq2Abort(n,a)}}async _sbq2CompleteExchange(){let e=this._sbq2State();if(e.keysDerived||!e.remoteBlob||!e.localBlob)return;this._peerSupportsRatchet=!0;let t=e.role===ve.OFFER;e.transcript=An({offerDescriptor:t?e.localDescriptor:e.remoteDescriptor,answerDescriptor:t?e.remoteDescriptor:e.localDescriptor,offerBlob:t?e.localBlob:e.remoteBlob,answerBlob:t?e.remoteBlob:e.localBlob}),this.sessionSalt=await xn(crypto.subtle,e.transcript),this.peerPublicKey=e.peerEcdhKey,this.peerECDHPublicKey=e.peerEcdhKey;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,e.peerEcdhKey,this.sessionSalt);await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),await this._initializeRatchet(r,t),e.keysDerived=!0;let i=new Uint8Array(await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},this.ecdsaKeyPair.privateKey,Vr(e.transcript)));if(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_PROOF,sig:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(i.buffer)})),e.proofSent=!0,e.pendingProof){let n=e.pendingProof;e.pendingProof=null,await this._sbq2VerifyProof(n)}}async _sbq2VerifyProof(e){let t=this._sbq2State();if(t.proofVerified)return;if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},t.peerEcdsaKey,e,Vr(t.transcript))){this._sbq2Abort("bad_proof","The other side could not prove it owns its identity key. The connection has been closed for safety.");return}t.proofVerified=!0,this.verificationCode=await Rn(crypto.subtle,{ecdhPrivateKey:this.ecdhKeyPair.privateKey,peerEcdhPublicKey:t.peerEcdhKey,transcript:t.transcript});let i=this.expectedDTLSFingerprint,n=this._peerDTLSFingerprint;i&&n&&this._setSASMaterialReady(i,n),t.completed=!0,t.timer&&(clearTimeout(t.timer),t.timer=null),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this._secureLog("info","SBQ2 in-band key exchange complete",{elapsedMs:Date.now()-t.startedAt,ratchetActive:this.isRatchetActive?.()===!0});try{this.onKeyExchange?.(this.keyFingerprint)}catch{}this._notifyVerificationReadyIfPossible(),this.initiateVerification()}_decodeKeyFingerprint(e){try{if(!e||typeof e!="string")throw new Error("Invalid hex string provided");return window.EnhancedSecureCryptoUtils.hexToUint8Array(e)}catch(t){throw this._secureLog("error","Key fingerprint decoding failed",{error:t.message,inputType:typeof e,inputLength:e?.length||0}),new Error(`Key fingerprint decoding failed: ${t.message}`)}}_emergencyWipeOnFingerprintMismatch(e="DTLS fingerprint mismatch"){try{this._secureLog("error","\u{1F6A8} EMERGENCY: Initiating security wipe due to fingerprint mismatch",{reason:e,timestamp:Date.now()}),this._secureWipeKeys(),this._secureWipeMemory(this.encryptionKey,"emergency_wipe"),this._secureWipeMemory(this.macKey,"emergency_wipe"),this._secureWipeMemory(this.metadataKey,"emergency_wipe"),this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this.isVerified=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.disconnect(),this.deliverMessageToUI("\u{1F6A8} SECURITY BREACH: Connection terminated due to fingerprint mismatch. Possible MITM attack detected!","system")}catch(t){this._secureLog("error","Failed to perform emergency wipe",{error:t.message})}}getCurrentDTLSFingerprint(){try{if(!this.expectedDTLSFingerprint)throw new Error("No DTLS fingerprint available - connection not established");return this.expectedDTLSFingerprint}catch(e){throw this._secureLog("error","Failed to get current DTLS fingerprint",{error:e.message}),e}}disableStrictDTLSValidation(){this.strictDTLSValidation=!1,this._secureLog("warn","\u26A0\uFE0F Strict DTLS validation disabled - security reduced",{timestamp:Date.now()}),this.deliverMessageToUI("\u26A0\uFE0F DTLS validation disabled for debugging","system")}enableStrictDTLSValidation(){this.strictDTLSValidation=!0,this._secureLog("info","\u2705 Strict DTLS validation re-enabled",{timestamp:Date.now()}),this.deliverMessageToUI("\u2705 DTLS validation re-enabled","system")}async _initializeRatchet(e,t){let r=e?.ratchetRoot;if(!r)return!1;if(!this._peerSupportsRatchet)return this._secureLog("warn","Peer did not advertise Double Ratchet \u2014 falling back to static session keys",{localVersion:s.RATCHET_VERSION}),window.EnhancedSecureCryptoUtils.zeroizeBuffer(r),!1;try{let i=this.peerPublicKey||this.peerECDHPublicKey;if(!i||!this.ecdhKeyPair?.privateKey)throw new Error("handshake ECDH keys unavailable");let n=new zt;return await n.init({sharedSecret:r,sessionSalt:new Uint8Array(this.sessionSalt||[]),selfPrivateKey:this.ecdhKeyPair.privateKey,remotePublicKey:i,isInitiator:t}),this._ratchet=n,this.securityFeatures.hasPFS=!0,this._secureLog("info","\u{1F510} Double Ratchet active \u2014 per-message forward secrecy enabled",{role:t?"initiator":"responder"}),!0}catch(i){return this._ratchet=null,this.securityFeatures.hasPFS=!1,this._secureLog("error","Double Ratchet initialisation failed \u2014 continuing with static session keys",{errorType:i?.constructor?.name||"Unknown"}),!1}finally{window.EnhancedSecureCryptoUtils.zeroizeBuffer(r)}}isRatchetActive(){return!!this._ratchet?.isInitialised}async _generateEphemeralECDHKeys(){try{this._secureLog("info","\u{1F511} Generating ephemeral ECDH keys for PFS",{sessionStartTime:this.sessionStartTime,timestamp:Date.now()});let e=await window.EnhancedSecureCryptoUtils.generateECDHKeyPair();if(!e||!this._validateKeyPairConstantTime(e))throw new Error("Ephemeral ECDH key pair validation failed");let t=this.currentSession?.sessionId||`session_${Date.now()}`;return this.ephemeralKeyPairs.set(t,{keyPair:e,timestamp:Date.now(),sessionId:t}),this._secureLog("info","\u2705 Ephemeral ECDH keys generated for PFS",{timestamp:Date.now()}),e}catch(e){throw this._secureLog("error","\u274C Failed to generate ephemeral ECDH keys",{error:e.message}),new Error(`Ephemeral key generation failed: ${e.message}`)}}async _hardWipeOldKeys(){try{this._secureLog("info","\u{1F9F9} Performing hard wipe of old keys for PFS",{oldKeysCount:this.oldKeys.size,timestamp:Date.now()});for(let[e,t]of this.oldKeys.entries())t.encryptionKey&&this._secureWipeMemory(t.encryptionKey,"pfs_key_wipe"),t.macKey&&this._secureWipeMemory(t.macKey,"pfs_key_wipe"),t.metadataKey&&this._secureWipeMemory(t.metadataKey,"pfs_key_wipe"),t.encryptionKey=null,t.macKey=null,t.metadataKey=null,t.keyFingerprint=null;this.oldKeys.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Hard wipe of old keys completed for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to perform hard wipe of old keys",{error:e.message})}}async _wipeEphemeralKeys(){try{this._secureLog("info","\u{1F9F9} Wiping ephemeral keys for PFS",{ephemeralKeysCount:this.ephemeralKeyPairs.size,timestamp:Date.now()});for(let[e,t]of this.ephemeralKeyPairs.entries())t.keyPair?.privateKey&&this._secureWipeMemory(t.keyPair.privateKey,"ephemeral_key_wipe"),t.keyPair?.publicKey&&this._secureWipeMemory(t.keyPair.publicKey,"ephemeral_key_wipe"),t.keyPair=null,t.timestamp=null,t.sessionId=null;this.ephemeralKeyPairs.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Ephemeral keys wiped for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to wipe ephemeral keys",{error:e.message})}}async _encryptFileMessage(e,t){try{if(!this.encryptionKey)throw new Error("No encryption key available for file message");let r=typeof e=="string"?e:JSON.stringify(e),n={type:"encrypted_file_message",encryptedData:await window.EnhancedSecureCryptoUtils.encryptDataWithAAD(r,this.encryptionKey,t),aad:t,timestamp:Date.now(),keyFingerprint:this.keyFingerprint};return JSON.stringify(n)}catch(r){throw this._secureLog("error","Failed to encrypt file message",{error:r.message}),new Error(`File message encryption failed: ${r.message}`)}}async _decryptFileMessage(e){try{let t=JSON.parse(e);if(t.type!=="encrypted_file_message")throw new Error("Invalid encrypted file message type");if(t.keyFingerprint!==this.keyFingerprint)throw new Error("Key fingerprint mismatch in encrypted file message");let r=this._validateMessageAAD(t.aad,"file_message");if(!this.encryptionKey)throw new Error("No encryption key available for file message decryption");return{decryptedData:await window.EnhancedSecureCryptoUtils.decryptDataWithAAD(t.encryptedData,this.encryptionKey,t.aad),aad:r}}catch(t){throw this._secureLog("error","Failed to decrypt file message",{error:t.message}),new Error(`File message decryption failed: ${t.message}`)}}_validateEncryptionKeys(e=!0){let t=!!(this.encryptionKey&&this.macKey&&this.metadataKey);if(!t&&e)throw new Error("Encryption keys not initialized");return t}async _tryReinitializeEncryptionKeys(){try{if(this.encryptionKey&&this.macKey&&this.metadataKey)return!0;let e=!!(this.ecdhKeyPair?.privateKey&&(this.peerPublicKey||this.peerECDHPublicKey)),t=this.peerPublicKey||this.peerECDHPublicKey;if(!e||!t||!this.sessionSalt)return!1;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,t,this.sessionSalt);return await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),!!(this.encryptionKey&&this.macKey&&this.metadataKey)}catch(e){return this._secureLog("error","Failed to reinitialize encryption keys",{error:e.message}),!1}}_isFileMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type&&t.type.startsWith("file_")}catch{return!1}return typeof e=="object"&&e.type?e.type.startsWith("file_"):!1}_isSystemMessage(e){let t=[s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.SECURITY_UPGRADE,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY];if(typeof e=="string")try{let r=JSON.parse(e);return t.includes(r.type)}catch{return!1}return typeof e=="object"&&e.type?t.includes(e.type):!1}_isFakeMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type===s.MESSAGE_TYPES.FAKE||t.isFakeTraffic===!0}catch{return!1}return typeof e=="object"&&e!==null?e.type===s.MESSAGE_TYPES.FAKE||e.isFakeTraffic===!0:!1}_withErrorHandling(e,t,r=null){try{return e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}async _withAsyncErrorHandling(e,t,r=null){try{return await e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}_getMessageType(e){if(typeof e=="string")try{return JSON.parse(e).type||null}catch{return null}return typeof e=="object"&&e!==null&&e.type||null}_resetNotificationFlags(){this.lastSecurityLevelNotification=null,this.verificationNotificationSent=!1,this.verificationInitiationSent=!1,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.disconnectNotificationSent=!1,this.reconnectionFailedNotificationSent=!1,this.peerDisconnectNotificationSent=!1,this.connectionClosedNotificationSent=!1,this.fakeTrafficDisabledNotificationSent=!1,this.advancedFeaturesDisabledNotificationSent=!1,this.securityUpgradeNotificationSent=!1,this.lastSecurityUpgradeStage=null,this.securityCalculationNotificationSent=!1,this.lastSecurityCalculationLevel=null}_isFilteredMessage(e){return Object.values(s.FILTERED_RESULTS).includes(e)}_cleanupLogs(){this._logCounts.size>500&&(this._logCounts.clear(),this._secureLog("debug","\u{1F9F9} Log counts cleared due to size limit"));let e=Date.now(),t=3e5,r=0;for(let[i,n]of this._logCounts.entries())n>10&&r++;r>20&&(this._logCounts.clear(),this._secureLog("warn","\u{1F6A8} Emergency log cleanup due to suspicious patterns")),this._logSecurityViolations>0&&r<5&&(this._logSecurityViolations=Math.max(0,this._logSecurityViolations-1)),(!this._lastIVCleanupTime||Date.now()-this._lastIVCleanupTime>3e5)&&(this._cleanupOldIVs(),this._lastIVCleanupTime=Date.now()),(!this._secureMemoryManager.memoryStats.lastCleanup||Date.now()-this._secureMemoryManager.memoryStats.lastCleanup>6e5)&&(this._performPeriodicMemoryCleanup().catch(i=>{this._secureLog("error","Periodic cleanup failed",{errorType:i?.constructor?.name||"Unknown"})}),this._secureMemoryManager.memoryStats.lastCleanup=Date.now())}_getLoggingStats(){let e={isProductionMode:this._isProductionMode,debugMode:this._debugMode,currentLogLevel:this._currentLogLevel,logCountsSize:this._logCounts.size,maxLogCount:this._maxLogCount,securityViolations:this._logSecurityViolations||0,maxSecurityViolations:this._maxLogSecurityViolations||3,systemStatus:this._currentLogLevel===-1?"DISABLED":"ACTIVE"},t={};for(let[r,i]of Object.entries(e))typeof i=="string"&&this._containsSensitiveContent(i)?t[r]="[SENSITIVE_DATA_REDACTED]":t[r]=i;return t}async _emergencyDisableLogging(){this._currentLogLevel=-1,this._logCounts.clear(),this._logSecurityViolations&&(this._logSecurityViolations=0),this._secureLog=()=>{arguments[0]==="error"&&this._originalConsole?.error&&this._originalConsole.error("\u{1F6A8} SECURITY: Logging system disabled - potential data exposure prevented")},this._originalSanitizeString=this._sanitizeString,this._originalSanitizeLogData=this._sanitizeLogData,this._originalAuditLogMessage=this._auditLogMessage,this._originalContainsSensitiveContent=this._containsSensitiveContent,this._sanitizeString=()=>"[LOGGING_DISABLED]",this._sanitizeLogData=()=>({error:"LOGGING_DISABLED"}),this._auditLogMessage=()=>!1,this._containsSensitiveContent=()=>!0,await this._performNaturalCleanup(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Secure logging system disabled due to potential data exposure")}_resetLoggingSystem(){this._secureLog("info","\u{1F527} Resetting logging system after emergency shutdown"),this._sanitizeString=this._originalSanitizeString||(e=>e),this._sanitizeLogData=this._originalSanitizeLogData||(e=>e),this._auditLogMessage=this._originalAuditLogMessage||(()=>!0),this._containsSensitiveContent=this._originalContainsSensitiveContent||(()=>!1),this._logSecurityViolations=0,this._secureLog("info","\u2705 Logging system reset successfully")}_auditLogMessage(e,t){if(!t||typeof t!="object")return!0;let r=JSON.stringify(t);if(this._containsSensitiveContent(e))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log message"),!1;if(this._containsSensitiveContent(r))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log data"),!1;let i=["secret","token","password","credential","auth","fingerprint","salt","signature","private_key","api_key","private","encryption","mac","metadata","session","jwt","bearer","key","hash","digest","nonce","iv","cipher"],n=r.toLowerCase();for(let a of i)if(n.includes(a)&&!this._safeFieldsWhitelist.has(a))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: Dangerous pattern detected in log: ${a}`),!1;for(let[a,o]of Object.entries(t))if(typeof o=="string"&&this._hasHighEntropy(o))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: High entropy value detected in log field: ${a}`),!1;return!0}initializeFileTransfer(){try{if(this._sessionAlive===!1)return;if(this._secureLog("info","\u{1F527} Initializing Enhanced Secure File Transfer system..."),this.fileTransferSystem){this._secureLog("info","\u2705 File transfer system already initialized");return}if(!!!(this.dataChannel&&this.dataChannel.readyState==="open")){if(this._secureLog("warn","\u26A0\uFE0F Data channel not open, deferring file transfer initialization"),this.dataChannel){let i=()=>{this._secureLog("info","\u{1F504} DataChannel opened, initializing file transfer..."),this.initializeFileTransfer()};this.dataChannel.addEventListener("open",i,{once:!0})}return}if(!this.isVerified){this._secureLog("warn","\u26A0\uFE0F Connection not verified yet, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(500);return}if(this.fileTransferSystem&&(this._secureLog("info","\u{1F9F9} Cleaning up existing file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),!this.encryptionKey||!this.macKey){this._secureLog("warn","\u26A0\uFE0F Encryption keys not ready, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(1e3);return}let t=i=>{try{this._secureLog("info","\u{1F3C1} Sender transfer summary",{summary:i}),this.onFileProgress&&this.onFileProgress({type:"complete",...i})}catch(n){this._secureLog("warn","\u26A0\uFE0F onComplete handler failed:",{details:n.message})}};this.fileTransferSystem=new je(this,this.onFileProgress||null,t,this.onFileError||null,this.onFileReceived||null,this.onIncomingFileRequest||null),this._fileTransferActive=!0,this._secureLog("info","\u2705 Enhanced Secure File Transfer system initialized successfully");let r=this.fileTransferSystem.getSystemStatus();this._secureLog("info","\u{1F50D} File transfer system status after init",{status:r})}catch(e){this._secureLog("error","\u274C Failed to initialize file transfer system",{errorType:e.constructor.name}),this.fileTransferSystem=null,this._fileTransferActive=!1}}_scheduleFileTransferInitRetry(e){if(this._sessionAlive===!1)return null;this._fileTransferInitRetryTimers||(this._fileTransferInitRetryTimers=new Set);let t=this._trackActiveTimer(setTimeout(()=>{this._fileTransferInitRetryTimers.delete(t),this._untrackActiveTimer(t),this._sessionAlive!==!1&&this.initializeFileTransfer()},e));return this._fileTransferInitRetryTimers.add(t),t}async initializeEnhancedSecurity(){try{await this.generateNestedEncryptionKey(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration()}catch(e){this._secureLog("error","\u274C Failed to initialize enhanced security",{errorType:e.constructor.name})}}getSafeRandomInt(e,t){if(!Number.isInteger(e)||!Number.isInteger(t))throw new Error("getSafeRandomInt requires integer min and max");if(e>=t)throw new Error("min must be less than max");let r=t-e+1,i=Math.ceil(Math.log2(r)),n=Math.ceil(i/8),a=(1<=r);return e+o}getSafeRandomFloat(e,t,r=1e3){if(typeof e!="number"||typeof t!="number")throw new Error("getSafeRandomFloat requires numeric min and max");if(e>=t)throw new Error("minFloat must be less than maxFloat");let i=this.getSafeRandomInt(0,r),n=(t-e)/r;return e+i*n}generateFingerprintMask(){return{timingOffset:this.getSafeRandomInt(0,1500),sizeVariation:this.getSafeRandomFloat(.75,1.25,1e3),noisePattern:Array.from(crypto.getRandomValues(new Uint8Array(64))),headerVariations:["X-Client-Version","X-Session-ID","X-Request-ID","X-Timestamp","X-Signature","X-Secure","X-Encrypted","X-Protected","X-Safe","X-Anonymous","X-Private"],noiseIntensity:this.getSafeRandomInt(50,150),sizeMultiplier:this.getSafeRandomFloat(.75,1.25,1e3),timingVariation:this.getSafeRandomInt(100,1100)}}configureSecurityForSession(){this._secureLog("info","\u{1F527} Configuring security - all features enabled by default"),this.sessionConstraints={},Object.keys(this.securityFeatures).forEach(e=>{this.sessionConstraints[e]=!0}),this.applySessionConstraints(),this._secureLog("info","\u2705 Security configured - all features enabled",{constraints:this.sessionConstraints}),this._validateCryptographicSecurity()||(this._secureLog("error","\u{1F6A8} CRITICAL: Cryptographic security validation failed after session configuration"),this.onStatusChange&&this.onStatusChange("security_breach",{type:"crypto_security_failure",message:"Cryptographic security validation failed after session configuration"})),this.notifySecurityLevel(),setTimeout(()=>{this.calculateAndReportSecurityLevel()},s.TIMEOUTS.SECURITY_CALC_DELAY)}applySessionConstraints(){this.sessionConstraints&&(Object.keys(this.sessionConstraints).forEach(e=>{switch(this.securityFeatures[e]=!0,e){case"hasFakeTraffic":this.fakeTrafficConfig.enabled=!0,this.isConnected()&&this.startFakeTrafficGeneration();break;case"hasDecoyChannels":this.decoyChannelConfig.enabled=!0,this.isConnected()&&this.initializeDecoyChannels();break;case"hasPacketReordering":this.reorderingConfig.enabled=!0;break;case"hasAntiFingerprinting":this.antiFingerprintingConfig.enabled=!0;break;case"hasMessageChunking":this.chunkingConfig.enabled=!0;break}}),this._secureLog("info","\u2705 All security features enabled by default",{constraints:this.sessionConstraints,currentFeatures:this.securityFeatures}))}_sanitizeIncomingChatMessage(e){return typeof e!="string"?e:window.EnhancedSecureCryptoUtils.sanitizeMessage(e)}deliverMessageToUI(e,t="received",r=null){try{if(this._secureLog("debug","\u{1F4E4} deliverMessageToUI called",{message:e,type:t,messageType:typeof e,hasOnMessage:!!this.onMessage}),typeof e=="object"&&e.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(e.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI: ${e.type}`);return}if(typeof e=="string"&&e.trim().startsWith("{"))try{let n=JSON.parse(e);if(n.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(n.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI (string): ${n.type}`);return}}catch{}let i=t==="received"?this._sanitizeIncomingChatMessage(e):e;if(this.onMessage){let n=r&&typeof this._sanitizeMessageMeta=="function"?this._sanitizeMessageMeta(r):null;this._secureLog("debug","\u{1F4E4} Calling this.onMessage callback",{message:i,type:t}),this.onMessage(i,t,n||void 0)}else this._secureLog("warn","\u26A0\uFE0F this.onMessage callback is null or undefined")}catch(i){this._secureLog("error","\u274C Failed to deliver message to UI:",{errorType:i?.constructor?.name||"Unknown"})}}notifySecurityLevel(){if(this.lastSecurityLevelNotification==="maximum")return;if(this.lastSecurityLevelNotification="maximum",this.onMessage&&this.deliverMessageToUI("\u{1F6E1}\uFE0F Maximum Security Active - All features enabled","system"),this.onMessage){let t=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r.replace("has","").replace(/([A-Z])/g," $1").trim().toLowerCase()).slice(0,5);this.deliverMessageToUI(`\u{1F527} Active: ${t.join(", ")}...`,"system")}}cleanupDecoyChannels(){for(let[e,t]of this.decoyTimers.entries())clearTimeout(t);this.decoyTimers.clear();for(let[e,t]of this.decoyChannels.entries())t.readyState==="open"&&t.close();this.decoyChannels.clear(),this._secureLog("info","\u{1F9F9} Decoy channels cleaned up")}async generateNestedEncryptionKey(){try{this.nestedEncryptionKey=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(e){throw this._secureLog("error","\u274C Failed to generate nested encryption key:",{errorType:e?.constructor?.name||"Unknown"}),e}}async applyNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;try{let t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"nestedEncryption"),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this.nestedEncryptionKey,e),i=new Uint8Array(s.SIZES.NESTED_ENCRYPTION_IV_SIZE+r.byteLength);return i.set(t,0),i.set(new Uint8Array(r),s.SIZES.NESTED_ENCRYPTION_IV_SIZE),this._secureLog("debug","\u2705 Nested encryption applied with secure IV",{ivSize:t.length,dataSize:e.byteLength,encryptedSize:r.byteLength}),i.buffer}catch(t){return this._secureLog("error","\u274C Nested encryption failed:",{errorType:t?.constructor?.name||"Unknown",errorMessage:t?.message||"Unknown error"}),t.message.includes("emergency mode")&&(this.securityFeatures.hasNestedEncryption=!1,this._secureLog("warn","\u26A0\uFE0F Nested encryption disabled due to IV emergency mode")),e}}async removeNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;if(!(e instanceof ArrayBuffer)||e.byteLengtht.length-4?(this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid packet padding size, skipping removal"),e):t.slice(4,4+i).buffer}catch(t){return this._debugMode&&this._secureLog("error","\u274C Packet padding removal failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}startFakeTrafficGeneration(){if(!this.fakeTrafficConfig.enabled||!this.isConnected())return;if(this.fakeTrafficTimer){this._secureLog("warn","\u26A0\uFE0F Fake traffic generation already running");return}let e=async()=>{if(!this.isConnected()){this.stopFakeTrafficGeneration();return}try{let n=this.generateFakeMessage();await this.sendFakeMessage(n);let a=this.fakeTrafficConfig.randomDecoyIntervals?this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minInterval,Math.min(this.fakeTrafficConfig.maxInterval,6e4)):this.fakeTrafficConfig.minInterval,o=Math.max(a,s.TIMEOUTS.FAKE_TRAFFIC_MIN_INTERVAL);this.fakeTrafficTimer=setTimeout(e,o)}catch(n){this._debugMode&&this._secureLog("error","\u274C Fake traffic generation failed:",{errorType:n?.constructor?.name||"Unknown"}),this.stopFakeTrafficGeneration()}},t=s.TIMEOUTS.DECOY_INITIAL_DELAY,r=Math.min(this.fakeTrafficConfig.maxInterval,3e4),i=this.getUnbiasedRandomInRange(t,r);this.fakeTrafficTimer=setTimeout(e,i)}stopFakeTrafficGeneration(){this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null)}generateFakeMessage(){let e=this.getUnbiasedRandomInRange(0,this.fakeTrafficConfig.patterns.length-1),t=this.fakeTrafficConfig.patterns[e],r=this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minSize,this.fakeTrafficConfig.maxSize),i=crypto.getRandomValues(new Uint8Array(r));return{type:s.MESSAGE_TYPES.FAKE,pattern:t,data:Array.from(i).map(n=>n.toString(16).padStart(2,"0")).join(""),timestamp:Date.now(),size:r,isFakeTraffic:!0,source:"fake_traffic_generator",fakeId:crypto.getRandomValues(new Uint32Array(1))[0].toString(36)}}emergencyDisableAdvancedFeatures(){this._secureLog("error","\u{1F6A8} Emergency disabling advanced security features due to errors"),this.securityFeatures.hasNestedEncryption=!1,this.securityFeatures.hasPacketReordering=!1,this.securityFeatures.hasAntiFingerprinting=!1,this.reorderingConfig.enabled=!1,this.antiFingerprintingConfig.enabled=!1,this.packetBuffer.clear(),this.emergencyDisableFakeTraffic(),this._secureLog("info","\u2705 Advanced features disabled, keeping basic encryption"),this.advancedFeaturesDisabledNotificationSent||(this.advancedFeaturesDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Advanced security features temporarily disabled due to compatibility issues","system"))}async sendFakeMessage(e){if(this._validateConnection(!1))try{this._secureLog("debug","\u{1F3AD} Sending fake message",{hasPattern:!!e.pattern,sizeRange:e.size>100?"large":"small"});let t=JSON.stringify({...e,type:s.MESSAGE_TYPES.FAKE,isFakeTraffic:!0,timestamp:Date.now()}),r=new TextEncoder().encode(t),i=await this.applySecurityLayers(r,!0);this.dataChannel.send(i),this._secureLog("debug","\u{1F3AD} Fake message sent successfully",{pattern:e.pattern})}catch(t){this._secureLog("error","\u274C Failed to send fake message",{error:t.message})}}checkFakeTrafficStatus(){let e={fakeTrafficEnabled:this.securityFeatures.hasFakeTraffic,fakeTrafficConfigEnabled:this.fakeTrafficConfig.enabled,timerActive:!!this.fakeTrafficTimer,patterns:this.fakeTrafficConfig.patterns,intervals:{min:this.fakeTrafficConfig.minInterval,max:this.fakeTrafficConfig.maxInterval}};return this._debugMode&&this._secureLog("info","\u{1F3AD} Fake Traffic Status",{status:e}),e}emergencyDisableFakeTraffic(){this._debugMode&&this._secureLog("error","\u{1F6A8} Emergency disabling fake traffic"),this.securityFeatures.hasFakeTraffic=!1,this.fakeTrafficConfig.enabled=!1,this.stopFakeTrafficGeneration(),this._debugMode&&this._secureLog("info","\u2705 Fake traffic disabled"),this.fakeTrafficDisabledNotificationSent||(this.fakeTrafficDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Fake traffic emergency disabled","system"))}async _applySecurityLayersWithoutMutex(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayersWithoutMutex:",{errorType:r?.constructor?.name||"Unknown"}),e}}async processChunkedMessage(e){try{if(!this.chunkingConfig.addChunkHeaders)return this.processMessage(e);let t=new Uint8Array(e);if(t.length<16)return this.processMessage(e);let r=new DataView(t.buffer,0,16),i=r.getUint32(0,!1),n=r.getUint32(4,!1),a=r.getUint32(8,!1),o=r.getUint32(12,!1),c=t.slice(16,16+o);this.chunkQueue[i]||(this.chunkQueue[i]={chunks:new Array(a),received:0,timestamp:Date.now()});let d=this.chunkQueue[i];if(d.chunks[n]=c,d.received++,this._secureLog("debug",`\u{1F4E6} Received chunk ${n+1}/${a} for message ${i}`),d.received===a){let h=d.chunks.reduce((y,b)=>y+b.length,0),u=new Uint8Array(h),m=0;for(let y of d.chunks)u.set(y,m),m+=y.length;await this.processMessage(u.buffer),delete this.chunkQueue[i],this._secureLog("info",`\u{1F4E6} Chunked message ${i} reassembled and processed`)}}catch(t){this._secureLog("error","\u274C Chunked message processing failed:",{errorType:t?.constructor?.name||"Unknown"})}}initializeDecoyChannels(){if(!(!this.decoyChannelConfig.enabled||!this.peerConnection)){if(this.decoyChannels.size>0){this._secureLog("warn","\u26A0\uFE0F Decoy channels already initialized, skipping...");return}try{let e=Math.min(this.decoyChannelConfig.maxDecoyChannels,this.decoyChannelConfig.decoyChannelNames.length);for(let t=0;t.5,maxRetransmits:Math.floor(Math.random()*3)});this.setupDecoyChannel(i,r),this.decoyChannels.set(r,i)}this._debugMode&&this._secureLog("info",`\u{1F3AD} Initialized ${e} decoy channels`)}catch(e){this._debugMode&&this._secureLog("error","\u274C Failed to initialize decoy channels:",{errorType:e?.constructor?.name||"Unknown"})}}}setupDecoyChannel(e,t){e.onopen=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" opened`),this.startDecoyTraffic(e,t)},e.onmessage=r=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Received decoy message on "${t}": ${r.data?.length||"undefined"} bytes`)},e.onclose=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" closed`),this.stopDecoyTraffic(t)},e.onerror=r=>{this._debugMode&&this._secureLog("error",`\u274C Decoy channel "${t}" error`,{error:r.message})}}startDecoyTraffic(e,t){let r=async()=>{if(e.readyState==="open")try{let n=this.generateDecoyData(t);e.send(n);let a=this.decoyChannelConfig.randomDecoyIntervals?Math.random()*15e3+1e4:2e4;this.decoyTimers.set(t,setTimeout(()=>r(),a))}catch(n){this._debugMode&&this._secureLog("error",`\u274C Failed to send decoy data on "${t}"`,{error:n.message})}},i=Math.random()*1e4+5e3;this.decoyTimers.set(t,setTimeout(()=>r(),i))}stopDecoyTraffic(e){let t=this.decoyTimers.get(e);t&&(clearTimeout(t),this.decoyTimers.delete(e))}generateDecoyData(e){let t={sync:()=>JSON.stringify({type:"sync",timestamp:Date.now(),sequence:Math.floor(Math.random()*1e3),data:Array.from(crypto.getRandomValues(new Uint8Array(32))).map(r=>r.toString(16).padStart(2,"0")).join("")}),status:()=>JSON.stringify({type:"status",status:["online","away","busy"][Math.floor(Math.random()*3)],uptime:Math.floor(Math.random()*3600),data:Array.from(crypto.getRandomValues(new Uint8Array(16))).map(r=>r.toString(16).padStart(2,"0")).join("")}),heartbeat:()=>JSON.stringify({type:"heartbeat",timestamp:Date.now(),data:Array.from(crypto.getRandomValues(new Uint8Array(24))).map(r=>r.toString(16).padStart(2,"0")).join("")}),metrics:()=>JSON.stringify({type:"metrics",cpu:Math.random()*100,memory:Math.random()*100,network:Math.random()*1e3,data:Array.from(crypto.getRandomValues(new Uint8Array(20))).map(r=>r.toString(16).padStart(2,"0")).join("")}),debug:()=>JSON.stringify({type:"debug",level:["info","warn","error"][Math.floor(Math.random()*3)],message:"Debug message",data:Array.from(crypto.getRandomValues(new Uint8Array(28))).map(r=>r.toString(16).padStart(2,"0")).join("")})};return t[e]?t[e]():Array.from(crypto.getRandomValues(new Uint8Array(64))).map(r=>r.toString(16).padStart(2,"0")).join("")}addReorderingHeaders(e){if(!this.reorderingConfig.enabled)return e;try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8,i=new ArrayBuffer(r),n=new DataView(i);this.reorderingConfig.useSequenceNumbers&&n.setUint32(0,this.sequenceNumber++,!1),this.reorderingConfig.useTimestamps&&n.setUint32(4,Date.now(),!1),n.setUint32(this.reorderingConfig.useTimestamps?8:4,t.length,!1);let a=new Uint8Array(r+t.length);return a.set(new Uint8Array(i),0),a.set(t,r),a.buffer}catch(t){return this._secureLog("error","\u274C Failed to add reordering headers:",{errorType:t?.constructor?.name||"Unknown"}),e}}async processReorderedPacket(e){if(!this.reorderingConfig.enabled)return this.processMessage(e);try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8;if(t.lengtht.length-r||o<=0)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid reordered packet data size, processing directly"),this.processMessage(e);let c=t.slice(r,r+o);try{let d=new TextDecoder().decode(c),h=JSON.parse(d);if(h.type==="fake"||h.isFakeTraffic===!0){this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Reordered fake message: ${h.pattern||"unknown"}`);return}}catch{}this.packetBuffer.set(n,{data:c.buffer,timestamp:a||Date.now()}),await this.processOrderedPackets()}catch(t){return this._secureLog("error","\u274C Failed to process reordered packet:",{errorType:t?.constructor?.name||"Unknown"}),this.processMessage(e)}}async processOrderedPackets(){let e=Date.now(),t=this.reorderingConfig.reorderTimeout;for(;;){let r=this.lastProcessedSequence+1,i=this.packetBuffer.get(r);if(i){try{let n=new TextDecoder().decode(i.data),a=JSON.parse(n);if(a.type==="fake"||a.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Ordered fake message: ${a.pattern||"unknown"}`),this.packetBuffer.delete(r),this.lastProcessedSequence=r;continue}}catch{}await this.processMessage(i.data),this.packetBuffer.delete(r),this.lastProcessedSequence=r}else{let n=this.findOldestPacket();if(n&&e-n.timestamp>t){this._secureLog("warn","\u26A0\uFE0F Packet ${oldestPacket.sequence} timed out, processing out of order");try{let a=new TextDecoder().decode(n.data),o=JSON.parse(a);if(o.type==="fake"||o.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Timed out fake message: ${o.pattern||"unknown"}`),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence;continue}}catch{}await this.processMessage(n.data),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence}else break}}this.cleanupOldPackets(e,t)}findOldestPacket(){let e=null;for(let[t,r]of this.packetBuffer.entries())(!e||r.timestampt&&(this._secureLog("warn","\u26A0\uFE0F \u{1F5D1}\uFE0F Removing timed out packet ${sequence}"),this.packetBuffer.delete(r))}applyAntiFingerprinting(e){if(!this.antiFingerprintingConfig.enabled)return e;try{let t=e;return this.antiFingerprintingConfig.addNoise&&(t=this.addNoise(t)),this.antiFingerprintingConfig.randomizeSizes&&(t=this.randomizeSize(t)),this.antiFingerprintingConfig.maskPatterns&&(t=this.maskPatterns(t)),this.antiFingerprintingConfig.useRandomHeaders&&(t=this.addRandomHeaders(t)),t}catch(t){return this._secureLog("error","\u274C Anti-fingerprinting failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}addNoise(e){let t=new Uint8Array(e),r=this.getUnbiasedRandomInRange(8,40),i=crypto.getRandomValues(new Uint8Array(r)),n=new Uint8Array(t.length+r);return n.set(t,0),n.set(i,t.length),n.buffer}randomizeSize(e){let t=new Uint8Array(e),r=this.fingerprintMask.sizeVariation,i=Math.floor(t.length*r);if(i>t.length){let n=crypto.getRandomValues(new Uint8Array(i-t.length)),a=new Uint8Array(i);return a.set(t,0),a.set(n,t.length),a.buffer}else if(i=256-256%this.fingerprintMask.headerVariations.length);let d=this.fingerprintMask.headerVariations[c%this.fingerprintMask.headerVariations.length],h;do h=crypto.getRandomValues(new Uint8Array(1))[0];while(h>=256-256%16);let u=crypto.getRandomValues(new Uint8Array(h%16+4)),m=new DataView(n.buffer,a);m.setUint32(0,u.length+8,!1),m.setUint32(4,this.hashString(d),!1),n.set(u,a+8);let y=this.calculateChecksum(n.slice(a,a+8+u.length));new DataView(n.buffer,a+8+u.length).setUint32(0,y,!1),a+=8+u.length+4}return n.set(t,a),n.buffer}hashString(e){let t=0;for(let r=0;r50)try{if(/^[A-Za-z0-9+/=]+$/.test(r.trim())&&(this._debugMode&&this._secureLog("debug","\u{1F513} Applying standard decryption..."),r=await window.EnhancedSecureCryptoUtils.decryptData(r,this.encryptionKey),this._debugMode&&this._secureLog("debug","\u2705 Standard decryption successful"),typeof r=="string")){try{let n=JSON.parse(r);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Legacy fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}r=new TextEncoder().encode(r).buffer}}catch(i){return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Standard decryption failed:",{details:i.message}),e}if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&r.byteLength>12)try{if(r=await this.removeNestedEncryption(r),r instanceof ArrayBuffer)try{let i=new TextDecoder().decode(r),n=JSON.parse(i);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Nested fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Nested decryption failed - skipping this layer:",{details:i.message})}if(this.securityFeatures.hasPacketReordering&&this.reorderingConfig.enabled&&r instanceof ArrayBuffer)try{let i=this.reorderingConfig.useTimestamps?12:8;if(r.byteLength>i)return await this.processReorderedPacket(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Reordering processing failed - using direct processing:",{details:i.message})}if(this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer)try{r=this.removePacketPadding(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Padding removal failed:",{details:i.message})}if(this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer)try{r=this.removeAntiFingerprinting(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Anti-fingerprinting removal failed:",{details:i.message})}if(r instanceof ArrayBuffer&&(r=new TextDecoder().decode(r)),typeof r=="string")try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Final check fake message: ${i.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}return r}catch(t){return this._secureLog("error","\u274C Critical error in removeSecurityLayers:",{errorType:t?.constructor?.name||"Unknown"}),e}}removeAntiFingerprinting(e){return e}async applySecurityLayers(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:r?.constructor?.name||"Unknown"}),e}}_sanitizeMessageMeta(e){if(!e||typeof e!="object")return null;let t={};if(typeof e.mid=="string"&&e.mid.length>0&&e.mid.length<=64&&(t.mid=e.mid.replace(/[^A-Za-z0-9_-]/g,"").slice(0,64)),e.code===!0&&(t.code=!0),e.once===!0&&(t.once=!0),Number.isFinite(e.onceTtl)){let r=Math.floor(e.onceTtl);r>=1&&r<=3600&&(t.onceTtl=r)}if(Number.isFinite(e.ttl)){let r=Math.floor(e.ttl);r>=5&&r<=86400&&(t.ttl=r)}return Object.keys(t).length?t:null}sendMessageDelete(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_DELETE,messageId:e.slice(0,64)})}sendDeliveryReceipt(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_RECEIPT,messageId:e.slice(0,64)})}async sendMessage(e,t=null){let r=this._validateInputData(e,"sendMessage");if(!r.isValid){let i=`Input validation failed: ${r.errors.join(", ")}`;throw this._secureLog("error","\u274C Input validation failed in sendMessage",{errors:r.errors,dataType:typeof e,dataLength:e?.length||e?.byteLength||0}),new Error(i)}if(!this._checkRateLimit("sendMessage"))throw new Error("Rate limit exceeded for message sending");if(this._enforceVerificationGate("sendMessage"),!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not ready");try{if(this.encryptionKey&&this.macKey&&this.metadataKey||await this._tryReinitializeEncryptionKeys(),this._secureLog("debug","sendMessage called",{hasDataChannel:!!this.dataChannel,dataChannelReady:this.dataChannel?.readyState==="open",isInitiator:this.isInitiator,isVerified:this.isVerified,connectionReady:this.peerConnection?.connectionState==="connected"}),this._secureLog("debug","\u{1F50D} sendMessage DEBUG",{dataType:typeof r.sanitizedData,isString:typeof r.sanitizedData=="string",isArrayBuffer:r.sanitizedData instanceof ArrayBuffer,dataLength:r.sanitizedData?.length||r.sanitizedData?.byteLength||0}),typeof r.sanitizedData=="string")try{let n=JSON.parse(r.sanitizedData);if(n.type&&n.type.startsWith("file_")){this._secureLog("debug","\u{1F4C1} File message detected - applying full encryption with AAD",{type:n.type});let a=this._createFileMessageAAD(n.type,n.data),o=await this._encryptFileMessage(r.sanitizedData,a);return this.dataChannel.send(o),!0}}catch{}if(typeof r.sanitizedData=="string"){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available. Manager may not be fully initialized.");let n=this._createMessageAAD("message",{content:r.sanitizedData}),a={type:"message",data:r.sanitizedData,timestamp:Date.now(),aad:n};return t&&typeof t=="object"&&(a.meta=this._sanitizeMessageMeta(t)),await this.sendSecureMessage(a)}this._secureLog("debug","\u{1F510} Applying security layers to non-string data");let i=await this._applySecurityLayersWithLimitedMutex(r.sanitizedData,!1);return this.dataChannel.send(i),!0}catch(i){throw this._secureLog("error","\u274C Failed to send message",{error:i.message,errorType:i.constructor.name}),i}}async _applySecurityLayersWithLimitedMutex(e,t=!1){return this._withMutex("cryptoOperation",async r=>{try{let i=e;return t?(this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&i instanceof ArrayBuffer&&(i=await this.applyNestedEncryption(i)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&i instanceof ArrayBuffer&&(i=this.applyPacketReordering(i)),this.securityFeatures.hasPacketPadding&&i instanceof ArrayBuffer&&(i=this.applyPacketPadding(i)),this.securityFeatures.hasAntiFingerprinting&&i instanceof ArrayBuffer&&(i=this.applyAntiFingerprinting(i)),this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i)}catch(i){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:i?.constructor?.name||"Unknown"}),e}},3e3)}async sendSystemMessage(e){if(e.type==="verification_request"||e.type==="verification_response"||e.type==="verification_required"||this._enforceVerificationGate("sendSystemMessage",!1),!this.dataChannel||this.dataChannel.readyState!=="open")return this._secureLog("warn","\u26A0\uFE0F Cannot send system message - data channel not ready"),!1;try{let r=JSON.stringify({type:e.type,data:e,timestamp:Date.now()});return this._secureLog("debug","\u{1F527} Sending system message",{type:e.type}),this.dataChannel.send(r),!0}catch(r){return this._secureLog("error","\u274C Failed to send system message:",{errorType:r?.constructor?.name||"Unknown"}),!1}}async processMessage(e){try{if(this._noteInboundActivity?.(),this._secureLog("debug","\uFFFD\uFFFD Processing message",{dataType:typeof e,isArrayBuffer:e instanceof ArrayBuffer,hasData:!!(e?.length||e?.byteLength)}),typeof e=="string")try{let i=JSON.parse(e),n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(i.type==="encrypted_file_message"){this._secureLog("debug","\u{1F4C1} Encrypted file message detected in processMessage");try{let{decryptedData:a,aad:o}=await this._decryptFileMessage(e),c=JSON.parse(a);if(this._secureLog("debug","\u{1F4C1} File message decrypted successfully",{type:c.type,aadMessageType:o.messageType}),this.fileTransferSystem&&typeof this.fileTransferSystem.handleFileMessage=="function"){await this.fileTransferSystem.handleFileMessage(c);return}}catch(a){this._secureLog("error","\u274C Failed to decrypt file message",{error:a.message});return}}if(i.type&&n.includes(i.type)){this._secureLog("warn","\u26A0\uFE0F Unencrypted file message detected - this should not happen in secure mode",{type:i.type}),this._secureLog("error","\u274C Dropping unencrypted file message for security",{type:i.type});return}if(i.type==="enhanced_message"){if(this._secureLog("debug","\u{1F510} Enhanced message detected in processMessage"),!this._checkInboundRateLimit("processMessage:enhanced_message"))return;try{let a=await window.EnhancedSecureCryptoUtils.decryptMessage(i.data,this.encryptionKey,this.macKey,this.metadataKey),o=JSON.parse(a.data);if(a.metadata&&a.metadata.sequenceNumber!==void 0&&!this._validateIncomingSequenceNumber(a.metadata.sequenceNumber,"enhanced_message")){this._secureLog("warn","\u26A0\uFE0F Enhanced message sequence number validation failed - possible replay attack",{received:a.metadata.sequenceNumber,expected:this.expectedSequenceNumber});return}o.type==="message"&&this.onMessage&&o.data&&this.deliverMessageToUI(o.data,"received",o.meta);return}catch(a){this._secureLog("error","\u274C Failed to decrypt enhanced message",{error:a.message});return}}if(i.type===s.MESSAGE_TYPES.MESSAGE){this._secureLog("error","Rejected unencrypted frame in processMessage",{messageType:"message"});return}if(i.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(i.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:i.type});return}let a=s.MESSAGE_TYPES;if(i.type===a.MESSAGE_DELETE){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelete?.(o.slice(0,64))}catch{}return}if(i.type===a.MESSAGE_RECEIPT){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelivered?.(o.slice(0,64))}catch{}return}if([a.CALL_OFFER,a.CALL_ANSWER,a.CALL_ICE,a.CALL_DECLINE,a.CALL_END].includes(i.type)){try{await this._handleCallSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C Call signal handling failed",{errorType:o?.constructor?.name})}return}if([a.ICE_RESTART_OFFER,a.ICE_RESTART_ANSWER,a.ICE_RESTART_REQUEST].includes(i.type)){try{await this._handleIceRestartSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:o?.constructor?.name})}return}return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn","\u{1F3AD} Fake message blocked in processMessage",{pattern:i.pattern});return}}catch{this._secureLog("error","Rejected malformed (non-JSON) frame in processMessage",{dataLength:typeof e=="string"?e.length:0});return}let t=await this._processEncryptedDataWithLimitedMutex(e);if(t==="FAKE_MESSAGE_FILTERED"||t==="FILE_MESSAGE_FILTERED"||t==="SYSTEM_MESSAGE_FILTERED")return;if(!t){this._secureLog("warn","\u26A0\uFE0F No data returned from removeSecurityLayers");return}let r;if(typeof t=="string")try{let i=JSON.parse(t);if(i.type&&fileMessageTypes.includes(i.type)){this._secureLog("debug","\u{1F4C1} File message detected after decryption",{type:i.type}),this.fileTransferSystem&&await this.fileTransferSystem.handleFileMessage(i);return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Post-decryption fake message blocked: ${i.pattern}`);return}i.type==="message"&&i.data?r=i.data:r=t}catch{r=t}else if(t instanceof ArrayBuffer)r=new TextDecoder().decode(t);else if(t&&typeof t=="object"&&t.message)r=t.message;else{this._secureLog("warn","\u26A0\uFE0F Unexpected data type after processing:",{details:typeof t});return}if(r&&r.trim().startsWith("{"))try{let i=JSON.parse(r);if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Final fake message check blocked: ${i.pattern}`);return}let n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error","heartbeat","verification","verification_response","peer_disconnect","key_rotation_signal","key_rotation_ready","security_upgrade","ice_restart_offer","ice_restart_answer","ice_restart_request"];if(i.type&&n.includes(i.type)){this._secureLog("warn",`\u{1F4C1} Final system/file message check blocked: ${i.type}`);return}}catch{}r&&this._secureLog("error","Rejected unauthenticated payload at the end of processMessage",{messageLength:typeof r=="string"?r.length:0})}catch(t){this._secureLog("error","\u274C Failed to process message:",{errorType:t?.constructor?.name||"Unknown"})}}async _processEncryptedDataWithLimitedMutex(e){return this._withMutex("cryptoOperation",async t=>{this._secureLog("debug","\u{1F510} Processing encrypted data with limited mutex",{operationId:t,dataType:typeof e});try{return await this.removeSecurityLayers(e)}catch(r){return this._secureLog("error","\u274C Error processing encrypted data",{operationId:t,errorType:r.constructor.name}),e}},2e3)}notifySecurityUpdate(){try{this._secureLog("debug","\u{1F512} Notifying about security level update",{isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasLastCalculation:!!this.lastSecurityCalculation}),this._dispatchAppEvent?.(new CustomEvent("security-level-updated",{detail:{timestamp:Date.now(),manager:"webrtc",webrtcManager:this,isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),lastCalculation:this.lastSecurityCalculation}})),setTimeout(()=>{},100),this.lastSecurityCalculation&&this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:this.lastSecurityCalculation,webrtcManager:this,timestamp:Date.now()}}))}catch(e){this._secureLog("error","\u274C Error in notifySecurityUpdate",{error:e.message})}}handleSystemMessage(e){switch(this._secureLog("debug","\u{1F527} Handling system message:",{type:e.type}),e.type){case"heartbeat":this.handleHeartbeat(e);break;case"verification":this.handleVerificationRequest(e.data);break;case"verification_response":this.handleVerificationResponse(e.data);break;case"sas_code":this.handleSASCode(e.data);break;case"verification_confirmed":this.handleVerificationConfirmed(e.data);break;case"verification_both_confirmed":this.handleVerificationBothConfirmed(e.data);break;case"peer_disconnect":this.handlePeerDisconnectNotification(e);break;case"key_rotation_signal":this._secureLog("debug","\u{1F504} Key rotation signal received (ignored for stability)");break;case"key_rotation_ready":this._secureLog("debug","\u{1F504} Key rotation ready signal received (ignored for stability)");break;case"security_upgrade":this._secureLog("debug","\u{1F512} Security upgrade notification received:",{type:e.type});break;default:this._secureLog("debug","\u{1F527} Unknown system message type:",{type:e.type})}}enableStage2Security(){this.sessionConstraints?.hasPacketReordering&&(this.securityFeatures.hasPacketReordering=!0,this.reorderingConfig.enabled=!0),this.sessionConstraints?.hasAntiFingerprinting&&(this.securityFeatures.hasAntiFingerprinting=!0,this.antiFingerprintingConfig.enabled=!0,this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!0),this.notifySecurityUpgrade(2),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage3Security(){this._secureLog("info","\u{1F512} Enabling Stage 3 features (traffic obfuscation)"),this.sessionConstraints?.hasMessageChunking&&(this.securityFeatures.hasMessageChunking=!0,this.chunkingConfig.enabled=!0),this.sessionConstraints?.hasFakeTraffic&&(this.securityFeatures.hasFakeTraffic=!0,this.fakeTrafficConfig.enabled=!0,this.startFakeTrafficGeneration()),this.notifySecurityUpgrade(3),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage4Security(){if(this._secureLog("info","\u{1F512} Enabling Stage 4 features (maximum safety)"),this.sessionConstraints?.hasDecoyChannels&&this.isConnected()&&this.isVerified){this.securityFeatures.hasDecoyChannels=!0,this.decoyChannelConfig.enabled=!0;try{this.initializeDecoyChannels()}catch(e){this._secureLog("warn","\u26A0\uFE0F Decoy channels initialization failed:",{details:e.message}),this.securityFeatures.hasDecoyChannels=!1,this.decoyChannelConfig.enabled=!1}}this.sessionConstraints?.hasAntiFingerprinting&&(this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!1),this.notifySecurityUpgrade(4),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}forceSecurityUpdate(){setTimeout(()=>{this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate()},100)}getSecurityStatus(){let e=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r);return{stage:4,securityLevel:"maximum",activeFeatures:e,totalFeatures:Object.keys(this.securityFeatures).length,activeFeaturesCount:e.length,activeFeaturesNames:e,sessionConstraints:this.sessionConstraints}}notifySecurityUpgrade(e){let t={1:"Basic Enhanced",2:"Medium Security",3:"High Security",4:"Maximum Security"},r=`\u{1F512} Security upgraded to Stage ${e}: ${t[e]}`;if((!this.securityUpgradeNotificationSent||this.lastSecurityUpgradeStage!==e)&&(this.securityUpgradeNotificationSent=!0,this.lastSecurityUpgradeStage=e,this.onMessage&&this.deliverMessageToUI(r,"system")),this.dataChannel&&this.dataChannel.readyState==="open")try{let n={type:"security_upgrade",stage:e,stageName:t[e],message:r,timestamp:Date.now()};this._secureLog("debug","\u{1F512} Sending security upgrade notification to peer:",{type:n.type,stage:n.stage}),this.dataChannel.send(JSON.stringify(n))}catch(n){this._secureLog("warn","\u26A0\uFE0F Failed to send security upgrade notification to peer:",{details:n.message})}let i=this.getSecurityStatus()}async calculateAndReportSecurityLevel(){try{if(!window.EnhancedSecureCryptoUtils)return this._secureLog("warn","\u26A0\uFE0F EnhancedSecureCryptoUtils not available for security calculation"),null;if(!this.isConnected()||!this.isVerified||!this.encryptionKey||!this.macKey)return this._secureLog("debug","\u26A0\uFE0F WebRTC not ready for security calculation",{connected:this.isConnected(),verified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey}),null;this._secureLog("debug","\u{1F50D} Calculating real security level",{managerState:"ready",hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey)});let e=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this);if(this._secureLog("info","Real security level calculated",{hasSecurityLevel:!!e.level,scoreRange:e.score>80?"high":e.score>50?"medium":"low",checksRatio:`${e.passedChecks}/${e.totalChecks}`,isRealCalculation:e.isRealData}),this.lastSecurityCalculation=e,this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:e,webrtcManager:this,timestamp:Date.now(),source:"calculateAndReportSecurityLevel"}})),e.isRealData&&this.onMessage&&(!this.securityCalculationNotificationSent||this.lastSecurityCalculationLevel!==e.level)){this.securityCalculationNotificationSent=!0,this.lastSecurityCalculationLevel=e.level;let t=`Security Level: ${e.level} (${e.score}%) - ${e.passedChecks}/${e.totalChecks} checks passed`;this.deliverMessageToUI(t,"system")}return e}catch(e){return this._secureLog("error","Failed to calculate real security level",{errorType:e.constructor.name}),null}}async autoEnableSecurityFeatures(){this._secureLog("info","Starting graduated security activation - all features enabled");let e=()=>this.isConnected()&&this.isVerified&&this.connectionAttempts===0&&this.messageQueue.length===0&&this.peerConnection?.connectionState==="connected";await this.calculateAndReportSecurityLevel(),this.notifySecurityUpgrade(1),setTimeout(async()=>{e()&&(this.enableStage2Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage3Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage4Security(),await this.calculateAndReportSecurityLevel())},2e4))},15e3))},1e4)}async establishConnection(){try{await this.initializeEnhancedSecurity(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels()}catch(e){throw this._secureLog("error","\u274C Failed to establish enhanced connection:",{errorType:e?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),e}}_clearVerificationStates(){try{this.localVerificationConfirmed=!1,this.remoteVerificationConfirmed=!1,this.bothVerificationsConfirmed=!1,this.isVerified=!1,this.verificationCode=null,this.pendingSASCode=null,this.sasValidationAttempts=0,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.keyFingerprint=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.connectionId=null,this.processedMessageIds.clear(),this.verificationNotificationSent=!1,this.verificationInitiationSent=!1}catch(e){this._secureLog("error","\u274C Error clearing verification states:",{errorType:e?.constructor?.name||"Unknown"})}}startPeriodicCleanup(){this._secureLog("info","\u{1F527} Periodic cleanup moved to unified scheduler")}async calculateSecurityLevel(){return await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this)}shouldRotateKeys(){return!this.isConnected()||!this.isVerified?!1:Date.now()-this.lastKeyRotation>this.keyRotationInterval||this.messageCounter%100===0}async rotateKeys(){return this._withMutex("keyOperation",async e=>{if(this._secureLog("info","\u{1F504} Starting key rotation with mutex",{operationId:e}),!this.isConnected()||!this.isVerified)return this._secureLog("warn"," Key rotation aborted - connection not ready",{operationId:e,isConnected:this.isConnected(),isVerified:this.isVerified}),!1;if(this._keySystemState.isRotating)return this._secureLog("warn"," Key rotation already in progress",{operationId:e}),!1;try{this._keySystemState.isRotating=!0,this._keySystemState.lastOperation="rotation",this._keySystemState.lastOperationTime=Date.now();let t={type:"key_rotation_signal",newVersion:this.currentKeyVersion+1,timestamp:Date.now(),operationId:e};if(this.dataChannel&&this.dataChannel.readyState==="open")this.dataChannel.send(JSON.stringify(t));else throw new Error("Data channel not ready for key rotation");return this._hardWipeOldKeys(),new Promise(r=>{this.pendingRotation={newVersion:this.currentKeyVersion+1,operationId:e,resolve:r,timeout:setTimeout(()=>{this._secureLog("error"," Key rotation timeout",{operationId:e}),this._keySystemState.isRotating=!1,this.pendingRotation=null,r(!1)},1e4)}})}catch(t){return this._secureLog("error"," Key rotation failed in critical section",{operationId:e,errorType:t.constructor.name}),this._keySystemState.isRotating=!1,!1}},1e4)}cleanupOldKeys(){let e=Date.now(),t=s.LIMITS.MAX_KEY_AGE,r=0;for(let[i,n]of this.oldKeys.entries())e-n.timestamp>t&&(n.encryptionKey&&this._secureWipeMemory(n.encryptionKey,"pfs_cleanup_wipe"),n.macKey&&this._secureWipeMemory(n.macKey,"pfs_cleanup_wipe"),n.metadataKey&&this._secureWipeMemory(n.metadataKey,"pfs_cleanup_wipe"),n.encryptionKey=null,n.macKey=null,n.metadataKey=null,n.keyFingerprint=null,this.oldKeys.delete(i),r++,this._secureLog("info","\u{1F9F9} Old PFS keys hard wiped and cleaned up",{version:i,age:Math.round((e-n.timestamp)/1e3)+"s",timestamp:Date.now()}));r>0&&this._secureLog("info",`PFS cleanup completed: ${r} keys hard wiped`,{timestamp:Date.now()})}getKeysForVersion(e){let t=this.oldKeys.get(e);return t&&t.encryptionKey&&t.macKey&&t.metadataKey?{encryptionKey:t.encryptionKey,macKey:t.macKey,metadataKey:t.metadataKey}:e===this.currentKeyVersion&&this.encryptionKey&&this.macKey&&this.metadataKey?{encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey}:(window.EnhancedSecureCryptoUtils.secureLog.log("error","No valid keys found for version",{requestedVersion:e,currentVersion:this.currentKeyVersion,availableVersions:Array.from(this.oldKeys.keys())}),null)}_hasTurnServer(){return(this._config.webrtc.iceServers||[]).some(e=>(Array.isArray(e.urls)?e.urls:[e.urls]).some(r=>typeof r=="string"&&r.toLowerCase().startsWith("turn:")))}_buildPeerConnectionConfig(){let e=this._isRelayOnlyMode(),t={iceServers:this._config.webrtc.iceServers,iceCandidatePoolSize:10,bundlePolicy:"balanced"};return e&&(t.iceTransportPolicy="relay"),t}_summarizeIceServerConfig(e=[]){let t={serverCount:0,stun:0,turn:0,turns:0,hasCredentials:!1};for(let r of e||[]){t.serverCount+=1,(r?.username||r?.credential)&&(t.hasCredentials=!0);let i=Array.isArray(r?.urls)?r.urls:[r?.urls];for(let n of i){let a=String(n||"").toLowerCase();a.startsWith("stun:")&&(t.stun+=1),a.startsWith("turn:")&&(t.turn+=1),a.startsWith("turns:")&&(t.turns+=1)}}return t}_isRelayOnlyMode(){return this._config.webrtc.privacyMode==="relay-only"}_setRelayOnlyMode(e){let t=e===!0;this._config.webrtc.privacyMode=t?"relay-only":"standard",this._config.webrtc.relayOnly=t}_warnIfTurnMissing(){if(this._ipLeakWarningShown)return;this._ipLeakWarningShown=!0;let e=this._isRelayOnlyMode(),t=this._hasTurnServer(),r=null;e&&!t?r="Privacy mode is relay-only, but no TURN server is configured. Relay-only mode cannot connect until TURN is configured; STUN alone does not hide IP addresses.":!e&&!t?r="Privacy warning: relay-only mode is disabled and no TURN server is configured. Direct WebRTC connections may expose host or server-reflexive IP addresses; STUN alone does not provide IP protection.":e||(r="Privacy warning: relay-only mode is disabled. Direct WebRTC connectivity may expose host or server-reflexive IP addresses even when TURN is available."),r&&this.deliverMessageToUI(r,"system")}createPeerConnection(){this._sessionAlive=!0;let e=this._buildPeerConnectionConfig();this._warnIfTurnMissing(),console.info("[SecureBit ICE] peer connection config",this._summarizeIceServerConfig(e.iceServers)),this.peerConnection=new RTCPeerConnection(e),this._callAudioSender=null,this._callVideoSender=null,this.peerConnection.onconnectionstatechange=()=>{let t=this.peerConnection.connectionState;console.info("[SecureBit ICE] connection state changed",{connectionState:t,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState}),t==="connected"&&!this.isVerified?this._notifyVerificationReadyIfPossible():t==="connected"&&this.isVerified?this._onPathRecovered()||this.onStatusChange("connected"):t==="disconnected"?this.intentionalDisconnect?(this.onStatusChange("disconnected"),setTimeout(()=>this.disconnect(),100)):this.isVerified?this._onPathDegraded("ice_disconnected"):console.warn(`[SecureBit ICE] State is ${t} but not verified yet. Keeping session open for manual exchange.`):t==="closed"?(this._resetReconnectState(),this.onStatusChange("disconnected"),this._clearVerificationStates(),this.intentionalDisconnect&&setTimeout(()=>this.disconnect(),100)):t==="failed"?(this._collectIceFailureDiagnostics().then(r=>{console.warn("[SecureBit ICE] failure diagnostics",r),this._noteIceFailureDiagnostics(r)}),this.isVerified?this._onPathLost("ice_failed"):console.warn("[SecureBit ICE] State is failed but not verified yet. Keeping session open for manual exchange.")):this.isReconnecting()&&(t==="connecting"||t==="new")||this.onStatusChange(t)},this.peerConnection.oniceconnectionstatechange=()=>{console.info("[SecureBit ICE] ICE connection state changed",{connectionState:this.peerConnection.connectionState,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState})},this.peerConnection.onicecandidateerror=t=>{console.warn("[SecureBit ICE] ICE candidate error",{url:t.url,errorCode:t.errorCode,errorText:t.errorText})},this.peerConnection.ontrack=t=>{try{this._refreshRemoteStream()}catch(r){this._secureLog("warn","\u26A0\uFE0F ontrack handling failed",{errorType:r?.constructor?.name})}},this.peerConnection.ondatachannel=t=>{t.channel.label==="securechat"?(this.dataChannel=t.channel,this.setupDataChannel(t.channel)):t.channel.label==="heartbeat"&&(this.heartbeatChannel=t.channel)}}setupDataChannel(e){this.dataChannel=e;let t=!1,r=async()=>{if(!t){t=!0;try{this.dataChannel&&typeof this.dataChannel.bufferedAmountLowThreshold=="number"&&(this.dataChannel.bufferedAmountLowThreshold=1024*1024)}catch{}if(this._handshakeMode==="sbq2")try{await this._runSbq2KeyExchange()}catch(i){this._secureLog("error","SBQ2 key exchange failed to start",{errorType:i?.constructor?.name||"Unknown"}),this._sbq2Abort("start_failed","The secure handshake could not be started. Please try connecting again.");return}try{await this.establishConnection(),this.initializeFileTransfer()}catch(i){this._secureLog("error","Error in establishConnection:",{errorType:i?.constructor?.name||"Unknown"})}if(this.pendingSASCode&&this.dataChannel&&this.dataChannel.readyState==="open")try{let i={type:"sas_code",data:{code:this.pendingSASCode,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(i)),this.pendingSASCode=null}catch{}else this.pendingSASCode;this.isVerified?(this.onStatusChange("connected"),this.processMessageQueue(),setTimeout(async()=>{await this.calculateAndReportSecurityLevel(),this.autoEnableSecurityFeatures(),this.notifySecurityUpdate()},500)):(this._notifyVerificationReadyIfPossible(),this.initiateVerification()),this.startHeartbeat()}};this.dataChannel.onopen=r,this.dataChannel.readyState==="open"&&Promise.resolve().then(()=>r()).catch(i=>{this._secureLog("error","Deferred data channel open handling failed",{errorType:i?.constructor?.name||"Unknown"})}),this.dataChannel.onclose=()=>{this._resetReconnectState?.(),this._teardownRecoveryLifecycleListeners?.(),this.intentionalDisconnect?(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed","system"))):(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed. Check connection status.","system"))),this._wipeEphemeralKeys(),this.stopHeartbeat(),this.isVerified=!1},this.dataChannel.onmessage=async i=>{try{if(this._noteInboundActivity?.(),typeof i.data=="string")try{let n=JSON.parse(i.data),a=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(n.type&&a.includes(n.type)){if(!this._enforceVerificationGate("file_message_receive",!1)){this._secureLog("error","Dropped file message received before verification",{messageType:n.type});return}if(!this.fileTransferSystem)try{if(this.isVerified&&this.dataChannel&&this.dataChannel.readyState==="open"){this.initializeFileTransfer();let o=0,c=30;for(;!this.fileTransferSystem&&osetTimeout(d,100)),o++}}catch(o){this._secureLog("error","Failed to initialize file transfer system for receiver:",{errorType:o?.constructor?.name||"Unknown"})}if(this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}this._secureLog("warn","\u26A0\uFE0F File transfer system not ready, attempting lazy init...");try{if(await this._ensureFileTransferReady(),this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}}catch(o){this._secureLog("error","Lazy init of file transfer failed:",{errorType:o?.message||o?.constructor?.name||"Unknown"})}this._secureLog("error","No file transfer system available for:",{errorType:n.type?.constructor?.name||"Unknown"});return}if(n.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(n.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:n.type});return}let o=s.MESSAGE_TYPES;if(n.type===o.MESSAGE_DELETE){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelete?.(c.slice(0,64))}catch{}return}if(n.type===o.MESSAGE_RECEIPT){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelivered?.(c.slice(0,64))}catch{}return}if([o.CALL_OFFER,o.CALL_ANSWER,o.CALL_ICE,o.CALL_DECLINE,o.CALL_END].includes(n.type)){try{await this._handleCallSignal(n.type,n.data||{})}catch{}return}if([o.ICE_RESTART_OFFER,o.ICE_RESTART_ANSWER,o.ICE_RESTART_REQUEST].includes(n.type)){try{await this._handleIceRestartSignal(n.type,n.data||{})}catch(c){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:c?.constructor?.name})}return}return}if(n.type===s.MESSAGE_TYPES.KEY_BLOB||n.type===s.MESSAGE_TYPES.KEY_PROOF){await this._sbq2HandleHandshakeFrame(n);return}if(n.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","sas_code","peer_disconnect","security_upgrade"].includes(n.type)){this.handleSystemMessage(n);return}if(n.type===s.MESSAGE_TYPES.RATCHET_MESSAGE){await this._processRatchetMessage(n);return}if(n.type==="enhanced_message"&&n.data){await this._processEnhancedMessageWithoutMutex(n);return}this._secureLog("error","Rejected unencrypted frame on the chat channel",{messageType:typeof n.type=="string"?n.type.slice(0,32):typeof n.type});return}catch{this._secureLog("error","Rejected malformed (non-JSON) frame on the chat channel",{dataLength:typeof i.data=="string"?i.data.length:0});return}else i.data instanceof ArrayBuffer&&await this._processBinaryDataWithoutMutex(i.data)}catch(n){this._secureLog("error","Failed to process message in onmessage:",{errorType:n?.constructor?.name||"Unknown"})}}}async _processBinaryDataWithoutMutex(e){try{if(!this._checkInboundRateLimit("binary_message"))return;let t=e;if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&t instanceof ArrayBuffer&&t.byteLength>12)try{t=await this.removeNestedEncryption(t)}catch{this._secureLog("warn","Nested decryption failed, continuing with original data")}if(this.securityFeatures.hasPacketPadding&&t instanceof ArrayBuffer)try{t=this.removePacketPadding(t)}catch{this._secureLog("warn","Packet padding removal failed, continuing with original data")}if(this.securityFeatures.hasAntiFingerprinting&&t instanceof ArrayBuffer)try{t=this.removeAntiFingerprinting(t)}catch{this._secureLog("warn","Anti-fingerprinting removal failed, continuing with original data")}if(t instanceof ArrayBuffer){let r=new TextDecoder().decode(t);try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return}catch{}this._secureLog("error","Rejected unauthenticated binary frame on the chat channel",{byteLength:e?.byteLength||0})}}catch(t){this._secureLog("error","Error processing binary data:",{errorType:t?.constructor?.name||"Unknown"})}}async _processRatchetMessage(e){try{if(!this._checkInboundRateLimit("ratchet_message"))return;if(!this.isRatchetActive()){this._secureLog("error","Received a ratchet message but no ratchet is active");return}if(typeof e?.h!="string"||typeof e?.c!="string"){this._secureLog("error","Malformed ratchet message frame");return}let t=await this._ratchet.decrypt(e.h,e.c);try{let r=JSON.parse(t);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.deliverMessageToUI(t,"received")}catch(t){this._secureLog("error","Failed to decrypt ratchet message",{errorType:t?.constructor?.name||"Unknown"})}}async _processEnhancedMessageWithoutMutex(e){try{if(!this._checkInboundRateLimit("enhanced_message"))return;if(!this.encryptionKey||!this.macKey||!this.metadataKey){this._secureLog("error","Missing encryption keys for enhanced message");return}let t=await window.EnhancedSecureCryptoUtils.decryptMessage(e.data,this.encryptionKey,this.macKey,this.metadataKey);if(!this._validateIncomingSequenceNumber(t?.sequenceNumber,"enhanced_message")){this._secureLog("error","Rejected chat message failing anti-replay validation",{messageId:t?.messageId?"present":"absent"});return}if(t&&t.message){try{let r=JSON.parse(t.message);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.onMessage&&this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.onMessage&&this.deliverMessageToUI(t.message,"received")}else this._secureLog("warn","No message content in decrypted result")}catch(t){this._secureLog("error","Error processing enhanced message:",{errorType:t?.constructor?.name||"Unknown"})}}_generateOperationId(){return`op_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async _acquireMutex(e,t,r=5e3){let i=`_${e}Mutex`,n=this[i];if(!n)throw this._secureLog("error",`Unknown mutex: ${e}`,{mutexPropertyName:i,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex: ${e}. Available: ${this._getAvailableMutexes().join(", ")}`);if(!t||typeof t!="string")throw new Error("Invalid operation ID for mutex acquisition");return new Promise((a,o)=>{(()=>{if(n.lockId===t){this._secureLog("warn",`Mutex '${e}' already locked by same operation`,{operationId:t}),a();return}if(!n.locked)n.locked=!0,n.lockId=t,n.lockTime=Date.now(),this._secureLog("debug",`Mutex '${e}' acquired atomically`,{operationId:t,lockTime:n.lockTime}),n.lockTimeout=setTimeout(()=>{this._handleMutexTimeout(e,t,r)},r),a();else{let d={resolve:a,reject:o,operationId:t,timestamp:Date.now(),timeout:setTimeout(()=>{let h=n.queue.findIndex(u=>u.operationId===t);h!==-1&&(n.queue.splice(h,1),o(new Error(`Mutex acquisition timeout for '${e}'`)))},r)};n.queue.push(d),this._secureLog("debug",`Operation queued for mutex '${e}'`,{operationId:t,queueLength:n.queue.length,currentLockId:n.lockId})}})()})}_releaseMutex(e,t){if(!e||typeof e!="string")throw new Error("Invalid mutex name provided for release");if(!t||typeof t!="string")throw new Error("Invalid operation ID provided for mutex release");let r=`_${e}Mutex`,i=this[r];if(!i)throw this._secureLog("error",`Unknown mutex for release: ${e}`,{mutexPropertyName:r,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex for release: ${e}`);if(i.lockId!==t)throw this._secureLog("error","CRITICAL: Invalid mutex release attempt - potential race condition",{mutexName:e,expectedLockId:i.lockId,providedOperationId:t,mutexState:{locked:i.locked,lockTime:i.lockTime,queueLength:i.queue.length}}),new Error(`Invalid mutex release attempt for '${e}': expected '${i.lockId}', got '${t}'`);if(!i.locked)throw this._secureLog("error","CRITICAL: Attempting to release unlocked mutex",{mutexName:e,operationId:t,mutexState:{locked:i.locked,lockId:i.lockId,lockTime:i.lockTime}}),new Error(`Attempting to release unlocked mutex: ${e}`);try{i.lockTimeout&&(clearTimeout(i.lockTimeout),i.lockTimeout=null);let n=i.lockTime?Date.now()-i.lockTime:0;i.locked=!1,i.lockId=null,i.lockTime=null,this._secureLog("debug",`Mutex released successfully: ${e}`,{operationId:t,lockDuration:n,queueLength:i.queue.length}),this._processNextInQueue(e)}catch(n){throw this._secureLog("error","Error during mutex release queue processing",{mutexName:e,operationId:t,errorType:n.constructor.name,errorMessage:n.message}),i.locked=!1,i.lockId=null,i.lockTime=null,i.lockTimeout=null,n}}_processNextInQueue(e){let t=this[`_${e}Mutex`];if(!t){this._secureLog("error",`Mutex not found for queue processing: ${e}`);return}if(t.queue.length===0)return;if(t.locked){this._secureLog("warn",`Mutex '${e}' is still locked, skipping queue processing`,{lockId:t.lockId,queueLength:t.queue.length});return}let r=t.queue.shift();if(!r){this._secureLog("warn",`Empty queue item for mutex '${e}'`);return}if(!r.operationId||!r.resolve||!r.reject){this._secureLog("error",`Invalid queue item structure for mutex '${e}'`,{hasOperationId:!!r.operationId,hasResolve:!!r.resolve,hasReject:!!r.reject});return}try{r.timeout&&clearTimeout(r.timeout),this._secureLog("debug",`Processing next operation in queue for mutex '${e}'`,{operationId:r.operationId,queueRemaining:t.queue.length,timestamp:Date.now()}),setTimeout(async()=>{try{await this._acquireMutex(e,r.operationId,5e3),this._secureLog("debug",`Queued operation acquired mutex '${e}'`,{operationId:r.operationId,acquisitionTime:Date.now()}),r.resolve()}catch(i){this._secureLog("error",`Queued operation failed to acquire mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message,timestamp:Date.now()}),r.reject(new Error(`Queue processing failed for '${e}': ${i.message}`)),setTimeout(()=>{this._processNextInQueue(e)},50)}},10)}catch(i){this._secureLog("error",`Critical error during queue processing for mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message});try{r.reject(new Error(`Queue processing critical error: ${i.message}`))}catch(n){this._secureLog("error","Failed to reject queue item",{originalError:i.message,rejectError:n.message})}setTimeout(()=>{this._processNextInQueue(e)},100)}}_getAvailableMutexes(){let e=[],t=Object.getOwnPropertyNames(this);for(let r of t)if(r.endsWith("Mutex")&&r.startsWith("_")){let i=r.slice(1,-5);e.push(i)}return e}async _withMutex(e,t,r=5e3){let i=this._generateOperationId();if(!this._validateMutexSystem())throw this._secureLog("error","Mutex system not properly initialized",{operationId:i,mutexName:e}),new Error("Mutex system not properly initialized. Call _initializeMutexSystem() first.");let n=this[`_${e}Mutex`];if(!n)throw new Error(`Mutex '${e}' not found`);let a=!1;try{await this._acquireMutex(e,i,r),a=!0;let o=`${e}Operations`;this._operationCounters&&this._operationCounters[o]!==void 0&&this._operationCounters[o]++;let c=await t(i);return c===void 0&&t.name!=="cleanup"&&this._secureLog("warn","Mutex operation returned undefined result",{operationId:i,mutexName:e,operationName:t.name}),c}catch(o){throw this._secureLog("error","Error in mutex operation",{operationId:i,mutexName:e,errorType:o.constructor.name,errorMessage:o.message,mutexAcquired:a,mutexState:n?{locked:n.locked,lockId:n.lockId,queueLength:n.queue.length}:"null"}),e==="keyOperation"&&this._handleKeyOperationError(o,i),(o.message.includes("timeout")||o.message.includes("race condition"))&&this._emergencyUnlockAllMutexes("errorHandler"),o}finally{if(a)try{await this._releaseMutex(e,i),n.locked&&n.lockId===i&&(this._secureLog("error","Mutex release verification failed",{operationId:i,mutexName:e}),n.locked=!1,n.lockId=null,n.lockTimeout=null)}catch(o){this._secureLog("error","Error releasing mutex in finally block",{operationId:i,mutexName:e,releaseErrorType:o.constructor.name,releaseErrorMessage:o.message}),n.locked=!1,n.lockId=null,n.lockTimeout=null}}}_validateMutexSystem(){let e=["keyOperation","cryptoOperation","connectionOperation"];for(let t of e){let r=`_${t}Mutex`,i=this[r];if(!i||typeof i!="object")return this._secureLog("error",`Missing or invalid mutex: ${t}`,{mutexPropertyName:r,mutexType:typeof i}),!1;let n=["locked","queue","lockId","lockTimeout"];for(let a of n)if(!(a in i))return this._secureLog("error",`Mutex ${t} missing property: ${a}`),!1}return!0}_emergencyRecoverMutexSystem(){this._secureLog("warn","Emergency mutex system recovery initiated");try{if(this._emergencyUnlockAllMutexes("emergencyRecovery"),this._initializeMutexSystem(),!this._validateMutexSystem())throw new Error("Mutex system validation failed after recovery");return this._secureLog("info","Mutex system recovered successfully with validation"),!0}catch(e){this._secureLog("error","Failed to recover mutex system",{errorType:e.constructor.name,errorMessage:e.message});try{return this._initializeMutexSystem(),this._secureLog("warn","Forced mutex system re-initialization completed"),!0}catch(t){return this._secureLog("error","CRITICAL: Forced re-initialization also failed",{originalError:e.message,reinitError:t.message}),!1}}}async _generateEncryptionKeys(){return this._withMutex("keyOperation",async e=>{this._secureLog("info","Generating encryption keys with atomic mutex",{operationId:e});let t=this._keySystemState;if(t.isInitializing){this._secureLog("warn","Key generation already in progress, waiting for completion",{operationId:e,lastOperation:t.lastOperation,lastOperationTime:t.lastOperationTime});let r=0,i=50;for(;t.isInitializing&&rsetTimeout(n,100)),r++;if(t.isInitializing)throw new Error("Key generation timeout - operation still in progress after 5 seconds")}try{t.isInitializing=!0,t.lastOperation="generation",t.lastOperationTime=Date.now(),t.operationId=e,this._secureLog("debug","Atomic key generation state set",{operationId:e,timestamp:t.lastOperationTime});let r=null,i=null;try{if(r=await this._generateEphemeralECDHKeys(),!r||!r.privateKey||!r.publicKey)throw new Error("Ephemeral ECDH key pair validation failed");if(!this._validateKeyPairConstantTime(r))throw new Error("Ephemeral ECDH keys are not valid CryptoKey instances");this._secureLog("debug","Ephemeral ECDH keys generated and validated for PFS",{operationId:e,privateKeyType:r.privateKey.algorithm?.name,publicKeyType:r.publicKey.algorithm?.name,isEphemeral:!0})}catch(n){this._secureLog("error","Ephemeral ECDH key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ephemeral_ecdh_key_generation")}try{if(i=await window.EnhancedSecureCryptoUtils.generateECDSAKeyPair(),!i||!i.privateKey||!i.publicKey)throw new Error("ECDSA key pair validation failed");if(!this._validateKeyPairConstantTime(i))throw new Error("ECDSA keys are not valid CryptoKey instances");this._secureLog("debug","ECDSA keys generated and validated",{operationId:e,privateKeyType:i.privateKey.algorithm?.name,publicKeyType:i.publicKey.algorithm?.name})}catch(n){this._secureLog("error","ECDSA key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ecdsa_key_generation")}if(!r||!i)throw new Error("One or both key pairs failed to generate");return this._enableSecurityFeaturesAfterKeyGeneration(r,i),this._secureLog("info","Encryption keys generated successfully with atomic protection",{operationId:e,hasECDHKeys:!!(r?.privateKey&&r?.publicKey),hasECDSAKeys:!!(i?.privateKey&&i?.publicKey),generationTime:Date.now()-t.lastOperationTime}),{ecdhKeyPair:r,ecdsaKeyPair:i}}catch(r){throw this._secureLog("error","Key generation failed, resetting state",{operationId:e,errorType:r.constructor.name}),r}finally{t.isInitializing=!1,t.operationId=null,this._secureLog("debug","Key generation state reset",{operationId:e})}})}_enableSecurityFeaturesAfterKeyGeneration(e,t){try{e&&e.privateKey&&e.publicKey&&(this.securityFeatures.hasEncryption=!0,this.securityFeatures.hasECDH=!0,this._secureLog("info","ECDH encryption features enabled")),t&&t.privateKey&&t.publicKey&&(this.securityFeatures.hasECDSA=!0,this._secureLog("info","ECDSA signature features enabled")),this.securityFeatures.hasEncryption&&(this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasNonExtractableKeys=!0,this._secureLog("info","Additional encryption-dependent features enabled")),e&&this.ephemeralKeyPairs.size>0&&(this.securityFeatures.hasPFS=!0,this._secureLog("info","Perfect Forward Secrecy enabled with ephemeral keys")),this._secureLog("info","Security features updated after key generation",{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasMetadataProtection:this.securityFeatures.hasMetadataProtection,hasEnhancedReplayProtection:this.securityFeatures.hasEnhancedReplayProtection,hasNonExtractableKeys:this.securityFeatures.hasNonExtractableKeys,hasPFS:this.securityFeatures.hasPFS})}catch(r){this._secureLog("error","Failed to enable security features after key generation",{errorType:r.constructor.name,errorMessage:r.message})}}_emergencyUnlockAllMutexes(e="unknown"){let t=["keyOperation","cryptoOperation","connectionOperation","emergencyRecovery","systemShutdown","errorHandler"];if(!t.includes(e))throw this._secureLog("error","UNAUTHORIZED emergency mutex unlock attempt",{callerContext:e,authorizedCallers:t,timestamp:Date.now()}),new Error(`Unauthorized emergency mutex unlock attempt by: ${e}`);let r=["keyOperation","cryptoOperation","connectionOperation"];this._secureLog("error","EMERGENCY: Unlocking all mutexes with authorization and state cleanup",{callerContext:e,timestamp:Date.now()});let i=0,n=0;if(r.forEach(a=>{let o=this[`_${a}Mutex`];if(o)try{o.lockTimeout&&clearTimeout(o.lockTimeout);let c={locked:o.locked,lockId:o.lockId,lockTime:o.lockTime,queueLength:o.queue.length};o.locked=!1,o.lockId=null,o.lockTimeout=null,o.lockTime=null;let d=0;o.queue.forEach(h=>{try{h.reject&&typeof h.reject=="function"&&(h.reject(new Error(`Emergency mutex unlock for ${a} by ${e}`)),d++)}catch(u){this._secureLog("warn","Failed to reject queue item during emergency unlock",{mutexName:a,errorType:u.constructor.name})}}),o.queue=[],i++,this._secureLog("debug",`Emergency unlocked mutex: ${a}`,{previousState:c,queueRejectCount:d,callerContext:e})}catch(c){n++,this._secureLog("error",`Error during emergency unlock of mutex: ${a}`,{errorType:c.constructor.name,errorMessage:c.message,callerContext:e})}}),this._keySystemState)try{let a={...this._keySystemState};this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null,this._keySystemState.concurrentOperations=0,this._secureLog("debug","Emergency reset key system state",{previousState:a,callerContext:e})}catch(a){this._secureLog("error","Error resetting key system state during emergency unlock",{errorType:a.constructor.name,errorMessage:a.message,callerContext:e})}this._secureLog("info","Emergency mutex unlock completed",{callerContext:e,unlockedCount:i,errorCount:n,totalMutexes:r.length,timestamp:Date.now()}),setTimeout(()=>{this._validateMutexSystemAfterEmergencyUnlock()},100)}_handleKeyOperationError(e,t){this._secureLog("error","Key operation error detected, initiating recovery",{operationId:t,errorType:e.constructor.name,errorMessage:e.message}),this._keySystemState&&(this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null),this.ecdhKeyPair=null,this.ecdsaKeyPair=null,this.encryptionKey=null,this.macKey=null,this.metadataKey=null,(e.message.includes("timeout")||e.message.includes("race condition"))&&(this._secureLog("warn","Race condition or timeout detected, triggering emergency recovery"),this._emergencyRecoverMutexSystem())}_generateSecureIV(e=12,t="general"){if(this._ivTrackingSystem.emergencyMode)throw this._secureLog("error","CRITICAL: IV generation blocked - emergency mode active due to IV reuse"),new Error("IV generation blocked - emergency mode active");let r=0,i=100;for(;ro.toString(16).padStart(2,"0")).join("");if(this._ivTrackingSystem.usedIVs.has(a)){if(this._ivTrackingSystem.collisionCount++,this._secureLog("error","CRITICAL: IV reuse detected!",{context:t,attempt:r,collisionCount:this._ivTrackingSystem.collisionCount,ivString:a.substring(0,16)+"..."}),this._ivTrackingSystem.collisionCount>5)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to excessive IV reuse"),new Error("Emergency mode: Excessive IV reuse detected");continue}if(!this._validateIVEntropy(n)){if(this._ivTrackingSystem.entropyValidation.entropyFailures++,this._secureLog("warn","Low entropy IV detected",{context:t,attempt:r,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures}),this._ivTrackingSystem.entropyValidation.entropyFailures>10)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to low entropy IVs"),new Error("Emergency mode: Low entropy IVs detected");continue}return this._ivTrackingSystem.usedIVs.add(a),this._ivTrackingSystem.ivHistory.set(a,{timestamp:Date.now(),context:t,attempt:r}),this.sessionId&&(this._ivTrackingSystem.sessionIVs.has(this.sessionId)||this._ivTrackingSystem.sessionIVs.set(this.sessionId,new Set),this._ivTrackingSystem.sessionIVs.get(this.sessionId).add(a)),this._validateRNGQuality(),this._secureLog("debug","Secure IV generated",{context:t,attempt:r,ivSize:e,totalIVs:this._ivTrackingSystem.usedIVs.size}),n}throw this._secureLog("error",`Failed to generate unique IV after ${i} attempts`,{context:t,totalIVs:this._ivTrackingSystem.usedIVs.size}),new Error(`Failed to generate unique IV after ${i} attempts`)}_validateIVEntropy(e){this._ivTrackingSystem.entropyValidation.entropyTests++;let t=new Array(256).fill(0);for(let b=0;b0){let p=t[b]/n;i-=p*Math.log2(p)}r.shannon=i;let o=Math.max(...t)/n;r.min=-Math.log2(o);let c=0;for(let b=0;b<256;b++)if(t[b]>0){let p=t[b]/n;c+=p*p}r.collision=-Math.log2(c);let d=Array.from(e).map(b=>String.fromCharCode(b)).join(""),h=this._estimateCompressedLength(d);r.compression=(1-h/n)*8,r.quantum=this._calculateQuantumResistantEntropy(e);let u=this._detectAdvancedSuspiciousPatterns(e),m=this._ivTrackingSystem.entropyValidation.minEntropy,y=r.shannon>=m&&r.min>=m*.8&&r.collision>=m*.9&&r.compression>=m*.7&&r.quantum>=m*.6&&!u;return y||this._secureLog("warn","Enhanced IV entropy validation failed",{shannon:r.shannon.toFixed(2),min:r.min.toFixed(2),collision:r.collision.toFixed(2),compression:r.compression.toFixed(2),quantum:r.quantum.toFixed(2),minThreshold:m,hasSuspiciousPatterns:u}),y}_estimateCompressedLength(e){let t=0,r=0;for(;ri&&(i=o,n=r-a)}i>=3?(t+=3,r+=i):(t+=1,r+=1)}return t}_calculateQuantumResistantEntropy(e){let t=0;this._detectQuantumVulnerablePatterns(e)&&(t-=2);let i=this._analyzeBitDistribution(e);t+=i.score;let n=this._detectPeriodicity(e);return t-=n*.5,Math.max(0,Math.min(8,t))}_detectQuantumVulnerablePatterns(e){let t=[[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,1,0,1,0,1,0,1],[1,0,1,0,1,0,1,0]];for(let r of t)for(let i=0;i<=e.length-r.length;i++){let n=!0;for(let a=0;a>>0).toString(2).split("1").length-1;let i=(r-t)/r,n=t/r,a=Math.abs(.5-n);return{score:Math.max(0,8-a*16),zeroRatio:i,oneRatio:n,deviation:a}}_detectPeriodicity(e){if(e.length<16)return 0;let t=0;for(let r=2;r<=e.length/2;r++){let i=0,n=0;for(let a=0;a0){let a=i/n;t=Math.max(t,a)}}return t}_detectAdvancedSuspiciousPatterns(e){let t=[[0,1,2,3,4,5,6,7],[255,254,253,252,251,250,249,248],[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,255,0,255,0,255,0,255],[255,0,255,0,255,0,255,0]];for(let n of t)for(let a=0;a<=e.length-n.length;a++){let o=!0;for(let c=0;cn<3).length>e.length*.3}_calculateLocalEntropy(e){let r=[];for(let i=0;i<=e.length-8;i++){let n=e.slice(i,i+8),a={};for(let c of n)a[c]=(a[c]||0)+1;let o=0;for(let c of Object.values(a)){let d=c/8;o-=d*Math.log2(d)}r.push(o)}return r}_detectSuspiciousIVPatterns(e){let t=e.every(n=>n===0),r=e.every(n=>n===255);if(t||r)return!0;let i=0;for(let n=1;n=3)return!0;for(let n=2;n<=Math.floor(e.length/2);n++)for(let a=0;a<=e.length-n*2;a++){let o=e.slice(a,a+n),c=e.slice(a+n,a+n*2);if(o.every((d,h)=>d===c[h]))return!0}return!1}async _cleanupOldIVs(){let e=Date.now(),t=18e5,r=0,i=[];if(this._ivTrackingSystem.ivHistory.size>this._ivTrackingSystem.maxIVHistorySize){let n=Array.from(this._ivTrackingSystem.ivHistory.entries()),a=n.slice(0,n.length-this._ivTrackingSystem.maxIVHistorySize);for(let[o]of a)i.push(o),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0)}for(let[n,a]of this._ivTrackingSystem.ivHistory.entries())e-a.timestamp>t&&(i.push(n),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0));i.length>0&&this._processCleanupBatch(i);for(let[n,a]of this._ivTrackingSystem.sessionIVs.entries())if(a.size>this._ivTrackingSystem.maxSessionIVs){let o=Array.from(a),c=o.slice(0,o.length-this._ivTrackingSystem.maxSessionIVs);for(let d of c)a.delete(d),this._ivTrackingSystem.usedIVs.delete(d),this._ivTrackingSystem.ivHistory.delete(d),r++}r>50&&await this._performNaturalCleanup(),r>0&&this._secureLog("debug",`Enhanced cleanup: ${r} old IVs removed`,{cleanedCount:r,remainingIVs:this._ivTrackingSystem.usedIVs.size,remainingHistory:this._ivTrackingSystem.ivHistory.size,memoryPressure:this._calculateMemoryPressure()})}_processCleanupBatch(e){for(let t of e)this._ivTrackingSystem.usedIVs.delete(t),this._ivTrackingSystem.ivHistory.delete(t)}_calculateMemoryPressure(){let e=this._ivTrackingSystem.usedIVs.size,t=this._resourceLimits.maxIVHistory;return Math.min(100,Math.floor(e/t*100))}_getIVTrackingStats(){return{totalIVs:this._ivTrackingSystem.usedIVs.size,collisionCount:this._ivTrackingSystem.collisionCount,entropyTests:this._ivTrackingSystem.entropyValidation.entropyTests,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures,rngTests:this._ivTrackingSystem.rngValidation.testsPerformed,weakRngDetected:this._ivTrackingSystem.rngValidation.weakRngDetected,emergencyMode:this._ivTrackingSystem.emergencyMode,sessionCount:this._ivTrackingSystem.sessionIVs.size,lastCleanup:this._lastIVCleanupTime||0}}_resetIVTrackingSystem(){this._secureLog("warn","Resetting IV tracking system"),this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.entropyValidation.entropyTests=0,this._ivTrackingSystem.entropyValidation.entropyFailures=0,this._ivTrackingSystem.rngValidation.testsPerformed=0,this._ivTrackingSystem.rngValidation.weakRngDetected=!1,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","IV tracking system reset completed")}_validateRNGQuality(){let e=Date.now();if(this._ivTrackingSystem.rngValidation.testsPerformed%1e3===0)try{let t=[];for(let n=0;n<100;n++)t.push(crypto.getRandomValues(new Uint8Array(12)));let r=t.map(n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("")),i=new Set(r);i.size<95&&(this._ivTrackingSystem.rngValidation.weakRngDetected=!0,this._secureLog("error","CRITICAL: Weak RNG detected in validation test",{uniqueIVs:i.size,totalTests:t.length})),this._ivTrackingSystem.rngValidation.lastValidation=e}catch(t){this._secureLog("error","RNG validation failed",{errorType:t.constructor.name})}this._ivTrackingSystem.rngValidation.testsPerformed++}_handleMutexTimeout(e,t,r){let i=this[`_${e}Mutex`];if(!i){this._secureLog("error",`Mutex '${e}' not found during timeout handling`);return}if(i.lockId!==t){this._secureLog("warn",`Timeout for different operation ID on mutex '${e}'`,{expectedOperationId:t,actualLockId:i.lockId,locked:i.locked});return}if(!i.locked){this._secureLog("warn",`Timeout for already unlocked mutex '${e}'`,{operationId:t});return}try{let n=i.lockTime?Date.now()-i.lockTime:0;this._secureLog("warn",`Mutex '${e}' auto-released due to timeout`,{operationId:t,lockDuration:n,timeout:r,queueLength:i.queue.length}),i.locked=!1,i.lockId=null,i.lockTimeout=null,i.lockTime=null,setTimeout(()=>{try{this._processNextInQueue(e)}catch(a){this._secureLog("error",`Error processing queue after timeout for mutex '${e}'`,{errorType:a.constructor.name,errorMessage:a.message})}},10)}catch(n){this._secureLog("error",`Critical error during mutex timeout handling for '${e}'`,{operationId:t,errorType:n.constructor.name,errorMessage:n.message});try{this._emergencyUnlockAllMutexes("timeoutHandler")}catch(a){this._secureLog("error","Emergency unlock failed during timeout handling",{originalError:n.message,emergencyError:a.message})}}}_validateMutexSystemAfterEmergencyUnlock(){let e=["keyOperation","cryptoOperation","connectionOperation"],t=0;this._secureLog("info","Validating mutex system after emergency unlock"),e.forEach(r=>{let i=this[`_${r}Mutex`];if(!i){t++,this._secureLog("error",`Mutex '${r}' not found after emergency unlock`);return}i.locked&&(t++,this._secureLog("error",`Mutex '${r}' still locked after emergency unlock`,{lockId:i.lockId,lockTime:i.lockTime})),i.lockId!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has lock ID after emergency unlock`,{lockId:i.lockId})),i.lockTimeout!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has timeout after emergency unlock`)),i.queue.length>0&&(t++,this._secureLog("error",`Mutex '${r}' still has queue items after emergency unlock`,{queueLength:i.queue.length}))}),this._keySystemState&&(this._keySystemState.isInitializing||this._keySystemState.isRotating||this._keySystemState.isDestroying)&&(t++,this._secureLog("error","Key system state not properly reset after emergency unlock",{isInitializing:this._keySystemState.isInitializing,isRotating:this._keySystemState.isRotating,isDestroying:this._keySystemState.isDestroying})),t===0?this._secureLog("info","Mutex system validation passed after emergency unlock"):(this._secureLog("error","Mutex system validation failed after emergency unlock",{validationErrors:t}),setTimeout(()=>{this._emergencyRecoverMutexSystem()},1e3))}_getMutexSystemDiagnostics(){let e={timestamp:Date.now(),systemValid:this._validateMutexSystem(),mutexes:{},counters:{...this._operationCounters},keySystemState:{...this._keySystemState}};return["keyOperation","cryptoOperation","connectionOperation"].forEach(r=>{let i=`_${r}Mutex`,n=this[i];n?e.mutexes[r]={locked:n.locked,lockId:n.lockId,queueLength:n.queue.length,hasTimeout:!!n.lockTimeout}:e.mutexes[r]={error:"not_found"}}),e}async createSecureOffer(){return this._withMutex("connectionOperation",async e=>{this._secureLog("info","Creating secure offer with mutex",{operationId:e,connectionAttempts:this.connectionAttempts,currentState:this.peerConnection?.connectionState||"none"});try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this.connectionAttempts=0,this.sessionSalt=window.EnhancedSecureCryptoUtils.generateSalt(),this._secureLog("debug","Session salt generated",{operationId:e,saltLength:this.sessionSalt.length,isValidSalt:Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64});let t=await this._generateEncryptionKeys();if(this.ecdhKeyPair=t.ecdhKeyPair,this.ecdsaKeyPair=t.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdhKeyPair?.publicKey)throw new Error("Failed to generate valid ECDH key pair");if(!this.ecdsaKeyPair?.privateKey||!this.ecdsaKeyPair?.publicKey)throw new Error("Failed to generate valid ECDSA key pair");let r=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdhKeyPair.publicKey)),i=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdsaKeyPair.publicKey));if(!r||!i)throw new Error("Failed to generate key fingerprints");this._secureLog("info","Generated unique key pairs for MITM protection",{operationId:e,hasECDHFingerprint:!!r,hasECDSAFingerprint:!!i,fingerprintLength:r.length,timestamp:Date.now()});let n=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),a=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!n||typeof n!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!a||typeof a!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.isInitiator=!0,this.onStatusChange("connecting"),this.createPeerConnection(),this.dataChannel=this.peerConnection.createDataChannel("securechat",{ordered:!0}),this.setupDataChannel(this.dataChannel),this._secureLog("debug","Data channel created",{operationId:e,channelLabel:this.dataChannel.label,channelOrdered:this.dataChannel.ordered});let o=await this.peerConnection.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});await this.peerConnection.setLocalDescription(o);try{let S=this._extractDTLSFingerprintFromSDP(o.sdp);this.expectedDTLSFingerprint=S,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:S,context:"offer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${S}`,"system")}catch(S){this._secureLog("error","Failed to extract DTLS fingerprint from offer",{error:S.message})}let c=Date.now(),d=await this.waitForIceGathering(),h=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),u=h.total;if(!d&&u===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the invitation would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");if(this._secureLog(u>0?"info":"warn","ICE candidates captured for offer export",{candidateSummary:h,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),this._logIceCandidateDiagnostics("offer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),d||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the invitation. Connectivity may still fail on restrictive networks.","system"),u===0&&this.deliverMessageToUI("No ICE candidates were gathered for the invitation yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed",{operationId:e,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState}),this.verificationCode=window.EnhancedSecureCryptoUtils.generateVerificationCode(),!this.verificationCode||this.verificationCode.lengthS.toString(16).padStart(2,"0")).join(""),!this.sessionId||this.sessionId.length!==s.SIZES.SESSION_ID_LENGTH*2)throw new Error("Failed to generate valid session ID");this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(S=>S.toString(16).padStart(2,"0")).join(""),this._storePendingOfferContext();let y={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},b=Date.now(),p={t:"offer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:b,e:n,d:a,sl:this.sessionSalt,si:this.sessionId,ci:this.connectionId,vc:this.verificationCode,ac:m,slv:"MAX",dr:s.RATCHET_VERSION,kf:{e:r.substring(0,12),d:i.substring(0,12)}};try{let S=this.validateEnhancedOfferData(p)}catch(S){throw new Error(`Offer package validation error: ${S.message}`)}if(this._secureLog("info","Enhanced secure offer created successfully",{operationId:e,version:p.version,hasECDSA:!0,hasMutualAuth:!0,hasSessionId:!!p.sessionId,securityLevel:y.level,timestamp:b,capabilitiesCount:10}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"offer",timestamp:b,securityLevel:y.level,operationId:e}})),s.SBQ2_SEND_ENABLED){this._latchHandshakeMode("sbq2");let{text:S}=await this._sbq2BuildDescriptor(de.OFFER);return{t:"offer",sbq2:S}}return this._latchHandshakeMode("sb1"),p}catch(t){throw this._secureLog("error","Enhanced secure offer creation failed in critical section",{operationId:e,errorType:t.constructor.name,errorMessage:t.message,phase:this._determineErrorPhase(t),connectionAttempts:this.connectionAttempts}),this._cleanupFailedOfferCreation(),this.onStatusChange("disconnected"),t}},6e4)}_determineErrorPhase(e){let t=e.message.toLowerCase();return t.includes("rate limit")?"rate_limiting":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("fingerprint")?"fingerprinting":t.includes("export")||t.includes("signature")?"key_export":t.includes("peer connection")?"webrtc_setup":t.includes("offer")||t.includes("sdp")?"sdp_creation":t.includes("verification")?"verification_setup":t.includes("session")?"session_setup":t.includes("validation")?"package_validation":"unknown"}_cleanupFailedOfferCreation(){try{this._secureCleanupCryptographicMaterials(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during offer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed offer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during offer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}_updateSecurityFeatures(e){let t={...this.securityFeatures};try{Object.assign(this.securityFeatures,e),this._secureLog("debug","Security features updated",{updatedCount:Object.keys(e).length,totalFeatures:Object.keys(this.securityFeatures).length})}catch(r){throw this.securityFeatures=t,this._secureLog("error","Security features update failed, rolled back",{errorType:r.constructor.name}),r}}async _createSbq2Answer(e){return this._withMutex("connectionOperation",async t=>{try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this._latchHandshakeMode("sbq2");let r=Ur(String(e.sbq2)),i=this._sbq2AdoptRemoteDescriptor(r,de.OFFER),{sdp:n}=Kr(i);this.isInitiator=!1,this.onStatusChange("connecting");let a=await this._generateEncryptionKeys();if(this.ecdhKeyPair=a.ecdhKeyPair,this.ecdsaKeyPair=a.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdsaKeyPair?.privateKey)throw new Error("Failed to generate valid key pairs");this.createPeerConnection(),this._peerDTLSFingerprint=Array.from(i.fingerprint,d=>d.toString(16).padStart(2,"0").toUpperCase()).join(":"),await this.peerConnection.setRemoteDescription({type:"offer",sdp:n}),await this.peerConnection.setLocalDescription(await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})),this.expectedDTLSFingerprint=this._extractDTLSFingerprintFromSDP(this.peerConnection.localDescription.sdp),await this.waitForIceGathering();let o=async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),{text:c}=await this._sbq2BuildDescriptor(de.ANSWER,{bindingTag:await Or(o,r)});return this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:Date.now(),operationId:t}})),{t:"answer",sbq2:c}}catch(r){throw this._secureLog("error","SBQ2 answer creation failed",{operationId:t,errorType:r?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),r}},6e4)}async createSecureAnswer(e){return e&&typeof e.sbq2=="string"?this._createSbq2Answer(e):this._withMutex("connectionOperation",async t=>{this._secureLog("info","Creating secure answer with mutex",{operationId:t,hasOfferData:!!e,offerType:e?.type,offerVersion:e?.version,offerTimestamp:e?.timestamp});try{if(this._resetNotificationFlags(),this._secureLog("debug","Starting enhanced offer validation",{operationId:t,hasOfferData:!!e,offerType:e?.type,hasECDHKey:!!e?.ecdhPublicKey,hasECDSAKey:!!e?.ecdsaPublicKey,hasSalt:!!e?.salt}),!this.validateEnhancedOfferData(e))throw new Error("Invalid connection data format - failed enhanced validation");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkConnectionRate(this.rateLimiterId))throw new Error("Connection rate limit exceeded. Please wait before trying again.");let r=e.ts||e.timestamp,i=e.v||e.version;if(!r||!i)throw new Error("Missing required security fields in offer data \u2013 possible MITM attack");let n=Date.now()-r,a=18e5;if(n>a)throw this._secureLog("error","Offer data is too old - possible replay attack",{operationId:t,offerAge:Math.round(n/1e3),maxAllowedAge:Math.round(a/1e3),timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Offer data is too old \u2013 possible replay attack"),new Error("Offer data is too old \u2013 possible replay attack");let o=i;if(o!==s.PROTOCOL_VERSION)throw this._secureLog("warn","Protocol version mismatch detected",{operationId:t,expectedVersion:s.PROTOCOL_VERSION,receivedVersion:o}),new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${o}`);if(this.sessionSalt=e.sl||e.salt,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,!Array.isArray(this.sessionSalt))throw new Error("Invalid session salt format - must be array");let c=64;if(this.sessionSalt.length!==c)throw new Error(`Invalid session salt length: expected ${c}, got ${this.sessionSalt.length}`);let d=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);this._secureLog("info","Session salt validated successfully",{operationId:t,saltLength:this.sessionSalt.length,saltFingerprint:d.substring(0,8)});let h=await this._generateEncryptionKeys();if(this.ecdhKeyPair=h.ecdhKeyPair,this.ecdsaKeyPair=h.ecdsaKeyPair,!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw this._secureLog("error","Local ECDH private key is not a CryptoKey",{operationId:t,hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a valid CryptoKey");let u;try{let R=e.d||e.ecdsaPublicKey;u=await crypto.subtle.importKey("spki",new Uint8Array(R.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"])}catch(R){this._throwSecureError(R,"ecdsa_key_import")}let m;try{let R=e.e||e.ecdhPublicKey;m=await window.EnhancedSecureCryptoUtils.importSignedPublicKey(R,u,"ECDH")}catch(R){this._secureLog("error","Failed to import signed ECDH public key",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"ecdh_key_import")}if(!(m instanceof CryptoKey))throw this._secureLog("error","Peer ECDH public key is not a CryptoKey",{operationId:t,publicKeyType:typeof m,publicKeyAlgorithm:m?.algorithm?.name}),new Error("Peer ECDH public key is not a valid CryptoKey");this.peerPublicKey=m;let y;try{this._secureLog("debug","About to call deriveSharedKeys",{operationId:t,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),y=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,m,this.sessionSalt),this._secureLog("debug","deriveSharedKeys completed successfully",{operationId:t,hasMessageKey:!!y.messageKey,hasMacKey:!!y.macKey,hasPfsKey:!!y.pfsKey,hasMetadataKey:!!y.metadataKey,hasFingerprint:!!y.fingerprint})}catch(R){this._secureLog("error","Failed to derive shared keys",{operationId:t,errorType:R.constructor.name,errorMessage:R.message,errorStack:R.stack,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),this._throwSecureError(R,"key_derivation")}if(await this._setEncryptionKeys(y.messageKey,y.macKey,y.metadataKey,y.fingerprint),await this._initializeRatchet(y,!1),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw this._secureLog("error","Invalid key types after derivation",{operationId:t,encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey}),new Error("Invalid key types after derivation");this.verificationCode=e.vc||e.verificationCode||null,this._secureLog("info","Encryption keys derived and set successfully",{operationId:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0});let b;if(e.authChallenge)try{b=await window.EnhancedSecureCryptoUtils.createAuthProof(e.authChallenge,this.ecdsaKeyPair.privateKey,this.ecdsaKeyPair.publicKey)}catch(R){this._secureLog("error","Failed to create authentication proof",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"authentication_proof_creation")}else this._secureLog("warn","No auth challenge in offer - mutual auth disabled",{operationId:t});if(this.isInitiator=!1,this.onStatusChange("connecting"),this.onKeyExchange(this.keyFingerprint),this.createPeerConnection(),this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp)}catch(R){this._secureLog("warn","Could not extract peer DTLS fingerprint from offer",{error:R.message,context:"offer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");try{this._secureLog("debug","Setting remote description from offer",{operationId:t,sdpLength:e.sdp?.length||0}),await this.peerConnection.setRemoteDescription(new RTCSessionDescription({type:"offer",sdp:e.s||e.sdp})),this._logIceCandidateDiagnostics("remote offer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("offer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully",{operationId:t,signalingState:this.peerConnection.signalingState})}catch(R){this._secureLog("error","Failed to set remote description",{error:R.message,operationId:t}),this._throwSecureError(R,"webrtc_remote_description")}this._secureLog("debug","Remote description set successfully",{operationId:t,connectionState:this.peerConnection.connectionState,signalingState:this.peerConnection.signalingState});let p;try{p=await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})}catch(R){this._throwSecureError(R,"webrtc_create_answer")}try{await this.peerConnection.setLocalDescription(p)}catch(R){this._throwSecureError(R,"webrtc_local_description")}try{let R=this._extractDTLSFingerprintFromSDP(p.sdp);this.expectedDTLSFingerprint=R,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:R,context:"answer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${R}`,"system")}catch(R){this._secureLog("error","Failed to extract DTLS fingerprint from answer",{error:R.message})}try{let R=this._extractDTLSFingerprintFromSDP(e.s||e.sdp),ue=this.expectedDTLSFingerprint,K=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(K,ue,R),this._setSASMaterialReady(ue,R)}catch(R){throw this._secureLog("error","SAS computation failed in createSecureAnswer (Answer side)",{errorType:R?.constructor?.name||"Unknown"}),new Error(`SAS computation failed: ${R.message}`)}let S=Date.now(),w=await this.waitForIceGathering(),M=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),F=M.total;if(!w&&F===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the response would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");this._secureLog(F>0?"info":"warn","ICE candidates captured for answer export",{candidateSummary:M,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-S,iceGatheringCompleted:w}),this._logIceCandidateDiagnostics("answer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-S,iceGatheringCompleted:w}),w||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the response. Connectivity may still fail on restrictive networks.","system"),F===0&&this.deliverMessageToUI("No ICE candidates were gathered for the response yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed for answer",{operationId:t,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState});let k=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),E=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!k||typeof k!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!k.keyData||!k.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!k.keyData,hasSignature:!!k.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!E||typeof E!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!E.keyData||!E.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!E.keyData,hasSignature:!!E.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");let _={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},A=Date.now(),x={t:"answer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:A,e:k,d:E,ap:b,slv:"MAX",dr:s.RATCHET_VERSION,sc:{sf:d.substring(0,12),kd:!0,ma:!0}},T=x.s||x.sdp,Y=x.e||x.ecdhPublicKey,B=x.d||x.ecdsaPublicKey;if(!T||!Y||!B)throw new Error("Generated answer package is incomplete");return this._secureLog("info","Enhanced secure answer created successfully",{operationId:t,version:x.version,hasECDSA:!0,hasMutualAuth:!!b,hasSessionConfirmation:!!x.sessionConfirmation,securityLevel:_.level,timestamp:A,processingTime:A-e.timestamp}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:A,securityLevel:_.level,operationId:t}})),setTimeout(async()=>{try{let R=await this.calculateAndReportSecurityLevel();R&&(this.notifySecurityUpdate(),this._secureLog("info","Post-connection security level calculated",{operationId:t,level:R.level}))}catch(R){this._secureLog("error","Error calculating post-connection security",{operationId:t,errorType:R.constructor.name})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(this._secureLog("info","Retrying security calculation",{operationId:t}),await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate(),x}catch(r){throw this._secureLog("error","Enhanced secure answer creation failed in critical section",{operationId:t,errorType:r.constructor.name,errorMessage:r.message,phase:this._determineAnswerErrorPhase(r),offerAge:e?.timestamp?Date.now()-e.timestamp:"unknown"}),this._cleanupFailedAnswerCreation(),this.onStatusChange("disconnected"),this.onAnswerError&&(r.message.includes("too old")||r.message.includes("replay")?this.onAnswerError("replay_attack",r.message):r.message.includes("MITM")||r.message.includes("signature")?this.onAnswerError("security_violation",r.message):r.message.includes("validation")||r.message.includes("format")?this.onAnswerError("invalid_format",r.message):this.onAnswerError("general_error",r.message)),r}},6e4)}_determineAnswerErrorPhase(e){let t=e.message.toLowerCase();return t.includes("validation")||t.includes("format")?"offer_validation":t.includes("rate limit")?"rate_limiting":t.includes("replay")||t.includes("too old")?"replay_protection":t.includes("salt")?"salt_validation":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("import")||t.includes("ecdsa")||t.includes("ecdh")?"key_import":t.includes("signature")||t.includes("mitm")?"signature_verification":t.includes("derive")||t.includes("shared")?"key_derivation":t.includes("auth")||t.includes("proof")?"authentication":t.includes("remote description")||t.includes("local description")?"webrtc_setup":t.includes("answer")||t.includes("sdp")?"sdp_creation":t.includes("export")?"key_export":t.includes("security level")?"security_calculation":"unknown"}_cleanupFailedAnswerCreation(){try{this._clearPendingOfferContext(),this._secureCleanupCryptographicMaterials(),this.currentKeyVersion=0,this.keyVersions.clear(),this.oldKeys.clear(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during answer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed answer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during answer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}async _setEncryptionKeys(e,t,r,i){return this._withMutex("keyOperation",async n=>{if(this._secureLog("info","Setting encryption keys with mutex",{operationId:n}),!(e instanceof CryptoKey)||!(t instanceof CryptoKey)||!(r instanceof CryptoKey))throw new Error("Invalid key types provided");if(!i||typeof i!="string")throw new Error("Invalid key fingerprint provided");let a={encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey,keyFingerprint:this.keyFingerprint};try{return this.encryptionKey=e,this.macKey=t,this.metadataKey=r,this.keyFingerprint=i,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._secureLog("info","Encryption keys set successfully",{operationId:n,hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasFingerprint:!!this.keyFingerprint}),!0}catch(o){throw this.encryptionKey=a.encryptionKey,this.macKey=a.macKey,this.metadataKey=a.metadataKey,this.keyFingerprint=a.keyFingerprint,this._secureLog("error","Key setting failed, rolled back",{operationId:n,errorType:o.constructor.name}),o}})}async _handleSbq2Answer(e){if(!this._isSbq2())throw new Error("Received a new-format response to an old-format invitation. Please start a new invitation.");let t=this._sbq2State(),r=Ur(String(e.sbq2)),i=Fr(r);if(i.type!==de.ANSWER)throw new Error("That code is an invitation, not a response to one.");if(!i.commitment)throw new Error("The response carries no key commitment");let a=await Or(async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),t.localDescriptor),o=0;for(let d=0;dd.toString(16).padStart(2,"0").toUpperCase()).join(":");let{sdp:c}=Kr(i);await this.peerConnection.setRemoteDescription({type:"answer",sdp:c}),this._secureLog("info","SBQ2 answer accepted; awaiting in-band key exchange",{bytes:r.length})}async handleSecureAnswer(e){if(e&&typeof e.sbq2=="string")return this._handleSbq2Answer(e);try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid answer data structure",{hasAnswerData:!!e,answerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Answer data must be a non-null object");let t=e.t==="answer"&&e.s,r=e.type==="enhanced_secure_answer"&&e.sdp;if(!t&&!r)throw this._secureLog("error","CRITICAL: Invalid answer format",{type:e.type||e.t,hasSdp:!!(e.sdp||e.s)}),new Error("CRITICAL SECURITY FAILURE: Invalid answer format - hard abort required");let i=e.v||e.version;if(i!==s.PROTOCOL_VERSION)throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${i||"unknown"}`);let n=e.ecdhPublicKey||e.e,a=e.ecdsaPublicKey||e.d;if(!n||typeof n!="object"||Array.isArray(n))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure in answer",{hasEcdhKey:!!n,ecdhKeyType:typeof n,isArray:Array.isArray(n),availableKeys:Object.keys(e)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDH public key structure");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature in answer",{hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!a||typeof a!="object"||Array.isArray(a))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure in answer",{hasEcdsaKey:!!a,ecdsaKeyType:typeof a,isArray:Array.isArray(a)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDSA public key structure");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature in answer",{hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");let o=e.ts||e.timestamp,c=e.v||e.version;if(!o||!c)throw new Error("Missing required fields in response data \u2013 possible MITM attack");if(e.sessionId&&this.sessionId&&e.sessionId!==this.sessionId)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Session ID mismatch detected - possible MITM attack",{}),new Error("Session ID mismatch \u2013 possible MITM attack");let d=Date.now()-e.timestamp;if(d>36e5)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Answer data is too old - possible replay attack",{answerAge:d,timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Response data is too old \u2013 possible replay attack"),new Error("Response data is too old \u2013 possible replay attack");i!==s.PROTOCOL_VERSION&&window.EnhancedSecureCryptoUtils.secureLog.log("warn","Incompatible protocol version in answer",{expectedVersion:s.PROTOCOL_VERSION,receivedVersion:i});let h=await crypto.subtle.importKey("spki",new Uint8Array(a.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),u=await window.EnhancedSecureCryptoUtils.importPublicKeyFromSignedPackage(n,h);if(this._restorePendingOfferContextIfNeeded(),!this.sessionSalt||this.sessionSalt.length!==64)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid session salt detected - possible session hijacking",{saltLength:this.sessionSalt?this.sessionSalt.length:0}),new Error("Missing pending offer context. Apply the response in the original creator window that generated the invitation.");let m=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);if(window.EnhancedSecureCryptoUtils.secureLog.log("info","Session salt integrity verified",{saltFingerprint:m.substring(0,8)}),!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Local ECDH private key is not a CryptoKey in handleSecureAnswer",{hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a CryptoKey");if(!(u instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Peer ECDH public key is not a CryptoKey in handleSecureAnswer",{publicKeyType:typeof u,publicKeyAlgorithm:u?.algorithm?.name}),new Error("Peer ECDH public key is not a CryptoKey");this.peerPublicKey=u,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,this.connectionId||(this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(p=>p.toString(16).padStart(2,"0")).join(""));let y=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,u,this.sessionSalt);if(this.encryptionKey=y.messageKey,this.macKey=y.macKey,this.metadataKey=y.metadataKey,this.keyFingerprint=y.fingerprint,await this._initializeRatchet(y,!0),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid key types after derivation in handleSecureAnswer",{encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey,encryptionKeyAlgorithm:this.encryptionKey?.algorithm?.name,macKeyAlgorithm:this.macKey?.algorithm?.name,metadataKeyAlgorithm:this.metadataKey?.algorithm?.name}),new Error("Invalid key types after export");this._secureLog("info","Encryption keys set in handleSecureAnswer",{hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasPFS=!0,this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0}),this.onKeyExchange(this.keyFingerprint);try{let p=this._extractDTLSFingerprintFromSDP(e.sdp||e.s),S=this.expectedDTLSFingerprint,w=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(w,S,p),this._setSASMaterialReady(S,p),this.pendingSASCode=this.verificationCode,this._secureLog("info","SAS verification code generated for MITM protection (Offer side)",{sasCode:this.verificationCode,localFP:S.substring(0,16)+"...",remoteFP:p.substring(0,16)+"...",timestamp:Date.now()})}catch(p){this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{errorType:p?.constructor?.name||"Unknown"}),this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{error:p.message,stack:p.stack,timestamp:Date.now()})}if(this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp||e.s)}catch(p){this._secureLog("warn","Could not extract peer DTLS fingerprint from answer",{error:p.message,context:"answer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");let b=e.sdp||e.s;if(this.peerConnection?.signalingState!=="have-local-offer"){this._secureLog("warn","Ignoring answer outside have-local-offer state",{signalingState:this.peerConnection?.signalingState||"unknown"});return}this._secureLog("debug","Setting remote description from answer",{sdpLength:b?.length||0,usingCompactSDP:!e.sdp&&!!e.s}),await this.peerConnection.setRemoteDescription({type:"answer",sdp:b}),this._logIceCandidateDiagnostics("remote answer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("answer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully from answer",{signalingState:this.peerConnection.signalingState}),setTimeout(async()=>{try{await this.calculateAndReportSecurityLevel()&&this.notifySecurityUpdate()}catch(p){this._secureLog("error","Error calculating security after connection:",{errorType:p?.constructor?.name||"Unknown"})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate()}catch(t){throw this._secureLog("error","Enhanced secure answer handling failed",{errorType:t.constructor.name}),this.onStatusChange("failed"),this.onAnswerError&&(t.message.includes("too old")||t.message.includes("\u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0441\u0442\u0430\u0440\u044B\u0435")?this.onAnswerError("replay_attack",t.message):t.message.includes("MITM")||t.message.includes("signature")||t.message.includes("\u043F\u043E\u0434\u043F\u0438\u0441\u044C")?this.onAnswerError("security_violation",t.message):this.onAnswerError("general_error",t.message)),t}}initiateVerification(){this.isInitiator?this.verificationInitiationSent||(this.verificationInitiationSent=!0,this.deliverMessageToUI("CRITICAL: Compare verification code with peer out-of-band (voice/video/in-person) to prevent MITM attack!","system"),this.deliverMessageToUI(`Your verification code: ${this.verificationCode}`,"system"),this.deliverMessageToUI("Ask peer to confirm this exact code before allowing traffic!","system")):this.deliverMessageToUI("Waiting for verification code from peer...","system")}_validateSASCode(e){if(!e||typeof e!="string"||!this.verificationCode||typeof this.verificationCode!="string")return!1;let t=e.replace(/[-\s]/g,"").toUpperCase(),r=this.verificationCode.replace(/[-\s]/g,"").toUpperCase();return t.length!==r.length?!1:window.EnhancedSecureCryptoUtils.constantTimeCompare(t,r)}confirmVerification(e){try{if(!this._validateSASCode(e))throw this.sasValidationAttempts=(this.sasValidationAttempts||0)+1,this._secureLog("warn","SAS validation failed: user entered incorrect code",{attempts:this.sasValidationAttempts,maxAttempts:s.MAX_SAS_ATTEMPTS}),this.sasValidationAttempts>=s.MAX_SAS_ATTEMPTS?(this.deliverMessageToUI("Verification failed 3 times. Session reset for safety.","system"),this.disconnect(),new Error("SAS_MAX_ATTEMPTS")):new Error("SAS_MISMATCH");this.localVerificationConfirmed=!0,this.sasValidationAttempts=0;let t={type:"verification_confirmed",data:{timestamp:Date.now(),verificationMethod:"MANUAL_SAS_ENTRY",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(t)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed(),this.deliverMessageToUI("Code verified locally. Waiting for peer confirmation...","system"),this.processMessageQueue()}catch(t){throw t.message==="SAS_MISMATCH"?this.deliverMessageToUI("Verification failed: the code you entered is incorrect.","system"):t.message!=="SAS_MAX_ATTEMPTS"&&(this._secureLog("error","SAS verification failed:",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("SAS verification failed","system")),t}}_checkBothVerificationsConfirmed(){if(this.localVerificationConfirmed&&this.remoteVerificationConfirmed&&!this.bothVerificationsConfirmed){this.bothVerificationsConfirmed=!0;let e={type:"verification_both_confirmed",data:{timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_COMPLETE"}};this.dataChannel.send(JSON.stringify(e)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{try{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")}catch(t){this._secureLog("error","Verified transition rejected - aborting session",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("Verification could not be completed safely. Connection aborted.","system"),this.disconnect()}},2e3)}}handleVerificationConfirmed(e){this.remoteVerificationConfirmed=!0,this.deliverMessageToUI("Peer confirmed the verification code. Waiting for your confirmation...","system"),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed()}handleVerificationBothConfirmed(e){if(!this.bothVerificationsConfirmed){if(!this.localVerificationConfirmed){this._secureLog("error","Peer claimed mutual SAS confirmation before local confirmation - possible MITM attack",{localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,timestamp:Date.now()}),this.deliverMessageToUI("Verification protocol violation: peer claimed confirmation before you verified the code. Connection aborted for safety.","system"),this.disconnect();return}this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")},2e3)}}handleVerificationRequest(e){if(this._validateSASCode(e?.code)){let t={type:"verification_response",data:{ok:!0,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTED"}};this.dataChannel.send(JSON.stringify(t)),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI("SAS verification successful! MITM protection confirmed. Channel is now secure!","system")),this.processMessageQueue()}else{let t={type:"verification_response",data:{ok:!1,timestamp:Date.now(),reason:"code_mismatch"}};this.dataChannel.send(JSON.stringify(t)),this._secureLog("error","SAS verification failed - possible MITM attack",{receivedCodeLength:typeof e?.code=="string"?e.code.length:0,timestamp:Date.now()}),this.deliverMessageToUI("SAS verification failed! Possible MITM attack detected. Connection aborted for safety!","system"),this.disconnect()}}handleSASCode(e){if(!e?.code||typeof e.code!="string"){this._secureLog("warn","Invalid SAS announcement received from peer");return}if(!this.verificationCode){this._secureLog("error","Received peer SAS announcement before local SAS was derived - refusing to adopt it",{timestamp:Date.now()}),this.deliverMessageToUI("Verification failed: no locally derived code to compare against. Connection aborted for safety.","system"),this.disconnect();return}if(!this._validateSASCode(e.code)){this._secureLog("error","Peer-announced SAS does not match locally computed SAS"),this.deliverMessageToUI("Version or SAS mismatch detected. Connection aborted for safety.","system"),this.disconnect();return}this._notifyVerificationReadyIfPossible(),this._secureLog("info","Peer SAS announcement matched locally derived code",{timestamp:Date.now()})}handleVerificationResponse(e){e.ok===!0?(this._secureLog("info","Mutual SAS verification completed - MITM protection active",{verificationMethod:e.verificationMethod||"SAS",securityLevel:e.securityLevel||"MITM_PROTECTED",timestamp:Date.now()}),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI(" Mutual SAS verification complete! MITM protection active. Channel is now secure!","system")),this.processMessageQueue()):(this._secureLog("error","Peer SAS verification failed - connection not secure",{responseData:e,timestamp:Date.now()}),this.deliverMessageToUI("Peer verification failed! Connection not secure!","system"),this.disconnect())}validateOfferData(e){return e&&e.type==="enhanced_secure_offer"&&e.sdp&&e.publicKey&&e.salt&&e.verificationCode&&Array.isArray(e.publicKey)&&Array.isArray(e.salt)&&e.salt.length===32}validateEnhancedOfferData(e){try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid offer data structure",{hasOfferData:!!e,offerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Offer data must be a non-null object");let t=e.v===s.PROTOCOL_VERSION&&e.e&&e.d,r=e.version===s.PROTOCOL_VERSION&&e.ecdhPublicKey&&e.ecdsaPublicKey;if(!(t?["offer"].includes(e.t):["enhanced_secure_offer","secure_offer"].includes(e.type)))throw new Error("Invalid offer type");if(t){let a=["e","d","sl","vc","si","ci","ac","slv"];for(let c of a)if(!e[c])throw new Error(`Missing required v4.1 compact field: ${c}`);if(!e.e||typeof e.e!="object"||Array.isArray(e.e))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure");if(!e.d||typeof e.d!="object"||Array.isArray(e.d))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure");if(!Array.isArray(e.sl)||e.sl.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");if(typeof e.vc!="string"||e.vc.length<6)throw new Error("Invalid verification code format");if(!["MAX","HIGH","MED","LOW"].includes(e.slv))throw new Error("Invalid security level");let o=Date.now()-e.ts;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");this._secureLog("info","v4.1 compact offer validation passed",{version:e.v,hasECDH:!!e.e,hasECDSA:!!e.d,hasSalt:!!e.sl,hasVerificationCode:!!e.vc,securityLevel:e.slv,offerAge:Math.round(o/1e3)+"s"})}else if(r){let a=["ecdhPublicKey","ecdsaPublicKey","salt","verificationCode","authChallenge","timestamp","version","securityLevel"];for(let c of a)if(!e[c])throw new Error(`Missing v4.1 field: ${c}`);if(!Array.isArray(e.salt)||e.salt.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");let o=Date.now()-e.timestamp;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");if(!e.ecdhPublicKey||typeof e.ecdhPublicKey!="object"||Array.isArray(e.ecdhPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure",{hasEcdhKey:!!e.ecdhPublicKey,ecdhKeyType:typeof e.ecdhPublicKey,isArray:Array.isArray(e.ecdhPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure - hard abort required");if(!e.ecdsaPublicKey||typeof e.ecdsaPublicKey!="object"||Array.isArray(e.ecdsaPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure",{hasEcdsaKey:!!e.ecdsaPublicKey,ecdsaKeyType:typeof e.ecdsaPublicKey,isArray:Array.isArray(e.ecdsaPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure - hard abort required");if(!e.ecdhPublicKey.keyData||!e.ecdhPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature",{hasKeyData:!!e.ecdhPublicKey.keyData,hasSignature:!!e.ecdhPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!e.ecdsaPublicKey.keyData||!e.ecdsaPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature",{hasKeyData:!!e.ecdsaPublicKey.keyData,hasSignature:!!e.ecdsaPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");if(typeof e.verificationCode!="string"||e.verificationCode.length<6)throw new Error("Invalid SAS verification code format - MITM protection required");this._secureLog("info","v4.1 offer validation passed",{version:e.version,hasSecurityLevel:!!e.securityLevel?.level,offerAge:Math.round(o/1e3)+"s"})}else{let a=e.v||e.version||"unknown";throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${a}`)}let n=t?e.s:e.sdp;if(typeof n!="string"||!n.includes("v=0"))throw new Error("Invalid SDP structure");return!0}catch(t){throw this._secureLog("error","CRITICAL: Security validation failed - hard abort required",{error:t.message,errorType:t.constructor.name,timestamp:Date.now()}),new Error(`CRITICAL SECURITY VALIDATION FAILURE: ${t.message}`)}}async sendSecureMessage(e){let t=this._validateInputData(e,"sendSecureMessage");if(!t.isValid){let r=`Input validation failed: ${t.errors.join(", ")}`;throw this._secureLog("error","Input validation failed in sendSecureMessage",{errors:t.errors,messageType:typeof e}),new Error(r)}if(!this._checkRateLimit("sendSecureMessage"))throw new Error("Rate limit exceeded for secure message sending");if(this._enforceVerificationGate("sendSecureMessage"),!this.isConnected())throw t.sanitizedData&&typeof t.sanitizedData=="object"&&t.sanitizedData.type&&t.sanitizedData.type.startsWith("file_")?new Error("Connection not ready for file transfer. Please ensure the connection is established and verified."):(this.messageQueue.push(t.sanitizedData),new Error("Connection not ready. Message queued for sending."));return this._withMutex("cryptoOperation",async r=>{if(!this.isConnected()||!this.isVerified)throw new Error("Connection lost during message preparation");if(!this.encryptionKey||!this.macKey||!this.metadataKey)throw new Error("Encryption keys not initialized");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkMessageRate(this.rateLimiterId))throw new Error("Message rate limit exceeded (60 messages per minute)");try{let i=typeof t.sanitizedData=="string"?t.sanitizedData:JSON.stringify(t.sanitizedData),n=window.EnhancedSecureCryptoUtils.sanitizeMessage(i),a=`msg_${Date.now()}_${this.messageCounter++}`;if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in sendSecureMessage. Manager may not be fully initialized.");let o=e.aad||this._createMessageAAD("enhanced_message",{content:n}),c;if(this._ratchet?.canEncrypt){let{header:d,ciphertext:h}=await this._ratchet.encrypt(n);c={type:s.MESSAGE_TYPES.RATCHET_MESSAGE,h:d,c:h,version:"5.0"}}else c={type:"enhanced_message",data:await window.EnhancedSecureCryptoUtils.encryptMessage(n,this.encryptionKey,this.macKey,this.metadataKey,a,JSON.parse(o).sequenceNumber),keyVersion:this.currentKeyVersion,version:"4.0"};this.dataChannel.send(JSON.stringify(c)),typeof t.sanitizedData=="string"&&this.deliverMessageToUI(t.sanitizedData,"sent"),this._secureLog("debug","Secure message sent successfully",{operationId:r,messageLength:n.length,keyVersion:this.currentKeyVersion})}catch(i){throw this._secureLog("error","Secure message sending failed",{operationId:r,errorType:i.constructor.name}),i.message.includes("Session expired")?new Error("Session expired. Please enter your password to unlock."):i.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):i.message.includes("Connection lost")?new Error("Connection lost. Please check your Internet connection."):i.message.includes("Rate limit exceeded")?new Error("Message rate limit exceeded. Please wait before sending another message."):i}},2e3)}processMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected()&&this.isVerified;){let e=this.messageQueue.shift();this.sendSecureMessage(e).catch(console.error)}}startHeartbeat(){this._heartbeatConfig={enabled:!0,interval:s.TIMEOUTS.HEARTBEAT_INTERVAL,lastHeartbeat:0},this.stopHeartbeat(!0),this._heartbeatTimer=setInterval(()=>{this._heartbeatConfig?.enabled&&this.dataChannel?.readyState==="open"&&this._sendHeartbeat()},s.TIMEOUTS.HEARTBEAT_INTERVAL),this._trackActiveTimer(this._heartbeatTimer),this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!1,this._startLivenessWatchdog(),this._setupRecoveryLifecycleListeners(),this._secureLog("info","\u{1F504} Liveness watchdog started",{heartbeatMs:s.TIMEOUTS.HEARTBEAT_INTERVAL,probeAfterMs:s.TIMEOUTS.LIVENESS_PROBE_AFTER,probeTimeoutMs:s.TIMEOUTS.LIVENESS_PROBE_TIMEOUT})}stopHeartbeat(e=!1){!e&&this._heartbeatConfig&&(this._heartbeatConfig.enabled=!1),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._activeTimers?.delete(this._heartbeatTimer),this._heartbeatTimer=null),e||this._stopLivenessWatchdog()}handleHeartbeat(e){this._lastInboundAt=Date.now(),this._livenessProbeAt=0;let t=e?.ack===!0||e?.data?.ack===!0;t||this._sendHeartbeat(!0),this._secureLog("debug",t?"\u{1F493} Heartbeat ack received":"\u{1F493} Heartbeat probe received")}_noteInboundActivity(){this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!0}_startLivenessWatchdog(){this._stopLivenessWatchdog(),this._livenessTimer=setInterval(()=>{try{this._checkLiveness()}catch(e){this._secureLog("error","\u274C Liveness check failed",{errorType:e?.constructor?.name||"Unknown"})}},s.TIMEOUTS.LIVENESS_CHECK_INTERVAL),this._trackActiveTimer(this._livenessTimer)}_stopLivenessWatchdog(){this._livenessTimer&&(clearInterval(this._livenessTimer),this._activeTimers?.delete(this._livenessTimer),this._livenessTimer=null)}_checkLiveness(){if(!this.isVerified||this._reconnect.phase!=="idle"||this.dataChannel?.readyState!=="open"||!this._lastInboundAt||!this._livenessArmed)return;let e=s.TIMEOUTS,t=Date.now();if(this.peerConnection?.connectionState==="connected"){this._livenessProbeAt=0;return}if(this._livenessProbeAt){if(t-this._livenessProbeAt"u"||this._recoveryLifecycleBound||(this._recoveryLifecycleBound=!0,this._onDeviceOnline=()=>{this.isVerified&&(this.isReconnecting()?(this._secureLog("info","\u{1F504} Device back online \u2014 retrying immediately"),this._attemptIceRestart()):this._checkLiveness())},this._onVisibilityRestored=()=>{typeof document>"u"||document.visibilityState!=="visible"||this.isVerified&&(this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._reconnect.phase==="idle"&&this.dataChannel?.readyState==="open"&&(this._livenessProbeAt=Date.now(),this._sendHeartbeat(!1),this._secureLog("info","\u{1F504} returned to foreground, probing peer")))},window.addEventListener("online",this._onDeviceOnline),typeof document<"u"&&document.addEventListener("visibilitychange",this._onVisibilityRestored))}_teardownRecoveryLifecycleListeners(){!this._recoveryLifecycleBound||typeof window>"u"||(this._recoveryLifecycleBound=!1,this._onDeviceOnline&&window.removeEventListener("online",this._onDeviceOnline),this._onVisibilityRestored&&typeof document<"u"&&document.removeEventListener("visibilitychange",this._onVisibilityRestored),this._onDeviceOnline=null,this._onVisibilityRestored=null)}_resetReconnectState(){let e=this._reconnect;e&&(e.graceTimer&&(clearTimeout(e.graceTimer),this._activeTimers?.delete(e.graceTimer)),e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer)),e.restartTimer&&(clearTimeout(e.restartTimer),this._activeTimers?.delete(e.restartTimer)),e.graceTimer=null,e.retryTimer=null,e.restartTimer=null,e.phase="idle",e.attempts=0,e.startedAt=0,e.inFlightAt=0,e.barrenFailures=0,e.pendingRole=null)}_onPathDegraded(e="ice_disconnected"){this.isVerified&&this._reconnect.phase==="idle"&&(this._reconnect.phase="grace",this._reconnect.startedAt=Date.now(),this._secureLog("info","\u{1F504} path degraded, holding grace window",{reason:e}),this.onStatusChange("reconnecting"),this._reconnect.graceTimer=setTimeout(()=>{if(this._reconnect.graceTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},s.TIMEOUTS.ICE_DISCONNECT_GRACE),this._trackActiveTimer(this._reconnect.graceTimer))}_onPathLost(e="ice_failed"){this.isVerified&&(this._reconnect.phase==="restarting"||this._reconnect.phase==="exhausted"||(this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.graceTimer&&(clearTimeout(this._reconnect.graceTimer),this._activeTimers?.delete(this._reconnect.graceTimer),this._reconnect.graceTimer=null),this._secureLog("info","\u{1F504} path lost, restarting ICE",{reason:e}),this._attemptIceRestart()))}_noteIceFailureDiagnostics(e){if(this.isReconnecting()&&e){if(e.pairCount>0){this._reconnect.barrenFailures=0;return}this._reconnect.barrenFailures=(this._reconnect.barrenFailures||0)+1,!(this._reconnect.barrenFailuress.TIMEOUTS.RECONNECT_MAX_DURATION){this._giveUpAutoReconnect("timeout");return}if(e.inFlightAt&&Date.now()-e.inFlightAt=2&&r>s.TIMEOUTS.RECOVERY_SILENCE_LIMIT){this._secureLog("warn","\u26A0\uFE0F nothing has reached us since the drop \u2014 the channel cannot carry a renegotiation",{silentForMs:r,attempts:e.attempts}),this._giveUpAutoReconnect("no_signalling_path");return}e.phase="restarting",e.attempts+=1,e.inFlightAt=Date.now(),this._secureLog("info","\u{1F504} ICE restart attempt",{attempt:e.attempts,role:this.isInitiator?"offerer":"answerer"});try{this.isInitiator?await this._sendIceRestartOffer():await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_REQUEST,timestamp:Date.now()})}catch(i){this._secureLog("warn","\u26A0\uFE0F ICE restart attempt failed to send",{errorType:i?.constructor?.name||"Unknown"})}this._scheduleReconnectRetry()}_scheduleReconnectRetry(){let e=this._reconnect;e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer));let t=s.RECONNECT_BACKOFF,r=t[Math.min(Math.max(e.attempts-1,0),t.length-1)];e.retryTimer=setTimeout(()=>{if(e.retryTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},r),this._trackActiveTimer(e.retryTimer)}_applyCurrentIceServers(e){try{if(!e||typeof e.getConfiguration!="function"||typeof e.setConfiguration!="function")return;let t=this._config?.webrtc?.iceServers;if(!Array.isArray(t)||t.length===0)return;e.setConfiguration({...e.getConfiguration(),iceServers:t})}catch(t){this._secureLog("warn","Could not refresh ICE servers before restart",{errorType:t?.constructor?.name||"Unknown"})}}async _sendIceRestartOffer(){let e=this.peerConnection;if(!e)return;if(this._applyCurrentIceServers(e),e.signalingState==="have-local-offer")try{await e.setLocalDescription({type:"rollback"})}catch{}let t=await e.createOffer({iceRestart:!0});await e.setLocalDescription(t),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_OFFER,sdp:e.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart offer sent")}_currentRemoteDtlsFingerprint(){let e=this.peerConnection?.currentRemoteDescription?.sdp||this.peerConnection?.remoteDescription?.sdp;if(!e)return null;try{return this._extractDTLSFingerprintFromSDP(e)}catch{return null}}async _assertSameRemoteIdentity(e,t){let r=this._currentRemoteDtlsFingerprint();if(!r)throw new Error(`Cannot verify peer identity for ${t}`);let i=this._extractDTLSFingerprintFromSDP(e);await this._validateDTLSFingerprint(i,r,t)}async _handleIceRestartSignal(e,t){let r=s.MESSAGE_TYPES,i=this.peerConnection;if(i)switch(this._noteInboundActivity(),e){case r.ICE_RESTART_REQUEST:{if(!this.isInitiator)return;this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this._reconnect.phase="restarting",this.onStatusChange("reconnecting")),await this._sendIceRestartOffer();return}case r.ICE_RESTART_OFFER:{if(!t.sdp)return;await this._assertSameRemoteIdentity(t.sdp,"ice_restart_offer"),this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.phase="restarting",this._applyCurrentIceServers(i),await i.setRemoteDescription({type:"offer",sdp:t.sdp});let n=await i.createAnswer();await i.setLocalDescription(n),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:r.ICE_RESTART_ANSWER,sdp:i.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart answer sent");return}case r.ICE_RESTART_ANSWER:{if(!t.sdp)return;if(i.signalingState!=="have-local-offer"){this._secureLog("warn","\u26A0\uFE0F Ignoring restart answer in unexpected state",{signalingState:i.signalingState});return}await this._assertSameRemoteIdentity(t.sdp,"ice_restart_answer"),await i.setRemoteDescription({type:"answer",sdp:t.sdp}),this._reconnect.inFlightAt=0,this._secureLog("debug","\u{1F504} ICE restart answer applied");return}default:}}_giveUpAutoReconnect(e){this._resetReconnectState(),this._reconnect.phase="exhausted",this._teardownRecoveryLifecycleListeners?.(),this._secureLog("warn","\u26A0\uFE0F automatic reconnection exhausted \u2014 ending session",{reason:e}),this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Could not restore the connection. This chat is being closed and its data wiped \u2014 start a new one to continue.","system")),this.onStatusChange("recovery_failed"),this._clearVerificationStates()}_stopAllTimers(){this._secureLog("info","Stopping all timers and cleanup scheduler"),this._maintenanceScheduler&&(clearInterval(this._maintenanceScheduler),this._maintenanceScheduler=null),this.stopHeartbeat?.(),this._resetReconnectState?.(),this._activeTimers&&(this._activeTimers.forEach(e=>{e&&(clearInterval(e),clearTimeout(e))}),this._activeTimers.clear()),this._fileTransferInitRetryTimers&&this._fileTransferInitRetryTimers.clear(),this._logCleanupInterval=null,this._secureLog("info","All timers stopped successfully")}waitForIceGathering(e=s.TIMEOUTS.ICE_GATHERING_TIMEOUT,t=s.TIMEOUTS.ICE_GATHERING_HARD_TIMEOUT){return new Promise(r=>{let i=this.peerConnection;if(!i){r(!1);return}if(i.iceGatheringState==="complete"){r(!0);return}let n=!1,a=null,o=null,c=()=>{try{let u=this.peerConnection?.localDescription?.sdp;return u?this._summarizeIceCandidatesInSDP(u).total>0:!1}catch{return!1}},d=u=>{if(!n){n=!0,a&&(clearTimeout(a),this._untrackActiveTimer?.(a)),o&&(clearTimeout(o),this._untrackActiveTimer?.(o));try{i.removeEventListener("icegatheringstatechange",h)}catch{}r(u)}},h=()=>{this.peerConnection?.iceGatheringState==="complete"&&d(!0)};i.addEventListener("icegatheringstatechange",h),a=setTimeout(()=>{c()&&d(!1)},e),this._trackActiveTimer?.(a),o=setTimeout(()=>d(!1),Math.max(t,e)),this._trackActiveTimer?.(o)})}retryConnection(){this._secureLog("info","Retrying connection",{attempt:this.connectionAttempts,maxAttempts:this.maxConnectionAttempts}),this.onStatusChange("retrying")}isConnected(){let e=!!this.dataChannel,r=this.dataChannel?.readyState==="open",i=this.isVerified,n=this.peerConnection?.connectionState;return this.dataChannel&&this.dataChannel.readyState==="open"&&this.isVerified}getConnectionInfo(){return{fingerprint:this.keyFingerprint,isConnected:this.isConnected(),isVerified:this.isVerified,connectionState:this.peerConnection?.connectionState,iceConnectionState:this.peerConnection?.iceConnectionState,verificationCode:this.verificationCode}}handleUnexpectedDisconnect(){this.sendDisconnectNotification(),this.isVerified=!1,this.disconnectNotificationSent||(this.disconnectNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Connection lost. Attempting to reconnect...","system")),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"connection_lost",timestamp:Date.now()}}))}sendDisconnectNotification(){try{if(this.dataChannel&&this.dataChannel.readyState==="open"){let e={type:"peer_disconnect",timestamp:Date.now(),reason:this.intentionalDisconnect?"user_disconnect":"connection_lost"};for(let t=0;t<3;t++)try{this.dataChannel.send(JSON.stringify(e)),window.EnhancedSecureCryptoUtils.secureLog.log("info","Disconnect notification sent",{reason:e.reason,attempt:t+1});break}catch(r){t===2&&window.EnhancedSecureCryptoUtils.secureLog.log("error","Failed to send disconnect notification",{error:r.message})}}}catch(e){window.EnhancedSecureCryptoUtils.secureLog.log("error","Could not send disconnect notification",{error:e.message})}}attemptReconnection(){return!this.isVerified||this.dataChannel?.readyState!=="open"?(this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Unable to reconnect. A new connection is required.","system")),!1):(this._resetReconnectState(),this.reconnectionFailedNotificationSent=!1,this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting"),this._attemptIceRestart(),!0)}handlePeerDisconnectNotification(e){let t=e.reason||"unknown",r=t==="user_disconnect"?"manually disconnected.":"connection lost.";this.peerDisconnectNotificationSent||(this.peerDisconnectNotificationSent=!0,this.deliverMessageToUI(`Peer ${r}`,"system")),this.onStatusChange("peer_disconnected"),this.intentionalDisconnect=!1,this.isVerified=!1,this.stopHeartbeat(),this.onKeyExchange(""),this.onVerificationRequired(""),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:t,timestamp:Date.now()}})),this._peerDisconnectCleanupTimer||(this._peerDisconnectCleanupTimer=this._trackActiveTimer(setTimeout(()=>{let i=this._peerDisconnectCleanupTimer;this._peerDisconnectCleanupTimer=null,this._untrackActiveTimer(i),this._sessionAlive!==!1&&this.disconnect()},2e3))),window.EnhancedSecureCryptoUtils.secureLog.log("info","Peer disconnect notification processed",{reason:t})}disconnect(){try{this._sessionAlive=!1;try{this._stopAdaptation?.()}catch{}try{this._stopLocalMediaPermanently?.()}catch{}this._callAudioSender=null,this._callVideoSender=null,this._callGroupContext=null,this._externalMediaStream=null,this._callStateListeners?.clear?.(),this.intentionalDisconnect=!0,window.EnhancedSecureCryptoUtils.secureLog.log("info","Starting intentional disconnect"),this.sendDisconnectNotification(),this._teardownRecoveryLifecycleListeners?.(),this._stopAllTimers(),this._peerDisconnectCleanupTimer=null,this.stopHeartbeat(),this.stopFakeTrafficGeneration();for(let e of this.decoyTimers.entries())clearTimeout(e[1]);this.decoyTimers.clear(),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null);for(let e of this.decoyChannels.values())e.readyState==="open"&&e.close();this.decoyChannels.clear(),this.heartbeatChannel&&(this.heartbeatChannel.close(),this.heartbeatChannel=null),this.isVerified=!1,this.processedMessageIds.clear(),this.messageCounter=0,this.packetBuffer.clear(),this.chunkQueue=[],this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this._secureCleanupCryptographicMaterials(),this.keyVersions.clear(),this.oldKeys.clear(),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.replayWindow.clear(),this._clearVerificationStates(),this.securityFeatures={hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0},this.dataChannel&&(this.dataChannel.close(),this.dataChannel.onopen=null,this.dataChannel.onclose=null,this.dataChannel.onmessage=null,this.dataChannel.onerror=null,this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection.onconnectionstatechange=null,this.peerConnection.ondatachannel=null,this.peerConnection=null),this.messageQueue&&this.messageQueue.length>0&&(this.messageQueue.forEach((e,t)=>{this._secureWipeMemory(e,`messageQueue[${t}]`)}),this.messageQueue=[]),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during disconnect",{errorType:e?.constructor?.name||"Unknown"})}),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"user_disconnect",timestamp:Date.now()}})),this._dispatchAppEvent?.(new CustomEvent("connection-cleaned",{detail:{timestamp:Date.now(),reason:"user_cleanup"}})),this.onStatusChange("disconnected"),this.onKeyExchange(""),this.onVerificationRequired(""),this._secureLog("info","Connection securely cleaned up with complete memory wipe")}catch(e){this._secureLog("error","\u274C Error during enhanced disconnect:",{errorType:e?.constructor?.name||"Unknown"})}finally{this.intentionalDisconnect=!1}}async sendFile(e,t={}){if(this._enforceVerificationGate("sendFile"),!this.isConnected())throw new Error("Connection not ready for file transfer. Please ensure the connection is established.");if(!this.fileTransferSystem&&(this.initializeFileTransfer(),await new Promise(r=>setTimeout(r,500)),!this.fileTransferSystem))throw new Error("File transfer system could not be initialized. Please try reconnecting.");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready. Please wait for connection to be fully established.");try{return await this.fileTransferSystem.sendFile(e,t)}catch(r){throw this._secureLog("error","File transfer error:",{errorType:r?.constructor?.name||"Unknown"}),r.message.includes("Connection not ready")?new Error("Connection not ready for file transfer. Check connection status."):r.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):r.message.includes("Transfer timeout")?new Error("File transfer timeout. Check connection and try again."):r}}getFileTransfers(){if(!this.fileTransferSystem)return{sending:[],receiving:[]};try{let e=[],t=[];return typeof this.fileTransferSystem.getActiveTransfers=="function"?e=this.fileTransferSystem.getActiveTransfers():this._secureLog("warn","getActiveTransfers method not available in file transfer system"),typeof this.fileTransferSystem.getReceivingTransfers=="function"?t=this.fileTransferSystem.getReceivingTransfers():this._secureLog("warn","getReceivingTransfers method not available in file transfer system"),{sending:e||[],receiving:t||[]}}catch(e){return this._secureLog("error","Error getting file transfers:",{errorType:e?.constructor?.name||"Unknown"}),{sending:[],receiving:[]}}}getFileTransferStatus(){if(!this.fileTransferSystem)return{initialized:!1,status:"not_initialized",message:"File transfer system not initialized"};let e=this.fileTransferSystem.getActiveTransfers(),t=this.fileTransferSystem.getReceivingTransfers();return{initialized:!0,status:"ready",activeTransfers:e.length,receivingTransfers:t.length,totalTransfers:e.length+t.length}}cancelFileTransfer(e){return this.fileTransferSystem?this.fileTransferSystem.cancelTransfer(e):!1}cleanupFileTransferSystem(){return this.fileTransferSystem?(this._secureLog("info","\u{1F9F9} Force cleaning up file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,!0):!1}reinitializeFileTransfer(){try{return this.fileTransferSystem&&this.fileTransferSystem.cleanup(),this.initializeFileTransfer(),!0}catch(e){return this._secureLog("error","Failed to reinitialize file transfer system:",{errorType:e?.constructor?.name||"Unknown"}),!1}}setFileTransferCallbacks(e,t,r,i=null){this.onFileProgress=e,this.onFileReceived=t,this.onFileError=r,this.onIncomingFileRequest=i,this.fileTransferSystem&&(this.fileTransferSystem.onProgress=e,this.fileTransferSystem.onFileReceived=t,this.fileTransferSystem.onError=r,this.fileTransferSystem.onIncomingFileRequest=i)}getPendingIncomingFiles(){return this.fileTransferSystem?this.fileTransferSystem.getPendingIncomingTransfers():[]}async acceptIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.acceptIncomingFile(e):!1}async rejectIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.rejectIncomingFile(e):!1}async getReceivedFileObjectURL(e){return this.fileTransferSystem?this.fileTransferSystem.getObjectURL(e):null}revokeReceivedFileObjectURL(e){this.fileTransferSystem&&this.fileTransferSystem.revokeObjectURL(e)}async handleSessionActivation(e){try{this.currentSession=e;let t=!!(this.encryptionKey&&this.macKey);e.sessionId&&this.onStatusChange("connected"),setTimeout(()=>{try{this.initializeFileTransfer()}catch(i){this._secureLog("warn","File transfer initialization failed during session activation:",{details:i.message})}},1e3),this.fileTransferSystem&&this.isConnected()&&typeof this.fileTransferSystem.onSessionUpdate=="function"&&this.fileTransferSystem.onSessionUpdate({keyFingerprint:this.keyFingerprint,sessionSalt:this.sessionSalt,hasMacKey:!!this.macKey})}catch(t){this._secureLog("error","Failed to handle session activation:",{errorType:t?.constructor?.name||"Unknown"})}}checkFileTransferReadiness(){let e={hasFileTransferSystem:!!this.fileTransferSystem,hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,ready:!1};return e.ready=e.hasFileTransferSystem&&e.hasDataChannel&&e.dataChannelState==="open"&&e.isConnected&&e.isVerified,e}forceReinitializeFileTransfer(){try{return this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),setTimeout(()=>{this.initializeFileTransfer()},500),!0}catch(e){return this._secureLog("error","Failed to force reinitialize file transfer:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferDiagnostics(){let e={timestamp:new Date().toISOString(),webrtcManager:{hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,isInitiator:this.isInitiator,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,hasSessionSalt:!!this.sessionSalt},fileTransferSystem:null,globalState:{fileTransferActive:this._fileTransferActive||!1,hasFileTransferSystem:!!this.fileTransferSystem,fileTransferSystemType:this.fileTransferSystem?"EnhancedSecureFileTransfer":"none"}};if(this.fileTransferSystem)try{e.fileTransferSystem=this.fileTransferSystem.getSystemStatus()}catch(t){e.fileTransferSystem={error:t.message}}return e}getSupportedFileTypes(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getSupportedFileTypes()}catch(e){return{error:e.message}}}validateFile(e){if(!this.fileTransferSystem)return{isValid:!1,errors:["File transfer system not initialized"],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"};try{return this.fileTransferSystem.validateFile(e)}catch(t){return{isValid:!1,errors:[t.message],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"}}}getFileTypeInfo(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getFileTypeInfo()}catch(e){return{error:e.message}}}async forceInitializeFileTransfer(e={}){let t=new AbortController,{signal:r=t.signal,timeout:i=6e3}=e;r&&r!==t.signal&&r.addEventListener("abort",()=>t.abort());try{if(!this.isVerified)throw new Error("Connection not verified");if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready");this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this.initializeFileTransfer();let n=0,a=50,o=100,c=a*o,d=new Promise((h,u)=>{let m=()=>{if(t.signal.aborted){u(new Error("Operation cancelled"));return}if(this.fileTransferSystem){h(!0);return}if(n>=a){u(new Error(`Initialization timeout after ${c}ms`));return}n++,setTimeout(m,o)};m()});if(await Promise.race([d,new Promise((h,u)=>setTimeout(()=>u(new Error(`Global timeout after ${i}ms`)),i))]),this.fileTransferSystem)return!0;throw new Error("Force initialization timeout")}catch(n){return n.name==="AbortError"||n.message.includes("cancelled")?(this._secureLog("info","File transfer initialization cancelled by user"),{cancelled:!0}):(this._secureLog("error","Force file transfer initialization failed:",{errorType:n?.constructor?.name||"Unknown",message:n.message,attempts}),{error:n.message,attempts})}}cancelFileTransferInitialization(){try{return this.fileTransferSystem?(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,this._fileTransferActive=!1,this._secureLog("info","File transfer initialization cancelled"),!0):!1}catch(e){return this._secureLog("error","Failed to cancel file transfer initialization:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferSystemStatus(){if(!this.fileTransferSystem)return{available:!1,status:"not_initialized"};try{let e=this.fileTransferSystem.getSystemStatus();return{available:!0,status:e.status||"unknown",activeTransfers:e.activeTransfers||0,receivingTransfers:e.receivingTransfers||0,systemType:"EnhancedSecureFileTransfer"}}catch(e){return this._secureLog("error","Failed to get file transfer system status:",{errorType:e?.constructor?.name||"Unknown"}),{available:!1,status:"error",error:e.message}}}_validateNestedEncryptionSecurity(){if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey)try{let e=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest1"),t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest2");return e.every((i,n)=>i===t[n])?(this._secureLog("error","CRITICAL: Nested encryption security validation failed - IVs are identical!"),!1):this._getIVTrackingStats().totalIVs<2?(this._secureLog("error","CRITICAL: IV tracking system not working properly"),!1):(this._secureLog("info","Nested encryption security validation passed - secure IV generation working"),!0)}catch(e){return this._secureLog("error","CRITICAL: Nested encryption security validation failed:",{errorType:e.constructor.name,errorMessage:e.message}),!1}return!0}getCallState(){return{...this.callState}}addCallStateListener(e){return typeof e!="function"?()=>{}:(this._callStateListeners.add(e),()=>this._callStateListeners.delete(e))}removeCallStateListener(e){this._callStateListeners.delete(e)}setCallGroupContext(e){this._callGroupContext=typeof e=="string"&&e?e:null,this._updateCallState({}),this._callGroupContext&&this._pendingCallOffer&&this.callState.phase==="incoming"&&this.acceptCall().catch(t=>{this._secureLog("warn","\u26A0\uFE0F Failed to answer a group call leg that was already ringing",{errorType:t?.constructor?.name})})}setExternalMediaStream(e){this._externalMediaStream=e||null}_usingExternalMedia(){return!!this._externalMediaStream&&this.localMediaStream===this._externalMediaStream}getRemoteMediaStream(){return this.remoteMediaStream}getLocalMediaStream(){return this.localMediaStream}_refreshRemoteStream(){let e=this.peerConnection;if(!e||typeof e.getReceivers!="function")return;let t=e.getReceivers().map(n=>n.track).filter(n=>n&&(n.kind==="audio"||n.kind==="video")&&n.readyState==="live"),r=this.remoteMediaStream?this.remoteMediaStream.getTracks():[];r.length===t.length&&r.every(n=>t.includes(n))||(this.remoteMediaStream=new MediaStream(t)),this._updateCallState({remoteHasVideo:t.some(n=>n.kind==="video")})}_scheduleRemoteRefresh(){this._refreshRemoteStream(),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},300),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},1200)}_updateCallState(e){this.callState={...this.callState,...e,groupCallId:this._callGroupContext};let t=this.getCallState();t.phase==="active"?this._startAdaptation():t.phase==="idle"&&this._stopAdaptation();try{this.onCallStateChanged?.(t)}catch{}for(let r of this._callStateListeners)try{r(t)}catch{}if(typeof document<"u")try{this._dispatchAppEvent?.(new CustomEvent("securebit-call-state",{detail:{managerId:this._managerId||null,state:t}}))}catch{}}_callCanStart(){let e=typeof this.isConnected=="function"?this.isConnected():!1,t=this.dataChannel&&this.dataChannel.readyState==="open";return!!(e&&t&&this.isVerified&&!this.isReconnecting())}async _sendCallSignal(e,t){return await this.sendSystemMessage({type:e,...t})}_audioConstraints(){return{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}}_videoConstraints(){return{facingMode:this._callFacingMode,width:{ideal:1280},height:{ideal:720}}}async _acquireLocalMedia(e){let t=this._externalMediaStream||await navigator.mediaDevices.getUserMedia({audio:this._audioConstraints(),video:e?this._videoConstraints():!1});this.localMediaStream=t;let r=this.peerConnection,i=t.getAudioTracks()[0]||null,n=t.getVideoTracks()[0]||null;return i&&(this._callAudioSender?await this._callAudioSender.replaceTrack(i):this._callAudioSender=r.addTrack(i,t)),n&&(this._callVideoSender?await this._callVideoSender.replaceTrack(n):this._callVideoSender=r.addTrack(n,t)),this._applyCallCodecPrefs(),t}_stopLocalMediaPermanently(){try{if(this.localMediaStream&&!this._usingExternalMedia())for(let e of this.localMediaStream.getTracks())try{e.stop()}catch{}}catch{}this.localMediaStream=null}_applyCallCodecPrefs(){try{let e=this.peerConnection?.getTransceivers?.()||[],t=e.find(i=>i.sender&&i.sender===this._callAudioSender);t&&Ji(t);let r=e.find(i=>i.sender&&i.sender===this._callVideoSender);r&&sn(r)}catch{}}_mungeCallSdp(e){try{let t=Cr(e,st.opusFmtp);return t=Qi(t,qi),t}catch{return e}}async _setLocalMunged(e){let t=this.peerConnection;try{await t.setLocalDescription({type:e.type,sdp:this._mungeCallSdp(e.sdp)});return}catch{try{await t.setLocalDescription({type:e.type,sdp:Cr(e.sdp,st.opusFmtp)});return}catch{await t.setLocalDescription(e)}}}async _applyCallSenderParams(){try{this._callAudioSender&&await Zi(this._callAudioSender,{}),this._callVideoSender&&await an(this._callVideoSender,{})}catch{}}_startAdaptation(){if(!(this._adaptationController||!this.peerConnection))try{this._adaptationController=new Nt(this.peerConnection,{getVideoSender:()=>this._callVideoSender,ceilingBitrate:15e5,onQuality:e=>{e!==this.callState.quality&&this._updateCallState({quality:e})}}),this._adaptationController.start()}catch{}}_stopAdaptation(){if(this._adaptationController){try{this._adaptationController.stop()}catch{}this._adaptationController=null}}_notifyCallMediaError(e,t){let r=e?.name||"",i=t?"camera/microphone":"microphone",n,a;r==="NotAllowedError"?(a="permission_denied",n=`\u26A0\uFE0F Call not started \u2014 ${i} access is blocked. Allow it for this site in the browser, and enable your browser under System Settings \u2192 Privacy & Security \u2192 ${t?"Camera/Microphone":"Microphone"}, then try again.`):r==="NotFoundError"||r==="OverconstrainedError"?(a="device_not_found",n=`\u26A0\uFE0F Call not started \u2014 no ${i} found on this device.`):r==="NotReadableError"||r==="AbortError"?(a="device_busy",n=`\u26A0\uFE0F Call not started \u2014 your ${i} is in use by another app. Close it and try again.`):(a="media_failed",n=`\u26A0\uFE0F Call not started \u2014 could not access ${i}${r?" ("+r+")":""}.`);try{this.deliverMessageToUI(n,"system")}catch{}return a}async startCall(e=!1){if(!this._callCanStart())throw this._updateCallState({error:"not_verified"}),new Error("Calls require a connected, SAS-verified session.");if(this.callState.active){this._secureLog("warn","\u26A0\uFE0F startCall ignored \u2014 a call is already active");return}let t=crypto?.randomUUID?.()||String(Date.now())+Math.random().toString(36).slice(2);this._updateCallState({active:!0,phase:"outgoing",withVideo:e,callId:t,micEnabled:!0,cameraEnabled:e,remoteHasVideo:!1,error:null});try{await this._acquireLocalMedia(e),this._callMakingOffer=!0;let r=await this.peerConnection.createOffer();await this._setLocalMunged(r),this._callMakingOffer=!1,await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:t,withVideo:e,sdp:this.peerConnection.localDescription.sdp})}catch(r){this._callMakingOffer=!1,this._secureLog("error","\u274C startCall failed",{errorType:r?.constructor?.name});let i=this._notifyCallMediaError(r,e);throw await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:i}),r}}async _onIncomingCallOffer(e){if(this.callState.active&&(this.callState.phase==="active"||this.callState.phase==="connecting")){await this._answerCallOffer(e,!0),e.withVideo&&this._updateCallState({withVideo:!0});return}this._pendingCallOffer=e,this._updateCallState({active:!0,phase:"incoming",withVideo:!!e.withVideo,callId:e.callId,remoteHasVideo:!!e.withVideo,error:null}),this._callGroupContext&&await this.acceptCall()}async _answerCallOffer(e,t=!1){await this.peerConnection.setRemoteDescription({type:"offer",sdp:e.sdp}),t||await this._acquireLocalMedia(!!e.withVideo);let r=await this.peerConnection.createAnswer();await this._setLocalMunged(r),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_ANSWER,{callId:e.callId,sdp:this.peerConnection.localDescription.sdp})}async acceptCall(){let e=this._pendingCallOffer;if(e){this._pendingCallOffer=null,this._updateCallState({phase:"connecting",cameraEnabled:!!e.withVideo});try{await this._answerCallOffer(e,!1),this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(t){this._secureLog("error","\u274C acceptCall failed",{errorType:t?.constructor?.name});let r=this._notifyCallMediaError(t,!!e.withVideo);try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:e.callId})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:r})}}}async declineCall(){let e=this.callState.callId;this._pendingCallOffer=null,await this._sendCallSignal(s.MESSAGE_TYPES.CALL_DECLINE,{callId:e}),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1})}async endCall(e=!0){let t=this.callState.callId;if(e&&t)try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:t})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,micEnabled:!0,cameraEnabled:!1,remoteHasVideo:!1,callId:null,quality:null})}async _teardownCallMedia(){this._stopAdaptation();let e=this.peerConnection;try{if(this.localMediaStream&&!this._usingExternalMedia())for(let t of this.localMediaStream.getTracks())try{t.stop()}catch{}if(e)for(let t of[this._callAudioSender,this._callVideoSender].filter(Boolean))try{await t.replaceTrack(null)}catch{}}catch{}this.localMediaStream=null,this.remoteMediaStream=null,this._callMakingOffer=!1;try{this.peerConnection&&(this.peerConnection.signalingState==="have-local-offer"||this.peerConnection.signalingState==="have-local-pranswer")&&await this.peerConnection.setLocalDescription({type:"rollback"})}catch{}}setMicEnabled(e){this.localMediaStream&&this.localMediaStream.getAudioTracks().forEach(t=>{t.enabled=e}),this._updateCallState({micEnabled:e})}toggleMic(){this.setMicEnabled(!this.callState.micEnabled)}async setCameraEnabled(e){if(!e){this.localMediaStream&&this.localMediaStream.getVideoTracks().forEach(r=>{r.enabled=!1}),this._updateCallState({cameraEnabled:!1});return}let t=this.localMediaStream?.getVideoTracks?.()||[];if(t.length){t.forEach(r=>{r.enabled=!0}),this._updateCallState({cameraEnabled:!0,withVideo:!0});return}await this.upgradeToVideo()}async toggleCamera(){await this.setCameraEnabled(!this.callState.cameraEnabled)}async upgradeToVideo(){if(this.localMediaStream)try{let t=(await navigator.mediaDevices.getUserMedia({video:this._videoConstraints()})).getVideoTracks()[0];if(!t)return;await this.addVideoTrack(t)}catch(e){this._secureLog("error","\u274C upgradeToVideo failed",{errorType:e?.constructor?.name}),this._updateCallState({cameraEnabled:!1,error:"camera_failed"})}}async addVideoTrack(e){!e||!this.localMediaStream||!this.peerConnection||(this.localMediaStream.getVideoTracks().includes(e)||this.localMediaStream.addTrack(e),this._callVideoSender?await this._callVideoSender.replaceTrack(e):this._callVideoSender=this.peerConnection.addTrack(e,this.localMediaStream),this._applyCallCodecPrefs(),this._updateCallState({cameraEnabled:!0,withVideo:!0}),await this._renegotiateCall())}async replaceVideoTrack(e){!e||!this._callVideoSender||await this._callVideoSender.replaceTrack(e)}async switchCamera(){if(!(!this._callVideoSender||!this.localMediaStream)){this._callFacingMode=this._callFacingMode==="user"?"environment":"user";try{let t=(await navigator.mediaDevices.getUserMedia({video:{facingMode:this._callFacingMode}})).getVideoTracks()[0],r=this.localMediaStream.getVideoTracks()[0];if(r){this.localMediaStream.removeTrack(r);try{r.stop()}catch{}}this.localMediaStream.addTrack(t),await this._callVideoSender.replaceTrack(t)}catch(e){this._secureLog("warn","\u26A0\uFE0F switchCamera failed",{errorType:e?.constructor?.name})}}}async _renegotiateCall(){if(!this._callMakingOffer)try{this._callMakingOffer=!0;let e=await this.peerConnection.createOffer();await this._setLocalMunged(e),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:this.callState.callId,withVideo:this.callState.withVideo,sdp:this.peerConnection.localDescription.sdp})}finally{this._callMakingOffer=!1}}async _handleCallSignal(e,t){let r=s.MESSAGE_TYPES;switch(e){case r.CALL_OFFER:{await this._onIncomingCallOffer(t);return}case r.CALL_ANSWER:{try{this.peerConnection.signalingState==="have-local-offer"&&await this.peerConnection.setRemoteDescription({type:"answer",sdp:t.sdp}),this.callState.phase==="outgoing"&&this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(i){this._secureLog("warn","\u26A0\uFE0F Failed to apply call answer",{errorType:i?.constructor?.name})}return}case r.CALL_ICE:{try{t.candidate&&await this.peerConnection.addIceCandidate(t.candidate)}catch{}return}case r.CALL_DECLINE:{await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1,error:"declined"});return}case r.CALL_END:{await this.endCall(!1);return}default:return}}},Gt=class{constructor(e=null){this._keyStore=new WeakMap,this._keyMetadata=new Map,this._keyReferences=new Map,this._masterKeyManager=e||new jt,this._persistentStorage=new Br(this._masterKeyManager),this._setupMasterKeyCallbacks(),setTimeout(()=>{this.validateStorageIntegrity()||this._secureLog("error","CRITICAL: Key storage integrity check failed")},100)}_secureLog(e,t,r={}){try{let i=typeof window<"u"&&window.EnhancedSecureCryptoUtils?.secureLog||null;if(i&&typeof i.log=="function"){i.log(e,`[KeyStorage] ${t}`,r);return}}catch{}e==="error"?console.error(`[KeyStorage] ${t}`):e==="warn"&&console.warn(`[KeyStorage] ${t}`)}_setupMasterKeyCallbacks(){this._masterKeyManager.setPasswordRequiredCallback((e,t)=>{this._secureLog("error","Master key password requested but no password UI is installed",{isRetry:!!e}),t(null)}),this._masterKeyManager.setSessionExpiredCallback(e=>{console.warn(`Master key session expired: ${e}`)}),this._masterKeyManager.setUnlockedCallback(()=>{console.log("Master key unlocked successfully")})}setPasswordCallback(e){this._masterKeyManager.setPasswordRequiredCallback(e)}setSessionExpiredCallback(e){this._masterKeyManager.setSessionExpiredCallback(e)}async _ensureMasterKeyUnlocked(){this._masterKeyManager.isUnlocked()||await this._masterKeyManager.unlock()}async storeKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");try{return t.extractable?(await this._persistentStorage.storeExtractableKey(e,t,r),this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0,encrypted:!0}),!0):(this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!1,persistent:!1,encrypted:!1}),!0)}catch(i){return this._secureLog("error","Failed to store key securely",{errorType:i?.constructor?.name||"Unknown"}),!1}}async retrieveKey(e){try{if(this._keyReferences.has(e)){let r=this._keyMetadata.get(e);return r&&(r.lastAccessed=Date.now()),this._keyReferences.get(e)}let t=await this._persistentStorage.retrieveKey(e);if(t){this._keyReferences.set(e,t);let r=this._keyMetadata.get(e);return this._keyMetadata.set(e,{...r,lastAccessed:Date.now(),restoredFromPersistent:!0}),t}return null}catch(t){return this._secureLog("error","Failed to retrieve key",{errorType:t?.constructor?.name||"Unknown"}),null}}async _encryptKeyData(e){let t=typeof e=="object"?JSON.stringify(e):e,i=new TextEncoder().encode(t);await this._ensureMasterKeyUnlocked();let{encryptedData:n,iv:a}=await this._masterKeyManager.encryptBytes(i),o=new Uint8Array(a.length+n.byteLength);return o.set(a,0),o.set(n,a.length),o}async _decryptKeyData(e){let t=e.slice(0,12),r=e.slice(12);await this._ensureMasterKeyUnlocked();let i=await this._masterKeyManager.decryptBytes(r,t),a=new TextDecoder().decode(i);try{return JSON.parse(a)}catch{return i}}async secureWipe(e){let t=this._keyReferences.get(e);t&&(this._keyStore.delete(t),this._keyReferences.delete(e),this._keyMetadata.delete(e)),await this._performNaturalCleanup()}async secureWipeAll(){try{await this._persistentStorage.clearAll()}catch(e){this._secureLog("error","Failed to clear persistent storage",{errorType:e?.constructor?.name||"Unknown"})}this._keyReferences.clear(),this._keyMetadata.clear(),this._keyStore=new WeakMap,await this._performNaturalCleanup()}validateStorageIntegrity(){let e=[];for(let[t,r]of this._keyMetadata.entries())r.extractable===!0&&r.encrypted!==!0&&e.push({keyId:t,type:"EXTRACTABLE_KEY_NOT_ENCRYPTED",metadata:r}),r.extractable===!1&&r.encrypted===!0&&e.push({keyId:t,type:"NON_EXTRACTABLE_KEY_ENCRYPTED",metadata:r});return e.length>0?(this._secureLog("error","Storage integrity violations detected",{violationCount:e.length}),!1):!0}async getStorageStats(){let e=await this._persistentStorage.getStorageStats();return{totalKeys:this._keyReferences.size,memoryKeys:this._keyReferences.size,persistentKeys:e.persistentKeys,metadata:Array.from(this._keyMetadata.entries()).map(([t,r])=>({id:t,created:r.created,lastAccessed:r.lastAccessed,age:Date.now()-r.created,persistent:r.persistent||!1})),persistent:e}}async listAllKeys(){try{let e=Array.from(this._keyMetadata.entries()).map(([i,n])=>({keyId:i,...n,location:"memory"})),r=(await this._persistentStorage.listStoredKeys()).map(i=>({...i,location:"persistent"}));return{memoryKeys:e,persistentKeys:r,totalCount:e.length+r.length}}catch(e){return this._secureLog("error","Failed to list keys",{errorType:e?.constructor?.name||"Unknown"}),{memoryKeys:[],persistentKeys:[],totalCount:0,error:e.message}}}async deleteKey(e){try{return this._keyReferences.delete(e),this._keyMetadata.delete(e),await this._persistentStorage.deleteKey(e),!0}catch(t){return this._secureLog("error","Failed to delete key",{errorType:t?.constructor?.name||"Unknown"}),!1}}},qt=class{constructor(e="SecureKeyStorage",t=1){this.dbName=e,this.version=t,this.db=null,this.KEYS_STORE="encrypted_keys",this.METADATA_STORE="key_metadata",this.SALT_STORE="master_salt"}async initialize(){return new Promise((e,t)=>{let r=indexedDB.open(this.dbName,this.version);r.onerror=()=>{t(new Error(`Failed to open IndexedDB: ${r.error}`))},r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=i=>{let n=i.target.result;if(!n.objectStoreNames.contains(this.KEYS_STORE)){let a=n.createObjectStore(this.KEYS_STORE,{keyPath:"keyId"});a.createIndex("timestamp","timestamp",{unique:!1}),a.createIndex("algorithm","algorithm",{unique:!1})}if(!n.objectStoreNames.contains(this.METADATA_STORE)){let a=n.createObjectStore(this.METADATA_STORE,{keyPath:"keyId"});a.createIndex("created","created",{unique:!1}),a.createIndex("lastAccessed","lastAccessed",{unique:!1})}n.objectStoreNames.contains(this.SALT_STORE)||n.createObjectStore(this.SALT_STORE,{keyPath:"id"})}})}async storeEncryptedKey(e,t,r,i,n,a,o={}){if(!this.db)throw new Error("Database not initialized");let c=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite"),d={keyId:e,encryptedData:Array.from(new Uint8Array(t)),iv:Array.from(new Uint8Array(r)),algorithm:i,usages:n,type:a},h={keyId:e,...o};return new Promise((u,m)=>{let y=c.objectStore(this.KEYS_STORE).put(d),b=c.objectStore(this.METADATA_STORE).put(h);c.oncomplete=()=>u(),c.onerror=()=>m(new Error(`Failed to store key: ${c.error}`))})}async getEncryptedKey(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.KEYS_STORE],"readonly").objectStore(this.KEYS_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>{let o=a.result;o&&(o.encryptedData=new Uint8Array(o.encryptedData),o.iv=new Uint8Array(o.iv)),i(o)},a.onerror=()=>n(new Error(`Failed to retrieve key: ${a.error}`))})}async updateKeyMetadata(e,t){if(!this.db)throw new Error("Database not initialized");let i=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((n,a)=>{let o=i.get(e);o.onsuccess=()=>{let c=o.result;if(c){Object.assign(c,t);let d=i.put(c);d.onsuccess=()=>n(),d.onerror=()=>a(new Error(`Failed to update metadata: ${d.error}`))}else a(new Error(`Key metadata not found: ${e}`))},o.onerror=()=>a(new Error(`Failed to get metadata: ${o.error}`))})}async getKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>i(a.result||null),a.onerror=()=>n(new Error(`Failed to get metadata: ${a.error}`))})}async putKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.put(e);a.onsuccess=()=>i(),a.onerror=()=>n(new Error(`Failed to store metadata: ${a.error}`))})}async deleteKey(e){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite");return new Promise((r,i)=>{let n=t.objectStore(this.KEYS_STORE).delete(e),a=t.objectStore(this.METADATA_STORE).delete(e);t.oncomplete=()=>r(),t.onerror=()=>i(new Error(`Failed to delete key: ${t.error}`))})}async listKeys(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((r,i)=>{let n=t.getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>i(new Error(`Failed to list keys: ${n.error}`))})}async storeMasterSalt(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.SALT_STORE],"readwrite").objectStore(this.SALT_STORE),i={id:"master_salt",salt:Array.from(new Uint8Array(e))};return new Promise((n,a)=>{let o=r.put(i);o.onsuccess=()=>n(),o.onerror=()=>a(new Error(`Failed to store salt: ${o.error}`))})}async getMasterSalt(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.SALT_STORE],"readonly").objectStore(this.SALT_STORE);return new Promise((r,i)=>{let n=t.get("master_salt");n.onsuccess=()=>{let a=n.result;r(a?new Uint8Array(a.salt):null)},n.onerror=()=>i(new Error(`Failed to retrieve salt: ${n.error}`))})}async clearAll(){if(!this.db)throw new Error("Database not initialized");let e=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE,this.SALT_STORE],"readwrite");return new Promise((t,r)=>{let i=e.objectStore(this.KEYS_STORE).clear(),n=e.objectStore(this.METADATA_STORE).clear(),a=e.objectStore(this.SALT_STORE).clear();e.oncomplete=()=>t(),e.onerror=()=>r(new Error(`Failed to clear database: ${e.error}`))})}close(){this.db&&(this.db.close(),this.db=null)}},Br=class{constructor(e,t=null){this._masterKeyManager=e,this._indexedDB=t||new qt,this._dbInitialized=!1,this._keyCache=new WeakMap,this._keyReferences=new Map}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}async _ensureMasterKeyUnlocked(){typeof this._masterKeyManager.isUnlocked=="function"&&!this._masterKeyManager.isUnlocked()&&await this._masterKeyManager.unlock()}async storeExtractableKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");if(!t.extractable)throw new Error("Key must be extractable for persistent storage");try{await this._ensureDBInitialized();let i=await crypto.subtle.exportKey("jwk",t),{encryptedData:n,iv:a}=await this._encryptKeyData(i),o=await this._encryptMetadata({...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0});await this._indexedDB.storeEncryptedKey(e,n,a,t.algorithm,t.usages,t.type,o);let c=await this._importAsNonExtractable(i,t.algorithm,t.usages);return this._keyReferences.set(e,c),!0}catch(i){throw new Error(`Failed to store extractable key: ${i.message}`)}}async retrieveKey(e){try{if(this._keyReferences.has(e))return this._keyReferences.get(e);await this._ensureDBInitialized();let t=await this._indexedDB.getEncryptedKey(e);if(!t)return null;let r=await this._decryptKeyData(t.encryptedData,t.iv),i=await this._importAsNonExtractable(r,t.algorithm,t.usages);return this._keyReferences.set(e,i),await this._updateEncryptedMetadata(e,{lastAccessed:Date.now()}),i}catch(t){throw new Error(`Failed to retrieve key: ${t.message}`)}}async deleteKey(e){try{return await this._ensureDBInitialized(),await this._indexedDB.deleteKey(e),this._keyReferences.delete(e),!0}catch(t){throw new Error(`Failed to delete key: ${t.message}`)}}async listStoredKeys(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys(),t=[];for(let r of e){let i=await this._readMetadataWithMigration(r);i&&t.push({keyId:r.keyId,...i})}return t}catch(e){throw new Error(`Failed to list keys: ${e.message}`)}}async clearAll(){try{return await this._ensureDBInitialized(),await this._indexedDB.clearAll(),this._keyReferences.clear(),!0}catch(e){throw new Error(`Failed to clear storage: ${e.message}`)}}async _encryptKeyData(e){let t=JSON.stringify(e),r=new TextEncoder().encode(t);return await this._ensureMasterKeyUnlocked(),await this._masterKeyManager.encryptBytes(r)}async _decryptKeyData(e,t){await this._ensureMasterKeyUnlocked();let r=await this._masterKeyManager.decryptBytes(e,t),i=new TextDecoder().decode(r);return JSON.parse(i)}async _encryptMetadata(e){let t=new TextEncoder().encode(JSON.stringify(e));await this._ensureMasterKeyUnlocked();let{encryptedData:r,iv:i}=await this._masterKeyManager.encryptBytes(t);return{metadataVersion:1,encryptedMetadata:Array.from(r),metadataIv:Array.from(i)}}async _decryptMetadataRecord(e){if(!e?.encryptedMetadata||!e?.metadataIv)throw new Error("Encrypted metadata missing");await this._ensureMasterKeyUnlocked();let t=await this._masterKeyManager.decryptBytes(new Uint8Array(e.encryptedMetadata),new Uint8Array(e.metadataIv));return JSON.parse(new TextDecoder().decode(t))}async _readMetadataWithMigration(e){if(!e)return null;if(e.encryptedMetadata)try{return await this._decryptMetadataRecord(e)}catch{return null}let{keyId:t,...r}=e,i={keyId:t,...await this._encryptMetadata(r)};return await this._indexedDB.putKeyMetadataRecord(i),r}async _updateEncryptedMetadata(e,t){let r=await this._indexedDB.getKeyMetadataRecord(e);if(!r)throw new Error(`Key metadata not found: ${e}`);let i=await this._readMetadataWithMigration(r);if(!i)throw new Error(`Key metadata corrupted: ${e}`);await this._indexedDB.putKeyMetadataRecord({keyId:e,...await this._encryptMetadata({...i,...t})})}async _importAsNonExtractable(e,t,r){return await crypto.subtle.importKey("jwk",e,t,!1,r)}async getStorageStats(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys();return{totalKeys:e.length,memoryKeys:this._keyReferences.size,persistentKeys:e.length,lastAccessed:e.reduce((t,r)=>Math.max(t,r.lastAccessed||0),0)}}catch(e){return{totalKeys:0,memoryKeys:this._keyReferences.size,persistentKeys:0,lastAccessed:0,error:e.message}}}},jt=class{constructor(e=null){this._keyHandle=null,this._isUnlocked=!1,this._sessionTimeout=null,this._lastActivity=null,this._sessionTimeoutMs=3600*1e3,this._inactivityTimeoutMs=1800*1e3,this._pbkdf2Iterations=31e4,this._saltSize=32,this._indexedDB=e||new qt,this._dbInitialized=!1,this._onPasswordRequired=null,this._onSessionExpired=null,this._onUnlocked=null}setPasswordRequiredCallback(e){this._onPasswordRequired=e}setSessionExpiredCallback(e){this._onSessionExpired=e}setUnlockedCallback(e){this._onUnlocked=e}_setupEventListeners(){typeof document<"u"&&(document.addEventListener("visibilitychange",()=>{document.hidden?this._handleFocusOut():this._handleFocusIn()}),window.addEventListener("blur",()=>this._handleFocusOut()),window.addEventListener("focus",()=>this._handleFocusIn()),["mousedown","mousemove","keypress","scroll","touchstart"].forEach(e=>{document.addEventListener(e,()=>this._updateActivity(),{passive:!0})}))}_handleFocusOut(){this._isUnlocked&&this._startInactivityTimer(this._inactivityTimeoutMs)}_handleFocusIn(){this._isUnlocked&&this._resetSessionTimer()}_updateActivity(){this._lastActivity=Date.now(),this._isUnlocked&&this._resetSessionTimer()}_startSessionTimer(){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("timeout")},this._sessionTimeoutMs)}_startInactivityTimer(e){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("inactivity")},e)}_resetSessionTimer(){this._isUnlocked&&this._startSessionTimer()}_clearTimers(){this._sessionTimeout&&(clearTimeout(this._sessionTimeout),this._sessionTimeout=null)}_expireSession(e="unknown"){this._isUnlocked&&(this._secureWipeMasterKey(),this._isUnlocked=!1,this._onSessionExpired&&this._onSessionExpired(e))}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}_generateSalt(){return crypto.getRandomValues(new Uint8Array(this._saltSize))}async _getOrCreateSalt(){await this._ensureDBInitialized();let e=await this._indexedDB.getMasterSalt();return e||(e=this._generateSalt(),await this._indexedDB.storeMasterSalt(e)),e}async _deriveKeyFromPassword(e,t){try{let r=await crypto.subtle.importKey("raw",new TextEncoder().encode(e),"PBKDF2",!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:this._pbkdf2Iterations,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,["encrypt","decrypt","wrapKey","unwrapKey"])}catch(r){throw new Error(`Key derivation failed: ${r.message}`)}}async _requestPassword(e=!1){if(!this._onPasswordRequired)throw new Error("Password callback not set");return new Promise((t,r)=>{this._onPasswordRequired(e,i=>{i?t(i):r(new Error("Password not provided"))})})}async unlock(e=null){try{e||(e=await this._requestPassword(!1));let t=await this._getOrCreateSalt();return this._keyHandle=await this._deriveKeyFromPassword(e,t),this._isUnlocked=!0,this._lastActivity=Date.now(),this._startSessionTimer(),e=null,this._onUnlocked&&this._onUnlocked(),{success:!0}}catch(t){throw e=null,t}}lock(){this._expireSession("manual")}async encryptBytes(e){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let t=crypto.getRandomValues(new Uint8Array(12)),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return{encryptedData:new Uint8Array(r),iv:t}}async decryptBytes(e,t){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let r=await crypto.subtle.decrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return new Uint8Array(r)}isUnlocked(){return this._isUnlocked&&this._keyHandle!==null}getSessionStatus(){return{isUnlocked:this._isUnlocked,lastActivity:this._lastActivity,sessionTimeoutMs:this._sessionTimeoutMs,inactivityTimeoutMs:this._inactivityTimeoutMs}}_secureWipeMasterKey(){this._keyHandle&&(this._keyHandle=null),this._clearTimers()}destroy(){this._secureWipeMasterKey(),this._isUnlocked=!1,typeof document<"u"&&(document.removeEventListener("visibilitychange",this._handleFocusOut),window.removeEventListener("blur",this._handleFocusOut),window.removeEventListener("focus",this._handleFocusIn))}};var $n=wi(Pn());var Fn="6.8.15";var Hr=()=>{if(Ke.length<2)return null;let[s,e]=React.useState(!1),t=React.useRef(null),r=typeof window<"u"?window.location.pathname:"/",i=Gi({pathname:r,active:Ge()}),n=i.find(c=>c.isCurrent)||i[0];React.useEffect(()=>{if(!s)return;let c=h=>{t.current&&!t.current.contains(h.target)&&e(!1)},d=h=>{h.key==="Escape"&&e(!1)};return document.addEventListener("pointerdown",c),document.addEventListener("keydown",d),()=>{document.removeEventListener("pointerdown",c),document.removeEventListener("keydown",d)}},[s]);let a=React.createElement("button",{key:"trigger",type:"button",onClick:()=>e(c=>!c),"aria-haspopup":"menu","aria-expanded":s?"true":"false","aria-label":f("language.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"7px 10px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:s?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",fontSize:"12.5px",fontWeight:600,cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"c"},n?n.abbr:""),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:s?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),o=React.createElement("div",{key:"menu",role:"menu",className:"sb-scroll",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:s?"block":"none",minWidth:"170px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",maxHeight:"min(62vh, 420px)",overflowY:"auto",overscrollBehavior:"contain"}},i.map(c=>React.createElement("a",{key:c.code,href:c.href,hrefLang:c.hrefLang,lang:c.hrefLang,dir:c.dir,role:"menuitem","aria-current":c.isCurrent?"page":void 0,onClick:()=>Hi(c.code),style:{display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",fontSize:"13px",fontWeight:c.isCurrent?600:500,color:c.isCurrent?"var(--sb-text-2)":"var(--sb-text-6)",background:c.isCurrent?"rgba(var(--sb-ink), 0.06)":"transparent",textDecoration:"none",whiteSpace:"nowrap"}},[React.createElement("span",{key:"a",style:{fontSize:"11px",fontWeight:700,letterSpacing:"0.4px",color:"var(--sb-text-9)",width:"22px",flex:"none",textAlign:"start"}},c.abbr),React.createElement("span",{key:"n"},c.label)])));return React.createElement("nav",{ref:t,"aria-label":f("language.label"),style:{position:"relative",display:"inline-flex"}},[a,o])};window.LanguageSwitcher=Hr;var ot={system:'',light:'',dark:''},$r=(s,e,t)=>React.createElement("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:t,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",dangerouslySetInnerHTML:{__html:s}}),Gr=()=>{let s=typeof window<"u"?window.SecureBitTheme:null;if(!s)return null;let[e,t]=React.useState(!1),[r,i]=React.useState(()=>s.get()),[n,a]=React.useState(()=>s.resolved()),o=React.useRef(null);React.useEffect(()=>s.subscribe((y,b)=>{i(y),a(b)}),[]),React.useEffect(()=>{if(!e)return;let y=p=>{o.current&&!o.current.contains(p.target)&&t(!1)},b=p=>{p.key==="Escape"&&t(!1)};return document.addEventListener("pointerdown",y),document.addEventListener("keydown",b),()=>{document.removeEventListener("pointerdown",y),document.removeEventListener("keydown",b)}},[e]);let c=[{mode:"system",icon:ot.system,label:f("theme.system")},{mode:"light",icon:ot.light,label:f("theme.light")},{mode:"dark",icon:ot.dark,label:f("theme.dark")}],d=r==="system"?ot.system:n==="light"?ot.light:ot.dark,h=c.find(y=>y.mode===r)||c[0],u=React.createElement("button",{key:"trigger",type:"button",onClick:()=>t(y=>!y),"aria-haspopup":"menu","aria-expanded":e?"true":"false","aria-label":f("theme.label")+": "+h.label,title:f("theme.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"8px 9px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:e?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"i",style:{display:"grid",placeItems:"center"}},$r(d,15,1.9)),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:e?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),m=React.createElement("div",{key:"menu",role:"menu",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:e?"block":"none",minWidth:"158px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))"}},c.map(y=>{let b=y.mode===r;return React.createElement("button",{key:y.mode,type:"button",role:"menuitemradio","aria-checked":b?"true":"false",onClick:()=>{s.set(y.mode),t(!1)},style:{width:"100%",display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",border:"none",fontSize:"13px",fontFamily:"inherit",fontWeight:b?600:500,color:b?"var(--sb-text-2)":"var(--sb-text-6)",background:b?"rgba(var(--sb-ink), 0.06)":"transparent",cursor:"pointer",textAlign:"start",whiteSpace:"nowrap"}},[React.createElement("span",{key:"i",style:{flex:"none",display:"grid",placeItems:"center",width:"16px",color:b?"var(--sb-orange)":"var(--sb-text-9)"}},$r(y.icon,14,1.9)),React.createElement("span",{key:"l",style:{flex:1}},y.label),b&&React.createElement("span",{key:"c",style:{flex:"none",display:"grid",placeItems:"center",color:"var(--sb-orange)"}},$r('',12,2.6))])}));return React.createElement("div",{ref:o,style:{position:"relative",display:"inline-flex"}},[u,m])};window.ThemeSwitcher=Gr;var Ma=`v${Fn}`,La=({status:s,fingerprint:e,verificationCode:t,onDisconnect:r,isConnected:i,securityLevel:n,webrtcManager:a})=>{let[o,c]=React.useState(null),[d,h]=React.useState(0),[u,m]=React.useState(!1),[y,b]=React.useState(0),[p,S]=React.useState("unknown");React.useEffect(()=>{let G=!1,U=0,I=async()=>{let N=Date.now();if(!(N-U<1e4)&&!G){G=!0,U=N;try{if(!a||!i)return;let z=a,W=null;if(typeof z.getRealSecurityLevel=="function"?W=await z.getRealSecurityLevel():typeof z.calculateAndReportSecurityLevel=="function"?W=await z.calculateAndReportSecurityLevel():W=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(z),W&&W.isRealData!==!1){let Z=o?.score||0,be=W.score||0;Z!==be||!o?(c(W),h(N)):window.DEBUG_MODE}}catch{}finally{G=!1}}};if(i&&(I(),!o||o.score<50)){let N=setInterval(()=>{!o||o.score<50?I():clearInterval(N)},5e3);setTimeout(()=>clearInterval(N),3e4)}let D=setInterval(I,3e4);return()=>clearInterval(D)},[a,i]),React.useEffect(()=>{let G=I=>{setTimeout(()=>{h(0)},100)},U=I=>{I.detail&&I.detail.securityData&&(c(I.detail.securityData),h(Date.now()))};return document.addEventListener("security-level-updated",G),document.addEventListener("real-security-calculated",U),window.forceHeaderSecurityUpdate=I=>{I&&window.EnhancedSecureCryptoUtils?window.EnhancedSecureCryptoUtils.calculateSecurityLevel(I).then(D=>{D&&D.isRealData!==!1&&(c(D),h(Date.now()))}).catch(D=>{}):h(0)},()=>{document.removeEventListener("security-level-updated",G),document.removeEventListener("real-security-calculated",U)}},[]),React.useEffect(()=>{m(!0),b(0),S("premium")},[]),React.useEffect(()=>{m(!0),b(0),S("premium")},[]),React.useEffect(()=>{let G=N=>{m(!0),b(0),S("premium")},U=()=>{c(null),h(0),m(!1),b(0),S("unknown")},I=()=>{c(null),h(0)},D=()=>{c(null),h(0),m(!1),b(0),S("unknown")};return document.addEventListener("force-header-update",G),document.addEventListener("peer-disconnect",I),document.addEventListener("connection-cleaned",U),document.addEventListener("disconnected",D),()=>{document.removeEventListener("force-header-update",G),document.removeEventListener("peer-disconnect",I),document.removeEventListener("connection-cleaned",U),document.removeEventListener("disconnected",D)}},[]);let w=async G=>{if(G&&(G.button===2||G.ctrlKey||G.metaKey)&&r&&typeof r=="function"){r();return}G.preventDefault(),G.stopPropagation();let U=null;if(a&&window.EnhancedSecureCryptoUtils)try{U=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(a)}catch{}if(!U&&!o){alert(f("sec.verificationWait"));return}let I=U||o;I||(I={level:"UNKNOWN",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:f("sec.verificationUnavailable"),isRealData:!1,passedChecks:0,totalChecks:0});let D=`REAL-TIME SECURITY VERIFICATION `;if(D+=`Security Level: ${I.level} (${I.score}%) `,D+=`Verification Time: ${new Date(I.timestamp).toLocaleTimeString()} @@ -102,9 +102,9 @@ ${I.details||f("sec.verificationDone")}`,I.isRealData?D+=` border: 1px solid var(--sb-surface-5); `,z.textContent=D,N.appendChild(z),N.addEventListener("click",Z=>{Z.target===N&&document.body.removeChild(N)});let W=Z=>{Z.key==="Escape"&&(document.body.removeChild(N),document.removeEventListener("keydown",W))};document.addEventListener("keydown",W),document.body.appendChild(N)},F=(()=>{switch(s){case"connected":return{text:f("status.connected"),className:"status-connected",badgeClass:"bg-green-500/10 text-green-400 border-green-500/20"};case"verifying":return{text:f("status.verifying"),className:"status-verifying",badgeClass:"bg-purple-500/10 text-purple-400 border-purple-500/20"};case"connecting":return{text:f("status.connecting"),className:"status-connecting",badgeClass:"bg-blue-500/10 text-blue-400 border-blue-500/20"};case"retrying":return{text:f("status.retrying"),className:"status-connecting",badgeClass:"bg-yellow-500/10 text-yellow-400 border-yellow-500/20"};case"failed":return{text:f("status.error"),className:"status-failed",badgeClass:"bg-red-500/10 text-red-400 border-red-500/20"};case"reconnecting":return{text:f("status.reconnecting"),className:"status-connecting",badgeClass:"bg-yellow-500/10 text-yellow-400 border-yellow-500/20"};case"peer_disconnected":return{text:f("status.peerDisconnected"),className:"status-failed",badgeClass:"bg-orange-500/10 text-orange-400 border-orange-500/20"};default:return{text:f("status.notConnected"),className:"status-disconnected",badgeClass:"bg-gray-500/10 text-gray-400 border-gray-500/20"}}})(),k=i?o||n:null,_=(()=>{if(!k)return{tooltip:f("sec.verificationInProgress"),isVerified:!1,dataSource:"loading"};let G=k.isRealData!==!1,U=`${k.level} (${k.score}%)`;return G?{tooltip:`${U} - Real-time verification \u2705 Right-click or Ctrl+click to disconnect`,isVerified:!0,dataSource:"real"}:{tooltip:`${U} - Estimated (connection establishing...) -Right-click or Ctrl+click to disconnect`,isVerified:!1,dataSource:"estimated"}})();React.useEffect(()=>(window.debugHeaderSecurity=void 0,()=>{delete window.debugHeaderSecurity}),[o,d,i,a,k,_]);let A=k?k.color==="green"?"var(--sb-green)":k.color==="orange"?"var(--sb-orange)":k.color==="yellow"?"var(--sb-yellow)":"var(--sb-red)":"var(--sb-green)",x=i?"var(--sb-green-solid)":["connecting","verifying","retrying","reconnecting"].includes(s)?"var(--sb-yellow-solid)":s==="failed"?"var(--sb-red-solid)":"var(--sb-text-9)",T=x==="var(--sb-green-solid)"?"rgba(var(--sb-green-rgb), 0.16)":x==="var(--sb-yellow-solid)"?"rgba(var(--sb-yellow-rgb), 0.16)":x==="var(--sb-red-solid)"?"rgba(var(--sb-red-rgb), 0.16)":"rgba(var(--sb-text-9-rgb), 0.16)",Y="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",B=!i,[R,ue]=React.useState(!1);React.useEffect(()=>{let G=()=>ue((window.scrollY||window.pageYOffset||0)>8);return G(),window.addEventListener("scroll",G,{passive:!0}),()=>window.removeEventListener("scroll",G)},[]);let K="blur(20px) saturate(180%)",O="background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease, border-color .25s ease",Q={paddingTop:"var(--sb-safe-top, 0px)",paddingBottom:"var(--sb-bar-extra, 0px)"},J={position:"fixed",top:0,left:0,right:0,...Q},ge=B?R?{...J,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)",transition:O}:{...J,background:"transparent",backdropFilter:"blur(0px) saturate(100%)",WebkitBackdropFilter:"blur(0px) saturate(100%)",borderBottom:"1px solid transparent",transition:O}:{...Q,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"};return React.createElement("header",{className:B?"header-minimal z-50":"header-minimal sticky top-0 z-50",style:ge},[React.createElement("div",{key:"container",className:"max-w-7xl mx-auto",style:{padding:"0 20px"}},[React.createElement("div",{key:"content",className:"flex items-center justify-between",style:{height:"var(--sb-bar-h, 64px)",gap:"16px"}},[React.createElement("div",{key:"left",style:{display:"flex",alignItems:"center",gap:"12px",minWidth:0}},[React.createElement("div",{key:"logo",style:{width:"36px",height:"36px",flex:"none",display:"grid",placeItems:"center"}},React.createElement("img",{src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{width:"100%",height:"100%",objectFit:"contain",display:"block"}})),React.createElement("div",{key:"txt",style:{lineHeight:1.2,minWidth:0}},[React.createElement("div",{key:"r1",style:{display:"flex",alignItems:"baseline",gap:"7px"}},[React.createElement("span",{key:"n",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-2)"}},"SecureBit"),React.createElement("span",{key:"v",style:{fontFamily:Y,fontSize:"10px",fontWeight:500,color:"var(--sb-text-faint)"}},Ma)]),React.createElement("div",{key:"r2",className:"hidden sm:block",style:{fontSize:"11px",color:"var(--sb-text-9)",fontWeight:500}},f("hdr.tagline"))])]),React.createElement("div",{key:"right",style:{display:"flex",alignItems:"center",gap:"9px"}},[B&&React.createElement(Hr,{key:"lang"}),B&&React.createElement(Gr,{key:"theme"}),!B&&React.createElement("button",{key:"net",type:"button",onClick:()=>window.dispatchEvent(new CustomEvent("securebit:open-network-settings")),title:f("hdr.netSettingsTitle"),"aria-label":f("hdr.netSettings"),className:"sb-disconnect",style:{display:"grid",placeItems:"center",width:"38px",height:"38px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-6)",cursor:"pointer",transition:"all .15s"}},React.createElement("i",{className:"fas fa-network-wired",style:{fontSize:"13px"}})),!B&&k&&React.createElement("div",{key:"sec",onClick:w,onContextMenu:G=>{G.preventDefault(),typeof r=="function"&&r()},title:_.tooltip,className:"sb-secpill",style:{display:"flex",alignItems:"center",gap:"8px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-shield-halved",style:{fontSize:"13px",color:A}}),React.createElement("span",{key:"l",className:"hidden sm:inline",style:{fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-2)"}},f(`secLevel.${k.level}`)===`secLevel.${k.level}`?String(k.level):f(`secLevel.${k.level}`)),React.createElement("span",{key:"s",style:{fontFamily:Y,fontSize:"11.5px",color:"var(--sb-text-7)"}},k.score+"%")]),!B&&React.createElement("div",{key:"status",style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 13px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)"}},[React.createElement("span",{key:"dot",style:{width:"7px",height:"7px",borderRadius:"50%",background:x,boxShadow:"0 0 0 3px "+T}}),React.createElement("span",{key:"t",className:"hidden sm:inline",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-4)"}},F.text)]),i&&React.createElement("button",{key:"dc",onClick:r,className:"sb-disconnect",style:{display:"flex",alignItems:"center",gap:"7px",padding:"8px 14px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"transparent",color:"var(--sb-text-6)",fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:"pointer",transition:"all .15s"}},[React.createElement("i",{key:"i",className:"fas fa-power-off",style:{fontSize:"12px"}}),React.createElement("span",{key:"t",className:"sb-hide-sm"},f("hdr.disconnect"))])])])])])};window.EnhancedMinimalHeader=La;var Jt="1.0.6",qr=`https://github.com/SecureBitChat/securebit-desktop/releases/download/v${Jt}`,Da=()=>{let s=[{id:"web",name:"Web App",subtitle:"Browser Version",icon:"fas fa-globe",platform:"Web",isActive:!0,url:"https://securebit.chat/",color:"green"},{id:"windows",name:"Windows",subtitle:"Desktop App",icon:"fab fa-windows",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64-setup.exe`,color:"blue"},{id:"macos",name:"macOS",subtitle:"Desktop App",icon:"fab fa-safari",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64.dmg`,color:"gray"},{id:"linux",name:"Linux",subtitle:"Desktop App",icon:"fab fa-linux",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_amd64.AppImage`,color:"orange"},{id:"ios",name:"iOS",subtitle:"iPhone & iPad",icon:"fab fa-apple",platform:"Mobile",isActive:!1,url:"https://apps.apple.com/app/securebit-chat/",color:"white"},{id:"android",name:"Android",subtitle:"Google Play",icon:"fab fa-android",platform:"Mobile",isActive:!1,url:"https://play.google.com/store/apps/details?id=com.securebit.chat",color:"green"},{id:"chrome",name:"Chrome",subtitle:"Browser Extension",icon:"fab fa-chrome",platform:"Browser",isActive:!1,url:"#",color:"yellow"},{id:"edge",name:"Edge",subtitle:"Browser Extension",icon:"fab fa-edge",platform:"Browser",isActive:!1,url:"#",color:"blue"},{id:"opera",name:"Opera",subtitle:"Browser Extension",icon:"fab fa-opera",platform:"Browser",isActive:!1,url:"#",color:"red"},{id:"firefox",name:"Firefox",subtitle:"Browser Extension",icon:"fab fa-firefox-browser",platform:"Browser",isActive:!1,url:"#",color:"orange"}],e=c=>{c.isActive&&window.open(c.url,"_blank")},t=s.filter(c=>c.platform==="Desktop"||c.platform==="Web"),r=s.filter(c=>c.platform==="Mobile"),i=s.filter(c=>c.platform==="Browser"),n="w-28 h-28",a={green:"text-green-500",blue:"text-blue-500",gray:"text-gray-500",orange:"text-orange-500",red:"text-red-500",white:"text-white",yellow:"text-yellow-400"},o=c=>React.createElement("div",{key:c.id,className:`group relative ${n} rounded-2xl overflow-hidden card-minimal cursor-pointer`},[React.createElement("i",{key:"bg-icon",className:`${c.icon} absolute text-[3rem] ${c.isActive?a[c.color]:"text-white/10"} top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none transition-all duration-500 group-hover:scale-105`}),React.createElement("div",{key:"overlay",className:"absolute inset-0 bg-black/30 backdrop-blur-md flex flex-col items-center justify-center text-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"},[React.createElement("h4",{key:"name",className:"text-sm font-semibold text-primary mb-1"},c.name),React.createElement("p",{key:"subtitle",className:"text-xs text-secondary mb-2"},c.subtitle),c.isActive?React.createElement("button",{key:"btn",onClick:()=>e(c),className:"px-2 py-1 rounded-xl bg-emerald-500 text-black font-medium hover:bg-emerald-600 transition-colors text-xs"},c.id==="web"?"Launch":"Download"):React.createElement("span",{key:"coming",className:"text-gray-400 font-medium text-xs"},"Coming Soon")])]);return React.createElement("div",{className:"mt-20 px-6"},[React.createElement("div",{key:"header",className:"text-center max-w-3xl mx-auto mb-12"},[React.createElement("h3",{key:"title",className:"text-3xl font-bold text-primary mb-3"},"Download SecureBit.chat"),React.createElement("p",{key:"subtitle",className:"text-secondary text-lg mb-5"},"Stay secure on every device. Choose your platform and start chatting privately.")]),React.createElement("div",{key:"desktop-row",className:"hidden sm:flex justify-center flex-wrap gap-6 mb-6"},t.map(o)),React.createElement("div",{key:"mobile-row",className:"flex justify-center gap-6 mb-6"},r.map(o)),React.createElement("div",{key:"browser-row",className:"flex justify-center gap-6"},i.map(o))])};window.DownloadApps=Da;var Pa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let p=window.matchMedia("(max-width:767px)"),S=()=>e(p.matches);return p.addEventListener?p.addEventListener("change",S):p.addListener(S),()=>{p.removeEventListener?p.removeEventListener("change",S):p.removeListener(S)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",n="'Manrope', system-ui, -apple-system, sans-serif",a="https://docs.google.com/forms/d/e/1FAIpQLSc9ijV9PCoyXkus6vEx1OWwvwAsLq8fKS6-H5BmX-c-bvia6w/viewform?usp=dialog",o=[{id:"aegis",name:"Aegis Investment",logo:"/logo/aegis.png",logoHeight:"42px",url:"https://aegis-investment.com/",desc:f("partners.aegis.desc"),role:f("partners.aegis.role"),delay:".5s"},{id:"furi",name:"FuriLabs",logo:"/logo/furi-160.png",logoHeight:"54px",url:"https://furilabs.com/",desc:f("partners.furilabs.desc"),role:f("partners.furilabs.role"),delay:".56s"}],c=(p,S,g,b,w)=>React.createElement("svg",{className:w,width:S,height:S,viewBox:"0 0 24 24",fill:"none",stroke:g,strokeWidth:b,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:p}}),d=p=>React.createElement("span",{key:"role",style:{fontFamily:i,fontSize:"10.5px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.2px",padding:"6px 11px",borderRadius:"8px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",whiteSpace:"nowrap"}},p),u=p=>React.createElement("a",{key:p.id,href:p.url,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",padding:"30px 30px 26px",display:"flex",flexDirection:"column",textDecoration:"none",color:"inherit",transition:"transform .28s cubic-bezier(.2,.7,.3,1), border-color .28s cubic-bezier(.2,.7,.3,1)",animation:`ptUp ${p.delay} cubic-bezier(.2,.7,.3,1)`},onMouseEnter:S=>{S.currentTarget.style.transform="translateY(-4px)",S.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.13)"},onMouseLeave:S=>{S.currentTarget.style.transform="none",S.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.06)"}},[React.createElement("div",{key:"logo",style:{display:"flex",alignItems:"center",marginBottom:"30px",height:"54px"}},React.createElement("img",{src:p.logo,alt:p.name,loading:"lazy",decoding:"async",style:{height:p.logoHeight,width:"auto",maxWidth:"190px",objectFit:"contain",display:"block"}})),React.createElement("h3",{key:"name",style:{margin:"0 0 9px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},p.name),React.createElement("p",{key:"desc",style:{margin:"0 0 22px",fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},p.desc),React.createElement("div",{key:"foot",style:{marginTop:"auto",paddingTop:"6px",display:"flex",alignItems:"center",gap:"12px"}},[d(p.role)])]),h=React.createElement("a",{key:"invite",href:a,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-bg)",border:"1px dashed rgba(var(--sb-ink), 0.12)",padding:"30px",display:"flex",flexDirection:"column",justifyContent:"space-between",textDecoration:"none",color:"inherit",transition:"border-color .28s cubic-bezier(.2,.7,.3,1)",animation:"ptUp .62s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-orange-rgb), 0.4)"},onMouseLeave:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.12)"}},[React.createElement("div",{key:"top"},[React.createElement("div",{key:"icon",style:{width:"48px",height:"48px",borderRadius:"13px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.28)",marginBottom:"24px"}},c('',23,r,1.9)),React.createElement("h3",{key:"title",style:{margin:"0 0 8px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},f("partners.inviteTitle")),React.createElement("p",{key:"desc",style:{margin:0,fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("partners.inviteDesc"))]),React.createElement("span",{key:"btn",style:{marginTop:"26px",width:"100%",display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"10px",padding:"15px 20px",borderRadius:"12px",border:"none",background:r,color:"var(--sb-on-accent)",fontFamily:n,fontSize:"15px",fontWeight:700,cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",boxSizing:"border-box",transition:"background .2s cubic-bezier(.2,.7,.3,1), transform .2s cubic-bezier(.2,.7,.3,1)"}},[f("partners.inviteCta"),c('',17,"currentColor",2.2,"sb-mirror-rtl")])]),m=React.createElement("div",{key:"inner",style:{maxWidth:"1240px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{marginBottom:"44px"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:i,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"14px"}},f("partners.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:s?"30px":"40px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.04,color:"var(--sb-text-1)"}},f("partners.heading"))]),React.createElement("div",{key:"cards",style:{display:"flex",gap:"18px",alignItems:"stretch",flexWrap:"wrap"}},[...o.map(u),h])]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:n,padding:s?"48px 0":"72px 0",background:"radial-gradient(1100px 640px at 50% -6%, rgba(var(--sb-orange-rgb), 0.055), transparent 62%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ptUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),m])};window.BecomePartner=Pa;var Fa=()=>{let[s,e]=React.useState(0),[t,r]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let E=window.matchMedia("(max-width:767px)"),_=()=>r(E.matches);return E.addEventListener?E.addEventListener("change",_):E.addListener(_),()=>{E.removeEventListener?E.removeEventListener("change",_):E.removeListener(_)}},[]);let i="var(--sb-orange)",n="var(--sb-orange-solid)",a="radial-gradient(130% 90% at 28% 0%, rgba(var(--sb-orange-rgb), 0.11), transparent 60%), var(--sb-surface)",o="rgba(var(--sb-orange-rgb), 0.3)",c="var(--sb-bg)",d="rgba(var(--sb-ink), 0.06)",u="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",h="'Manrope', system-ui, -apple-system, sans-serif",m=[{num:"01",title:[f("unique.s1.titleTop"),f("unique.s1.titleBottom")],collapsed:f("unique.s1.collapsed"),desc:f("unique.s1.desc"),tags:Oe("unique.s1.tags"),icon:''},{num:"02",title:[f("unique.s2.titleTop"),f("unique.s2.titleBottom")],collapsed:f("unique.s2.collapsed"),desc:f("unique.s2.desc"),tags:Oe("unique.s2.tags"),icon:''},{num:"03",title:[f("unique.s3.titleTop"),f("unique.s3.titleBottom")],collapsed:f("unique.s3.collapsed"),desc:f("unique.s3.desc"),tags:Oe("unique.s3.tags"),icon:''},{num:"04",title:[f("unique.s4.titleTop"),f("unique.s4.titleBottom")],collapsed:f("unique.s4.collapsed"),desc:f("unique.s4.desc"),tags:Oe("unique.s4.tags"),icon:''},{num:"05",title:[f("unique.s5.titleTop"),f("unique.s5.titleBottom")],collapsed:f("unique.s5.collapsed"),desc:f("unique.s5.desc"),tags:Oe("unique.s5.tags"),icon:''}],p=(E,_,A,x)=>React.createElement("svg",{width:_,height:_,viewBox:"0 0 24 24",fill:"none",stroke:A,strokeWidth:x,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:E}}),S=E=>e(_=>(_+E+m.length)%m.length),g=(E,_,A)=>React.createElement("button",{key:E,onClick:_,"aria-label":E,className:"sb-mirror-rtl",style:{width:"46px",height:"46px",display:"grid",placeItems:"center",borderRadius:"50%",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.025)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:x=>{x.currentTarget.style.borderColor=o,x.currentTarget.style.color=i},onMouseLeave:x=>{x.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",x.currentTarget.style.color="var(--sb-text-4)"}},p(A,18,"currentColor",2.1)),b=E=>React.createElement("span",{key:E,style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",fontFamily:u,fontSize:"11.5px",fontWeight:500,color:"var(--sb-text-6)"}},[React.createElement("span",{key:"dot",style:{width:"5px",height:"5px",borderRadius:"50%",background:"var(--sb-green-solid)"}}),E]),w=E=>React.createElement("div",{key:"exp",style:{height:"100%",display:"flex",flexDirection:"column",justifyContent:t?"flex-start":"space-between",gap:t?"18px":0,padding:t?"24px 22px":"32px 34px",minWidth:t?"auto":"320px",animation:"wuUp .42s cubic-bezier(.2,.7,.3,1)"}},[React.createElement("div",{key:"top",style:{display:"flex",alignItems:"center",justifyContent:"space-between"}},[React.createElement("div",{key:"ic",style:{width:"54px",height:"54px",borderRadius:"15px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.13)",border:"1px solid rgba(var(--sb-orange-rgb), 0.3)"}},p(E.icon,26,n,1.9)),React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"13px",fontWeight:600,color:"var(--sb-text-9)"}},E.num)]),React.createElement("div",{key:"mid"},[React.createElement("h3",{key:"h",style:{margin:"0 0 12px",fontSize:t?"24px":"30px",fontWeight:800,letterSpacing:"-0.7px",lineHeight:1.08,color:"var(--sb-text-1)"}},[E.title[0],React.createElement("br",{key:"br"}),E.title[1]]),React.createElement("p",{key:"p",style:{margin:0,fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-6)",maxWidth:"380px"}},E.desc)]),React.createElement("div",{key:"tags",style:{display:"flex",flexWrap:"wrap",gap:"8px"}},E.tags.map(b))]),M=E=>t?React.createElement("div",{key:"col",style:{display:"flex",alignItems:"center",gap:"16px",padding:"20px 22px"}},[React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)"}},E.collapsed)]):React.createElement("div",{key:"col",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"space-between",padding:"24px 0"}},[React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{writingMode:"vertical-rl",transform:"rotate(180deg)",fontSize:"17px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)",whiteSpace:"nowrap"}},E.collapsed),p(E.icon,22,"var(--sb-text-faint)",1.8)]),F=m.map((E,_)=>{let A=s===_;return React.createElement("div",{key:_,onClick:()=>e(_),onMouseEnter:x=>{A||(x.currentTarget.style.filter="brightness(1.18)")},onMouseLeave:x=>{x.currentTarget.style.filter="none"},style:{flex:t?"none":A?6.2:1,minWidth:t?"auto":"72px",position:"relative",borderRadius:"18px",overflow:"hidden",cursor:"pointer",background:A?a:c,border:"1px solid "+(A?o:d),color:"var(--sb-text-7)",transition:"flex .46s cubic-bezier(.2,.7,.3,1), background .3s ease, border-color .3s ease, filter .2s ease"}},A?w(E):M(E))}),k=React.createElement("div",{key:"inner",style:{maxWidth:"1180px",margin:"0 auto",padding:t?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{display:"flex",alignItems:"flex-end",justifyContent:"space-between",gap:"24px",marginBottom:"28px"}},[React.createElement("div",{key:"titles"},[React.createElement("div",{key:"eyebrow",style:{fontFamily:u,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.4px",marginBottom:"12px"}},f("unique.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:t?"28px":"38px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("unique.heading"))]),React.createElement("div",{key:"nav",style:{display:"flex",alignItems:"center",gap:"10px",flex:"none"}},[g("prev",()=>S(-1),''),g("next",()=>S(1),'')])]),React.createElement("div",{key:"accordion",style:{display:"flex",flexDirection:t?"column":"row",gap:t?"12px":"14px",height:t?"auto":"440px"}},F)]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:h,padding:t?"44px 0":"64px 0",background:"radial-gradient(1100px 700px at 18% 8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes wuUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}"}}),k])};window.UniqueFeatureSlider=Fa;function Ka(){let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let w=window.matchMedia("(max-width:767px)"),M=()=>e(w.matches);return w.addEventListener?w.addEventListener("change",M):w.addListener(M),()=>{w.removeEventListener?w.removeEventListener("change",M):w.removeListener(M)}},[]);let t="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",r="'Manrope', system-ui, -apple-system, sans-serif",i=[{v:"v1.0",k:"r1",status:"released"},{v:"v1.5",k:"r2",status:"released"},{v:"v2.0",k:"r3",status:"released"},{v:"v3.0",k:"r4",status:"released"},{v:"v3.5",k:"r5",status:"released"},{v:"v4.5",k:"r6",status:"released"},{v:"v5.0",k:"r7",status:"released"},{v:"v5.5",k:"r8",status:"released"},{v:"v6.0",k:"r9",status:"current"},{v:"v6.5",k:"r10",status:"dev"},{v:"v7.0",k:"r11",status:"planned"},{v:"v7.5",k:"r12",status:"research"},{v:"v8.0",k:"r13",status:"research"}].map(w=>({...w,title:f(`roadmap.${w.k}.title`),sub:f(`roadmap.${w.k}.sub`),date:f(`roadmap.${w.k}.date`),features:Oe(`roadmap.${w.k}.features`)})),n={released:{solid:"var(--sb-green-solid)",line:"rgba(var(--sb-green-rgb), 0.32)"},current:{solid:"var(--sb-orange-solid)",line:"rgba(var(--sb-orange-rgb), 0.32)"},dev:{solid:"var(--sb-yellow-2-solid)",line:"rgba(var(--sb-ink), 0.08)"},planned:{solid:"var(--sb-text-7)",line:"rgba(var(--sb-ink), 0.08)"},research:{solid:"var(--sb-text-9)",line:"rgba(var(--sb-ink), 0.08)"}},[a,o]=React.useState({}),c=w=>a[w]===void 0?i[w].status==="current":a[w],d=w=>o(M=>({...M,[w]:!c(w)})),u=i.length,h=i.filter(w=>w.status==="released"||w.status==="current").length,m=u-h,p=(h/u*100).toFixed(1)+"%",[S,g]=f("roadmap.progress",{total:u}).split("{shipped}"),b=w=>w==="released"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-green-rgb), 0.16),rgba(var(--sb-green-rgb), 0.16)), var(--sb-bg)",border:"1px solid rgba(var(--sb-green-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:"2.4",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M5 13l4 4 10-11"}))):w==="current"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-orange-rgb), 0.2),rgba(var(--sb-orange-rgb), 0.2)), var(--sb-bg)",border:"1px solid var(--sb-orange-solid)",zIndex:2,animation:"rmPulse 2.4s ease-out infinite"}},React.createElement("span",{style:{width:"9px",height:"9px",borderRadius:"50%",background:"var(--sb-orange-solid)"}})):w==="dev"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-yellow-2-rgb), 0.15),rgba(var(--sb-yellow-2-rgb), 0.15)), var(--sb-bg)",border:"1px solid rgba(var(--sb-yellow-2-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-yellow-2-solid)",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M12 3a9 9 0 1 0 9 9"}))):React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"var(--sb-bg)",border:`1px ${w==="research"?"dashed":"solid"} rgba(var(--sb-ink), 0.18)`,zIndex:2}},React.createElement("span",{style:{width:"7px",height:"7px",borderRadius:"50%",background:n[w].solid}}));return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:r,padding:s?"48px 0":"64px 0",background:"radial-gradient(1200px 720px at 50% -8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},React.createElement("style",{dangerouslySetInnerHTML:{__html:"@keyframes rmExp{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes rmPulse{0%,100%{box-shadow:0 0 0 0 rgba(var(--sb-orange-rgb), 0.18)}60%{box-shadow:0 0 0 9px rgba(var(--sb-orange-rgb), 0)}}"}}),React.createElement("div",{style:{maxWidth:"1040px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},React.createElement("div",{style:{marginBottom:"30px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"13px"}},f("roadmap.eyebrow")),React.createElement("h2",{style:{margin:"0 0 14px",fontSize:s?"27px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("roadmap.heading")),React.createElement("p",{style:{margin:0,fontSize:"15.5px",lineHeight:1.6,color:"var(--sb-text-7)",maxWidth:"660px"}},f("roadmap.subheading"))),React.createElement("div",{style:{display:"flex",alignItems:"center",gap:"18px",flexWrap:"wrap",padding:"18px 22px",borderRadius:"14px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",marginBottom:"36px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"12px",fontWeight:600,color:"var(--sb-text-2)",whiteSpace:"nowrap"}},S,React.createElement("span",{style:{color:"var(--sb-green)"}},h),g),React.createElement("div",{style:{flex:"1 1 240px",minWidth:"200px",height:"8px",borderRadius:"99px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.06)",overflow:"hidden"}},React.createElement("div",{style:{height:"100%",width:p,background:"linear-gradient(90deg, var(--sb-green), var(--sb-orange))"}})),React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},f("roadmap.upcoming",{upcoming:m}))),i.map((w,M)=>{let F=n[w.status],k=c(M),E=Md(M),style:{display:"flex",alignItems:"center",gap:s?"11px":"16px",padding:s?"16px 16px":"18px 22px",cursor:"pointer",transition:"background .18s ease"},onMouseEnter:_=>{_.currentTarget.style.background="rgba(var(--sb-ink), 0.018)"},onMouseLeave:_=>{_.currentTarget.style.background="transparent"}},React.createElement("div",{style:{flex:"none",minWidth:"52px",textAlign:"center",padding:"7px 10px",borderRadius:"9px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.07)",fontFamily:t,fontSize:"13px",fontWeight:700,color:w.status==="current"?"var(--sb-orange)":"var(--sb-text-4)"}},w.v),React.createElement("div",{style:{flex:1,minWidth:0}},React.createElement("div",{style:{fontSize:s?"15.5px":"17px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},w.title),!s&&React.createElement("div",{style:{marginTop:"3px",fontSize:"13.5px",color:"var(--sb-text-6)"}},w.sub)),React.createElement("div",{style:{flex:"none",display:"flex",alignItems:"center",gap:s?"8px":"14px"}},!s&&React.createElement("span",{style:{fontFamily:t,fontSize:"12px",fontWeight:500,color:"var(--sb-text-7)",whiteSpace:"nowrap",minWidth:"74px",textAlign:"end"}},w.date),React.createElement("span",{style:{color:"var(--sb-text-9)",display:"inline-flex",transition:"transform .22s cubic-bezier(.2,.7,.3,1)",transform:k?"rotate(180deg)":"rotate(0deg)"}},React.createElement("svg",{width:"17",height:"17",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.1",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M6 9l6 6 6-6"}))))),k&&React.createElement("div",{style:{padding:"4px 22px 22px 22px",animation:"rmExp .24s cubic-bezier(.2,.7,.3,1)"}},React.createElement("div",{style:{fontFamily:t,fontSize:"10px",fontWeight:600,color:"var(--sb-text-faint)",textTransform:"uppercase",letterSpacing:"1.2px",marginBottom:"14px",paddingTop:"14px",borderTop:"1px solid rgba(var(--sb-ink), 0.05)"}},f("roadmap.keyFeatures")),React.createElement("div",{style:{display:"grid",gridTemplateColumns:s?"1fr":"1fr 1fr",gap:"11px 28px"}},w.features.map((_,A)=>React.createElement("div",{key:A,style:{display:"flex",alignItems:"flex-start",gap:"10px"}},React.createElement("span",{style:{flex:"none",marginTop:"7px",width:"5px",height:"5px",borderRadius:"50%",background:F.solid}}),React.createElement("span",{style:{fontSize:"13.5px",lineHeight:1.5,color:"var(--sb-text-4)"}},_)))))))})))}window.Roadmap=Ka;var Et=[{id:"usdt",tab:"USDT",coin:"Tether USDT",badge:"trx",address:"TMopDoco5EwJB1QvQYsuhjUJdMvzPXNQYu"},{id:"btc",tab:"BTC",coin:"Bitcoin",badge:null,address:"bc1qnmc2xl7p0pxcy6lzf2tyf52wnslgzkgaq9kxpr"},{id:"eth",tab:"ETH",coin:"Ethereum",badge:null,address:"0xCDfDfaD4EC1fa657C3d2A7EFabc1cb751bf1dAf7"}],jr=s=>`/assets/crypto/${s}.svg`,Wr="__sbScrollToDonate",Yr="securebit:scroll-to-donate",Na=5e3,Xr=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches),[t,r]=React.useState(0),[i,n]=React.useState(!1),[a,o]=React.useState(0),c=React.useRef(null),d=React.useRef(null),u=React.useRef(null);React.useEffect(()=>{let K=window.matchMedia("(max-width:767px)"),O=()=>e(K.matches);return K.addEventListener?K.addEventListener("change",O):K.addListener(O),()=>{K.removeEventListener?K.removeEventListener("change",O):K.removeListener(O),clearTimeout(u.current)}},[]),React.useEffect(()=>{let K=null,O=()=>{let Q=window[Wr];window[Wr]=0,!(!Q||Date.now()-Q>Na)&&(clearTimeout(K),K=setTimeout(()=>{let J=d.current;if(!J)return;let ge=window.matchMedia("(prefers-reduced-motion: reduce)").matches;J.scrollIntoView({behavior:ge?"auto":"smooth",block:"center"})},350))};return O(),document.addEventListener(Yr,O),()=>{document.removeEventListener(Yr,O),clearTimeout(K)}},[]);let h=Et[t],m=K=>{let O=(K+Et.length)%Et.length;O!==t&&(o(K>t?1:-1),r(O),n(!1))},p=K=>{let O=K.touches[0];c.current={x:O.clientX,y:O.clientY}},S=K=>{let O=c.current;if(c.current=null,!O)return;let Q=K.changedTouches[0],J=Q.clientX-O.x,ge=Q.clientY-O.y;if(Math.abs(J)<40||Math.abs(J)0:J<0;m(t+(G?1:-1))},g=async()=>{try{await navigator.clipboard.writeText(h.address)}catch{let O=document.createElement("textarea");O.value=h.address,document.body.appendChild(O),O.select();try{document.execCommand("copy")}catch{}O.remove()}n(!0),clearTimeout(u.current),u.current=setTimeout(()=>n(!1),1800)},b="'Manrope', system-ui, -apple-system, sans-serif",w="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",M={borderRadius:"14px",background:"var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)"},F=React.createElement("div",{key:"tabs",role:"tablist",style:{...M,display:"flex",gap:"6px",padding:"5px",marginBottom:"14px"}},Et.map((K,O)=>{let Q=O===t;return React.createElement("button",{key:K.id,type:"button",role:"tab","aria-selected":Q,onClick:()=>m(O),style:{flex:"1 1 0",minWidth:0,display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"9px",padding:"11px 10px",borderRadius:"10px",border:"none",cursor:"pointer",fontFamily:b,fontSize:"14px",fontWeight:700,transition:"all .18s",background:Q?"var(--sb-surface-2)":"transparent",color:Q?"var(--sb-text-1)":"var(--sb-text-7)",boxShadow:Q?"inset 0 0 0 1px rgba(var(--sb-orange-rgb), 0.45)":"none"}},[React.createElement("span",{key:"ic",style:{position:"relative",flex:"none",width:"22px",height:"22px"}},[React.createElement("img",{key:"logo",src:jr(K.id),alt:"",width:22,height:22,style:{display:"block",width:"22px",height:"22px"}}),K.badge&&React.createElement("img",{key:"badge",src:jr(K.badge),alt:"",width:11,height:11,style:{position:"absolute",right:"-3px",bottom:"-3px",width:"11px",height:"11px",borderRadius:"50%",border:"1.5px solid var(--sb-surface-2)",background:"var(--sb-surface-2)"}})]),K.tab])})),k=React.createElement("button",{key:"copy",type:"button",onClick:g,style:{flex:"none",display:"inline-flex",alignItems:"center",gap:"8px",padding:"12px 16px",borderRadius:"10px",fontFamily:b,fontSize:"13.5px",fontWeight:700,cursor:"pointer",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-2)",border:"1px solid rgba(var(--sb-ink), 0.1)",transition:"all .18s"},onMouseEnter:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.09)"},onMouseLeave:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.05)"}},[i?React.createElement("svg",{key:"ok",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}):React.createElement("svg",{key:"cp",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),React.createElement("span",{key:"l","aria-live":"polite"},i?f("donate.copied"):f("donate.copy"))]),E=React.createElement("div",{key:"addr",style:{...M,display:"flex",alignItems:"center",gap:"12px",padding:"8px 8px 8px 18px"}},[React.createElement("div",{key:"tx",style:{flex:1,minWidth:0}},[React.createElement("div",{key:"net",style:{fontSize:"11.5px",fontWeight:600,color:"var(--sb-text-9)",marginBottom:"2px"}},f(`donate.net.${h.id}`)),React.createElement("div",{key:"a",title:h.address,dir:"ltr",style:{fontFamily:w,fontSize:"14px",color:"var(--sb-text-2)",letterSpacing:"0.3px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},h.address.slice(0,8)+"\u2026"+h.address.slice(-8))]),k]),_=React.createElement("div",{key:"warn",style:{display:"flex",alignItems:"center",gap:"7px",marginTop:"14px",fontSize:"12px",color:"var(--sb-text-9)"}},[React.createElement("svg",{key:"i",width:13,height:13,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-orange-solid)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{flex:"none"},dangerouslySetInnerHTML:{__html:''}}),f(`donate.warn.${h.id}`)]),A=React.createElement("div",{key:"left",style:{flex:"1 1 440px",minWidth:0,padding:s?"32px 22px 8px":"44px",display:"flex",flexDirection:"column"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:w,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.8px",marginBottom:"14px"}},f("donate.eyebrow")),React.createElement("h2",{key:"title",style:{margin:"0 0 10px",fontSize:s?"28px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("donate.title")),React.createElement("p",{key:"desc",style:{margin:"0 0 30px",fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("donate.description")),F,E,_]),x=Pt()?-1:1,T=a===0?"none":`${a*x>0?"cdInEnd":"cdInStart"} .28s cubic-bezier(.2,.7,.3,1)`,Y=React.createElement("div",{key:"plate",onTouchStart:p,onTouchEnd:S,style:{position:"relative",width:"232px",height:"232px",padding:"14px",borderRadius:"20px",background:"#fff",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",border:"1px solid rgba(var(--sb-ink), 0.07)",overflow:"hidden",touchAction:"pan-y",userSelect:"none"}},React.createElement("div",{key:h.id,style:{position:"relative",width:"100%",height:"100%",animation:T}},[React.createElement("img",{key:"qr",src:`/assets/crypto/qr-${h.id}.svg`,alt:f("donate.qrAlt",{coin:h.coin}),width:204,height:204,draggable:!1,style:{display:"block",width:"100%",height:"100%",imageRendering:"pixelated"}}),React.createElement("div",{key:"logo",style:{position:"absolute",left:"50%",top:"50%",transform:"translate(-50%,-50%)",width:"48px",height:"48px",borderRadius:"12px",background:"#fff",display:"grid",placeItems:"center"}},React.createElement("img",{src:jr(h.id),alt:"",width:34,height:34,draggable:!1,style:{display:"block",width:"34px",height:"34px"}}))])),B=s&&React.createElement("div",{key:"dots","aria-hidden":!0,style:{display:"flex",justifyContent:"center",gap:"7px",marginTop:"18px"}},Et.map((K,O)=>React.createElement("span",{key:K.id,style:{width:O===t?"18px":"7px",height:"7px",borderRadius:"4px",transition:"all .25s",background:O===t?"var(--sb-orange-solid)":"rgba(var(--sb-ink), 0.16)"}}))),R=React.createElement("div",{key:"right",style:{flex:"0 0 auto",minWidth:s?0:"300px",margin:"0 auto",padding:s?"24px 22px 32px":"44px",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[Y,B]),ue=React.createElement("div",{key:"card",style:{width:"100%",maxWidth:"1000px",position:"relative",overflow:"hidden",borderRadius:"24px",background:"radial-gradient(520px 420px at 100% 50%, rgba(var(--sb-orange-rgb), 0.09), transparent 70%), var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.07)",display:"flex",flexWrap:"wrap",alignItems:"stretch",animation:"cdUp .45s cubic-bezier(.2,.7,.3,1)"}},[A,R]);return React.createElement("section",{id:"donate",ref:d,style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",color:"var(--sb-text-2)",fontFamily:b,padding:s?"48px 18px":"64px 32px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:'@keyframes cdUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes cdInEnd{from{opacity:0;transform:translateX(36px)}to{opacity:1;transform:none}}@keyframes cdInStart{from{opacity:0;transform:translateX(-36px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion: reduce){#donate [style*="cdIn"]{animation:none!important}}'}}),ue])};Xr.SCROLL_FLAG=Wr;Xr.SCROLL_EVENT=Yr;window.DonateCrypto=Xr;var Oa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let u=window.matchMedia("(max-width:767px)"),h=()=>e(u.matches);return u.addEventListener?u.addEventListener("change",h):u.addListener(h),()=>{u.removeEventListener?u.removeEventListener("change",h):u.removeListener(h)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'Manrope', system-ui, -apple-system, sans-serif",n="https://github.com/SecureBitChat/securebit-chat/",a="mailto:lockbitchat@tutanota.com",o=React.createElement("a",{key:"gh",href:n,target:"_blank",rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:r,color:"var(--sb-on-accent)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:u=>{u.currentTarget.style.background="var(--sb-orange-hi)",u.currentTarget.style.transform="translateY(-2px)"},onMouseLeave:u=>{u.currentTarget.style.background=r,u.currentTarget.style.transform="none"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"currentColor",dangerouslySetInnerHTML:{__html:''}}),f("community.github")]),c=React.createElement("a",{key:"fb",href:a,rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:"rgba(var(--sb-ink), 0.03)",color:"var(--sb-text-2)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",border:"1px solid rgba(var(--sb-ink), 0.1)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:u=>{u.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.24)",u.currentTarget.style.background="rgba(var(--sb-ink), 0.06)"},onMouseLeave:u=>{u.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",u.currentTarget.style.background="rgba(var(--sb-ink), 0.03)"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.9,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),f("community.feedback")]),d=React.createElement("div",{key:"card",style:{position:"relative",overflow:"hidden",maxWidth:"860px",width:"100%",borderRadius:"24px",background:"radial-gradient(700px 360px at 50% 0%, rgba(var(--sb-orange-rgb), 0.1), transparent 65%), var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)",padding:s?"40px 24px 36px":"56px 56px 48px",textAlign:"center",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))"}},[React.createElement("div",{key:"hairline",style:{position:"absolute",top:0,left:"50%",transform:"translateX(-50%)",width:"180px",height:"1px",background:"linear-gradient(90deg, transparent, rgba(var(--sb-orange-rgb), 0.7), transparent)"}}),React.createElement("img",{key:"icon",src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{display:"inline-block",width:"64px",height:"64px",objectFit:"contain",marginBottom:"22px",animation:"ccUp .4s cubic-bezier(.2,.7,.3,1)"}}),React.createElement("h2",{key:"title",style:{margin:"0 0 16px",fontSize:s?"28px":"36px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("community.title")),React.createElement("p",{key:"desc",style:{margin:"0 auto 32px",maxWidth:"560px",fontSize:"16px",lineHeight:1.65,color:"var(--sb-text-6)"}},f("community.description")),React.createElement("div",{key:"btns",style:{display:"flex",gap:"14px",justifyContent:"center",flexWrap:"wrap"}},[o,c]),React.createElement("div",{key:"snap",style:{display:"flex",justifyContent:s?"center":"flex-end",marginTop:"28px"}},React.createElement("a",{href:"https://snapcraft.io/securebit-chat",target:"_blank",rel:"noopener noreferrer","aria-label":"Get it from the Snap Store",style:{display:"inline-flex",opacity:.9,transition:"opacity .2s"},onMouseEnter:u=>{u.currentTarget.style.opacity=1},onMouseLeave:u=>{u.currentTarget.style.opacity=.9}},React.createElement("img",{src:"/assets/badges/snap-store.svg",alt:"Get it from the Snap Store",width:182,height:56,loading:"lazy",style:{display:"block"}})))]);return React.createElement("section",{style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",fontFamily:i,padding:s?"48px 18px":"64px 48px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ccUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),d])};window.CommunityCTA=Oa;var Ua=({webrtcManager:s,isConnected:e,pendingIncomingFiles:t=[],onIncomingDecision:r,showDropzone:i=!0})=>{let[n,a]=React.useState(!1),[o,c]=React.useState({sending:[],receiving:[]}),d=React.useRef(null);React.useEffect(()=>{if(!e||!s)return;let A=setInterval(()=>{let x=s.getFileTransfers();c(x)},500);return()=>clearInterval(A)},[e,s]),React.useEffect(()=>{e||c({sending:[],receiving:[]})},[e]);let u=async _=>{if(!e||!s){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435.");return}if(!s.isConnected()||!s.isVerified){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0444\u0430\u0439\u043B\u043E\u0432. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F.");return}for(let A of _)try{let x=s.validateFile(A);if(!x.isValid){let T=x.errors.join(". ");alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${T}`);continue}await s.sendFile(A)}catch(x){x.message.includes(f("file.notReady"))?alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0441\u0435\u0439\u0447\u0430\u0441. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430.`):x.message.includes(f("file.tooLarge"))||x.message.includes("exceeds maximum")?alert(`\u0424\u0430\u0439\u043B ${A.name} \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439: ${x.message}`):x.message.includes(f("file.maxConcurrent"))?alert("\u0414\u043E\u0441\u0442\u0438\u0433\u043D\u0443\u0442 \u043B\u0438\u043C\u0438\u0442 \u043E\u0434\u043D\u043E\u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0442\u0435\u043A\u0443\u0449\u0438\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447."):x.message.includes(f("file.typeNotAllowed"))?alert(`\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 ${A.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F: ${x.message}`):alert(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${A.name}: ${x.message}`)}},h=_=>{_.preventDefault(),a(!1);let A=Array.from(_.dataTransfer.files);u(A)},m=_=>{_.preventDefault(),a(!0)},p=_=>{_.preventDefault(),a(!1)},S=_=>{let A=Array.from(_.target.files);u(A),_.target.value=""},g=_=>{if(_===0)return"0 B";let A=1024,x=["B","KB","MB","GB"],T=Math.floor(Math.log(_)/Math.log(A));return parseFloat((_/Math.pow(A,T)).toFixed(2))+" "+x[T]},b=_=>{switch(_){case"metadata_sent":case"preparing":return"fas fa-cog fa-spin";case"transmitting":case"receiving":return"fas fa-exchange-alt fa-pulse";case"assembling":return"fas fa-puzzle-piece fa-pulse";case"completed":return"fas fa-check text-green-400";case"failed":return"fas fa-times text-red-400";default:return"fas fa-circle"}},w=_=>{switch(_){case"metadata_sent":return"\u041F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0430...";case"transmitting":return"\u041E\u0442\u043F\u0440\u0430\u0432\u043A\u0430...";case"receiving":return"\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435...";case"assembling":return"\u0421\u0431\u043E\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u0430...";case"completed":return"\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E";case"failed":return"\u041E\u0448\u0438\u0431\u043A\u0430";default:return _}},M=(_,A)=>{let x=_.totalChunks||0,T=_.transferredChunks||0,Y=_.status==="completed",B=x>0?Math.min(x,32):24,R;return Y?R=B:x>0?R=Math.floor(T/x*B):R=Math.floor((_.progress||0)/100*B),R=Math.max(0,Math.min(B,R)),React.createElement("div",{key:"progress"},[React.createElement("div",{key:"squares",style:{display:"flex",flexWrap:"wrap",gap:"3px",marginBottom:"7px"}},Array.from({length:B},(ue,K)=>React.createElement("div",{key:K,style:{width:"11px",height:"11px",borderRadius:"2px",background:K0?`${Math.min(T,x)} / ${x} chunks`:`${(_.progress||0).toFixed(0)}%`)])])},F=_=>_.status==="completed",k=async(_,A)=>{typeof r=="function"&&await r(_,A),c(s.getFileTransfers())};return e?s&&s.isConnected()&&s.isVerified?React.createElement("div",{className:"file-transfer-component"},[i&&React.createElement("div",{key:"drop-zone",onDrop:h,onDragOver:m,onDragLeave:p,style:{position:"relative",border:"1.5px dashed "+(n?"rgba(var(--sb-orange-rgb), 0.7)":"rgba(var(--sb-ink), 0.14)"),borderRadius:"14px",background:n?"rgba(var(--sb-orange-rgb), 0.07)":"var(--sb-surface)",padding:"24px 22px",textAlign:"center",transition:"all .15s"}},[React.createElement("div",{key:"icon-box",style:{width:"42px",height:"42px",margin:"0 auto 10px",borderRadius:"12px",display:"grid",placeItems:"center",background:"rgba(var(--sb-ink), 0.04)",border:"1px solid rgba(var(--sb-ink), 0.08)"}},React.createElement("i",{className:"fas fa-arrow-up-from-bracket",style:{color:"var(--sb-text-6)",fontSize:"18px"}})),React.createElement("div",{key:"title",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-2)"}},f("file.drop")),React.createElement("div",{key:"sub",style:{fontSize:"12px",color:"var(--sb-text-8)",marginTop:"4px"}},f("file.dropHint")),React.createElement("button",{key:"browse",type:"button",onClick:()=>d.current?.click(),className:"sb-send",style:{marginTop:"14px",display:"inline-flex",alignItems:"center",gap:"7px",padding:"9px 16px",borderRadius:"9px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-folder-open",style:{fontSize:"13px"}}),f("file.browse")])]),i&&React.createElement("input",{key:"file-input",ref:d,type:"file",multiple:!0,className:"hidden",onChange:S}),t.length>0&&React.createElement("div",{key:"incoming-consent",className:"mt-4 space-y-2"},t.map(_=>React.createElement("div",{key:_.fileId,style:{borderRadius:"12px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",padding:"12px 14px"}},[React.createElement("div",{key:"info",style:{marginBottom:"12px",display:"flex",alignItems:"center",gap:"11px"}},[React.createElement("div",{key:"ic",style:{flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.22)"}},React.createElement("i",{className:"fas fa-file-arrow-down",style:{color:"var(--sb-orange)",fontSize:"15px"}})),React.createElement("div",{key:"text",style:{minWidth:0}},[React.createElement("div",{key:"title",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-2)"}},f("file.incoming")),React.createElement("div",{key:"meta",style:{fontSize:"11.5px",color:"var(--sb-text-8)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},`${_.fileName} \xB7 ${g(_.fileSize)} \xB7 ${_.mimeType}`)])]),React.createElement("div",{key:"actions",style:{display:"flex",gap:"8px"}},[React.createElement("button",{key:"accept",onClick:()=>k(_.fileId,!0),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",padding:"8px 14px",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-check",style:{fontSize:"12px"}}),f("file.accept")]),React.createElement("button",{key:"reject",onClick:()=>k(_.fileId,!1),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"rgba(var(--sb-red-rgb), 0.08)",color:"var(--sb-red)",padding:"8px 14px",fontSize:"13px",fontWeight:600,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-xmark",style:{fontSize:"12px"}}),f("file.reject")])])]))),(o.sending.length>0||o.receiving.length>0)&&React.createElement("div",{key:"transfers",className:"active-transfers mt-4"},[React.createElement("h4",{key:"title",style:{display:"flex",alignItems:"center",gap:"8px",fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-7)",marginBottom:"10px"}},[React.createElement("i",{key:"icon",className:"fas fa-right-left",style:{fontSize:"12px"}}),f("file.title")]),...o.sending.map(_=>React.createElement("div",{key:`send-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-up",style:{color:"var(--sb-orange)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(_.fileSize))]),React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])]),M(_,"var(--sb-orange)")])),...o.receiving.map(_=>React.createElement("div",{key:`recv-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-down",style:{color:"var(--sb-green)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(_.fileSize))]),React.createElement("div",{key:"actions",className:"flex items-center space-x-2"},[_.status==="completed"?React.createElement("button",{key:"download",className:"text-green-400 hover:text-green-300 text-xs flex items-center",onClick:async()=>{try{let A=await s.getReceivedFileObjectURL(_.fileId);if(!A){alert(f("file.gone"));return}let x=document.createElement("a");x.href=A,x.download=_.fileName||"file",x.click(),setTimeout(()=>s.revokeReceivedFileObjectURL(A),1e4)}catch(A){alert(A.message||f("file.gone"))}}},[React.createElement("i",{key:"i",className:"fas fa-download me-1"}),f("file.download")]):null,React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])])]),M(_,"var(--sb-green)")]))])]):React.createElement("div",{className:"p-4 text-center text-yellow-600"},[React.createElement("i",{key:"icon",className:"fas fa-exclamation-triangle me-2"}),"\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F... \u041F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u0431\u0443\u0434\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043F\u043E\u0441\u043B\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438."]):React.createElement("div",{className:"p-4 text-center text-muted"},f("file.needConnection"))};window.FileTransferComponent=Ua;var ze=Object.freeze({MAX_SERVERS:10,MAX_URLS_PER_SERVER:8,MAX_STRING_LENGTH:512}),Jo=Object.freeze(["stun","stuns","turn","turns"]),za=/^(stuns?|turns?):/i,Va=/^(\[[0-9a-f:]+\]|[a-z0-9.-]+)(:\d{1,5})?$/i,Ba=/^transport=(udp|tcp)$/i;function On(s){for(let e=0;eze.MAX_STRING_LENGTH)return f("iceUrl.tooLong");if(On(e))return f("iceUrl.badChars");let t=e.match(za);if(!t)return f("iceUrl.badScheme");let r=e.slice(t[0].length),[i,n,...a]=r.split("?");return a.length>0?f("iceUrl.badQuery"):i?Va.test(i)?n!==void 0&&!Ba.test(n)?f("iceUrl.badTransport"):null:f("iceUrl.badHost"):f("iceUrl.noHost")}function Un(s){return typeof s=="string"&&/^turns?:/i.test(s.trim())}function Kn(s,e){return s==null||s===""?null:typeof s!="string"?`${e} must be a string`:s.length>ze.MAX_STRING_LENGTH?`${e} is too long`:On(s)?`${e} contains invalid characters`:null}function Nn(s){let e=[],t=[],r=[];return Array.isArray(s)?s.length===0?{servers:[],errors:[],warnings:[]}:s.length>ze.MAX_SERVERS?(e.push(f("iceErr.tooMany",{max:ze.MAX_SERVERS})),{servers:[],errors:e,warnings:t}):(s.forEach((i,n)=>{let a=`Server #${n+1}`;if(!i||typeof i!="object"){e.push(f("iceErr.invalidEntry",{label:a}));return}let o=Array.isArray(i.urls)?i.urls:[i.urls];if(o.length===0||o.length>ze.MAX_URLS_PER_SERVER){e.push(f("iceErr.urlCount",{label:a,max:ze.MAX_URLS_PER_SERVER}));return}let c=[],d=!1;for(let p of o){let S=Ha(p);if(S){e.push(`${a}: ${S}`);continue}let g=p.trim();c.push(g),Un(g)&&(d=!0)}if(c.length===0)return;let u=Kn(i.username,`${a} username`);u&&e.push(u);let h=Kn(i.credential,`${a} credential`);h&&e.push(h);let m={urls:c.length===1?c[0]:c};i.username&&(m.username=String(i.username)),i.credential&&(m.credential=String(i.credential)),d&&(!m.username||!m.credential)&&t.push(f("iceErr.turnCreds",{label:a})),r.push(m)}),{servers:r,errors:e,warnings:t}):{servers:[],errors:[f("iceErr.notArray")],warnings:[]}}function zn(s){if(typeof s!="string"||!s.trim())return{servers:[],errors:[],warnings:[]};let e=s.trim();if(e.startsWith("[")||e.startsWith("{")){let r;try{r=JSON.parse(e)}catch{return{servers:[],errors:[f("iceErr.invalidJson")],warnings:[]}}let i=Array.isArray(r)?r:[r];return Nn(i)}let t=e.split(` -`).map(r=>r.trim()).filter(Boolean).map(r=>({urls:r}));return Nn(t)}function Vn(s){return Array.isArray(s)?s.some(e=>(Array.isArray(e?.urls)?e.urls:[e?.urls]).some(Un)):!1}var Ve=window.React,$a=["# One URL per line, e.g.:","stun:stun.example.com:3478","turn:turn.example.com:3478?transport=udp","","# Or paste JSON for servers with credentials:",'[{"urls":"turns:turn.example.com:5349","username":"user","credential":"secret"}]'].join(` -`);async function Ga(s,e=6e3){let t={host:0,srflx:0,relay:0};if(typeof RTCPeerConnection>"u")return{...t,error:f("ice.errUnavailable")};let r;try{r=new RTCPeerConnection({iceServers:s})}catch(i){return{...t,error:i.message||f("ice.errInvalid")}}return new Promise(i=>{let n=!1,a=()=>{if(!n){n=!0,clearTimeout(o);try{r.close()}catch{}i(t)}},o=setTimeout(a,e);r.onicecandidate=c=>{if(!c.candidate){a();return}let d=c.candidate.candidate||"";/ typ host/.test(d)?t.host++:/ typ srflx/.test(d)?t.srflx++:/ typ relay/.test(d)&&t.relay++};try{r.createDataChannel("securebit-ice-test"),r.createOffer().then(c=>r.setLocalDescription(c)).catch(()=>a())}catch{a()}})}var qa=({isOpen:s,onClose:e,initial:t,hasSaved:r,onApply:i,onForget:n,embedded:a})=>{if(!s)return null;let[o,c]=Ve.useState(t?.useCustom||!1),[d,u]=Ve.useState(t?.serversText||""),[h,m]=Ve.useState(t?.privacyMode==="relay-only"),[p,S]=Ve.useState(t?.persisted||!1),[g,b]=Ve.useState("idle"),[w,M]=Ve.useState(null),F=o?zn(d):{servers:[],errors:[],warnings:[]},k=Vn(F.servers),E=!o||F.servers.length>0&&F.errors.length===0,_=async()=>{b("running"),M(null);let U=await Ga(F.servers);M(U),b("done")},A=()=>{E&&i({useCustom:o,servers:o?F.servers:[],privacyMode:h?"relay-only":"standard",serversText:d},p)},x=async()=>{n&&await n(),S(!1)},T=Ve.createElement,Y="var(--sb-orange)",B="var(--sb-green)",R="var(--sb-orange-solid)",ue="var(--sb-green-solid)",K="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",O=(U,I,D,N,z)=>T("button",{type:"button",onClick:I,style:Object.assign({width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${U?"rgba(var(--sb-orange-rgb), 0.45)":"rgba(var(--sb-ink), 0.07)"}`,background:U?"rgba(var(--sb-orange-rgb), 0.06)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"},z||{})},[T("span",{key:"ring",style:{flex:"none",width:"18px",height:"18px",marginTop:"1px",borderRadius:"50%",border:`1.5px solid ${U?Y:"rgba(var(--sb-ink), 0.22)"}`,display:"grid",placeItems:"center"}},T("span",{style:{width:"8px",height:"8px",borderRadius:"50%",background:U?R:"transparent"}})),T("span",{key:"tx",style:{flex:1}},[T("span",{key:"t",style:{display:"block",fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},D),T("span",{key:"d",style:{display:"block",fontSize:"12.5px",color:"var(--sb-text-7)",marginTop:"2px"}},N)])]),Q=(U,I,D,N,z,W)=>T("button",{type:"button",onClick:I,style:{width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${U?"rgba(var(--sb-green-rgb), 0.3)":"rgba(var(--sb-ink), 0.07)"}`,background:U?"rgba(var(--sb-green-rgb), 0.05)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"}},[T("span",{key:"tx",style:{flex:1}},[T("span",{key:"r1",style:{display:"flex",alignItems:"center",gap:"8px"}},[T("span",{key:"t",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},D),W&&T("span",{key:"b",style:{fontSize:"10px",fontWeight:700,color:B,padding:"2px 7px",borderRadius:"5px",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.22)"}},W)]),T("span",{key:"d",style:{display:"block",fontSize:"12.5px",lineHeight:1.5,color:"var(--sb-text-7)",marginTop:"3px"}},N)]),T("span",{key:"tr",style:{flex:"none",width:"42px",height:"24px",borderRadius:"99px",background:U?z||ue:"rgba(var(--sb-ink), 0.08)",border:`1px solid ${U?z||B:"rgba(var(--sb-ink), 0.12)"}`,position:"relative",transition:"all .18s",marginTop:"1px"}},T("span",{style:{position:"absolute",top:"2px",insetInlineStart:"2px",width:"18px",height:"18px",borderRadius:"50%",background:"#fff",transform:U?`translateX(${18*$i()}px)`:"translateX(0)",transition:"transform .18s"}}))]),J=[];if(J.push(T("p",{key:"intro",style:{margin:"0 0 18px",fontSize:"13.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},f("ice.intro"))),J.push(O(!o,()=>c(!1),f("ice.publicTitle"),f("ice.publicDesc"))),J.push(O(o,()=>c(!0),f("ice.customTitle"),f("ice.customDesc",{max:ze.MAX_SERVERS}),o?{marginBottom:"14px"}:null)),o){let U=[];U.push(T("div",{key:"ta",style:{borderRadius:"13px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-bg-deep)",overflow:"hidden",marginBottom:"12px"}},T("textarea",{dir:"ltr",value:d,onChange:D=>u(D.target.value),rows:5,spellCheck:!1,autoComplete:"off",placeholder:$a,style:{width:"100%",resize:"vertical",border:"none",outline:"none",background:"transparent",color:"var(--sb-text-code)",fontFamily:K,fontSize:"12px",lineHeight:1.65,padding:"13px 14px",minHeight:"104px"}}))),F.errors.length>0&&U.push(T("ul",{key:"err",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-red)",fontSize:"12.5px"}},F.errors.slice(0,6).map((D,N)=>T("li",{key:N},D)))),F.warnings.length>0&&U.push(T("ul",{key:"warn",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-yellow)",fontSize:"12.5px"}},F.warnings.slice(0,6).map((D,N)=>T("li",{key:N},D)))),F.servers.length>0&&F.errors.length===0&&U.push(T("p",{key:"ok",style:{margin:"0 0 10px",fontSize:"12.5px",color:B}},`${F.servers.length} server(s) parsed${k?" (TURN present)":" (STUN only \u2014 does not hide IP)"}.`)),U.push(T("div",{key:"note",style:{display:"flex",alignItems:"flex-start",gap:"9px",padding:"12px 13px",borderRadius:"11px",border:"1px solid rgba(var(--sb-green-rgb), 0.18)",background:"rgba(var(--sb-green-rgb), 0.05)",marginBottom:"12px"}},[T("i",{key:"i",className:"fas fa-info-circle",style:{color:B,fontSize:"13px",marginTop:"2px",flex:"none"}}),T("span",{key:"t",style:{fontSize:"12px",lineHeight:1.55,color:"var(--sb-green-muted)"}},[f("ice.turnNote"),T("span",{key:"m",style:{fontFamily:K,color:B}},"turns:"),f("ice.turnNoteTls")])]));let I=g==="done"&&w&&!w.error?B:"var(--sb-text-4)";U.push(T("div",{key:"test",style:{display:"flex",alignItems:"center",gap:"12px",flexWrap:"wrap",marginBottom:"4px"}},[T("button",{key:"btn",type:"button",disabled:!E||g==="running",onClick:_,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"10px 15px",borderRadius:"10px",border:`1px solid ${g==="done"&&w&&!w.error?"rgba(var(--sb-green-rgb), 0.4)":"rgba(var(--sb-ink), 0.1)"}`,background:g==="done"&&w&&!w.error?"rgba(var(--sb-green-rgb), 0.08)":"rgba(var(--sb-ink), 0.04)",color:I,fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:!E||g==="running"?"not-allowed":"pointer",opacity:!E||g==="running"?.6:1}},[T("i",{key:"i",className:g==="running"?"fas fa-circle-notch":"fas fa-play-circle",style:g==="running"?{animation:"sbSpin 1s linear infinite"}:null}),g==="running"?f("ice.testing"):f("ice.test")]),g==="done"&&w?T("span",{key:"res",style:{fontSize:"12px",color:w.error?"var(--sb-red)":"var(--sb-text-7)"}},w.error?`Test failed: ${w.error}`:w.srflx>0||w.relay>0?`STUN ${w.srflx>0?"OK":"none"} \xB7 TURN ${w.relay>0?"OK":"none"} \xB7 host ${w.host}`:`host ${w.host} \xB7 this browser hides STUN/TURN candidates from the test \u2014 your servers still apply to real connections`):null])),J.push(T("div",{key:"custom",style:{marginBottom:"16px"}},U))}J.push(Q(h,()=>m(!h),f("ice.relayTitle"),f("ice.relayDesc"),B,f("ice.relayBadge"))),h&&o&&!k&&J.push(T("p",{key:"relaywarn",style:{margin:"-4px 0 10px",fontSize:"12.5px",color:"var(--sb-yellow)"}},f("ice.relayWarning"))),J.push(Q(p,()=>S(!p),f("ice.persist"),f("ice.persistDesc"),Y));let ge=[];return r&&ge.push(T("button",{key:"forget",type:"button",onClick:x,style:{marginInlineEnd:"auto",padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"transparent",color:"var(--sb-red)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.forget"))),ge.push(T("button",{key:"cancel",type:"button",onClick:e,style:{padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"transparent",color:"var(--sb-text-5)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.cancel"))),ge.push(T("button",{key:"apply",type:"button",onClick:A,disabled:!E,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"11px 20px",borderRadius:"11px",border:"none",background:R,color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:700,cursor:E?"pointer":"not-allowed",opacity:E?1:.5,boxShadow:"0 6px 18px rgba(var(--sb-orange-rgb), 0.28)"}},[T("i",{key:"i",className:"fas fa-check"}),f("ice.apply")])),T("div",{className:"sb-ice-overlay",style:a?{position:"absolute",inset:0,zIndex:60,display:"flex",flexDirection:"column",background:"var(--sb-bg)",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}:{position:"fixed",inset:0,zIndex:60,display:"flex",flexDirection:"column",alignItems:"stretch",background:"var(--sb-bg)",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}},[T(Ve.Fragment,{key:"panel"},[T("div",{key:"head",style:{display:"flex",alignItems:"center",gap:"12px",padding:"20px 24px",borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"}},[T("div",{key:"ic",style:{width:"38px",height:"38px",flex:"none",display:"grid",placeItems:"center",borderRadius:"10px",background:"rgba(var(--sb-ink), 0.03)",border:"1px solid rgba(var(--sb-ink), 0.06)"}},T("i",{className:"fas fa-sliders-h",style:{color:"var(--sb-text-4)",fontSize:"15px"}})),T("div",{key:"tx",style:{flex:1,lineHeight:1.25}},[T("div",{key:"t",style:{fontSize:"16.5px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-1)"}},f("ice.title")),T("div",{key:"s",style:{fontSize:"12px",color:"var(--sb-text-8)"}},f("ice.subtitle"))]),T("button",{key:"x",type:"button",onClick:e,style:{width:"32px",height:"32px",flex:"none",display:"grid",placeItems:"center",borderRadius:"9px",border:"none",background:"rgba(var(--sb-ink), 0.04)",color:"var(--sb-text-7)",cursor:"pointer"}},T("i",{className:"fas fa-times"}))]),T("div",{key:"body",className:"custom-scrollbar",style:{flex:1,overflowY:"auto",padding:"20px 24px"}},J),T("div",{key:"foot",style:{display:"flex",alignItems:"center",justifyContent:"flex-end",gap:"10px",padding:"16px 24px",borderTop:"1px solid rgba(var(--sb-ink), 0.06)",background:"var(--sb-bg-deep)",borderRadius:"0"}},ge)])])};window.IceServerSettings=qa;var ja=({webrtcManager:s,peerTitle:e})=>{let t=React.createElement,r="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",i={lock:'',minimize:'',expand:'',user:'',micOn:'',micOff:'',camOn:'',camOff:'',flip:'',phone:'',phoneHangup:''},n=(N,z,W)=>t("span",{style:{display:"grid",placeItems:"center",width:z+"px",height:z+"px"},dangerouslySetInnerHTML:{__html:`${N}`}}),[a,o]=React.useState(()=>s?.getCallState?.()||{phase:"idle",active:!1}),[c,d]=React.useState(!1),[u,h]=React.useState(0),m=React.useRef(null),p=React.useRef(null),S=React.useRef(null);React.useEffect(()=>{if(!s)return;let N=W=>o(W),z=s.onCallStateChanged;return s.onCallStateChanged=N,o(s.getCallState?s.getCallState():{phase:"idle",active:!1}),()=>{s.onCallStateChanged===N&&(s.onCallStateChanged=z||null)}},[s]);let g=a.phase||"idle",b=!!a.active,w=!!a.withVideo||!!a.remoteHasVideo;if(React.useEffect(()=>{let N=s?.getRemoteMediaStream?.(),z=s?.getLocalMediaStream?.(),W=(Z,be,_e)=>{if(!Z||!be)return;Z.srcObject!==be&&(Z.muted=_e,Z.srcObject=be);let me=Z.play&&Z.play();me&&me.catch&&me.catch(()=>{})};W(p.current,N,!1,"remoteAudio"),W(m.current,N,!0,"remoteVideo"),W(S.current,z,!0,"selfVideo")}),React.useEffect(()=>{if(g!=="active"){h(0);return}let N=Date.now(),z=setInterval(()=>h(Math.floor((Date.now()-N)/1e3)),1e3);return()=>clearInterval(z)},[g]),React.useEffect(()=>{g==="idle"&&d(!1)},[g]),!b||g==="idle"||g==="ended"||a.groupCallId)return null;let M=N=>`${String(Math.floor(N/60)).padStart(2,"0")}:${String(N%60).padStart(2,"0")}`,F=g==="outgoing"||g==="connecting",k=g==="outgoing"?f("call.ringing"):g==="connecting"?f("call.connecting"):g==="active"?M(u):f("call.ringing"),E=e||f("call.peer"),_={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"},A={..._,background:"var(--sb-red-strong-solid)",color:"#fff",border:"1px solid transparent"},x={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"var(--sb-red-strong-solid)",color:"#fff",cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-red-strong-rgb), 0.35)",transition:"transform .15s"},T=N=>({width:"36px",height:"36px",borderRadius:"9px",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), "+(N?"0.15":"0.1")+")",background:N?"rgba(0,0,0,0.35)":"rgba(var(--sb-ink), 0.04)",color:N?"#fff":"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}),Y=t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"4px",fontSize:"11px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,11,2),f("call.encryptedShort")]),B={excellent:{bars:4,color:"var(--sb-green)",solid:"var(--sb-green-solid)",label:f("call.qualityExcellent")},good:{bars:3,color:"var(--sb-green)",solid:"var(--sb-green-solid)",label:f("call.qualityGood")},fair:{bars:2,color:"var(--sb-yellow)",solid:"var(--sb-yellow-solid)",label:f("call.qualityFair")},poor:{bars:1,color:"var(--sb-red)",solid:"var(--sb-red-solid)",label:f("call.qualityWeak")}},R=N=>{let z=B[a.quality];if(!z)return null;let W=t("span",{key:"bars",style:{display:"inline-flex",alignItems:"flex-end",gap:"2px",height:"14px"}},[0,1,2,3].map(Z=>t("span",{key:Z,style:{width:"3px",height:5+Z*3+"px",borderRadius:"1px",background:Zs?.acceptCall?.(),K=()=>s?.declineCall?.(),O=()=>{d(!1),s?.endCall?.()},Q=()=>s?.toggleMic?.(),J=()=>s?.toggleCamera?.(),ge=()=>s?.switchCamera?.(),G=()=>s?.upgradeToVideo?.(),U=t("audio",{key:"ra",ref:p,autoPlay:!0,playsInline:!0,style:{display:"none"}}),I=(N,z,W)=>t("div",{key:N,style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"}},[z,t("span",{key:"l",style:{fontFamily:r,fontSize:"10.5px",color:"var(--sb-text-7)"}},W)]),D=(N,z)=>t("div",{key:"av",style:{position:"relative",width:"120px",height:"120px",marginBottom:"28px",display:"grid",placeItems:"center"}},[z&&t("span",{key:"p1",style:{position:"absolute",inset:0,borderRadius:"50%",border:"1.5px solid rgba(var(--sb-orange-rgb), 0.5)",animation:"sbCallPulse 2s ease-out infinite"}}),z&&t("span",{key:"p2",style:{position:"absolute",inset:0,borderRadius:"50%",border:"1.5px solid rgba(var(--sb-orange-rgb), 0.4)",animation:"sbCallPulse 2s ease-out infinite",animationDelay:"1s"}}),t("div",{key:"c",style:{width:"104px",height:"104px",borderRadius:"50%",display:"grid",placeItems:"center",background:"radial-gradient(circle at 35% 30%, var(--sb-surface-4), var(--sb-surface))",border:"1px solid rgba(var(--sb-ink), 0.1)",boxShadow:"0 12px 30px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))",color:"var(--sb-text-7)"}},n(i.user,N,1.6))]);return g==="incoming"?t("div",{style:{position:"absolute",inset:0,zIndex:40,display:"flex",flexDirection:"column",background:"radial-gradient(680px 460px at 50% 36%, rgba(var(--sb-orange-rgb), 0.08), transparent 70%), var(--sb-bg-deep)",animation:"sbExpand .2s ease"}},[U,t("div",{key:"top",style:{flex:"none",display:"flex",alignItems:"center",justifyContent:"flex-start",padding:"16px 18px"}},t("span",{style:{display:"inline-flex",alignItems:"center",gap:"7px",fontSize:"12px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,13,2),f("call.encrypted")])),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[D(46,!0),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},E),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},a.withVideo?f("call.incomingVideo"):f("call.incoming"))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"48px",padding:"28px 24px 40px"}},[I("dec",t("button",{onClick:K,title:f("call.decline"),style:{...x,width:"62px",height:"62px"}},n(i.phoneHangup,24,1.9)),f("call.decline")),I("acc",t("button",{onClick:ue,title:f("call.accept"),style:{width:"62px",height:"62px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"var(--sb-green-solid)",color:"var(--sb-on-green)",cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-green-rgb), 0.35)"}},n(i.phone,24,1.9)),f("call.accept"))])]):c?t("div",{style:{position:"absolute",bottom:"18px",insetInlineEnd:"18px",zIndex:40,width:"236px",borderRadius:"14px",overflow:"hidden",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.1)",boxShadow:"0 18px 44px rgba(var(--sb-shadow-rgb), calc(0.55 * var(--sb-shadow-k)))",animation:"sbExpand .18s ease"}},[U,w&&t("div",{key:"v",style:{position:"relative",height:"132px",background:"#111"}},[t("video",{key:"rv",ref:m,autoPlay:!0,muted:!0,playsInline:!0,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}}),!a.remoteHasVideo&&t("div",{key:"off",style:{position:"absolute",inset:0,display:"grid",placeItems:"center",background:"linear-gradient(120deg,var(--sb-grad-1),var(--sb-grad-2))",color:"var(--sb-text-9)"}},n(i.camOff,22,1.8)),t("span",{key:"s",style:{position:"absolute",top:"8px",insetInlineStart:"9px",fontFamily:r,fontSize:"11px",fontWeight:600,color:"#fff",padding:"3px 7px",borderRadius:"6px",background:"rgba(0,0,0,0.5)"}},k)]),t("div",{key:"bar",style:{display:"flex",alignItems:"center",gap:"11px",padding:"11px 12px"}},[t("span",{key:"ic",style:{position:"relative",flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.25)",color:"var(--sb-green)"}},n(i.user,16,1.9)),t("div",{key:"tx",style:{flex:1,minWidth:0}},[t("div",{key:"n",style:{fontSize:"13px",fontWeight:700,color:"var(--sb-text-1)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},E),t("div",{key:"s",style:{display:"flex",alignItems:"center",gap:"7px",fontFamily:r,fontSize:"11px",color:"var(--sb-text-6)"}},[(w?f("call.videoPrefix"):f("call.voicePrefix"))+k,g==="active"&&R(!0)])]),t("button",{key:"exp",onClick:()=>d(!1),title:f("call.expand"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}},n(i.expand,15,2)),t("button",{key:"end",onClick:O,title:f("call.end"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"var(--sb-red-strong-solid)",color:"#fff",cursor:"pointer",transition:"transform .15s"}},n(i.phoneHangup,15,2))])]):w?t("div",{style:{position:"absolute",inset:0,zIndex:40,overflow:"hidden",background:"var(--sb-bg-deepest)",animation:"sbExpand .2s ease"}},[U,a.remoteHasVideo?t("video",{key:"rv",ref:m,autoPlay:!0,muted:!0,playsInline:!0,style:{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",background:"var(--sb-bg-deepest)"}}):t("div",{key:"ph",style:{position:"absolute",inset:0,background:"linear-gradient(120deg, var(--sb-grad-1), var(--sb-grad-2), var(--sb-grad-3))",backgroundSize:"200% 200%",animation:"sbLiveBg 9s ease-in-out infinite",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"18px"}},[t("div",{key:"a",style:{width:"120px",height:"120px",borderRadius:"50%",display:"grid",placeItems:"center",background:"radial-gradient(circle at 35% 30%, var(--sb-surface-4), var(--sb-surface))",border:"1px solid rgba(var(--sb-ink), 0.1)",color:"var(--sb-text-6)"}},n(i.user,54,1.5)),t("div",{key:"t",style:{fontSize:"15px",fontWeight:600,color:"var(--sb-text-7)"}},f("call.peerCameraOff"))]),t("div",{key:"top",style:{position:"absolute",top:0,left:0,right:0,display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:"14px",padding:"18px 20px",background:"linear-gradient(180deg, rgba(0,0,0,0.55), transparent)"}},[t("div",{key:"l"},[t("div",{key:"n",style:{fontSize:"18px",fontWeight:800,letterSpacing:"-0.3px",color:"#fff"}},E),t("div",{key:"s",style:{display:"inline-flex",alignItems:"center",gap:"9px",marginTop:"4px"}},[t("span",{key:"st",style:{fontFamily:r,fontSize:"12.5px",fontWeight:500,color:"var(--sb-text-2)"}},k),Y,g==="active"&&R(!1)])]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:{flex:"none",...T(!0)}},n(i.minimize,16,2))]),t("div",{key:"self",style:{position:"absolute",bottom:"108px",insetInlineEnd:"18px",width:"132px",height:"176px",borderRadius:"14px",overflow:"hidden",border:"1px solid rgba(var(--sb-ink), 0.16)",boxShadow:"0 12px 30px rgba(var(--sb-shadow-rgb), calc(0.5 * var(--sb-shadow-k)))",background:"#111"}},[t("video",{key:"sv",ref:S,autoPlay:!0,muted:!0,playsInline:!0,style:{width:"100%",height:"100%",objectFit:"cover",transform:"scaleX(-1)",display:"block"}}),!a.cameraEnabled&&t("div",{key:"off",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"8px",background:"var(--sb-surface)",color:"var(--sb-text-9)"}},[n(i.camOff,24,1.8),t("span",{key:"t",style:{fontSize:"10.5px",color:"var(--sb-text-9)",fontFamily:r}},f("call.cameraOff"))])]),t("div",{key:"ctrls",style:{position:"absolute",bottom:0,left:0,right:0,display:"flex",alignItems:"center",justifyContent:"center",gap:"18px",padding:"22px 24px 28px",background:"linear-gradient(0deg, rgba(0,0,0,0.6), transparent)"}},[t("button",{key:"mute",onClick:Q,title:f("call.mute"),style:a.micEnabled?_:A},n(a.micEnabled?i.micOn:i.micOff,21,1.9)),t("button",{key:"cam",onClick:J,title:f("call.camera"),style:a.cameraEnabled?_:A},n(a.cameraEnabled?i.camOn:i.camOff,21,1.8)),t("button",{key:"flip",onClick:ge,title:f("call.flipCamera"),style:_},n(i.flip,21,1.8)),t("button",{key:"end",onClick:O,title:f("call.end"),style:x},n(i.phoneHangup,22,1.9))])]):t("div",{style:{position:"absolute",inset:0,zIndex:40,display:"flex",flexDirection:"column",background:"radial-gradient(680px 460px at 50% 36%, rgba(var(--sb-orange-rgb), 0.08), transparent 70%), var(--sb-bg-deep)",animation:"sbExpand .2s ease"}},[U,t("div",{key:"top",style:{flex:"none",display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 18px"}},[t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"7px",fontSize:"12px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,13,2),f("call.encrypted")]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:T(!1)},n(i.minimize,16,2))]),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[D(46,F),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},E),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},k),g==="active"&&t("div",{key:"q",style:{marginTop:"12px"}},R(!1))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"26px",padding:"28px 24px 34px"}},[I("mute",t("button",{onClick:Q,title:f("call.mute"),style:a.micEnabled?_:A},n(a.micEnabled?i.micOn:i.micOff,22,1.9)),a.micEnabled?"Mute":f("call.muted")),I("video",t("button",{onClick:G,title:f("call.addVideo"),style:_},n(i.camOn,22,1.8)),f("call.video")),I("end",t("button",{onClick:O,title:f("call.end"),style:x},n(i.phoneHangup,22,1.9)),f("call.endShort"))])])};typeof window<"u"&&(window.CallUIComponent=ja);window.EnhancedSecureCryptoUtils=Mt;window.EnhancedSecureWebRTCManager=$t;window.EnhancedSecureFileTransfer=je;window.NotificationIntegration=$n.NotificationIntegration;var Wa=()=>{try{let s=[];for(let e=0;e(window.__qrReady||(window.__qrReady=import("/dist/qr-local.js").then(()=>{window.dispatchEvent(new Event("securebit:qr-ready"))}).catch(s=>{console.warn("QR bundle failed to load:",s&&s.message),window.__qrReady=null})),window.__qrReady),Ya=()=>{typeof window.requestIdleCallback=="function"?window.requestIdleCallback(Bn,{timeout:3e3}):setTimeout(Bn,1200)},Hn=()=>{Wa(),typeof window.initializeApp=="function"?window.initializeApp():window.DEBUG_MODE&&console.error("initializeApp is not defined on window"),Ya()};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Hn):Hn(); +Right-click or Ctrl+click to disconnect`,isVerified:!1,dataSource:"estimated"}})();React.useEffect(()=>(window.debugHeaderSecurity=void 0,()=>{delete window.debugHeaderSecurity}),[o,d,i,a,k,_]);let A=k?k.color==="green"?"var(--sb-green)":k.color==="orange"?"var(--sb-orange)":k.color==="yellow"?"var(--sb-yellow)":"var(--sb-red)":"var(--sb-green)",x=i?"var(--sb-green-solid)":["connecting","verifying","retrying","reconnecting"].includes(s)?"var(--sb-yellow-solid)":s==="failed"?"var(--sb-red-solid)":"var(--sb-text-9)",T=x==="var(--sb-green-solid)"?"rgba(var(--sb-green-rgb), 0.16)":x==="var(--sb-yellow-solid)"?"rgba(var(--sb-yellow-rgb), 0.16)":x==="var(--sb-red-solid)"?"rgba(var(--sb-red-rgb), 0.16)":"rgba(var(--sb-text-9-rgb), 0.16)",Y="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",B=!i,[R,ue]=React.useState(!1);React.useEffect(()=>{let G=()=>ue((window.scrollY||window.pageYOffset||0)>8);return G(),window.addEventListener("scroll",G,{passive:!0}),()=>window.removeEventListener("scroll",G)},[]);let K="blur(20px) saturate(180%)",O="background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease, border-color .25s ease",Q={paddingTop:"var(--sb-safe-top, 0px)",paddingBottom:"var(--sb-bar-extra, 0px)"},J={position:"fixed",top:0,left:0,right:0,...Q},ge=B?R?{...J,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)",transition:O}:{...J,background:"transparent",backdropFilter:"blur(0px) saturate(100%)",WebkitBackdropFilter:"blur(0px) saturate(100%)",borderBottom:"1px solid transparent",transition:O}:{...Q,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"};return React.createElement("header",{className:B?"header-minimal z-50":"header-minimal sticky top-0 z-50",style:ge},[React.createElement("div",{key:"container",className:"max-w-7xl mx-auto",style:{padding:"0 20px"}},[React.createElement("div",{key:"content",className:"flex items-center justify-between",style:{height:"var(--sb-bar-h, 64px)",gap:"16px"}},[React.createElement("div",{key:"left",style:{display:"flex",alignItems:"center",gap:"12px",minWidth:0}},[React.createElement("div",{key:"logo",style:{width:"36px",height:"36px",flex:"none",display:"grid",placeItems:"center"}},React.createElement("img",{src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{width:"100%",height:"100%",objectFit:"contain",display:"block"}})),React.createElement("div",{key:"txt",style:{lineHeight:1.2,minWidth:0}},[React.createElement("div",{key:"r1",style:{display:"flex",alignItems:"baseline",gap:"7px"}},[React.createElement("span",{key:"n",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-2)"}},"SecureBit"),React.createElement("span",{key:"v",style:{fontFamily:Y,fontSize:"10px",fontWeight:500,color:"var(--sb-text-faint)"}},Ma)]),React.createElement("div",{key:"r2",className:"hidden sm:block",style:{fontSize:"11px",color:"var(--sb-text-9)",fontWeight:500}},f("hdr.tagline"))])]),React.createElement("div",{key:"right",style:{display:"flex",alignItems:"center",gap:"9px"}},[B&&React.createElement(Hr,{key:"lang"}),B&&React.createElement(Gr,{key:"theme"}),!B&&React.createElement("button",{key:"net",type:"button",onClick:()=>window.dispatchEvent(new CustomEvent("securebit:open-network-settings")),title:f("hdr.netSettingsTitle"),"aria-label":f("hdr.netSettings"),className:"sb-disconnect",style:{display:"grid",placeItems:"center",width:"38px",height:"38px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-6)",cursor:"pointer",transition:"all .15s"}},React.createElement("i",{className:"fas fa-network-wired",style:{fontSize:"13px"}})),!B&&k&&React.createElement("div",{key:"sec",onClick:w,onContextMenu:G=>{G.preventDefault(),typeof r=="function"&&r()},title:_.tooltip,className:"sb-secpill",style:{display:"flex",alignItems:"center",gap:"8px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-shield-halved",style:{fontSize:"13px",color:A}}),React.createElement("span",{key:"l",className:"hidden sm:inline",style:{fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-2)"}},f(`secLevel.${k.level}`)===`secLevel.${k.level}`?String(k.level):f(`secLevel.${k.level}`)),React.createElement("span",{key:"s",style:{fontFamily:Y,fontSize:"11.5px",color:"var(--sb-text-7)"}},k.score+"%")]),!B&&React.createElement("div",{key:"status",style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 13px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)"}},[React.createElement("span",{key:"dot",style:{width:"7px",height:"7px",borderRadius:"50%",background:x,boxShadow:"0 0 0 3px "+T}}),React.createElement("span",{key:"t",className:"hidden sm:inline",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-4)"}},F.text)]),i&&React.createElement("button",{key:"dc",onClick:r,className:"sb-disconnect",style:{display:"flex",alignItems:"center",gap:"7px",padding:"8px 14px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"transparent",color:"var(--sb-text-6)",fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:"pointer",transition:"all .15s"}},[React.createElement("i",{key:"i",className:"fas fa-power-off",style:{fontSize:"12px"}}),React.createElement("span",{key:"t",className:"sb-hide-sm"},f("hdr.disconnect"))])])])])])};window.EnhancedMinimalHeader=La;var Jt="1.0.6",qr=`https://github.com/SecureBitChat/securebit-desktop/releases/download/v${Jt}`,Da="0.8.1",Pa=()=>{let s=[{id:"web",name:"Web App",subtitle:"Browser Version",icon:"fas fa-globe",platform:"Web",isActive:!0,url:"https://securebit.chat/",color:"green"},{id:"windows",name:"Windows",subtitle:"Desktop App",icon:"fab fa-windows",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64-setup.exe`,color:"blue"},{id:"macos",name:"macOS",subtitle:"Desktop App",icon:"fab fa-safari",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64.dmg`,color:"gray"},{id:"linux",name:"Linux",subtitle:"Desktop App",icon:"fab fa-linux",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_amd64.AppImage`,color:"orange"},{id:"ios",name:"iOS",subtitle:"iPhone & iPad",icon:"fab fa-apple",platform:"Mobile",isActive:!1,url:"https://apps.apple.com/app/securebit-chat/",color:"white"},{id:"android",name:"Android",subtitle:"APK",icon:"fab fa-android",platform:"Mobile",isActive:!0,url:`/downloads/SecureBit-${Da}.apk`,color:"green"},{id:"chrome",name:"Chrome",subtitle:"Browser Extension",icon:"fab fa-chrome",platform:"Browser",isActive:!1,url:"#",color:"yellow"},{id:"edge",name:"Edge",subtitle:"Browser Extension",icon:"fab fa-edge",platform:"Browser",isActive:!1,url:"#",color:"blue"},{id:"opera",name:"Opera",subtitle:"Browser Extension",icon:"fab fa-opera",platform:"Browser",isActive:!1,url:"#",color:"red"},{id:"firefox",name:"Firefox",subtitle:"Browser Extension",icon:"fab fa-firefox-browser",platform:"Browser",isActive:!1,url:"#",color:"orange"}],e=c=>{c.isActive&&window.open(c.url,"_blank")},t=s.filter(c=>c.platform==="Desktop"||c.platform==="Web"),r=s.filter(c=>c.platform==="Mobile"),i=s.filter(c=>c.platform==="Browser"),n="w-28 h-28",a={green:"text-green-500",blue:"text-blue-500",gray:"text-gray-500",orange:"text-orange-500",red:"text-red-500",white:"text-white",yellow:"text-yellow-400"},o=c=>React.createElement("div",{key:c.id,className:`group relative ${n} rounded-2xl overflow-hidden card-minimal cursor-pointer`},[React.createElement("i",{key:"bg-icon",className:`${c.icon} absolute text-[3rem] ${c.isActive?a[c.color]:"text-white/10"} top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none transition-all duration-500 group-hover:scale-105`}),React.createElement("div",{key:"overlay",className:"absolute inset-0 bg-black/30 backdrop-blur-md flex flex-col items-center justify-center text-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"},[React.createElement("h4",{key:"name",className:"text-sm font-semibold text-primary mb-1"},c.name),React.createElement("p",{key:"subtitle",className:"text-xs text-secondary mb-2"},c.subtitle),c.isActive?React.createElement("button",{key:"btn",onClick:()=>e(c),className:"px-2 py-1 rounded-xl bg-emerald-500 text-black font-medium hover:bg-emerald-600 transition-colors text-xs"},c.id==="web"?"Launch":"Download"):React.createElement("span",{key:"coming",className:"text-gray-400 font-medium text-xs"},"Coming Soon")])]);return React.createElement("div",{className:"mt-20 px-6"},[React.createElement("div",{key:"header",className:"text-center max-w-3xl mx-auto mb-12"},[React.createElement("h3",{key:"title",className:"text-3xl font-bold text-primary mb-3"},"Download SecureBit.chat"),React.createElement("p",{key:"subtitle",className:"text-secondary text-lg mb-5"},"Stay secure on every device. Choose your platform and start chatting privately.")]),React.createElement("div",{key:"desktop-row",className:"hidden sm:flex justify-center flex-wrap gap-6 mb-6"},t.map(o)),React.createElement("div",{key:"mobile-row",className:"flex justify-center gap-6 mb-6"},r.map(o)),React.createElement("div",{key:"browser-row",className:"flex justify-center gap-6"},i.map(o))])};window.DownloadApps=Pa;var Fa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let y=window.matchMedia("(max-width:767px)"),b=()=>e(y.matches);return y.addEventListener?y.addEventListener("change",b):y.addListener(b),()=>{y.removeEventListener?y.removeEventListener("change",b):y.removeListener(b)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",n="'Manrope', system-ui, -apple-system, sans-serif",a="https://docs.google.com/forms/d/e/1FAIpQLSc9ijV9PCoyXkus6vEx1OWwvwAsLq8fKS6-H5BmX-c-bvia6w/viewform?usp=dialog",o=[{id:"aegis",name:"Aegis Investment",logo:"/logo/aegis.png",logoHeight:"42px",url:"https://aegis-investment.com/",desc:f("partners.aegis.desc"),role:f("partners.aegis.role"),delay:".5s"},{id:"furi",name:"FuriLabs",logo:"/logo/furi-160.png",logoHeight:"54px",url:"https://furilabs.com/",desc:f("partners.furilabs.desc"),role:f("partners.furilabs.role"),delay:".56s"}],c=(y,b,p,S,w)=>React.createElement("svg",{className:w,width:b,height:b,viewBox:"0 0 24 24",fill:"none",stroke:p,strokeWidth:S,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:y}}),d=y=>React.createElement("span",{key:"role",style:{fontFamily:i,fontSize:"10.5px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.2px",padding:"6px 11px",borderRadius:"8px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",whiteSpace:"nowrap"}},y),h=y=>React.createElement("a",{key:y.id,href:y.url,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",padding:"30px 30px 26px",display:"flex",flexDirection:"column",textDecoration:"none",color:"inherit",transition:"transform .28s cubic-bezier(.2,.7,.3,1), border-color .28s cubic-bezier(.2,.7,.3,1)",animation:`ptUp ${y.delay} cubic-bezier(.2,.7,.3,1)`},onMouseEnter:b=>{b.currentTarget.style.transform="translateY(-4px)",b.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.13)"},onMouseLeave:b=>{b.currentTarget.style.transform="none",b.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.06)"}},[React.createElement("div",{key:"logo",style:{display:"flex",alignItems:"center",marginBottom:"30px",height:"54px"}},React.createElement("img",{src:y.logo,alt:y.name,loading:"lazy",decoding:"async",style:{height:y.logoHeight,width:"auto",maxWidth:"190px",objectFit:"contain",display:"block"}})),React.createElement("h3",{key:"name",style:{margin:"0 0 9px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},y.name),React.createElement("p",{key:"desc",style:{margin:"0 0 22px",fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},y.desc),React.createElement("div",{key:"foot",style:{marginTop:"auto",paddingTop:"6px",display:"flex",alignItems:"center",gap:"12px"}},[d(y.role)])]),u=React.createElement("a",{key:"invite",href:a,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-bg)",border:"1px dashed rgba(var(--sb-ink), 0.12)",padding:"30px",display:"flex",flexDirection:"column",justifyContent:"space-between",textDecoration:"none",color:"inherit",transition:"border-color .28s cubic-bezier(.2,.7,.3,1)",animation:"ptUp .62s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:y=>{y.currentTarget.style.borderColor="rgba(var(--sb-orange-rgb), 0.4)"},onMouseLeave:y=>{y.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.12)"}},[React.createElement("div",{key:"top"},[React.createElement("div",{key:"icon",style:{width:"48px",height:"48px",borderRadius:"13px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.28)",marginBottom:"24px"}},c('',23,r,1.9)),React.createElement("h3",{key:"title",style:{margin:"0 0 8px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},f("partners.inviteTitle")),React.createElement("p",{key:"desc",style:{margin:0,fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("partners.inviteDesc"))]),React.createElement("span",{key:"btn",style:{marginTop:"26px",width:"100%",display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"10px",padding:"15px 20px",borderRadius:"12px",border:"none",background:r,color:"var(--sb-on-accent)",fontFamily:n,fontSize:"15px",fontWeight:700,cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",boxSizing:"border-box",transition:"background .2s cubic-bezier(.2,.7,.3,1), transform .2s cubic-bezier(.2,.7,.3,1)"}},[f("partners.inviteCta"),c('',17,"currentColor",2.2,"sb-mirror-rtl")])]),m=React.createElement("div",{key:"inner",style:{maxWidth:"1240px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{marginBottom:"44px"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:i,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"14px"}},f("partners.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:s?"30px":"40px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.04,color:"var(--sb-text-1)"}},f("partners.heading"))]),React.createElement("div",{key:"cards",style:{display:"flex",gap:"18px",alignItems:"stretch",flexWrap:"wrap"}},[...o.map(h),u])]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:n,padding:s?"48px 0":"72px 0",background:"radial-gradient(1100px 640px at 50% -6%, rgba(var(--sb-orange-rgb), 0.055), transparent 62%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ptUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),m])};window.BecomePartner=Fa;var Ka=()=>{let[s,e]=React.useState(0),[t,r]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let E=window.matchMedia("(max-width:767px)"),_=()=>r(E.matches);return E.addEventListener?E.addEventListener("change",_):E.addListener(_),()=>{E.removeEventListener?E.removeEventListener("change",_):E.removeListener(_)}},[]);let i="var(--sb-orange)",n="var(--sb-orange-solid)",a="radial-gradient(130% 90% at 28% 0%, rgba(var(--sb-orange-rgb), 0.11), transparent 60%), var(--sb-surface)",o="rgba(var(--sb-orange-rgb), 0.3)",c="var(--sb-bg)",d="rgba(var(--sb-ink), 0.06)",h="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",u="'Manrope', system-ui, -apple-system, sans-serif",m=[{num:"01",title:[f("unique.s1.titleTop"),f("unique.s1.titleBottom")],collapsed:f("unique.s1.collapsed"),desc:f("unique.s1.desc"),tags:Oe("unique.s1.tags"),icon:''},{num:"02",title:[f("unique.s2.titleTop"),f("unique.s2.titleBottom")],collapsed:f("unique.s2.collapsed"),desc:f("unique.s2.desc"),tags:Oe("unique.s2.tags"),icon:''},{num:"03",title:[f("unique.s3.titleTop"),f("unique.s3.titleBottom")],collapsed:f("unique.s3.collapsed"),desc:f("unique.s3.desc"),tags:Oe("unique.s3.tags"),icon:''},{num:"04",title:[f("unique.s4.titleTop"),f("unique.s4.titleBottom")],collapsed:f("unique.s4.collapsed"),desc:f("unique.s4.desc"),tags:Oe("unique.s4.tags"),icon:''},{num:"05",title:[f("unique.s5.titleTop"),f("unique.s5.titleBottom")],collapsed:f("unique.s5.collapsed"),desc:f("unique.s5.desc"),tags:Oe("unique.s5.tags"),icon:''}],y=(E,_,A,x)=>React.createElement("svg",{width:_,height:_,viewBox:"0 0 24 24",fill:"none",stroke:A,strokeWidth:x,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:E}}),b=E=>e(_=>(_+E+m.length)%m.length),p=(E,_,A)=>React.createElement("button",{key:E,onClick:_,"aria-label":E,className:"sb-mirror-rtl",style:{width:"46px",height:"46px",display:"grid",placeItems:"center",borderRadius:"50%",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.025)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:x=>{x.currentTarget.style.borderColor=o,x.currentTarget.style.color=i},onMouseLeave:x=>{x.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",x.currentTarget.style.color="var(--sb-text-4)"}},y(A,18,"currentColor",2.1)),S=E=>React.createElement("span",{key:E,style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",fontFamily:h,fontSize:"11.5px",fontWeight:500,color:"var(--sb-text-6)"}},[React.createElement("span",{key:"dot",style:{width:"5px",height:"5px",borderRadius:"50%",background:"var(--sb-green-solid)"}}),E]),w=E=>React.createElement("div",{key:"exp",style:{height:"100%",display:"flex",flexDirection:"column",justifyContent:t?"flex-start":"space-between",gap:t?"18px":0,padding:t?"24px 22px":"32px 34px",minWidth:t?"auto":"320px",animation:"wuUp .42s cubic-bezier(.2,.7,.3,1)"}},[React.createElement("div",{key:"top",style:{display:"flex",alignItems:"center",justifyContent:"space-between"}},[React.createElement("div",{key:"ic",style:{width:"54px",height:"54px",borderRadius:"15px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.13)",border:"1px solid rgba(var(--sb-orange-rgb), 0.3)"}},y(E.icon,26,n,1.9)),React.createElement("span",{key:"n",style:{fontFamily:h,fontSize:"13px",fontWeight:600,color:"var(--sb-text-9)"}},E.num)]),React.createElement("div",{key:"mid"},[React.createElement("h3",{key:"h",style:{margin:"0 0 12px",fontSize:t?"24px":"30px",fontWeight:800,letterSpacing:"-0.7px",lineHeight:1.08,color:"var(--sb-text-1)"}},[E.title[0],React.createElement("br",{key:"br"}),E.title[1]]),React.createElement("p",{key:"p",style:{margin:0,fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-6)",maxWidth:"380px"}},E.desc)]),React.createElement("div",{key:"tags",style:{display:"flex",flexWrap:"wrap",gap:"8px"}},E.tags.map(S))]),M=E=>t?React.createElement("div",{key:"col",style:{display:"flex",alignItems:"center",gap:"16px",padding:"20px 22px"}},[React.createElement("span",{key:"n",style:{fontFamily:h,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)"}},E.collapsed)]):React.createElement("div",{key:"col",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"space-between",padding:"24px 0"}},[React.createElement("span",{key:"n",style:{fontFamily:h,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{writingMode:"vertical-rl",transform:"rotate(180deg)",fontSize:"17px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)",whiteSpace:"nowrap"}},E.collapsed),y(E.icon,22,"var(--sb-text-faint)",1.8)]),F=m.map((E,_)=>{let A=s===_;return React.createElement("div",{key:_,onClick:()=>e(_),onMouseEnter:x=>{A||(x.currentTarget.style.filter="brightness(1.18)")},onMouseLeave:x=>{x.currentTarget.style.filter="none"},style:{flex:t?"none":A?6.2:1,minWidth:t?"auto":"72px",position:"relative",borderRadius:"18px",overflow:"hidden",cursor:"pointer",background:A?a:c,border:"1px solid "+(A?o:d),color:"var(--sb-text-7)",transition:"flex .46s cubic-bezier(.2,.7,.3,1), background .3s ease, border-color .3s ease, filter .2s ease"}},A?w(E):M(E))}),k=React.createElement("div",{key:"inner",style:{maxWidth:"1180px",margin:"0 auto",padding:t?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{display:"flex",alignItems:"flex-end",justifyContent:"space-between",gap:"24px",marginBottom:"28px"}},[React.createElement("div",{key:"titles"},[React.createElement("div",{key:"eyebrow",style:{fontFamily:h,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.4px",marginBottom:"12px"}},f("unique.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:t?"28px":"38px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("unique.heading"))]),React.createElement("div",{key:"nav",style:{display:"flex",alignItems:"center",gap:"10px",flex:"none"}},[p("prev",()=>b(-1),''),p("next",()=>b(1),'')])]),React.createElement("div",{key:"accordion",style:{display:"flex",flexDirection:t?"column":"row",gap:t?"12px":"14px",height:t?"auto":"440px"}},F)]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:u,padding:t?"44px 0":"64px 0",background:"radial-gradient(1100px 700px at 18% 8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes wuUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}"}}),k])};window.UniqueFeatureSlider=Ka;function Na(){let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let w=window.matchMedia("(max-width:767px)"),M=()=>e(w.matches);return w.addEventListener?w.addEventListener("change",M):w.addListener(M),()=>{w.removeEventListener?w.removeEventListener("change",M):w.removeListener(M)}},[]);let t="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",r="'Manrope', system-ui, -apple-system, sans-serif",i=[{v:"v1.0",k:"r1",status:"released"},{v:"v1.5",k:"r2",status:"released"},{v:"v2.0",k:"r3",status:"released"},{v:"v3.0",k:"r4",status:"released"},{v:"v3.5",k:"r5",status:"released"},{v:"v4.5",k:"r6",status:"released"},{v:"v5.0",k:"r7",status:"released"},{v:"v5.5",k:"r8",status:"released"},{v:"v6.0",k:"r9",status:"released"},{v:"v6.8",k:"r10",status:"current"},{v:"v7.0",k:"r11",status:"dev"},{v:"v8.0",k:"r12",status:"planned"},{v:"v9.0",k:"r13",status:"research"}].map(w=>({...w,title:f(`roadmap.${w.k}.title`),sub:f(`roadmap.${w.k}.sub`),date:f(`roadmap.${w.k}.date`),features:Oe(`roadmap.${w.k}.features`)})),n={released:{solid:"var(--sb-green-solid)",line:"rgba(var(--sb-green-rgb), 0.32)"},current:{solid:"var(--sb-orange-solid)",line:"rgba(var(--sb-orange-rgb), 0.32)"},dev:{solid:"var(--sb-yellow-2-solid)",line:"rgba(var(--sb-ink), 0.08)"},planned:{solid:"var(--sb-text-7)",line:"rgba(var(--sb-ink), 0.08)"},research:{solid:"var(--sb-text-9)",line:"rgba(var(--sb-ink), 0.08)"}},[a,o]=React.useState({}),c=w=>a[w]===void 0?i[w].status==="current":a[w],d=w=>o(M=>({...M,[w]:!c(w)})),h=i.length,u=i.filter(w=>w.status==="released"||w.status==="current").length,m=h-u,y=(u/h*100).toFixed(1)+"%",[b,p]=f("roadmap.progress",{total:h}).split("{shipped}"),S=w=>w==="released"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-green-rgb), 0.16),rgba(var(--sb-green-rgb), 0.16)), var(--sb-bg)",border:"1px solid rgba(var(--sb-green-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:"2.4",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M5 13l4 4 10-11"}))):w==="current"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-orange-rgb), 0.2),rgba(var(--sb-orange-rgb), 0.2)), var(--sb-bg)",border:"1px solid var(--sb-orange-solid)",zIndex:2,animation:"rmPulse 2.4s ease-out infinite"}},React.createElement("span",{style:{width:"9px",height:"9px",borderRadius:"50%",background:"var(--sb-orange-solid)"}})):w==="dev"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-yellow-2-rgb), 0.15),rgba(var(--sb-yellow-2-rgb), 0.15)), var(--sb-bg)",border:"1px solid rgba(var(--sb-yellow-2-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-yellow-2-solid)",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M12 3a9 9 0 1 0 9 9"}))):React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"var(--sb-bg)",border:`1px ${w==="research"?"dashed":"solid"} rgba(var(--sb-ink), 0.18)`,zIndex:2}},React.createElement("span",{style:{width:"7px",height:"7px",borderRadius:"50%",background:n[w].solid}}));return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:r,padding:s?"48px 0":"64px 0",background:"radial-gradient(1200px 720px at 50% -8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},React.createElement("style",{dangerouslySetInnerHTML:{__html:"@keyframes rmExp{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes rmPulse{0%,100%{box-shadow:0 0 0 0 rgba(var(--sb-orange-rgb), 0.18)}60%{box-shadow:0 0 0 9px rgba(var(--sb-orange-rgb), 0)}}"}}),React.createElement("div",{style:{maxWidth:"1040px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},React.createElement("div",{style:{marginBottom:"30px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"13px"}},f("roadmap.eyebrow")),React.createElement("h2",{style:{margin:"0 0 14px",fontSize:s?"27px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("roadmap.heading")),React.createElement("p",{style:{margin:0,fontSize:"15.5px",lineHeight:1.6,color:"var(--sb-text-7)",maxWidth:"660px"}},f("roadmap.subheading"))),React.createElement("div",{style:{display:"flex",alignItems:"center",gap:"18px",flexWrap:"wrap",padding:"18px 22px",borderRadius:"14px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",marginBottom:"36px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"12px",fontWeight:600,color:"var(--sb-text-2)",whiteSpace:"nowrap"}},b,React.createElement("span",{style:{color:"var(--sb-green)"}},u),p),React.createElement("div",{style:{flex:"1 1 240px",minWidth:"200px",height:"8px",borderRadius:"99px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.06)",overflow:"hidden"}},React.createElement("div",{style:{height:"100%",width:y,background:"linear-gradient(90deg, var(--sb-green), var(--sb-orange))"}})),React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},f("roadmap.upcoming",{upcoming:m}))),i.map((w,M)=>{let F=n[w.status],k=c(M),E=Md(M),style:{display:"flex",alignItems:"center",gap:s?"11px":"16px",padding:s?"16px 16px":"18px 22px",cursor:"pointer",transition:"background .18s ease"},onMouseEnter:_=>{_.currentTarget.style.background="rgba(var(--sb-ink), 0.018)"},onMouseLeave:_=>{_.currentTarget.style.background="transparent"}},React.createElement("div",{style:{flex:"none",minWidth:"52px",textAlign:"center",padding:"7px 10px",borderRadius:"9px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.07)",fontFamily:t,fontSize:"13px",fontWeight:700,color:w.status==="current"?"var(--sb-orange)":"var(--sb-text-4)"}},w.v),React.createElement("div",{style:{flex:1,minWidth:0}},React.createElement("div",{style:{fontSize:s?"15.5px":"17px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},w.title),!s&&React.createElement("div",{style:{marginTop:"3px",fontSize:"13.5px",color:"var(--sb-text-6)"}},w.sub)),React.createElement("div",{style:{flex:"none",display:"flex",alignItems:"center",gap:s?"8px":"14px"}},!s&&React.createElement("span",{style:{fontFamily:t,fontSize:"12px",fontWeight:500,color:"var(--sb-text-7)",whiteSpace:"nowrap",minWidth:"74px",textAlign:"end"}},w.date),React.createElement("span",{style:{color:"var(--sb-text-9)",display:"inline-flex",transition:"transform .22s cubic-bezier(.2,.7,.3,1)",transform:k?"rotate(180deg)":"rotate(0deg)"}},React.createElement("svg",{width:"17",height:"17",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.1",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M6 9l6 6 6-6"}))))),k&&React.createElement("div",{style:{padding:"4px 22px 22px 22px",animation:"rmExp .24s cubic-bezier(.2,.7,.3,1)"}},React.createElement("div",{style:{fontFamily:t,fontSize:"10px",fontWeight:600,color:"var(--sb-text-faint)",textTransform:"uppercase",letterSpacing:"1.2px",marginBottom:"14px",paddingTop:"14px",borderTop:"1px solid rgba(var(--sb-ink), 0.05)"}},f("roadmap.keyFeatures")),React.createElement("div",{style:{display:"grid",gridTemplateColumns:s?"1fr":"1fr 1fr",gap:"11px 28px"}},w.features.map((_,A)=>React.createElement("div",{key:A,style:{display:"flex",alignItems:"flex-start",gap:"10px"}},React.createElement("span",{style:{flex:"none",marginTop:"7px",width:"5px",height:"5px",borderRadius:"50%",background:F.solid}}),React.createElement("span",{style:{fontSize:"13.5px",lineHeight:1.5,color:"var(--sb-text-4)"}},_)))))))})))}window.Roadmap=Na;var Et=[{id:"usdt",tab:"USDT",coin:"Tether USDT",badge:"trx",address:"TMopDoco5EwJB1QvQYsuhjUJdMvzPXNQYu"},{id:"btc",tab:"BTC",coin:"Bitcoin",badge:null,address:"bc1qnmc2xl7p0pxcy6lzf2tyf52wnslgzkgaq9kxpr"},{id:"eth",tab:"ETH",coin:"Ethereum",badge:null,address:"0xCDfDfaD4EC1fa657C3d2A7EFabc1cb751bf1dAf7"}],jr=s=>`/assets/crypto/${s}.svg`,Wr="__sbScrollToDonate",Yr="securebit:scroll-to-donate",Oa=5e3,Xr=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches),[t,r]=React.useState(0),[i,n]=React.useState(!1),[a,o]=React.useState(0),c=React.useRef(null),d=React.useRef(null),h=React.useRef(null);React.useEffect(()=>{let K=window.matchMedia("(max-width:767px)"),O=()=>e(K.matches);return K.addEventListener?K.addEventListener("change",O):K.addListener(O),()=>{K.removeEventListener?K.removeEventListener("change",O):K.removeListener(O),clearTimeout(h.current)}},[]),React.useEffect(()=>{let K=null,O=()=>{let Q=window[Wr];window[Wr]=0,!(!Q||Date.now()-Q>Oa)&&(clearTimeout(K),K=setTimeout(()=>{let J=d.current;if(!J)return;let ge=window.matchMedia("(prefers-reduced-motion: reduce)").matches;J.scrollIntoView({behavior:ge?"auto":"smooth",block:"center"})},350))};return O(),document.addEventListener(Yr,O),()=>{document.removeEventListener(Yr,O),clearTimeout(K)}},[]);let u=Et[t],m=K=>{let O=(K+Et.length)%Et.length;O!==t&&(o(K>t?1:-1),r(O),n(!1))},y=K=>{let O=K.touches[0];c.current={x:O.clientX,y:O.clientY}},b=K=>{let O=c.current;if(c.current=null,!O)return;let Q=K.changedTouches[0],J=Q.clientX-O.x,ge=Q.clientY-O.y;if(Math.abs(J)<40||Math.abs(J)0:J<0;m(t+(G?1:-1))},p=async()=>{try{await navigator.clipboard.writeText(u.address)}catch{let O=document.createElement("textarea");O.value=u.address,document.body.appendChild(O),O.select();try{document.execCommand("copy")}catch{}O.remove()}n(!0),clearTimeout(h.current),h.current=setTimeout(()=>n(!1),1800)},S="'Manrope', system-ui, -apple-system, sans-serif",w="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",M={borderRadius:"14px",background:"var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)"},F=React.createElement("div",{key:"tabs",role:"tablist",style:{...M,display:"flex",gap:"6px",padding:"5px",marginBottom:"14px"}},Et.map((K,O)=>{let Q=O===t;return React.createElement("button",{key:K.id,type:"button",role:"tab","aria-selected":Q,onClick:()=>m(O),style:{flex:"1 1 0",minWidth:0,display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"9px",padding:"11px 10px",borderRadius:"10px",border:"none",cursor:"pointer",fontFamily:S,fontSize:"14px",fontWeight:700,transition:"all .18s",background:Q?"var(--sb-surface-2)":"transparent",color:Q?"var(--sb-text-1)":"var(--sb-text-7)",boxShadow:Q?"inset 0 0 0 1px rgba(var(--sb-orange-rgb), 0.45)":"none"}},[React.createElement("span",{key:"ic",style:{position:"relative",flex:"none",width:"22px",height:"22px"}},[React.createElement("img",{key:"logo",src:jr(K.id),alt:"",width:22,height:22,style:{display:"block",width:"22px",height:"22px"}}),K.badge&&React.createElement("img",{key:"badge",src:jr(K.badge),alt:"",width:11,height:11,style:{position:"absolute",right:"-3px",bottom:"-3px",width:"11px",height:"11px",borderRadius:"50%",border:"1.5px solid var(--sb-surface-2)",background:"var(--sb-surface-2)"}})]),K.tab])})),k=React.createElement("button",{key:"copy",type:"button",onClick:p,style:{flex:"none",display:"inline-flex",alignItems:"center",gap:"8px",padding:"12px 16px",borderRadius:"10px",fontFamily:S,fontSize:"13.5px",fontWeight:700,cursor:"pointer",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-2)",border:"1px solid rgba(var(--sb-ink), 0.1)",transition:"all .18s"},onMouseEnter:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.09)"},onMouseLeave:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.05)"}},[i?React.createElement("svg",{key:"ok",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}):React.createElement("svg",{key:"cp",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),React.createElement("span",{key:"l","aria-live":"polite"},i?f("donate.copied"):f("donate.copy"))]),E=React.createElement("div",{key:"addr",style:{...M,display:"flex",alignItems:"center",gap:"12px",padding:"8px 8px 8px 18px"}},[React.createElement("div",{key:"tx",style:{flex:1,minWidth:0}},[React.createElement("div",{key:"net",style:{fontSize:"11.5px",fontWeight:600,color:"var(--sb-text-9)",marginBottom:"2px"}},f(`donate.net.${u.id}`)),React.createElement("div",{key:"a",title:u.address,dir:"ltr",style:{fontFamily:w,fontSize:"14px",color:"var(--sb-text-2)",letterSpacing:"0.3px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},u.address.slice(0,8)+"\u2026"+u.address.slice(-8))]),k]),_=React.createElement("div",{key:"warn",style:{display:"flex",alignItems:"center",gap:"7px",marginTop:"14px",fontSize:"12px",color:"var(--sb-text-9)"}},[React.createElement("svg",{key:"i",width:13,height:13,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-orange-solid)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{flex:"none"},dangerouslySetInnerHTML:{__html:''}}),f(`donate.warn.${u.id}`)]),A=React.createElement("div",{key:"left",style:{flex:"1 1 440px",minWidth:0,padding:s?"32px 22px 8px":"44px",display:"flex",flexDirection:"column"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:w,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.8px",marginBottom:"14px"}},f("donate.eyebrow")),React.createElement("h2",{key:"title",style:{margin:"0 0 10px",fontSize:s?"28px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("donate.title")),React.createElement("p",{key:"desc",style:{margin:"0 0 30px",fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("donate.description")),F,E,_]),x=Pt()?-1:1,T=a===0?"none":`${a*x>0?"cdInEnd":"cdInStart"} .28s cubic-bezier(.2,.7,.3,1)`,Y=React.createElement("div",{key:"plate",onTouchStart:y,onTouchEnd:b,style:{position:"relative",width:"232px",height:"232px",padding:"14px",borderRadius:"20px",background:"#fff",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",border:"1px solid rgba(var(--sb-ink), 0.07)",overflow:"hidden",touchAction:"pan-y",userSelect:"none"}},React.createElement("div",{key:u.id,style:{position:"relative",width:"100%",height:"100%",animation:T}},[React.createElement("img",{key:"qr",src:`/assets/crypto/qr-${u.id}.svg`,alt:f("donate.qrAlt",{coin:u.coin}),width:204,height:204,draggable:!1,style:{display:"block",width:"100%",height:"100%",imageRendering:"pixelated"}}),React.createElement("div",{key:"logo",style:{position:"absolute",left:"50%",top:"50%",transform:"translate(-50%,-50%)",width:"48px",height:"48px",borderRadius:"12px",background:"#fff",display:"grid",placeItems:"center"}},React.createElement("img",{src:jr(u.id),alt:"",width:34,height:34,draggable:!1,style:{display:"block",width:"34px",height:"34px"}}))])),B=s&&React.createElement("div",{key:"dots","aria-hidden":!0,style:{display:"flex",justifyContent:"center",gap:"7px",marginTop:"18px"}},Et.map((K,O)=>React.createElement("span",{key:K.id,style:{width:O===t?"18px":"7px",height:"7px",borderRadius:"4px",transition:"all .25s",background:O===t?"var(--sb-orange-solid)":"rgba(var(--sb-ink), 0.16)"}}))),R=React.createElement("div",{key:"right",style:{flex:"0 0 auto",minWidth:s?0:"300px",margin:"0 auto",padding:s?"24px 22px 32px":"44px",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[Y,B]),ue=React.createElement("div",{key:"card",style:{width:"100%",maxWidth:"1000px",position:"relative",overflow:"hidden",borderRadius:"24px",background:"radial-gradient(520px 420px at 100% 50%, rgba(var(--sb-orange-rgb), 0.09), transparent 70%), var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.07)",display:"flex",flexWrap:"wrap",alignItems:"stretch",animation:"cdUp .45s cubic-bezier(.2,.7,.3,1)"}},[A,R]);return React.createElement("section",{id:"donate",ref:d,style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",color:"var(--sb-text-2)",fontFamily:S,padding:s?"48px 18px":"64px 32px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:'@keyframes cdUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes cdInEnd{from{opacity:0;transform:translateX(36px)}to{opacity:1;transform:none}}@keyframes cdInStart{from{opacity:0;transform:translateX(-36px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion: reduce){#donate [style*="cdIn"]{animation:none!important}}'}}),ue])};Xr.SCROLL_FLAG=Wr;Xr.SCROLL_EVENT=Yr;window.DonateCrypto=Xr;var Ua=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let p=window.matchMedia("(max-width:767px)"),S=()=>e(p.matches);return p.addEventListener?p.addEventListener("change",S):p.addListener(S),()=>{p.removeEventListener?p.removeEventListener("change",S):p.removeListener(S)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'Manrope', system-ui, -apple-system, sans-serif",n="https://github.com/SecureBitChat/securebit-chat/",a="mailto:lockbitchat@tutanota.com",o=React.createElement("a",{key:"gh",href:n,target:"_blank",rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:r,color:"var(--sb-on-accent)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:p=>{p.currentTarget.style.background="var(--sb-orange-hi)",p.currentTarget.style.transform="translateY(-2px)"},onMouseLeave:p=>{p.currentTarget.style.background=r,p.currentTarget.style.transform="none"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"currentColor",dangerouslySetInnerHTML:{__html:''}}),f("community.github")]),c=React.createElement("a",{key:"fb",href:a,rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:"rgba(var(--sb-ink), 0.03)",color:"var(--sb-text-2)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",border:"1px solid rgba(var(--sb-ink), 0.1)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.24)",p.currentTarget.style.background="rgba(var(--sb-ink), 0.06)"},onMouseLeave:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",p.currentTarget.style.background="rgba(var(--sb-ink), 0.03)"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.9,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),f("community.feedback")]),h="/downloads/SecureBit-0.8.1.apk",u={display:"inline-flex",opacity:.9,transition:"opacity .2s"},m=p=>{p.currentTarget.style.opacity=1},y=p=>{p.currentTarget.style.opacity=.9},b=React.createElement("div",{key:"card",style:{position:"relative",overflow:"hidden",maxWidth:"860px",width:"100%",borderRadius:"24px",background:"radial-gradient(700px 360px at 50% 0%, rgba(var(--sb-orange-rgb), 0.1), transparent 65%), var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)",padding:s?"40px 24px 36px":"56px 56px 48px",textAlign:"center",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))"}},[React.createElement("div",{key:"hairline",style:{position:"absolute",top:0,left:"50%",transform:"translateX(-50%)",width:"180px",height:"1px",background:"linear-gradient(90deg, transparent, rgba(var(--sb-orange-rgb), 0.7), transparent)"}}),React.createElement("img",{key:"icon",src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{display:"inline-block",width:"64px",height:"64px",objectFit:"contain",marginBottom:"22px",animation:"ccUp .4s cubic-bezier(.2,.7,.3,1)"}}),React.createElement("h2",{key:"title",style:{margin:"0 0 16px",fontSize:s?"28px":"36px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("community.title")),React.createElement("p",{key:"desc",style:{margin:"0 auto 32px",maxWidth:"560px",fontSize:"16px",lineHeight:1.65,color:"var(--sb-text-6)"}},f("community.description")),React.createElement("div",{key:"btns",style:{display:"flex",gap:"14px",justifyContent:"center",flexWrap:"wrap"}},[o,c]),React.createElement("div",{key:"stores",style:{display:"flex",flexWrap:"wrap",gap:"12px",justifyContent:s?"center":"flex-end",marginTop:"28px"}},[React.createElement("a",{key:"apk",href:h,download:"","aria-label":"Download Android APK",style:u,onMouseEnter:m,onMouseLeave:y},React.createElement("img",{src:"/assets/badges/android-apk.svg",alt:"Download Android APK",width:171,height:56,loading:"lazy",style:{display:"block"}})),React.createElement("a",{key:"snap",href:"https://snapcraft.io/securebit-chat",target:"_blank",rel:"noopener noreferrer","aria-label":"Get it from the Snap Store",style:u,onMouseEnter:m,onMouseLeave:y},React.createElement("img",{src:"/assets/badges/snap-store.svg",alt:"Get it from the Snap Store",width:182,height:56,loading:"lazy",style:{display:"block"}}))])]);return React.createElement("section",{style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",fontFamily:i,padding:s?"48px 18px":"64px 48px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ccUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),b])};window.CommunityCTA=Ua;var za=({webrtcManager:s,isConnected:e,pendingIncomingFiles:t=[],onIncomingDecision:r,showDropzone:i=!0})=>{let[n,a]=React.useState(!1),[o,c]=React.useState({sending:[],receiving:[]}),d=React.useRef(null);React.useEffect(()=>{if(!e||!s)return;let A=setInterval(()=>{let x=s.getFileTransfers();c(x)},500);return()=>clearInterval(A)},[e,s]),React.useEffect(()=>{e||c({sending:[],receiving:[]})},[e]);let h=async _=>{if(!e||!s){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435.");return}if(!s.isConnected()||!s.isVerified){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0444\u0430\u0439\u043B\u043E\u0432. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F.");return}for(let A of _)try{let x=s.validateFile(A);if(!x.isValid){let T=x.errors.join(". ");alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${T}`);continue}await s.sendFile(A)}catch(x){x.message.includes(f("file.notReady"))?alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0441\u0435\u0439\u0447\u0430\u0441. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430.`):x.message.includes(f("file.tooLarge"))||x.message.includes("exceeds maximum")?alert(`\u0424\u0430\u0439\u043B ${A.name} \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439: ${x.message}`):x.message.includes(f("file.maxConcurrent"))?alert("\u0414\u043E\u0441\u0442\u0438\u0433\u043D\u0443\u0442 \u043B\u0438\u043C\u0438\u0442 \u043E\u0434\u043D\u043E\u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0442\u0435\u043A\u0443\u0449\u0438\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447."):x.message.includes(f("file.typeNotAllowed"))?alert(`\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 ${A.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F: ${x.message}`):alert(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${A.name}: ${x.message}`)}},u=_=>{_.preventDefault(),a(!1);let A=Array.from(_.dataTransfer.files);h(A)},m=_=>{_.preventDefault(),a(!0)},y=_=>{_.preventDefault(),a(!1)},b=_=>{let A=Array.from(_.target.files);h(A),_.target.value=""},p=_=>{if(_===0)return"0 B";let A=1024,x=["B","KB","MB","GB"],T=Math.floor(Math.log(_)/Math.log(A));return parseFloat((_/Math.pow(A,T)).toFixed(2))+" "+x[T]},S=_=>{switch(_){case"metadata_sent":case"preparing":return"fas fa-cog fa-spin";case"transmitting":case"receiving":return"fas fa-exchange-alt fa-pulse";case"assembling":return"fas fa-puzzle-piece fa-pulse";case"completed":return"fas fa-check text-green-400";case"failed":return"fas fa-times text-red-400";default:return"fas fa-circle"}},w=_=>{switch(_){case"metadata_sent":return"\u041F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0430...";case"transmitting":return"\u041E\u0442\u043F\u0440\u0430\u0432\u043A\u0430...";case"receiving":return"\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435...";case"assembling":return"\u0421\u0431\u043E\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u0430...";case"completed":return"\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E";case"failed":return"\u041E\u0448\u0438\u0431\u043A\u0430";default:return _}},M=(_,A)=>{let x=_.totalChunks||0,T=_.transferredChunks||0,Y=_.status==="completed",B=x>0?Math.min(x,32):24,R;return Y?R=B:x>0?R=Math.floor(T/x*B):R=Math.floor((_.progress||0)/100*B),R=Math.max(0,Math.min(B,R)),React.createElement("div",{key:"progress"},[React.createElement("div",{key:"squares",style:{display:"flex",flexWrap:"wrap",gap:"3px",marginBottom:"7px"}},Array.from({length:B},(ue,K)=>React.createElement("div",{key:K,style:{width:"11px",height:"11px",borderRadius:"2px",background:K0?`${Math.min(T,x)} / ${x} chunks`:`${(_.progress||0).toFixed(0)}%`)])])},F=_=>_.status==="completed",k=async(_,A)=>{typeof r=="function"&&await r(_,A),c(s.getFileTransfers())};return e?s&&s.isConnected()&&s.isVerified?React.createElement("div",{className:"file-transfer-component"},[i&&React.createElement("div",{key:"drop-zone",onDrop:u,onDragOver:m,onDragLeave:y,style:{position:"relative",border:"1.5px dashed "+(n?"rgba(var(--sb-orange-rgb), 0.7)":"rgba(var(--sb-ink), 0.14)"),borderRadius:"14px",background:n?"rgba(var(--sb-orange-rgb), 0.07)":"var(--sb-surface)",padding:"24px 22px",textAlign:"center",transition:"all .15s"}},[React.createElement("div",{key:"icon-box",style:{width:"42px",height:"42px",margin:"0 auto 10px",borderRadius:"12px",display:"grid",placeItems:"center",background:"rgba(var(--sb-ink), 0.04)",border:"1px solid rgba(var(--sb-ink), 0.08)"}},React.createElement("i",{className:"fas fa-arrow-up-from-bracket",style:{color:"var(--sb-text-6)",fontSize:"18px"}})),React.createElement("div",{key:"title",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-2)"}},f("file.drop")),React.createElement("div",{key:"sub",style:{fontSize:"12px",color:"var(--sb-text-8)",marginTop:"4px"}},f("file.dropHint")),React.createElement("button",{key:"browse",type:"button",onClick:()=>d.current?.click(),className:"sb-send",style:{marginTop:"14px",display:"inline-flex",alignItems:"center",gap:"7px",padding:"9px 16px",borderRadius:"9px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-folder-open",style:{fontSize:"13px"}}),f("file.browse")])]),i&&React.createElement("input",{key:"file-input",ref:d,type:"file",multiple:!0,className:"hidden",onChange:b}),t.length>0&&React.createElement("div",{key:"incoming-consent",className:"mt-4 space-y-2"},t.map(_=>React.createElement("div",{key:_.fileId,style:{borderRadius:"12px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",padding:"12px 14px"}},[React.createElement("div",{key:"info",style:{marginBottom:"12px",display:"flex",alignItems:"center",gap:"11px"}},[React.createElement("div",{key:"ic",style:{flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.22)"}},React.createElement("i",{className:"fas fa-file-arrow-down",style:{color:"var(--sb-orange)",fontSize:"15px"}})),React.createElement("div",{key:"text",style:{minWidth:0}},[React.createElement("div",{key:"title",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-2)"}},f("file.incoming")),React.createElement("div",{key:"meta",style:{fontSize:"11.5px",color:"var(--sb-text-8)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},`${_.fileName} \xB7 ${p(_.fileSize)} \xB7 ${_.mimeType}`)])]),React.createElement("div",{key:"actions",style:{display:"flex",gap:"8px"}},[React.createElement("button",{key:"accept",onClick:()=>k(_.fileId,!0),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",padding:"8px 14px",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-check",style:{fontSize:"12px"}}),f("file.accept")]),React.createElement("button",{key:"reject",onClick:()=>k(_.fileId,!1),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"rgba(var(--sb-red-rgb), 0.08)",color:"var(--sb-red)",padding:"8px 14px",fontSize:"13px",fontWeight:600,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-xmark",style:{fontSize:"12px"}}),f("file.reject")])])]))),(o.sending.length>0||o.receiving.length>0)&&React.createElement("div",{key:"transfers",className:"active-transfers mt-4"},[React.createElement("h4",{key:"title",style:{display:"flex",alignItems:"center",gap:"8px",fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-7)",marginBottom:"10px"}},[React.createElement("i",{key:"icon",className:"fas fa-right-left",style:{fontSize:"12px"}}),f("file.title")]),...o.sending.map(_=>React.createElement("div",{key:`send-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-up",style:{color:"var(--sb-orange)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},p(_.fileSize))]),React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])]),M(_,"var(--sb-orange)")])),...o.receiving.map(_=>React.createElement("div",{key:`recv-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-down",style:{color:"var(--sb-green)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},p(_.fileSize))]),React.createElement("div",{key:"actions",className:"flex items-center space-x-2"},[_.status==="completed"?React.createElement("button",{key:"download",className:"text-green-400 hover:text-green-300 text-xs flex items-center",onClick:async()=>{try{let A=await s.getReceivedFileObjectURL(_.fileId);if(!A){alert(f("file.gone"));return}let x=document.createElement("a");x.href=A,x.download=_.fileName||"file",x.click(),setTimeout(()=>s.revokeReceivedFileObjectURL(A),1e4)}catch(A){alert(A.message||f("file.gone"))}}},[React.createElement("i",{key:"i",className:"fas fa-download me-1"}),f("file.download")]):null,React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])])]),M(_,"var(--sb-green)")]))])]):React.createElement("div",{className:"p-4 text-center text-yellow-600"},[React.createElement("i",{key:"icon",className:"fas fa-exclamation-triangle me-2"}),"\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F... \u041F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u0431\u0443\u0434\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043F\u043E\u0441\u043B\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438."]):React.createElement("div",{className:"p-4 text-center text-muted"},f("file.needConnection"))};window.FileTransferComponent=za;var ze=Object.freeze({MAX_SERVERS:10,MAX_URLS_PER_SERVER:8,MAX_STRING_LENGTH:512}),Zo=Object.freeze(["stun","stuns","turn","turns"]),Va=/^(stuns?|turns?):/i,Ba=/^(\[[0-9a-f:]+\]|[a-z0-9.-]+)(:\d{1,5})?$/i,Ha=/^transport=(udp|tcp)$/i;function On(s){for(let e=0;eze.MAX_STRING_LENGTH)return f("iceUrl.tooLong");if(On(e))return f("iceUrl.badChars");let t=e.match(Va);if(!t)return f("iceUrl.badScheme");let r=e.slice(t[0].length),[i,n,...a]=r.split("?");return a.length>0?f("iceUrl.badQuery"):i?Ba.test(i)?n!==void 0&&!Ha.test(n)?f("iceUrl.badTransport"):null:f("iceUrl.badHost"):f("iceUrl.noHost")}function Un(s){return typeof s=="string"&&/^turns?:/i.test(s.trim())}function Kn(s,e){return s==null||s===""?null:typeof s!="string"?`${e} must be a string`:s.length>ze.MAX_STRING_LENGTH?`${e} is too long`:On(s)?`${e} contains invalid characters`:null}function Nn(s){let e=[],t=[],r=[];return Array.isArray(s)?s.length===0?{servers:[],errors:[],warnings:[]}:s.length>ze.MAX_SERVERS?(e.push(f("iceErr.tooMany",{max:ze.MAX_SERVERS})),{servers:[],errors:e,warnings:t}):(s.forEach((i,n)=>{let a=`Server #${n+1}`;if(!i||typeof i!="object"){e.push(f("iceErr.invalidEntry",{label:a}));return}let o=Array.isArray(i.urls)?i.urls:[i.urls];if(o.length===0||o.length>ze.MAX_URLS_PER_SERVER){e.push(f("iceErr.urlCount",{label:a,max:ze.MAX_URLS_PER_SERVER}));return}let c=[],d=!1;for(let y of o){let b=$a(y);if(b){e.push(`${a}: ${b}`);continue}let p=y.trim();c.push(p),Un(p)&&(d=!0)}if(c.length===0)return;let h=Kn(i.username,`${a} username`);h&&e.push(h);let u=Kn(i.credential,`${a} credential`);u&&e.push(u);let m={urls:c.length===1?c[0]:c};i.username&&(m.username=String(i.username)),i.credential&&(m.credential=String(i.credential)),d&&(!m.username||!m.credential)&&t.push(f("iceErr.turnCreds",{label:a})),r.push(m)}),{servers:r,errors:e,warnings:t}):{servers:[],errors:[f("iceErr.notArray")],warnings:[]}}function zn(s){if(typeof s!="string"||!s.trim())return{servers:[],errors:[],warnings:[]};let e=s.trim();if(e.startsWith("[")||e.startsWith("{")){let r;try{r=JSON.parse(e)}catch{return{servers:[],errors:[f("iceErr.invalidJson")],warnings:[]}}let i=Array.isArray(r)?r:[r];return Nn(i)}let t=e.split(` +`).map(r=>r.trim()).filter(Boolean).map(r=>({urls:r}));return Nn(t)}function Vn(s){return Array.isArray(s)?s.some(e=>(Array.isArray(e?.urls)?e.urls:[e?.urls]).some(Un)):!1}var Ve=window.React,Ga=["# One URL per line, e.g.:","stun:stun.example.com:3478","turn:turn.example.com:3478?transport=udp","","# Or paste JSON for servers with credentials:",'[{"urls":"turns:turn.example.com:5349","username":"user","credential":"secret"}]'].join(` +`);async function qa(s,e=6e3){let t={host:0,srflx:0,relay:0};if(typeof RTCPeerConnection>"u")return{...t,error:f("ice.errUnavailable")};let r;try{r=new RTCPeerConnection({iceServers:s})}catch(i){return{...t,error:i.message||f("ice.errInvalid")}}return new Promise(i=>{let n=!1,a=()=>{if(!n){n=!0,clearTimeout(o);try{r.close()}catch{}i(t)}},o=setTimeout(a,e);r.onicecandidate=c=>{if(!c.candidate){a();return}let d=c.candidate.candidate||"";/ typ host/.test(d)?t.host++:/ typ srflx/.test(d)?t.srflx++:/ typ relay/.test(d)&&t.relay++};try{r.createDataChannel("securebit-ice-test"),r.createOffer().then(c=>r.setLocalDescription(c)).catch(()=>a())}catch{a()}})}var ja=({isOpen:s,onClose:e,initial:t,hasSaved:r,onApply:i,onForget:n,embedded:a})=>{if(!s)return null;let[o,c]=Ve.useState(t?.useCustom||!1),[d,h]=Ve.useState(t?.serversText||""),[u,m]=Ve.useState(t?.privacyMode==="relay-only"),[y,b]=Ve.useState(t?.persisted||!1),[p,S]=Ve.useState("idle"),[w,M]=Ve.useState(null),F=o?zn(d):{servers:[],errors:[],warnings:[]},k=Vn(F.servers),E=!o||F.servers.length>0&&F.errors.length===0,_=async()=>{S("running"),M(null);let U=await qa(F.servers);M(U),S("done")},A=()=>{E&&i({useCustom:o,servers:o?F.servers:[],privacyMode:u?"relay-only":"standard",serversText:d},y)},x=async()=>{n&&await n(),b(!1)},T=Ve.createElement,Y="var(--sb-orange)",B="var(--sb-green)",R="var(--sb-orange-solid)",ue="var(--sb-green-solid)",K="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",O=(U,I,D,N,z)=>T("button",{type:"button",onClick:I,style:Object.assign({width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${U?"rgba(var(--sb-orange-rgb), 0.45)":"rgba(var(--sb-ink), 0.07)"}`,background:U?"rgba(var(--sb-orange-rgb), 0.06)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"},z||{})},[T("span",{key:"ring",style:{flex:"none",width:"18px",height:"18px",marginTop:"1px",borderRadius:"50%",border:`1.5px solid ${U?Y:"rgba(var(--sb-ink), 0.22)"}`,display:"grid",placeItems:"center"}},T("span",{style:{width:"8px",height:"8px",borderRadius:"50%",background:U?R:"transparent"}})),T("span",{key:"tx",style:{flex:1}},[T("span",{key:"t",style:{display:"block",fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},D),T("span",{key:"d",style:{display:"block",fontSize:"12.5px",color:"var(--sb-text-7)",marginTop:"2px"}},N)])]),Q=(U,I,D,N,z,W)=>T("button",{type:"button",onClick:I,style:{width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${U?"rgba(var(--sb-green-rgb), 0.3)":"rgba(var(--sb-ink), 0.07)"}`,background:U?"rgba(var(--sb-green-rgb), 0.05)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"}},[T("span",{key:"tx",style:{flex:1}},[T("span",{key:"r1",style:{display:"flex",alignItems:"center",gap:"8px"}},[T("span",{key:"t",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},D),W&&T("span",{key:"b",style:{fontSize:"10px",fontWeight:700,color:B,padding:"2px 7px",borderRadius:"5px",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.22)"}},W)]),T("span",{key:"d",style:{display:"block",fontSize:"12.5px",lineHeight:1.5,color:"var(--sb-text-7)",marginTop:"3px"}},N)]),T("span",{key:"tr",style:{flex:"none",width:"42px",height:"24px",borderRadius:"99px",background:U?z||ue:"rgba(var(--sb-ink), 0.08)",border:`1px solid ${U?z||B:"rgba(var(--sb-ink), 0.12)"}`,position:"relative",transition:"all .18s",marginTop:"1px"}},T("span",{style:{position:"absolute",top:"2px",insetInlineStart:"2px",width:"18px",height:"18px",borderRadius:"50%",background:"#fff",transform:U?`translateX(${18*$i()}px)`:"translateX(0)",transition:"transform .18s"}}))]),J=[];if(J.push(T("p",{key:"intro",style:{margin:"0 0 18px",fontSize:"13.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},f("ice.intro"))),J.push(O(!o,()=>c(!1),f("ice.publicTitle"),f("ice.publicDesc"))),J.push(O(o,()=>c(!0),f("ice.customTitle"),f("ice.customDesc",{max:ze.MAX_SERVERS}),o?{marginBottom:"14px"}:null)),o){let U=[];U.push(T("div",{key:"ta",style:{borderRadius:"13px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-bg-deep)",overflow:"hidden",marginBottom:"12px"}},T("textarea",{dir:"ltr",value:d,onChange:D=>h(D.target.value),rows:5,spellCheck:!1,autoComplete:"off",placeholder:Ga,style:{width:"100%",resize:"vertical",border:"none",outline:"none",background:"transparent",color:"var(--sb-text-code)",fontFamily:K,fontSize:"12px",lineHeight:1.65,padding:"13px 14px",minHeight:"104px"}}))),F.errors.length>0&&U.push(T("ul",{key:"err",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-red)",fontSize:"12.5px"}},F.errors.slice(0,6).map((D,N)=>T("li",{key:N},D)))),F.warnings.length>0&&U.push(T("ul",{key:"warn",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-yellow)",fontSize:"12.5px"}},F.warnings.slice(0,6).map((D,N)=>T("li",{key:N},D)))),F.servers.length>0&&F.errors.length===0&&U.push(T("p",{key:"ok",style:{margin:"0 0 10px",fontSize:"12.5px",color:B}},`${F.servers.length} server(s) parsed${k?" (TURN present)":" (STUN only \u2014 does not hide IP)"}.`)),U.push(T("div",{key:"note",style:{display:"flex",alignItems:"flex-start",gap:"9px",padding:"12px 13px",borderRadius:"11px",border:"1px solid rgba(var(--sb-green-rgb), 0.18)",background:"rgba(var(--sb-green-rgb), 0.05)",marginBottom:"12px"}},[T("i",{key:"i",className:"fas fa-info-circle",style:{color:B,fontSize:"13px",marginTop:"2px",flex:"none"}}),T("span",{key:"t",style:{fontSize:"12px",lineHeight:1.55,color:"var(--sb-green-muted)"}},[f("ice.turnNote"),T("span",{key:"m",style:{fontFamily:K,color:B}},"turns:"),f("ice.turnNoteTls")])]));let I=p==="done"&&w&&!w.error?B:"var(--sb-text-4)";U.push(T("div",{key:"test",style:{display:"flex",alignItems:"center",gap:"12px",flexWrap:"wrap",marginBottom:"4px"}},[T("button",{key:"btn",type:"button",disabled:!E||p==="running",onClick:_,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"10px 15px",borderRadius:"10px",border:`1px solid ${p==="done"&&w&&!w.error?"rgba(var(--sb-green-rgb), 0.4)":"rgba(var(--sb-ink), 0.1)"}`,background:p==="done"&&w&&!w.error?"rgba(var(--sb-green-rgb), 0.08)":"rgba(var(--sb-ink), 0.04)",color:I,fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:!E||p==="running"?"not-allowed":"pointer",opacity:!E||p==="running"?.6:1}},[T("i",{key:"i",className:p==="running"?"fas fa-circle-notch":"fas fa-play-circle",style:p==="running"?{animation:"sbSpin 1s linear infinite"}:null}),p==="running"?f("ice.testing"):f("ice.test")]),p==="done"&&w?T("span",{key:"res",style:{fontSize:"12px",color:w.error?"var(--sb-red)":"var(--sb-text-7)"}},w.error?`Test failed: ${w.error}`:w.srflx>0||w.relay>0?`STUN ${w.srflx>0?"OK":"none"} \xB7 TURN ${w.relay>0?"OK":"none"} \xB7 host ${w.host}`:`host ${w.host} \xB7 this browser hides STUN/TURN candidates from the test \u2014 your servers still apply to real connections`):null])),J.push(T("div",{key:"custom",style:{marginBottom:"16px"}},U))}J.push(Q(u,()=>m(!u),f("ice.relayTitle"),f("ice.relayDesc"),B,f("ice.relayBadge"))),u&&o&&!k&&J.push(T("p",{key:"relaywarn",style:{margin:"-4px 0 10px",fontSize:"12.5px",color:"var(--sb-yellow)"}},f("ice.relayWarning"))),J.push(Q(y,()=>b(!y),f("ice.persist"),f("ice.persistDesc"),Y));let ge=[];return r&&ge.push(T("button",{key:"forget",type:"button",onClick:x,style:{marginInlineEnd:"auto",padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"transparent",color:"var(--sb-red)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.forget"))),ge.push(T("button",{key:"cancel",type:"button",onClick:e,style:{padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"transparent",color:"var(--sb-text-5)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.cancel"))),ge.push(T("button",{key:"apply",type:"button",onClick:A,disabled:!E,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"11px 20px",borderRadius:"11px",border:"none",background:R,color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:700,cursor:E?"pointer":"not-allowed",opacity:E?1:.5,boxShadow:"0 6px 18px rgba(var(--sb-orange-rgb), 0.28)"}},[T("i",{key:"i",className:"fas fa-check"}),f("ice.apply")])),T("div",{className:"sb-ice-overlay",style:a?{position:"absolute",inset:0,zIndex:60,display:"flex",flexDirection:"column",background:"var(--sb-bg)",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}:{position:"fixed",inset:0,zIndex:60,display:"flex",flexDirection:"column",alignItems:"stretch",background:"var(--sb-bg)",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}},[T(Ve.Fragment,{key:"panel"},[T("div",{key:"head",style:{display:"flex",alignItems:"center",gap:"12px",padding:"20px 24px",borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"}},[T("div",{key:"ic",style:{width:"38px",height:"38px",flex:"none",display:"grid",placeItems:"center",borderRadius:"10px",background:"rgba(var(--sb-ink), 0.03)",border:"1px solid rgba(var(--sb-ink), 0.06)"}},T("i",{className:"fas fa-sliders-h",style:{color:"var(--sb-text-4)",fontSize:"15px"}})),T("div",{key:"tx",style:{flex:1,lineHeight:1.25}},[T("div",{key:"t",style:{fontSize:"16.5px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-1)"}},f("ice.title")),T("div",{key:"s",style:{fontSize:"12px",color:"var(--sb-text-8)"}},f("ice.subtitle"))]),T("button",{key:"x",type:"button",onClick:e,style:{width:"32px",height:"32px",flex:"none",display:"grid",placeItems:"center",borderRadius:"9px",border:"none",background:"rgba(var(--sb-ink), 0.04)",color:"var(--sb-text-7)",cursor:"pointer"}},T("i",{className:"fas fa-times"}))]),T("div",{key:"body",className:"custom-scrollbar",style:{flex:1,overflowY:"auto",padding:"20px 24px"}},J),T("div",{key:"foot",style:{display:"flex",alignItems:"center",justifyContent:"flex-end",gap:"10px",padding:"16px 24px",borderTop:"1px solid rgba(var(--sb-ink), 0.06)",background:"var(--sb-bg-deep)",borderRadius:"0"}},ge)])])};window.IceServerSettings=ja;var Wa=({webrtcManager:s,peerTitle:e})=>{let t=React.createElement,r="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",i={lock:'',minimize:'',expand:'',user:'',micOn:'',micOff:'',camOn:'',camOff:'',flip:'',phone:'',phoneHangup:''},n=(N,z,W)=>t("span",{style:{display:"grid",placeItems:"center",width:z+"px",height:z+"px"},dangerouslySetInnerHTML:{__html:`${N}`}}),[a,o]=React.useState(()=>s?.getCallState?.()||{phase:"idle",active:!1}),[c,d]=React.useState(!1),[h,u]=React.useState(0),m=React.useRef(null),y=React.useRef(null),b=React.useRef(null);React.useEffect(()=>{if(!s)return;let N=W=>o(W),z=s.onCallStateChanged;return s.onCallStateChanged=N,o(s.getCallState?s.getCallState():{phase:"idle",active:!1}),()=>{s.onCallStateChanged===N&&(s.onCallStateChanged=z||null)}},[s]);let p=a.phase||"idle",S=!!a.active,w=!!a.withVideo||!!a.remoteHasVideo;if(React.useEffect(()=>{let N=s?.getRemoteMediaStream?.(),z=s?.getLocalMediaStream?.(),W=(Z,be,_e)=>{if(!Z||!be)return;Z.srcObject!==be&&(Z.muted=_e,Z.srcObject=be);let me=Z.play&&Z.play();me&&me.catch&&me.catch(()=>{})};W(y.current,N,!1,"remoteAudio"),W(m.current,N,!0,"remoteVideo"),W(b.current,z,!0,"selfVideo")}),React.useEffect(()=>{if(p!=="active"){u(0);return}let N=Date.now(),z=setInterval(()=>u(Math.floor((Date.now()-N)/1e3)),1e3);return()=>clearInterval(z)},[p]),React.useEffect(()=>{p==="idle"&&d(!1)},[p]),!S||p==="idle"||p==="ended"||a.groupCallId)return null;let M=N=>`${String(Math.floor(N/60)).padStart(2,"0")}:${String(N%60).padStart(2,"0")}`,F=p==="outgoing"||p==="connecting",k=p==="outgoing"?f("call.ringing"):p==="connecting"?f("call.connecting"):p==="active"?M(h):f("call.ringing"),E=e||f("call.peer"),_={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"},A={..._,background:"var(--sb-red-strong-solid)",color:"#fff",border:"1px solid transparent"},x={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"var(--sb-red-strong-solid)",color:"#fff",cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-red-strong-rgb), 0.35)",transition:"transform .15s"},T=N=>({width:"36px",height:"36px",borderRadius:"9px",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), "+(N?"0.15":"0.1")+")",background:N?"rgba(0,0,0,0.35)":"rgba(var(--sb-ink), 0.04)",color:N?"#fff":"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}),Y=t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"4px",fontSize:"11px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,11,2),f("call.encryptedShort")]),B={excellent:{bars:4,color:"var(--sb-green)",solid:"var(--sb-green-solid)",label:f("call.qualityExcellent")},good:{bars:3,color:"var(--sb-green)",solid:"var(--sb-green-solid)",label:f("call.qualityGood")},fair:{bars:2,color:"var(--sb-yellow)",solid:"var(--sb-yellow-solid)",label:f("call.qualityFair")},poor:{bars:1,color:"var(--sb-red)",solid:"var(--sb-red-solid)",label:f("call.qualityWeak")}},R=N=>{let z=B[a.quality];if(!z)return null;let W=t("span",{key:"bars",style:{display:"inline-flex",alignItems:"flex-end",gap:"2px",height:"14px"}},[0,1,2,3].map(Z=>t("span",{key:Z,style:{width:"3px",height:5+Z*3+"px",borderRadius:"1px",background:Zs?.acceptCall?.(),K=()=>s?.declineCall?.(),O=()=>{d(!1),s?.endCall?.()},Q=()=>s?.toggleMic?.(),J=()=>s?.toggleCamera?.(),ge=()=>s?.switchCamera?.(),G=()=>s?.upgradeToVideo?.(),U=t("audio",{key:"ra",ref:y,autoPlay:!0,playsInline:!0,style:{display:"none"}}),I=(N,z,W)=>t("div",{key:N,style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"}},[z,t("span",{key:"l",style:{fontFamily:r,fontSize:"10.5px",color:"var(--sb-text-7)"}},W)]),D=(N,z)=>t("div",{key:"av",style:{position:"relative",width:"120px",height:"120px",marginBottom:"28px",display:"grid",placeItems:"center"}},[z&&t("span",{key:"p1",style:{position:"absolute",inset:0,borderRadius:"50%",border:"1.5px solid rgba(var(--sb-orange-rgb), 0.5)",animation:"sbCallPulse 2s ease-out infinite"}}),z&&t("span",{key:"p2",style:{position:"absolute",inset:0,borderRadius:"50%",border:"1.5px solid rgba(var(--sb-orange-rgb), 0.4)",animation:"sbCallPulse 2s ease-out infinite",animationDelay:"1s"}}),t("div",{key:"c",style:{width:"104px",height:"104px",borderRadius:"50%",display:"grid",placeItems:"center",background:"radial-gradient(circle at 35% 30%, var(--sb-surface-4), var(--sb-surface))",border:"1px solid rgba(var(--sb-ink), 0.1)",boxShadow:"0 12px 30px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))",color:"var(--sb-text-7)"}},n(i.user,N,1.6))]);return p==="incoming"?t("div",{style:{position:"absolute",inset:0,zIndex:40,display:"flex",flexDirection:"column",background:"radial-gradient(680px 460px at 50% 36%, rgba(var(--sb-orange-rgb), 0.08), transparent 70%), var(--sb-bg-deep)",animation:"sbExpand .2s ease"}},[U,t("div",{key:"top",style:{flex:"none",display:"flex",alignItems:"center",justifyContent:"flex-start",padding:"16px 18px"}},t("span",{style:{display:"inline-flex",alignItems:"center",gap:"7px",fontSize:"12px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,13,2),f("call.encrypted")])),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[D(46,!0),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},E),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},a.withVideo?f("call.incomingVideo"):f("call.incoming"))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"48px",padding:"28px 24px 40px"}},[I("dec",t("button",{onClick:K,title:f("call.decline"),style:{...x,width:"62px",height:"62px"}},n(i.phoneHangup,24,1.9)),f("call.decline")),I("acc",t("button",{onClick:ue,title:f("call.accept"),style:{width:"62px",height:"62px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"var(--sb-green-solid)",color:"var(--sb-on-green)",cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-green-rgb), 0.35)"}},n(i.phone,24,1.9)),f("call.accept"))])]):c?t("div",{style:{position:"absolute",bottom:"18px",insetInlineEnd:"18px",zIndex:40,width:"236px",borderRadius:"14px",overflow:"hidden",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.1)",boxShadow:"0 18px 44px rgba(var(--sb-shadow-rgb), calc(0.55 * var(--sb-shadow-k)))",animation:"sbExpand .18s ease"}},[U,w&&t("div",{key:"v",style:{position:"relative",height:"132px",background:"#111"}},[t("video",{key:"rv",ref:m,autoPlay:!0,muted:!0,playsInline:!0,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}}),!a.remoteHasVideo&&t("div",{key:"off",style:{position:"absolute",inset:0,display:"grid",placeItems:"center",background:"linear-gradient(120deg,var(--sb-grad-1),var(--sb-grad-2))",color:"var(--sb-text-9)"}},n(i.camOff,22,1.8)),t("span",{key:"s",style:{position:"absolute",top:"8px",insetInlineStart:"9px",fontFamily:r,fontSize:"11px",fontWeight:600,color:"#fff",padding:"3px 7px",borderRadius:"6px",background:"rgba(0,0,0,0.5)"}},k)]),t("div",{key:"bar",style:{display:"flex",alignItems:"center",gap:"11px",padding:"11px 12px"}},[t("span",{key:"ic",style:{position:"relative",flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.25)",color:"var(--sb-green)"}},n(i.user,16,1.9)),t("div",{key:"tx",style:{flex:1,minWidth:0}},[t("div",{key:"n",style:{fontSize:"13px",fontWeight:700,color:"var(--sb-text-1)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},E),t("div",{key:"s",style:{display:"flex",alignItems:"center",gap:"7px",fontFamily:r,fontSize:"11px",color:"var(--sb-text-6)"}},[(w?f("call.videoPrefix"):f("call.voicePrefix"))+k,p==="active"&&R(!0)])]),t("button",{key:"exp",onClick:()=>d(!1),title:f("call.expand"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}},n(i.expand,15,2)),t("button",{key:"end",onClick:O,title:f("call.end"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"var(--sb-red-strong-solid)",color:"#fff",cursor:"pointer",transition:"transform .15s"}},n(i.phoneHangup,15,2))])]):w?t("div",{style:{position:"absolute",inset:0,zIndex:40,overflow:"hidden",background:"var(--sb-bg-deepest)",animation:"sbExpand .2s ease"}},[U,a.remoteHasVideo?t("video",{key:"rv",ref:m,autoPlay:!0,muted:!0,playsInline:!0,style:{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",background:"var(--sb-bg-deepest)"}}):t("div",{key:"ph",style:{position:"absolute",inset:0,background:"linear-gradient(120deg, var(--sb-grad-1), var(--sb-grad-2), var(--sb-grad-3))",backgroundSize:"200% 200%",animation:"sbLiveBg 9s ease-in-out infinite",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"18px"}},[t("div",{key:"a",style:{width:"120px",height:"120px",borderRadius:"50%",display:"grid",placeItems:"center",background:"radial-gradient(circle at 35% 30%, var(--sb-surface-4), var(--sb-surface))",border:"1px solid rgba(var(--sb-ink), 0.1)",color:"var(--sb-text-6)"}},n(i.user,54,1.5)),t("div",{key:"t",style:{fontSize:"15px",fontWeight:600,color:"var(--sb-text-7)"}},f("call.peerCameraOff"))]),t("div",{key:"top",style:{position:"absolute",top:0,left:0,right:0,display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:"14px",padding:"18px 20px",background:"linear-gradient(180deg, rgba(0,0,0,0.55), transparent)"}},[t("div",{key:"l"},[t("div",{key:"n",style:{fontSize:"18px",fontWeight:800,letterSpacing:"-0.3px",color:"#fff"}},E),t("div",{key:"s",style:{display:"inline-flex",alignItems:"center",gap:"9px",marginTop:"4px"}},[t("span",{key:"st",style:{fontFamily:r,fontSize:"12.5px",fontWeight:500,color:"var(--sb-text-2)"}},k),Y,p==="active"&&R(!1)])]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:{flex:"none",...T(!0)}},n(i.minimize,16,2))]),t("div",{key:"self",style:{position:"absolute",bottom:"108px",insetInlineEnd:"18px",width:"132px",height:"176px",borderRadius:"14px",overflow:"hidden",border:"1px solid rgba(var(--sb-ink), 0.16)",boxShadow:"0 12px 30px rgba(var(--sb-shadow-rgb), calc(0.5 * var(--sb-shadow-k)))",background:"#111"}},[t("video",{key:"sv",ref:b,autoPlay:!0,muted:!0,playsInline:!0,style:{width:"100%",height:"100%",objectFit:"cover",transform:"scaleX(-1)",display:"block"}}),!a.cameraEnabled&&t("div",{key:"off",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"8px",background:"var(--sb-surface)",color:"var(--sb-text-9)"}},[n(i.camOff,24,1.8),t("span",{key:"t",style:{fontSize:"10.5px",color:"var(--sb-text-9)",fontFamily:r}},f("call.cameraOff"))])]),t("div",{key:"ctrls",style:{position:"absolute",bottom:0,left:0,right:0,display:"flex",alignItems:"center",justifyContent:"center",gap:"18px",padding:"22px 24px 28px",background:"linear-gradient(0deg, rgba(0,0,0,0.6), transparent)"}},[t("button",{key:"mute",onClick:Q,title:f("call.mute"),style:a.micEnabled?_:A},n(a.micEnabled?i.micOn:i.micOff,21,1.9)),t("button",{key:"cam",onClick:J,title:f("call.camera"),style:a.cameraEnabled?_:A},n(a.cameraEnabled?i.camOn:i.camOff,21,1.8)),t("button",{key:"flip",onClick:ge,title:f("call.flipCamera"),style:_},n(i.flip,21,1.8)),t("button",{key:"end",onClick:O,title:f("call.end"),style:x},n(i.phoneHangup,22,1.9))])]):t("div",{style:{position:"absolute",inset:0,zIndex:40,display:"flex",flexDirection:"column",background:"radial-gradient(680px 460px at 50% 36%, rgba(var(--sb-orange-rgb), 0.08), transparent 70%), var(--sb-bg-deep)",animation:"sbExpand .2s ease"}},[U,t("div",{key:"top",style:{flex:"none",display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 18px"}},[t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"7px",fontSize:"12px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,13,2),f("call.encrypted")]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:T(!1)},n(i.minimize,16,2))]),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[D(46,F),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},E),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},k),p==="active"&&t("div",{key:"q",style:{marginTop:"12px"}},R(!1))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"26px",padding:"28px 24px 34px"}},[I("mute",t("button",{onClick:Q,title:f("call.mute"),style:a.micEnabled?_:A},n(a.micEnabled?i.micOn:i.micOff,22,1.9)),a.micEnabled?"Mute":f("call.muted")),I("video",t("button",{onClick:G,title:f("call.addVideo"),style:_},n(i.camOn,22,1.8)),f("call.video")),I("end",t("button",{onClick:O,title:f("call.end"),style:x},n(i.phoneHangup,22,1.9)),f("call.endShort"))])])};typeof window<"u"&&(window.CallUIComponent=Wa);window.EnhancedSecureCryptoUtils=Mt;window.EnhancedSecureWebRTCManager=$t;window.EnhancedSecureFileTransfer=je;window.NotificationIntegration=$n.NotificationIntegration;var Ya=()=>{try{let s=[];for(let e=0;e(window.__qrReady||(window.__qrReady=import("/dist/qr-local.js").then(()=>{window.dispatchEvent(new Event("securebit:qr-ready"))}).catch(s=>{console.warn("QR bundle failed to load:",s&&s.message),window.__qrReady=null})),window.__qrReady),Xa=()=>{typeof window.requestIdleCallback=="function"?window.requestIdleCallback(Bn,{timeout:3e3}):setTimeout(Bn,1200)},Hn=()=>{Ya(),typeof window.initializeApp=="function"?window.initializeApp():window.DEBUG_MODE&&console.error("initializeApp is not defined on window"),Xa()};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Hn):Hn(); /** * Secure and Reliable Notification Manager for P2P WebRTC Chat * Follows best practices: OWASP, MDN, Chrome DevRel diff --git a/dist/app-boot.js.map b/dist/app-boot.js.map index ad8f3c8..4cbdb66 100644 --- a/dist/app-boot.js.map +++ b/dist/app-boot.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/notifications/SecureNotificationManager.js", "../src/notifications/NotificationIntegration.js", "../node_modules/dompurify/src/utils.ts", "../node_modules/dompurify/src/tags.ts", "../node_modules/dompurify/src/attrs.ts", "../node_modules/dompurify/src/regexp.ts", "../node_modules/dompurify/src/purify.ts", "../src/crypto/EnhancedSecureCryptoUtils.js", "../src/i18n/generated.js", "../src/i18n/dict/en.js", "../src/i18n/index.js", "../src/transfer/EnhancedSecureFileTransfer.js", "../src/network/webrtc/config.js", "../src/network/webrtc/sdp.js", "../src/network/webrtc/audio.js", "../src/network/webrtc/video.js", "../src/network/webrtc/adaptation/metrics.js", "../src/network/webrtc/adaptation/controller.js", "../src/crypto/DoubleRatchet.js", "../src/network/descriptor/sbq2.js", "../src/network/descriptor/keyexchange.js", "../src/network/EnhancedSecureWebRTCManager.js", "../src/scripts/app-boot.js", "../package.json", "../src/components/ui/LanguageSwitcher.jsx", "../src/components/ui/ThemeSwitcher.jsx", "../src/components/ui/Header.jsx", "../src/components/ui/DownloadApps.jsx", "../src/components/ui/BecomePartner.jsx", "../src/components/ui/UniqueFeatureSlider.jsx", "../src/components/ui/Roadmap.jsx", "../src/components/ui/DonateCrypto.jsx", "../src/components/ui/CommunityCTA.jsx", "../src/components/ui/FileTransfer.jsx", "../src/network/iceServers.js", "../src/components/ui/IceServerSettings.jsx", "../src/components/ui/CallUI.jsx"], - "sourcesContent": ["/**\n * Secure and Reliable Notification Manager for P2P WebRTC Chat\n * Follows best practices: OWASP, MDN, Chrome DevRel\n * \n * @version 1.0.0\n * @author SecureBit Team\n * @license MIT\n */\n\nclass SecureChatNotificationManager {\n constructor(config = {}) {\n // Safely read Notification permission (iOS Safari may not define Notification)\n this.permission = (typeof Notification !== 'undefined' && Notification && typeof Notification.permission === 'string')\n ? Notification.permission\n : 'denied';\n this.isTabActive = this.checkTabActive(); // Initialize with proper check\n this.unreadCount = 0;\n this.originalTitle = document.title;\n this.notificationQueue = [];\n this.maxQueueSize = config.maxQueueSize || 5;\n this.rateLimitMs = config.rateLimitMs || 2000; // Spam protection\n this.lastNotificationTime = 0;\n this.trustedOrigins = config.trustedOrigins || [];\n \n // Secure context flag\n this.isSecureContext = window.isSecureContext;\n \n // Cross-browser compatibility for Page Visibility API\n this.hidden = this.getHiddenProperty();\n this.visibilityChange = this.getVisibilityChangeEvent();\n \n this.initVisibilityTracking();\n this.initSecurityChecks();\n }\n\n /**\n * Initialize security checks and validation\n * @private\n */\n initSecurityChecks() {\n // Security checks are performed silently\n }\n\n /**\n * Get hidden property name for cross-browser compatibility\n * @returns {string} Hidden property name\n * @private\n */\n getHiddenProperty() {\n if (typeof document.hidden !== \"undefined\") {\n return \"hidden\";\n } else if (typeof document.msHidden !== \"undefined\") {\n return \"msHidden\";\n } else if (typeof document.webkitHidden !== \"undefined\") {\n return \"webkitHidden\";\n }\n return \"hidden\"; // fallback\n }\n\n /**\n * Get visibility change event name for cross-browser compatibility\n * @returns {string} Visibility change event name\n * @private\n */\n getVisibilityChangeEvent() {\n if (typeof document.hidden !== \"undefined\") {\n return \"visibilitychange\";\n } else if (typeof document.msHidden !== \"undefined\") {\n return \"msvisibilitychange\";\n } else if (typeof document.webkitHidden !== \"undefined\") {\n return \"webkitvisibilitychange\";\n }\n return \"visibilitychange\"; // fallback\n }\n\n /**\n * Check if tab is currently active using multiple methods\n * @returns {boolean} True if tab is active\n * @private\n */\n checkTabActive() {\n // Primary method: Page Visibility API\n if (this.hidden && typeof document[this.hidden] !== \"undefined\") {\n return !document[this.hidden];\n }\n \n // Fallback method: document.hasFocus()\n if (typeof document.hasFocus === \"function\") {\n return document.hasFocus();\n }\n \n // Ultimate fallback: assume active\n return true;\n }\n\n /**\n * Initialize page visibility tracking (Page Visibility API)\n * @private\n */\n initVisibilityTracking() {\n // Primary method: Page Visibility API with cross-browser support\n if (typeof document.addEventListener !== \"undefined\" && typeof document[this.hidden] !== \"undefined\") {\n document.addEventListener(this.visibilityChange, () => {\n this.isTabActive = this.checkTabActive();\n \n if (this.isTabActive) {\n this.resetUnreadCount();\n this.clearNotificationQueue();\n }\n });\n }\n\n // Fallback method: Window focus/blur events\n window.addEventListener('focus', () => {\n this.isTabActive = this.checkTabActive();\n if (this.isTabActive) {\n this.resetUnreadCount();\n }\n });\n\n window.addEventListener('blur', () => {\n this.isTabActive = this.checkTabActive();\n });\n\n // Page unload cleanup\n window.addEventListener('beforeunload', () => {\n this.clearNotificationQueue();\n });\n }\n\n /**\n * Request notification permission (BEST PRACTICE: Only call in response to user action)\n * Never call on page load!\n * @returns {Promise} Permission granted status\n */\n async requestPermission() {\n // Secure context check\n if (!this.isSecureContext || !('Notification' in window)) {\n return false;\n }\n\n if (this.permission === 'granted') {\n return true;\n }\n\n if (this.permission === 'denied') {\n return false;\n }\n\n try {\n this.permission = await Notification.requestPermission();\n return this.permission === 'granted';\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Update page title with unread count\n * @private\n */\n updateTitle() {\n if (this.unreadCount > 0) {\n document.title = `(${this.unreadCount}) ${this.originalTitle}`;\n } else {\n document.title = this.originalTitle;\n }\n }\n\n /**\n * XSS Protection: Sanitize input text\n * @param {string} text - Text to sanitize\n * @returns {string} Sanitized text\n * @private\n */\n sanitizeText(text) {\n if (typeof text !== 'string') {\n return '';\n }\n \n // Remove HTML tags and potentially dangerous characters\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .substring(0, 500); // Length limit\n }\n\n /**\n * Validate icon URL (XSS protection)\n * @param {string} url - URL to validate\n * @returns {string|null} Validated URL or null\n * @private\n */\n validateIconUrl(url) {\n if (!url) return null;\n \n try {\n const parsedUrl = new URL(url, window.location.origin);\n \n // Only allow HTTPS and data URLs\n if (parsedUrl.protocol === 'https:' || parsedUrl.protocol === 'data:') {\n // Check trusted origins if specified\n if (this.trustedOrigins.length > 0) {\n const isTrusted = this.trustedOrigins.some(origin => \n parsedUrl.origin === origin\n );\n return isTrusted ? parsedUrl.href : null;\n }\n return parsedUrl.href;\n }\n \n return null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Rate limiting for spam protection\n * @returns {boolean} Rate limit check passed\n * @private\n */\n checkRateLimit() {\n const now = Date.now();\n if (now - this.lastNotificationTime < this.rateLimitMs) {\n return false;\n }\n this.lastNotificationTime = now;\n return true;\n }\n\n /**\n * Send secure notification\n * @param {string} senderName - Name of message sender\n * @param {string} message - Message content\n * @param {Object} options - Notification options\n * @returns {Notification|null} Created notification or null\n */\n notify(senderName, message, options = {}) {\n // Abort if Notifications API is not available (e.g., iOS Safari)\n if (typeof Notification === 'undefined') {\n return null;\n }\n // Update tab active state before checking\n this.isTabActive = this.checkTabActive();\n \n // Only show if tab is NOT active (user is on another tab or minimized)\n if (this.isTabActive) {\n return null;\n }\n\n // Permission check\n if (this.permission !== 'granted') {\n return null;\n }\n\n // Rate limiting\n if (!this.checkRateLimit()) {\n return null;\n }\n\n // Data sanitization (XSS Protection)\n const safeSenderName = this.sanitizeText(senderName || 'Unknown');\n const safeMessage = this.sanitizeText(message || '');\n const safeIcon = this.validateIconUrl(options.icon) || '/logo/icon-192x192.png';\n\n // Queue overflow protection\n if (this.notificationQueue.length >= this.maxQueueSize) {\n this.clearNotificationQueue();\n }\n\n try {\n \n const notification = new Notification(\n `${safeSenderName}`,\n {\n body: safeMessage.substring(0, 200), // Length limit\n icon: safeIcon,\n badge: safeIcon,\n tag: `chat-${options.senderId || 'unknown'}`, // Grouping\n requireInteraction: false, // Don't block user\n silent: options.silent || false,\n // Vibrate only for mobile and if supported\n vibrate: navigator.vibrate ? [200, 100, 200] : undefined,\n // Safe metadata\n data: {\n senderId: this.sanitizeText(options.senderId),\n timestamp: Date.now(),\n // Don't include sensitive data!\n }\n }\n );\n\n // Increment counter\n this.unreadCount++;\n this.updateTitle();\n\n // Add to queue for management\n this.notificationQueue.push(notification);\n\n // Safe click handler\n notification.onclick = (event) => {\n event.preventDefault(); // Prevent default behavior\n window.focus();\n notification.close();\n \n // Safe callback\n if (typeof options.onClick === 'function') {\n try {\n options.onClick(options.senderId);\n } catch (error) {\n console.error('[Notifications] Error in onClick handler:', error);\n }\n }\n };\n\n // Error handler\n notification.onerror = (event) => {\n console.error('[Notifications] Error showing notification:', event);\n };\n\n // Auto-close after reasonable time\n const autoCloseTimeout = Math.min(options.autoClose || 5000, 10000);\n setTimeout(() => {\n notification.close();\n this.removeFromQueue(notification);\n }, autoCloseTimeout);\n\n return notification;\n \n } catch (error) {\n console.error('[Notifications] Failed to create notification:', error);\n return null;\n }\n }\n\n /**\n * Remove notification from queue\n * @param {Notification} notification - Notification to remove\n * @private\n */\n removeFromQueue(notification) {\n const index = this.notificationQueue.indexOf(notification);\n if (index > -1) {\n this.notificationQueue.splice(index, 1);\n }\n }\n\n /**\n * Clear all notifications\n */\n clearNotificationQueue() {\n this.notificationQueue.forEach(notification => {\n try {\n notification.close();\n } catch (error) {\n // Ignore errors when closing\n }\n });\n this.notificationQueue = [];\n }\n\n /**\n * Reset unread counter\n */\n resetUnreadCount() {\n this.unreadCount = 0;\n this.updateTitle();\n }\n\n /**\n * Get current status\n * @returns {Object} Current notification status\n */\n getStatus() {\n return {\n permission: this.permission,\n isTabActive: this.isTabActive,\n unreadCount: this.unreadCount,\n isSecureContext: this.isSecureContext,\n queueSize: this.notificationQueue.length\n };\n }\n}\n\n/**\n * Secure integration with WebRTC\n */\nclass SecureP2PChat {\n constructor() {\n this.notificationManager = new SecureChatNotificationManager({\n maxQueueSize: 5,\n rateLimitMs: 2000,\n trustedOrigins: [\n window.location.origin,\n // Add other trusted origins for CDN icons\n ]\n });\n \n this.dataChannel = null;\n this.peerConnection = null;\n this.remotePeerName = 'Peer';\n this.messageHistory = [];\n this.maxHistorySize = 100;\n }\n\n /**\n * Initialize when user connects\n */\n async init() {\n // Initialize notification manager silently\n }\n\n /**\n * Method for manual permission request (called on click)\n * @returns {Promise} Permission granted status\n */\n async enableNotifications() {\n const granted = await this.notificationManager.requestPermission();\n return granted;\n }\n\n /**\n * Setup DataChannel with security checks\n * @param {RTCDataChannel} dataChannel - WebRTC data channel\n */\n setupDataChannel(dataChannel) {\n if (!dataChannel) {\n console.error('[Chat] Invalid DataChannel');\n return;\n }\n\n this.dataChannel = dataChannel;\n \n // Setup handlers\n this.dataChannel.onmessage = (event) => {\n this.handleIncomingMessage(event.data);\n };\n\n this.dataChannel.onerror = (error) => {\n // Handle error silently\n };\n }\n\n /**\n * XSS Protection: Validate incoming messages\n * @param {string|Object} data - Message data\n * @returns {Object|null} Validated message or null\n * @private\n */\n validateMessage(data) {\n try {\n const message = typeof data === 'string' ? JSON.parse(data) : data;\n \n // Check message structure\n if (!message || typeof message !== 'object') {\n throw new Error('Invalid message structure');\n }\n\n // Check required fields\n if (!message.text || typeof message.text !== 'string') {\n throw new Error('Invalid message text');\n }\n\n // Message length limit (DoS protection)\n if (message.text.length > 10000) {\n throw new Error('Message too long');\n }\n\n return {\n text: message.text,\n senderName: message.senderName || 'Unknown',\n senderId: message.senderId || 'unknown',\n timestamp: message.timestamp || Date.now(),\n senderAvatar: message.senderAvatar || null\n };\n \n } catch (error) {\n console.error('[Chat] Message validation failed:', error);\n return null;\n }\n }\n\n /**\n * Secure handling of incoming messages\n * @param {string|Object} data - Message data\n * @private\n */\n handleIncomingMessage(data) {\n const message = this.validateMessage(data);\n \n if (!message) {\n return;\n }\n\n // Save to history (with limit)\n this.messageHistory.push(message);\n if (this.messageHistory.length > this.maxHistorySize) {\n this.messageHistory.shift();\n }\n\n // Display in UI (with sanitization)\n this.displayMessage(message);\n\n // Send notification only if tab is inactive\n this.notificationManager.notify(\n message.senderName,\n message.text,\n {\n icon: message.senderAvatar,\n senderId: message.senderId,\n onClick: (senderId) => {\n this.scrollToLatestMessage();\n }\n }\n );\n\n // Optional: sound (with check)\n if (!this.notificationManager.isTabActive) {\n this.playNotificationSound();\n }\n }\n\n /**\n * XSS Protection: Safe message display\n * @param {Object} message - Message to display\n * @private\n */\n displayMessage(message) {\n const container = document.getElementById('messages');\n if (!container) {\n return;\n }\n\n const messageEl = document.createElement('div');\n messageEl.className = 'message';\n \n // Use textContent to prevent XSS\n const nameEl = document.createElement('strong');\n nameEl.textContent = message.senderName + ': ';\n \n const textEl = document.createElement('span');\n textEl.textContent = message.text;\n textEl.style.wordWrap = 'break-word';\n textEl.style.overflowWrap = 'break-word';\n textEl.style.whiteSpace = 'normal';\n \n const timeEl = document.createElement('small');\n timeEl.textContent = new Date(message.timestamp).toLocaleTimeString();\n \n messageEl.appendChild(nameEl);\n messageEl.appendChild(textEl);\n messageEl.appendChild(document.createElement('br'));\n messageEl.appendChild(timeEl);\n \n container.appendChild(messageEl);\n this.scrollToLatestMessage();\n }\n\n /**\n * Safe sound playback\n * @private\n */\n playNotificationSound() {\n try {\n // Use only local audio files\n const audio = new Audio('/assets/audio/notification.mp3');\n audio.volume = 0.3; // Moderate volume\n \n // Error handling\n audio.play().catch(error => {\n // Handle audio error silently\n });\n } catch (error) {\n // Handle audio creation error silently\n }\n }\n\n /**\n * Scroll to latest message\n * @private\n */\n scrollToLatestMessage() {\n const container = document.getElementById('messages');\n if (container) {\n container.scrollTop = container.scrollHeight;\n }\n }\n\n /**\n * Get status\n * @returns {Object} Current chat status\n */\n getStatus() {\n return {\n notifications: this.notificationManager.getStatus(),\n messageCount: this.messageHistory.length,\n connected: this.dataChannel?.readyState === 'open'\n };\n }\n}\n\n// Export for use in other modules\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = { SecureChatNotificationManager, SecureP2PChat };\n}\n\n// Global export for browser usage\nif (typeof window !== 'undefined') {\n window.SecureChatNotificationManager = SecureChatNotificationManager;\n window.SecureP2PChat = SecureP2PChat;\n}\n", "/**\n * Notification Integration Module for SecureBit WebRTC Chat\n * Integrates secure notifications with existing WebRTC architecture\n * \n * @version 1.0.0\n * @author SecureBit Team\n * @license MIT\n */\n\nimport { SecureChatNotificationManager } from './SecureNotificationManager.js';\n\nclass NotificationIntegration {\n constructor(webrtcManager) {\n this.webrtcManager = webrtcManager;\n this.notificationManager = new SecureChatNotificationManager({\n maxQueueSize: 10,\n rateLimitMs: 1000, // Reduced from 2000ms to 1000ms\n trustedOrigins: [\n window.location.origin,\n // Add other trusted origins for CDN icons\n ]\n });\n \n this.isInitialized = false;\n this.originalOnMessage = null;\n this.originalOnStatusChange = null;\n this.processedMessages = new Set(); // Track processed messages to avoid duplicates\n }\n\n /**\n * Initialize notification integration\n * @returns {Promise} Initialization success\n */\n async init() {\n try {\n if (this.isInitialized) {\n return true;\n }\n\n // Store original callbacks\n this.originalOnMessage = this.webrtcManager.onMessage;\n this.originalOnStatusChange = this.webrtcManager.onStatusChange;\n\n\n // Wrap the original onMessage callback.\n // IMPORTANT: forward ALL arguments (incl. per-message `meta`) so the app\n // still receives view-once / disappearing / unsend metadata.\n this.webrtcManager.onMessage = (message, type, ...rest) => {\n this.handleIncomingMessage(message, type, rest[0]);\n\n // Call original callback if it exists\n if (this.originalOnMessage) {\n this.originalOnMessage(message, type, ...rest);\n }\n };\n\n // Wrap the original onStatusChange callback\n this.webrtcManager.onStatusChange = (status) => {\n this.handleStatusChange(status);\n \n // Call original callback if it exists\n if (this.originalOnStatusChange) {\n this.originalOnStatusChange(status);\n }\n };\n\n // Also hook into the deliverMessageToUI method if it exists.\n // IMPORTANT: forward ALL arguments (incl. per-message `meta`) to the\n // original, otherwise view-once / disappearing / unsend metadata is lost.\n if (this.webrtcManager.deliverMessageToUI) {\n this.originalDeliverMessageToUI = this.webrtcManager.deliverMessageToUI.bind(this.webrtcManager);\n this.webrtcManager.deliverMessageToUI = (message, type, ...rest) => {\n this.handleIncomingMessage(message, type, rest[0]);\n this.originalDeliverMessageToUI(message, type, ...rest);\n };\n }\n\n this.isInitialized = true;\n return true;\n\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Handle incoming messages and trigger notifications\n * @param {*} message - Message content\n * @param {string} type - Message type\n * @private\n */\n handleIncomingMessage(message, type, meta) {\n try {\n // Create a unique key for this message to avoid duplicates\n const messageKey = `${type}:${typeof message === 'string' ? message : JSON.stringify(message)}`;\n \n // Skip if we've already processed this message\n if (this.processedMessages.has(messageKey)) {\n return;\n }\n \n // Mark message as processed\n this.processedMessages.add(messageKey);\n \n // Clean up old processed messages (keep only last 100)\n if (this.processedMessages.size > 100) {\n const messagesArray = Array.from(this.processedMessages);\n this.processedMessages.clear();\n messagesArray.slice(-50).forEach(msg => this.processedMessages.add(msg));\n }\n \n \n // Only process chat messages, not system messages\n if (type === 'system' || type === 'file-transfer' || type === 'heartbeat') {\n return;\n }\n\n // Extract message information\n const messageInfo = this.extractMessageInfo(message, type);\n if (!messageInfo) {\n return;\n }\n\n // PRIVACY: a view-once or disappearing message must not be copied into the\n // OS notification. Notifications are shown only while the tab is in the\n // background \u2014 i.e. typically on a lock screen \u2014 and once the OS has the\n // text it lands in the notification centre, in backups and on the user's\n // other synced devices. From there the app can no longer delete it, so the\n // message the UI destroys after 30 seconds outlives itself indefinitely.\n // Show that something arrived; never what it said.\n const isEphemeral = !!meta && typeof meta === 'object' &&\n (meta.once === true || (Number.isFinite(meta.ttl) && meta.ttl > 0));\n const notificationText = isEphemeral ? 'Sent you a private message' : messageInfo.text;\n\n // Send notification\n const notificationResult = this.notificationManager.notify(\n messageInfo.senderName,\n notificationText,\n {\n icon: messageInfo.senderAvatar,\n senderId: messageInfo.senderId,\n onClick: (senderId) => {\n this.focusChatWindow();\n }\n }\n );\n\n } catch (error) {\n // Handle error silently\n }\n }\n\n /**\n * Handle status changes\n * @param {string} status - Connection status\n * @private\n */\n handleStatusChange(status) {\n try {\n // Clear notifications when connection is lost\n if (status === 'disconnected' || status === 'failed') {\n this.notificationManager.clearNotificationQueue();\n this.notificationManager.resetUnreadCount();\n }\n } catch (error) {\n // Handle error silently\n }\n }\n\n /**\n * Extract message information for notifications\n * @param {*} message - Message content\n * @param {string} type - Message type\n * @returns {Object|null} Extracted message info or null\n * @private\n */\n extractMessageInfo(message, type) {\n try {\n let messageData = message;\n\n // Handle different message formats\n if (typeof message === 'string') {\n try {\n messageData = JSON.parse(message);\n } catch (e) {\n // Plain text message\n return {\n senderName: 'Peer',\n text: message,\n senderId: 'peer',\n senderAvatar: null\n };\n }\n }\n\n // Handle structured message data\n if (typeof messageData === 'object' && messageData !== null) {\n return {\n senderName: messageData.senderName || messageData.name || 'Peer',\n text: messageData.text || messageData.message || messageData.content || '',\n senderId: messageData.senderId || messageData.id || 'peer',\n senderAvatar: messageData.senderAvatar || messageData.avatar || null\n };\n }\n\n return null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Focus chat window when notification is clicked\n * @private\n */\n focusChatWindow() {\n try {\n window.focus();\n \n // Scroll to bottom of messages if container exists\n const messagesContainer = document.getElementById('messages');\n if (messagesContainer) {\n messagesContainer.scrollTop = messagesContainer.scrollHeight;\n }\n } catch (error) {\n // Handle error silently\n }\n }\n\n /**\n * Request notification permission\n * @returns {Promise} Permission granted status\n */\n async requestPermission() {\n try {\n return await this.notificationManager.requestPermission();\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Get notification status\n * @returns {Object} Notification status\n */\n getStatus() {\n return this.notificationManager.getStatus();\n }\n\n /**\n * Clear all notifications\n */\n clearNotifications() {\n this.notificationManager.clearNotificationQueue();\n this.notificationManager.resetUnreadCount();\n }\n\n /**\n * Cleanup integration\n */\n cleanup() {\n try {\n if (this.isInitialized) {\n // Restore original callbacks\n if (this.originalOnMessage) {\n this.webrtcManager.onMessage = this.originalOnMessage;\n }\n if (this.originalOnStatusChange) {\n this.webrtcManager.onStatusChange = this.originalOnStatusChange;\n }\n if (this.originalDeliverMessageToUI) {\n this.webrtcManager.deliverMessageToUI = this.originalDeliverMessageToUI;\n }\n\n // Clear notifications\n this.clearNotifications();\n\n this.isInitialized = false;\n }\n } catch (error) {\n // Handle error silently\n }\n }\n}\n\n// Export for use in other modules\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = { NotificationIntegration };\n}\n\n// Global export for browser usage\nif (typeof window !== 'undefined') {\n window.NotificationIntegration = NotificationIntegration;\n}\n", "const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n} = Object;\n\nlet { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports\nlet { apply, construct } = typeof Reflect !== 'undefined' && Reflect;\n\nif (!freeze) {\n freeze = function (x: T): T {\n return x;\n };\n}\n\nif (!seal) {\n seal = function (x: T): T {\n return x;\n };\n}\n\nif (!apply) {\n apply = function (\n func: (thisArg: any, ...args: any[]) => T,\n thisArg: any,\n ...args: any[]\n ): T {\n return func.apply(thisArg, args);\n };\n}\n\nif (!construct) {\n construct = function (Func: new (...args: any[]) => T, ...args: any[]): T {\n return new Func(...args);\n };\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayIndexOf = unapply(Array.prototype.indexOf);\nconst arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst arraySlice = unapply(Array.prototype.slice);\nconst arraySplice = unapply(Array.prototype.splice);\nconst arrayIsArray = Array.isArray;\n\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\n\nconst numberToString = unapply(Number.prototype.toString);\nconst booleanToString = unapply(Boolean.prototype.toString);\nconst bigintToString =\n typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);\nconst symbolToString =\n typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);\n\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\nconst objectToString = unapply(Object.prototype.toString);\n\nconst regExpTest = unapply(RegExp.prototype.test);\n\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param func - The function to be wrapped and called.\n * @returns A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply(\n func: (thisArg: any, ...args: any[]) => T\n): (thisArg: any, ...args: any[]) => T {\n return (thisArg: any, ...args: any[]): T => {\n if (thisArg instanceof RegExp) {\n thisArg.lastIndex = 0;\n }\n\n return apply(func, thisArg, args);\n };\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param func - The constructor function to be wrapped and called.\n * @returns A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct(\n Func: new (...args: any[]) => T\n): (...args: any[]) => T {\n return (...args: any[]): T => construct(Func, args);\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param set - The set to which elements will be added.\n * @param array - The array containing elements to be added to the set.\n * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns The modified set with added elements.\n */\nfunction addToSet(\n set: Record,\n array: readonly unknown[],\n transformCaseFunc: ReturnType> = stringToLowerCase\n): Record {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n if (!arrayIsArray(array)) {\n return set;\n }\n\n let l = array.length;\n while (l--) {\n let element = array[l];\n\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n (array as unknown[])[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element as string] = true;\n }\n\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param array - The array to be cleaned.\n * @returns The cleaned version of the array\n */\nfunction cleanArray(array: T[]): Array {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param object - The object to be cloned.\n * @returns A new object that copies the original.\n */\nfunction clone>(object: T): T {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n\n if (isPropertyExist) {\n if (arrayIsArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (\n value &&\n typeof value === 'object' &&\n value.constructor === Object\n ) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n\n return newObject;\n}\n\n/**\n * Convert non-node values into strings without depending on direct property access.\n *\n * @param value - The value to stringify.\n * @returns A string representation of the provided value.\n */\nfunction stringifyValue(value: unknown): string {\n switch (typeof value) {\n case 'string': {\n return value;\n }\n\n case 'number': {\n return numberToString(value);\n }\n\n case 'boolean': {\n return booleanToString(value);\n }\n\n case 'bigint': {\n return bigintToString ? bigintToString(value) : '0';\n }\n\n case 'symbol': {\n return symbolToString ? symbolToString(value) : 'Symbol()';\n }\n\n case 'undefined': {\n return objectToString(value);\n }\n\n case 'function':\n case 'object': {\n if (value === null) {\n return objectToString(value);\n }\n\n const valueAsRecord = value as Record;\n const valueToString = lookupGetter(valueAsRecord, 'toString');\n\n if (typeof valueToString === 'function') {\n const stringified = valueToString(valueAsRecord);\n\n return typeof stringified === 'string'\n ? stringified\n : objectToString(stringified);\n }\n\n return objectToString(value);\n }\n\n default: {\n return objectToString(value);\n }\n }\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param object - The object to look up the getter function in its prototype chain.\n * @param prop - The property name for which to find the getter function.\n * @returns The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter>(\n object: T,\n prop: string\n): ReturnType> | (() => null) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue(): null {\n return null;\n }\n\n return fallbackValue;\n}\n\nfunction isRegex(value: unknown): value is RegExp {\n try {\n regExpTest(value as RegExp, '');\n return true;\n } catch {\n return false;\n }\n}\n\nexport {\n // Array\n arrayForEach,\n arrayIndexOf,\n arrayIsArray,\n arrayLastIndexOf,\n arrayPop,\n arrayPush,\n arraySlice,\n arraySplice,\n // Object\n entries,\n freeze,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n isFrozen,\n setPrototypeOf,\n seal,\n clone,\n create,\n objectHasOwnProperty,\n objectToString,\n // RegExp\n regExpTest,\n isRegex,\n // String\n stringIndexOf,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringTrim,\n // Other conversion\n stringifyValue,\n // Errors\n typeErrorCreate,\n // Other\n lookupGetter,\n addToSet,\n // Reflect\n unapply,\n unconstruct,\n};\n", "import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'a',\n 'abbr',\n 'acronym',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blink',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'content',\n 'data',\n 'datalist',\n 'dd',\n 'decorator',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'element',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'font',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hgroup',\n 'hr',\n 'html',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'marquee',\n 'menu',\n 'menuitem',\n 'meter',\n 'nav',\n 'nobr',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'search',\n 'section',\n 'select',\n 'shadow',\n 'slot',\n 'small',\n 'source',\n 'spacer',\n 'span',\n 'strike',\n 'strong',\n 'style',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'tt',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n] as const);\n\nexport const svg = freeze([\n 'svg',\n 'a',\n 'altglyph',\n 'altglyphdef',\n 'altglyphitem',\n 'animatecolor',\n 'animatemotion',\n 'animatetransform',\n 'circle',\n 'clippath',\n 'defs',\n 'desc',\n 'ellipse',\n 'enterkeyhint',\n 'exportparts',\n 'filter',\n 'font',\n 'g',\n 'glyph',\n 'glyphref',\n 'hkern',\n 'image',\n 'inputmode',\n 'line',\n 'lineargradient',\n 'marker',\n 'mask',\n 'metadata',\n 'mpath',\n 'part',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialgradient',\n 'rect',\n 'stop',\n 'style',\n 'switch',\n 'symbol',\n 'text',\n 'textpath',\n 'title',\n 'tref',\n 'tspan',\n 'view',\n 'vkern',\n] as const);\n\nexport const svgFilters = freeze([\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n] as const);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nexport const svgDisallowed = freeze([\n 'animate',\n 'color-profile',\n 'cursor',\n 'discard',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignobject',\n 'hatch',\n 'hatchpath',\n 'mesh',\n 'meshgradient',\n 'meshpatch',\n 'meshrow',\n 'missing-glyph',\n 'script',\n 'set',\n 'solidcolor',\n 'unknown',\n 'use',\n] as const);\n\nexport const mathMl = freeze([\n 'math',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mglyph',\n 'mi',\n 'mlabeledtr',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'ms',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'mprescripts',\n] as const);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nexport const mathMlDisallowed = freeze([\n 'maction',\n 'maligngroup',\n 'malignmark',\n 'mlongdiv',\n 'mscarries',\n 'mscarry',\n 'msgroup',\n 'mstack',\n 'msline',\n 'msrow',\n 'semantics',\n 'annotation',\n 'annotation-xml',\n 'mprescripts',\n 'none',\n] as const);\n\nexport const text = freeze(['#text'] as const);\n", "import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'accept',\n 'action',\n 'align',\n 'alt',\n 'autocapitalize',\n 'autocomplete',\n 'autopictureinpicture',\n 'autoplay',\n 'background',\n 'bgcolor',\n 'border',\n 'capture',\n 'cellpadding',\n 'cellspacing',\n 'checked',\n 'cite',\n 'class',\n 'clear',\n 'color',\n 'cols',\n 'colspan',\n 'command',\n 'commandfor',\n 'controls',\n 'controlslist',\n 'coords',\n 'crossorigin',\n 'datetime',\n 'decoding',\n 'default',\n 'dir',\n 'disabled',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'download',\n 'draggable',\n 'enctype',\n 'enterkeyhint',\n 'exportparts',\n 'face',\n 'for',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hreflang',\n 'id',\n 'inert',\n 'inputmode',\n 'integrity',\n 'ismap',\n 'kind',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxlength',\n 'media',\n 'method',\n 'min',\n 'minlength',\n 'multiple',\n 'muted',\n 'name',\n 'nonce',\n 'noshade',\n 'novalidate',\n 'nowrap',\n 'open',\n 'optimum',\n 'part',\n 'pattern',\n 'placeholder',\n 'playsinline',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'poster',\n 'preload',\n 'pubdate',\n 'radiogroup',\n 'readonly',\n 'rel',\n 'required',\n 'rev',\n 'reversed',\n 'role',\n 'rows',\n 'rowspan',\n 'spellcheck',\n 'scope',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'slot',\n 'span',\n 'srclang',\n 'start',\n 'src',\n 'srcset',\n 'step',\n 'style',\n 'summary',\n 'tabindex',\n 'title',\n 'translate',\n 'type',\n 'usemap',\n 'valign',\n 'value',\n 'width',\n 'wrap',\n 'xmlns',\n] as const);\n\nexport const svg = freeze([\n 'accent-height',\n 'accumulate',\n 'additive',\n 'alignment-baseline',\n 'amplitude',\n 'ascent',\n 'attributename',\n 'attributetype',\n 'azimuth',\n 'basefrequency',\n 'baseline-shift',\n 'begin',\n 'bias',\n 'by',\n 'class',\n 'clip',\n 'clippathunits',\n 'clip-path',\n 'clip-rule',\n 'color',\n 'color-interpolation',\n 'color-interpolation-filters',\n 'color-profile',\n 'color-rendering',\n 'cx',\n 'cy',\n 'd',\n 'dx',\n 'dy',\n 'diffuseconstant',\n 'direction',\n 'display',\n 'divisor',\n 'dur',\n 'edgemode',\n 'elevation',\n 'end',\n 'exponent',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'filter',\n 'filterunits',\n 'flood-color',\n 'flood-opacity',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-weight',\n 'fx',\n 'fy',\n 'g1',\n 'g2',\n 'glyph-name',\n 'glyphref',\n 'gradientunits',\n 'gradienttransform',\n 'height',\n 'href',\n 'id',\n 'image-rendering',\n 'in',\n 'in2',\n 'intercept',\n 'k',\n 'k1',\n 'k2',\n 'k3',\n 'k4',\n 'kerning',\n 'keypoints',\n 'keysplines',\n 'keytimes',\n 'lang',\n 'lengthadjust',\n 'letter-spacing',\n 'kernelmatrix',\n 'kernelunitlength',\n 'lighting-color',\n 'local',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'markerheight',\n 'markerunits',\n 'markerwidth',\n 'maskcontentunits',\n 'maskunits',\n 'max',\n 'mask',\n 'mask-type',\n 'media',\n 'method',\n 'mode',\n 'min',\n 'name',\n 'numoctaves',\n 'offset',\n 'operator',\n 'opacity',\n 'order',\n 'orient',\n 'orientation',\n 'origin',\n 'overflow',\n 'paint-order',\n 'path',\n 'pathlength',\n 'patterncontentunits',\n 'patterntransform',\n 'patternunits',\n 'points',\n 'preservealpha',\n 'preserveaspectratio',\n 'primitiveunits',\n 'r',\n 'rx',\n 'ry',\n 'radius',\n 'refx',\n 'refy',\n 'repeatcount',\n 'repeatdur',\n 'restart',\n 'result',\n 'rotate',\n 'scale',\n 'seed',\n 'shape-rendering',\n 'slope',\n 'specularconstant',\n 'specularexponent',\n 'spreadmethod',\n 'startoffset',\n 'stddeviation',\n 'stitchtiles',\n 'stop-color',\n 'stop-opacity',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-miterlimit',\n 'stroke-opacity',\n 'stroke',\n 'stroke-width',\n 'style',\n 'surfacescale',\n 'systemlanguage',\n 'tabindex',\n 'tablevalues',\n 'targetx',\n 'targety',\n 'transform',\n 'transform-origin',\n 'text-anchor',\n 'text-decoration',\n 'text-rendering',\n 'textlength',\n 'type',\n 'u1',\n 'u2',\n 'unicode',\n 'values',\n 'viewbox',\n 'visibility',\n 'version',\n 'vert-adv-y',\n 'vert-origin-x',\n 'vert-origin-y',\n 'width',\n 'word-spacing',\n 'wrap',\n 'writing-mode',\n 'xchannelselector',\n 'ychannelselector',\n 'x',\n 'x1',\n 'x2',\n 'xmlns',\n 'y',\n 'y1',\n 'y2',\n 'z',\n 'zoomandpan',\n] as const);\n\nexport const mathMl = freeze([\n 'accent',\n 'accentunder',\n 'align',\n 'bevelled',\n 'close',\n 'columnalign',\n 'columnlines',\n 'columnspacing',\n 'columnspan',\n 'denomalign',\n 'depth',\n 'dir',\n 'display',\n 'displaystyle',\n 'encoding',\n 'fence',\n 'frame',\n 'height',\n 'href',\n 'id',\n 'largeop',\n 'length',\n 'linethickness',\n 'lquote',\n 'lspace',\n 'mathbackground',\n 'mathcolor',\n 'mathsize',\n 'mathvariant',\n 'maxsize',\n 'minsize',\n 'movablelimits',\n 'notation',\n 'numalign',\n 'open',\n 'rowalign',\n 'rowlines',\n 'rowspacing',\n 'rowspan',\n 'rspace',\n 'rquote',\n 'scriptlevel',\n 'scriptminsize',\n 'scriptsizemultiplier',\n 'selection',\n 'separator',\n 'separators',\n 'stretchy',\n 'subscriptshift',\n 'supscriptshift',\n 'symmetric',\n 'voffset',\n 'width',\n 'xmlns',\n]);\n\nexport const xml = freeze([\n 'xlink:href',\n 'xml:id',\n 'xlink:title',\n 'xml:space',\n 'xmlns:xlink',\n] as const);\n", "import { seal } from './utils.js';\n\nexport const MUSTACHE_EXPR = seal(/{{[\\w\\W]*|^[\\w\\W]*}}/g);\nexport const ERB_EXPR = seal(/<%[\\w\\W]*|^[\\w\\W]*%>/g);\nexport const TMPLIT_EXPR = seal(/\\${[\\w\\W]*/g);\nexport const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]+$/); // eslint-disable-line no-useless-escape\nexport const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nexport const IS_ALLOWED_URI = seal(\n /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nexport const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nexport const ATTR_WHITESPACE = seal(\n /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nexport const DOCTYPE_NAME = seal(/^html$/i);\nexport const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n\n// Markup-significant character probes used by _sanitizeElements.\n// Shared module-level instances are safe despite the sticky /g flags:\n// unapply() resets lastIndex for RegExp receivers before every call.\nexport const ELEMENT_MARKUP_PROBE = seal(/<[/\\w!]/g);\nexport const COMMENT_MARKUP_PROBE = seal(/<[/\\w]/g);\nexport const FALLBACK_TAG_CLOSE = seal(/<\\/no(script|embed|frames)/i);\nexport const SELF_CLOSING_TAG = seal(/\\/>/i);\n", "/* eslint-disable @typescript-eslint/indent */\n\nimport type { Config, UseProfilesConfig } from './config';\nimport type { DOMPurify, HooksMap, HookFunction, WindowLike } from './types';\nimport * as TAGS from './tags.js';\nimport * as ATTRS from './attrs.js';\nimport * as EXPRESSIONS from './regexp.js';\nimport {\n addToSet,\n clone,\n entries,\n freeze,\n seal,\n arrayForEach,\n arrayIsArray,\n arrayLastIndexOf,\n arrayPop,\n arrayPush,\n arraySplice,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringIndexOf,\n stringTrim,\n regExpTest,\n isRegex,\n typeErrorCreate,\n lookupGetter,\n create,\n objectHasOwnProperty,\n stringifyValue,\n} from './utils.js';\n\nexport type { Config } from './config';\n\nexport type {\n DOMPurify,\n RemovedElement,\n RemovedAttribute,\n HookName,\n NodeHook,\n ElementHook,\n DocumentFragmentHook,\n UponSanitizeElementHook,\n UponSanitizeAttributeHook,\n UponSanitizeElementHookEvent,\n UponSanitizeAttributeHookEvent,\n WindowLike,\n} from './types';\n\ndeclare const VERSION: string;\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5, // Deprecated\n entityNode: 6, // Deprecated\n processingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12, // Deprecated\n};\n\nconst getGlobal = function (): WindowLike {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param trustedTypes The policy factory.\n * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function (\n trustedTypes: TrustedTypePolicyFactory,\n purifyHostElement: HTMLScriptElement\n) {\n if (\n typeof trustedTypes !== 'object' ||\n typeof trustedTypes.createPolicy !== 'function'\n ) {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n },\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn(\n 'TrustedTypes policy ' + policyName + ' could not be created.'\n );\n return null;\n }\n};\n\nconst _createHooksMap = function (): HooksMap {\n return {\n afterSanitizeAttributes: [],\n afterSanitizeElements: [],\n afterSanitizeShadowDOM: [],\n beforeSanitizeAttributes: [],\n beforeSanitizeElements: [],\n beforeSanitizeShadowDOM: [],\n uponSanitizeAttribute: [],\n uponSanitizeElement: [],\n uponSanitizeShadowNode: [],\n };\n};\n\n/**\n * Resolve a set-valued configuration option: a fresh set built from\n * cfg[key] when it is an own array property (seeded with a clone of\n * options.base when given, case-normalized via options.transform),\n * the fallback set otherwise.\n *\n * @param cfg the cloned, prototype-free configuration object\n * @param key the configuration property to read\n * @param fallback the set to use when the option is absent or not an array\n * @param options transform and optional base set to merge into\n * @returns the resolved set\n */\nconst _resolveSetOption = function (\n cfg: Config,\n key: keyof Config,\n fallback: Record,\n options: {\n transform: Parameters[2];\n base?: Record;\n }\n): Record {\n return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key])\n ? addToSet(\n options.base ? clone(options.base) : {},\n cfg[key] as readonly unknown[],\n options.transform\n )\n : fallback;\n};\n\nfunction createDOMPurify(window: WindowLike = getGlobal()): DOMPurify {\n const DOMPurify: DOMPurify = (root: WindowLike) => createDOMPurify(root);\n\n DOMPurify.version = VERSION;\n\n DOMPurify.removed = [];\n\n if (\n !window ||\n !window.document ||\n window.document.nodeType !== NODE_TYPE.document ||\n !window.Element\n ) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n let { document } = window;\n\n const originalDocument = document;\n const currentScript: HTMLScriptElement =\n originalDocument.currentScript as HTMLScriptElement;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || (window as any).MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes,\n } = window;\n\n const ElementPrototype = Element.prototype;\n\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const remove = lookupGetter(ElementPrototype, 'remove');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');\n const getAttributes = lookupGetter(ElementPrototype, 'attributes');\n const getNodeType =\n Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;\n const getNodeName =\n Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n\n // The instance's own internal Trusted Types policy. Unlike a caller-supplied\n // `TRUSTED_TYPES_POLICY`, this is created at most once \u2014 Trusted Types throws\n // on duplicate policy names \u2014 and is the only policy allowed to persist\n // across configurations and survive `clearConfig()`.\n let defaultTrustedTypesPolicy;\n let defaultTrustedTypesPolicyResolved = false;\n\n // Tracks whether we are already inside a call to the configured Trusted Types\n // policy (`createHTML` or `createScriptURL`). If a supplied policy callback\n // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would\n // re-enter the policy and recurse until the stack overflows. We detect that\n // re-entry and throw a clear, actionable error instead. The guard is shared\n // across both callbacks, because either one re-entering `sanitize` triggers\n // the same unbounded recursion.\n let IN_TRUSTED_TYPES_POLICY = 0;\n const _assertNotInTrustedTypesPolicy = function (): void {\n if (IN_TRUSTED_TYPES_POLICY > 0) {\n throw typeErrorCreate(\n 'A configured TRUSTED_TYPES_POLICY callback (createHTML or ' +\n 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' +\n 'infinite recursion. Do not pass a policy whose callbacks wrap ' +\n 'DOMPurify as TRUSTED_TYPES_POLICY; see the \"DOMPurify and Trusted ' +\n 'Types\" section of the README.'\n );\n }\n };\n\n const _createTrustedHTML = function (html: string): string {\n _assertNotInTrustedTypesPolicy();\n\n IN_TRUSTED_TYPES_POLICY++;\n try {\n return trustedTypesPolicy.createHTML(html);\n } finally {\n IN_TRUSTED_TYPES_POLICY--;\n }\n };\n\n const _createTrustedScriptURL = function (scriptUrl: string): string {\n _assertNotInTrustedTypesPolicy();\n\n IN_TRUSTED_TYPES_POLICY++;\n try {\n return trustedTypesPolicy.createScriptURL(scriptUrl);\n } finally {\n IN_TRUSTED_TYPES_POLICY--;\n }\n };\n\n // Lazily resolve (and cache) the instance's internal default policy.\n // Resolution is attempted at most once: a successful `createPolicy` cannot be\n // repeated (Trusted Types throws on duplicate names), and a failed or\n // unsupported attempt must not be retried on every parse.\n const _getDefaultTrustedTypesPolicy = function () {\n if (!defaultTrustedTypesPolicyResolved) {\n defaultTrustedTypesPolicy = _createTrustedTypesPolicy(\n trustedTypes,\n currentScript\n );\n defaultTrustedTypesPolicyResolved = true;\n }\n\n return defaultTrustedTypesPolicy;\n };\n\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName,\n } = document;\n const { importNode } = originalDocument;\n\n let hooks = _createHooksMap();\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported =\n typeof entries === 'function' &&\n typeof getParentNode === 'function' &&\n implementation &&\n implementation.createHTMLDocument !== undefined;\n\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT,\n } = EXPRESSIONS;\n\n let { IS_ALLOWED_URI } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [\n ...TAGS.html,\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.mathMl,\n ...TAGS.text,\n ]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [\n ...ATTRS.html,\n ...ATTRS.svg,\n ...ATTRS.mathMl,\n ...ATTRS.xml,\n ]);\n\n /*\n * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false,\n },\n })\n );\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */\n const EXTRA_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n })\n );\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with ... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (\u00A77.3.3)\n * - DOM Tree Accessors (\u00A73.1.5)\n * - Form Element Parent-Child Relations (\u00A74.10.3)\n * - Iframe srcdoc / Nested WindowProxies (\u00A74.8.5)\n * - HTMLCollection (\u00A74.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES: UseProfilesConfig | false = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, [\n 'annotation-xml',\n 'audio',\n 'colgroup',\n 'desc',\n 'foreignobject',\n 'head',\n 'iframe',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mtext',\n 'noembed',\n 'noframes',\n 'noscript',\n 'plaintext',\n 'script',\n // mirrors the selected