diff --git a/404.html b/404.html index e0c46ea..5338b69 100644 --- a/404.html +++ b/404.html @@ -11,6 +11,27 @@ Page not found - SecureBit.chat diff --git a/CHANGELOG.md b/CHANGELOG.md index e76e1ca..62305a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v6.8.0 — Light theme + +Added a light theme. The switch is in the header next to the language menu, with three +settings: follow the system, light, or dark. Your choice is remembered. + +Installing on Android now installs the app itself, rather than putting a shortcut on the +home screen that opened in a browser tab. + ## v6.7.3 — Faster loading, and pages search engines can actually read Loading got a lot lighter. The bundles used to carry all thirteen translations at once, diff --git a/README.md b/README.md index e02d3bd..66fb95e 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.7.3-3ecf8e.svg)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-6.8.0-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 5471e04..04a39be 100644 --- a/ar/index.html +++ b/ar/index.html @@ -30,13 +30,33 @@ - + + + + + + + - + + @@ -96,7 +116,7 @@ - + @@ -105,16 +125,25 @@ - + - - - + + + + @@ -235,7 +264,7 @@ - + - - + + - + - + - + - - + + - + + + + + + + - + + @@ -96,7 +116,7 @@ - + @@ -105,16 +125,25 @@ - + - - - + + + + @@ -235,7 +264,7 @@ - + - - + + - + - + - + - - + + "),typeof k!="string"&&!dt(k)&&(k=_s(k),typeof k!="string"))throw $e("dirty is not a string, aborting");if(!e.isSupported)return k;Zt||li(d),e.removed=[];let B=ii&&typeof k!="string"&&dt(k);if(B){let we=R?R(k):k.nodeName;if(typeof we=="string"){let Ee=Z(we);if(!Y[Ee]||ot[Ee])throw $e("root node is forbidden and cannot be sanitized in-place")}if(kt(k))throw $e("root node is clobbered and cannot be sanitized in-place");try{ui(k)}catch(Ee){throw rr(k),Ee}}else if(dt(k))y=nr(""),T=y.ownerDocument.importNode(k,!0),T.nodeType===ve.element&&T.nodeName==="BODY"||T.nodeName==="HTML"?y=T:y.appendChild(T),ui(T);else{if(!Xe&&!Le&&!Be&&k.indexOf("<")===-1)return E&&bt?x(k):k;if(y=nr(k),!y)return Xe?null:bt?C:""}y&&ei&&De(y.firstChild);let se=sr(B?k:y);try{for(;L=se.nextNode();)ar(L),lr(L),et(L.content)&&At(L.content)}catch(we){throw B&&rr(k),we}if(B)return ut(e.removed,we=>{we.element&&qn(we.element)}),Le&&di(k),k;if(Xe){if(Le&&di(y),Et)for(N=j.call(y.ownerDocument);y.firstChild;)N.appendChild(y.firstChild);else N=y;return(ee.shadowroot||ee.shadowrootmode)&&(N=H.call(i,N,!0)),N}let ie=Be?y.outerHTML:y.innerHTML;return Be&&Y["!doctype"]&&y.ownerDocument&&y.ownerDocument.doctype&&y.ownerDocument.doctype.name&&ae(Rs,y.ownerDocument.doctype.name)&&(ie=" -`+ie),Le&&(ie=vt(ie)),E&&bt?x(ie):ie},e.setConfig=function(){let k=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};li(k),Zt=!0},e.clearConfig=function(){Ze=null,Zt=!1,E=M,C=""},e.isValidAttribute=function(k,d,y){Ze||li({});let T=Z(k),L=Z(d);return or(T,L,y)},e.addHook=function(k,d){typeof d=="function"&&tt(A[k],d)},e.removeHook=function(k,d){if(d!==void 0){let y=hs(A[k],d);return y===-1?void 0:fs(A[k],y,1)[0]}return yr(A[k])},e.removeHooks=function(k){A[k]=[]},e.removeAllHooks=function(){A=kr()},e}var Rr=xr();var xt=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(i=>{t[i]=s.sortObjectKeys(e[i])}),t}static assertCryptoKey(e,t=null,i=[]){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 r of i)if(!e.usages||!e.usages.includes(r))throw new Error(`Missing required key usage: ${r}`)}static arrayBufferToBase64(e){let t="",i=new Uint8Array(e),r=i.byteLength;for(let n=0;n=4294967296-4294967296%t);r+=e[a%t]}return r}static async calculateSecurityLevel(e){let t=0,i=100,r={};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,r.verifyEncryption={passed:!0,details:u.details,points:20}):r.verifyEncryption={passed:!1,details:u.details,points:0}}catch(u){r.verifyEncryption={passed:!1,details:`Encryption check failed: ${u.message}`,points:0}}try{let u=await s.verifyECDHKeyExchange(e);u.passed?(t+=15,r.verifyECDHKeyExchange={passed:!0,details:u.details,points:15}):r.verifyECDHKeyExchange={passed:!1,details:u.details,points:0}}catch(u){r.verifyECDHKeyExchange={passed:!1,details:`Key exchange check failed: ${u.message}`,points:0}}try{let u=await s.verifyMessageIntegrity(e);u.passed?(t+=10,r.verifyMessageIntegrity={passed:!0,details:u.details,points:10}):r.verifyMessageIntegrity={passed:!1,details:u.details,points:0}}catch(u){r.verifyMessageIntegrity={passed:!1,details:`Message integrity check failed: ${u.message}`,points:0}}try{let u=await s.verifyECDSASignatures(e);u.passed?(t+=15,r.verifyECDSASignatures={passed:!0,details:u.details,points:15}):r.verifyECDSASignatures={passed:!1,details:u.details,points:0}}catch(u){r.verifyECDSASignatures={passed:!1,details:`Digital signatures check failed: ${u.message}`,points:0}}try{let u=await s.verifyRateLimiting(e);u.passed?(t+=5,r.verifyRateLimiting={passed:!0,details:u.details,points:5}):r.verifyRateLimiting={passed:!1,details:u.details,points:0}}catch(u){r.verifyRateLimiting={passed:!1,details:`Rate limiting check failed: ${u.message}`,points:0}}try{let u=await s.verifyMetadataProtection(e);u.passed?(t+=10,r.verifyMetadataProtection={passed:!0,details:u.details,points:10}):r.verifyMetadataProtection={passed:!1,details:u.details,points:0}}catch(u){r.verifyMetadataProtection={passed:!1,details:`Metadata protection check failed: ${u.message}`,points:0}}try{let u=await s.verifyPerfectForwardSecrecy(e);u.passed?(t+=10,r.verifyPerfectForwardSecrecy={passed:!0,details:u.details,points:10}):r.verifyPerfectForwardSecrecy={passed:!1,details:u.details,points:0}}catch(u){r.verifyPerfectForwardSecrecy={passed:!1,details:`PFS check failed: ${u.message}`,points:0}}await s.verifyNestedEncryption(e)?(t+=5,r.nestedEncryption={passed:!0,details:"Nested encryption active",points:5}):r.nestedEncryption={passed:!1,details:"Nested encryption failed",points:0},await s.verifyPacketPadding(e)?(t+=5,r.packetPadding={passed:!0,details:"Packet padding active",points:5}):r.packetPadding={passed:!1,details:"Packet padding failed",points:0},await s.verifyAdvancedFeatures(e)?(t+=10,r.advancedFeatures={passed:!0,details:"Advanced features active",points:10}):r.advancedFeatures={passed:!1,details:"Advanced features failed",points:0};let o=Math.round(t/i*100),c=10,l=Object.values(r).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:r,timestamp:Date.now(),details:`Real verification: ${t}/${i} security checks passed (${l}/${c} available)`,isRealData:!0,passedChecks:l,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 i of t){let n=new TextEncoder().encode(i),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)!==i)return{passed:!1,details:`Decryption mismatch for: ${i.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,i=e.ecdhKeyPair.privateKey.algorithm.namedCurve;if(t!=="ECDH")return{passed:!1,details:`Invalid key type: ${t}, expected ECDH`};if(i!=="P-384"&&i!=="P-256")return{passed:!1,details:`Unsupported curve: ${i}, 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(r){return{passed:!1,details:`Key derivation test failed: ${r.message}`}}return{passed:!0,details:`ECDH key exchange working with ${i} 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 i of t){let n=new TextEncoder().encode(i),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: ${i.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 i of t){let n=new TextEncoder().encode(i),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: ${i.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 i=`selftest_${crypto.getRandomValues(new Uint32Array(1))[0]}`,r=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 r=new TextEncoder().encode("Test packet padding verification"),n=Math.floor(Math.random()*(e.paddingConfig.maxPadding-e.paddingConfig.minPadding))+e.paddingConfig.minPadding,a=new Uint8Array(r.byteLength+n);return a.set(new Uint8Array(r),0),a.byteLength>=r.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,i=e.decoyChannelsConfig&&e.decoyChannelsConfig.enabled,r=e.antiFingerprintingConfig&&e.antiFingerprintingConfig.enabled;return t||i||r}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[i,r]of t){if(!r||!(r instanceof CryptoKey))return!1;if(r.extractable!==!1)return s.secureLog.log("error","Session key is extractable",{keyName:i}),!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,i=6e4){if(typeof e!="string"||e.length>256)return!1;let r=`msg_${e}`;if(this.locks.has(r))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkMessageRate(e,t,i);this.locks.set(r,!0);try{let n=Date.now();this.messages.has(r)||this.messages.set(r,[]);let o=this.messages.get(r).filter(c=>n-c=t?!1:(o.push(n),this.messages.set(r,o),!0)}finally{this.locks.delete(r)}},async checkConnectionRate(e,t=5,i=3e5){if(typeof e!="string"||e.length>256)return!1;let r=`conn_${e}`;if(this.locks.has(r))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkConnectionRate(e,t,i);this.locks.set(r,!0);try{let n=Date.now();this.connections.has(r)||this.connections.set(r,[]);let o=this.connections.get(r).filter(c=>n-c=t?!1:(o.push(n),this.connections.set(r,o),!0)}finally{this.locks.delete(r)}},cleanup(){let e=Date.now(),t=36e5;for(let[i,r]of this.messages.entries()){if(this.locks.has(i))continue;let n=r.filter(a=>e-ae-a3e4&&this.locks.delete(i)}}};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,i={}){let r=this.sanitizeContext(i),n={timestamp:Date.now(),level:e,message:t,context:r,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:r?.constructor?.name||"Unknown"}):e==="warn"?console.warn(`\u26A0\uFE0F [SecureChat] ${t}`,{details:r}):console.log(`[SecureChat] ${t}`,r)},_generateErrorCode(e){let t=e.split("").reduce((i,r)=>(i=(i<<5)-i+r.charCodeAt(0),i&i),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],i={};for(let[r,n]of Object.entries(e))t.some(o=>o.test(r)||typeof n=="string"&&o.test(n))?i[r]="[REDACTED]":typeof n=="string"&&n.length>100?i[r]=n.substring(0,100)+"...[TRUNCATED]":n instanceof ArrayBuffer||n instanceof Uint8Array?i[r]=`[${n.constructor.name}(${n.byteLength||n.length} bytes)]`:n&&typeof n=="object"&&!Array.isArray(n)?i[r]=this.sanitizeContext(n):i[r]=n;return i},getLogs(e=null){return e?this.logs.filter(t=>t.level===e):[...this.logs]},clearLogs(){this.logs=[]},async sendErrorToServer(e,t,i={}){if(this.isProductionMode)try{let r={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:",r)}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 i=new TextEncoder,r=typeof t=="string"?i.encode(t):t;try{let n=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},e,r);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,r);return Array.from(new Uint8Array(a))}}catch(i){throw s.secureLog.log("error","Data signing failed",{error:i.message}),new Error("Failed to sign data")}}static async verifySignature(e,t,i){try{let r=new TextEncoder,n=typeof i=="string"?r.encode(i):i,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(r){throw s.secureLog.log("error","Signature verification failed",{error:r.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 i=new Uint8Array(e);if(i.length<50)throw new Error("Key data too short - invalid SPKI structure");if(i.length>2e3)throw new Error("Key data too long - possible attack");let r=s.parseASN1(i);if(!r||r.tag!==48)throw new Error("Invalid SPKI structure - missing SEQUENCE tag");if(r.children.length!==2)throw new Error(`Invalid SPKI structure - expected 2 elements, got ${r.children.length}`);let n=r.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 p=n.children[1];if(p.tag!==6)throw new Error("Invalid curve OID - not an OBJECT IDENTIFIER");let S=s.oidToString(p.value);if(!{"1.2.840.10045.3.1.7":"P-256","1.3.132.0.34":"P-384"}[S])throw new Error(`Invalid or unsupported curve OID: ${S}`)}let u=r.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 p=u.value.slice(1);if(p[0]!==4)throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${p[0].toString(16)}`);let S={"P-256":65,"P-384":97},g=s.oidToString(n.children[1].value)==="1.2.840.10045.3.1.7"?"P-256":"P-384",m=S[g];if(p.length!==m)throw new Error(`Invalid EC point size for ${g}: expected ${m}, got ${p.length}`)}try{let p=t==="ECDSA"||t==="ECDH"?{name:t,namedCurve:"P-384"}:{name:t},S=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",i.buffer,p,!1,S)}catch(p){if(t==="ECDSA"||t==="ECDH")try{let S={name:t,namedCurve:"P-256"},w=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",i.buffer,S,!1,w)}catch(S){throw new Error(`Key import validation failed: ${S.message}`)}else throw new Error(`Key import validation failed: ${p.message}`)}return!0}catch(i){throw s.secureLog.log("error","Key structure validation failed",{error:i.message,algorithm:t}),new Error(`Invalid key structure: ${i.message}`)}}static parseASN1(e,t=0){if(t>=e.length)return null;let i=e[t],r=t+1;if(r>=e.length)throw new Error("Truncated ASN.1 structure");let n=e[r],a=r+1;if(n&128){let l=n&127;if(l>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+=l}if(a+n>e.length)throw new Error("ASN.1 structure extends beyond data");let o=e.slice(a,a+n),c={tag:i,length:n,value:o,children:[]};if(i===48||i===49){let l=0;for(;l2)throw new Error(`Invalid OID first component: ${i[0]}`);if((i[0]===0||i[0]===1)&&i[1]>39)throw new Error(`Invalid OID second component: ${i[1]} (must be <= 39 for first component ${i[0]})`);return!0}static async exportPublicKeyWithSignature(e,t,i="ECDH"){try{if(!["ECDH","ECDSA"].includes(i))throw new Error("Invalid key type");let r=await crypto.subtle.exportKey("spki",e),n=Array.from(new Uint8Array(r));await s.validateKeyStructure(n,i);let a={keyType:i,keyData:n,timestamp:Date.now(),version:"4.0"},o=JSON.stringify(a),c=await s.signData(t,o);return{...a,signature:c}}catch(r){throw s.secureLog.log("error","Public key export failed",{error:r.message,keyType:i}),new Error(`Failed to export ${i} key: ${r.message}`)}}static async importSignedPublicKey(e,t,i="ECDH"){try{if(!e||typeof e!="object")throw new Error("Invalid signed package format");let{keyType:r,keyData:n,timestamp:a,version:o,signature:c}=e;if(!r||!n||!a||!c)throw new Error("Missing required fields in signed package");if(!s.constantTimeCompare(r,i))throw new Error(`Key type mismatch: expected ${i}, got ${r}`);if(Date.now()-a>36e5)throw new Error("Signed key package is too old");await s.validateKeyStructure(n,r);let u=JSON.stringify({keyType:r,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 S=new Uint8Array(n);try{let w=r==="ECDH"?{name:"ECDH",namedCurve:"P-384"}:{name:"ECDSA",namedCurve:"P-384"},g=r==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",S,w,!1,g)}catch(w){s.secureLog.log("warn","Elliptic curve P-384 import failed, switching curve",{error:w.message});let g=r==="ECDH"?{name:"ECDH",namedCurve:"P-256"}:{name:"ECDSA",namedCurve:"P-256"},m=r==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",S,g,!1,m)}}catch(r){throw s.secureLog.log("error","Signed public key import failed",{error:r.message,expectedKeyType:i}),new Error(`Failed to import the signed key: ${r.message}`)}}static async exportPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),i=Array.from(new Uint8Array(t));return await s.validateKeyStructure(i,"ECDH"),i}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(i){return s.secureLog.log("warn","P-384 import failed, trying P-256",{error:i.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,i={}){try{if(!e||!e.keyData||!e.signature)throw new Error("Invalid signed key package format");let n=["keyData","signature","keyType","timestamp","version"].filter(p=>!e[p]);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 l=await s.calculateKeyFingerprint(e.keyData),h=new Uint8Array(e.keyData),u=e.keyType||"ECDH";try{let p=await crypto.subtle.importKey("spki",h,{name:u,namedCurve:"P-384"},!1,u==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(p,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),p}catch(p){s.secureLog.log("warn","P-384 import failed, trying P-256",{error:p.message});let S=await crypto.subtle.importKey("spki",h,{name:u,namedCurve:"P-256"},!1,u==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(S,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),S}}catch(r){throw s.secureLog.log("error","Signed package key import failed",{error:r.message,securityImplications:"Potential security breach prevented"}),new Error(`Failed to import the public key from the signed package: ${r.message}`)}}static async deriveSharedKeys(e,t,i){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(!i||i.length!==64)throw new Error("Salt must be exactly 64 bytes for enhanced security");let r=new Uint8Array(i),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(m){throw s.secureLog.log("error","ECDH derivation failed",{error:m.message}),m}finally{o&&(s.zeroizeBuffer(o),o=null)}let c;c=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:r,info:n.encode("message-encryption-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let l;l=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:r,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:r,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:r,info:n.encode("metadata-protection-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let p=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:r,info:n.encode("double-ratchet-root-v1")},a,256),S=new Uint8Array(p),w=null,g;try{w=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:r,info:n.encode("fingerprint-generation-v4")},a,256),g=await s.generateKeyFingerprint(new Uint8Array(w))}finally{w&&(s.zeroizeBuffer(w),w=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(!(l instanceof CryptoKey))throw s.secureLog.log("error","Derived MAC key is not a CryptoKey",{macKeyType:typeof l,macKeyAlgorithm:l?.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:l,pfsKey:h,metadataKey:u,ratchetRoot:S,fingerprint:g,timestamp:Date.now(),version:"4.0"}}catch(r){throw s.secureLog.log("error","Enhanced key derivation failed",{error:r.message,errorStack:r.stack,privateKeyType:typeof e,publicKeyType:typeof t,saltLength:i?.length,privateKeyAlgorithm:e?.algorithm?.name,publicKeyAlgorithm:t?.algorithm?.name}),new Error(`Failed to create shared encryption keys: ${r.message}`)}}static async generateKeyFingerprint(e){let t=new Uint8Array(e),i=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(i)).slice(0,12).map(n=>n.toString(16).padStart(2,"0")).join(":")}static generateMutualAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(48)),t=Date.now(),i=crypto.getRandomValues(new Uint8Array(16));return{challenge:Array.from(e),timestamp:t,nonce:Array.from(i),version:"4.0"}}static async createAuthProof(e,t,i){try{if(!e||!e.challenge||!e.timestamp||!e.nonce)throw new Error("Invalid challenge structure");let r=Date.now()-e.timestamp;if(r>12e4)throw new Error("Challenge expired");let n={challenge:e.challenge,timestamp:e.timestamp,nonce:e.nonce,responseTimestamp:Date.now(),publicKeyHash:await s.hashPublicKey(i)},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(r/1e3)+"s"}),c}catch(r){throw s.secureLog.log("error","Authentication proof creation failed",{error:r.message}),new Error(`Failed to create cryptographic proof: ${r.message}`)}}static async verifyAuthProof(e,t,i){try{if(await new Promise(h=>setTimeout(h,Math.floor(Math.random()*20)+5)),s.assertCryptoKey(i,"ECDSA",["verify"]),!e||!t||!i)throw new Error("Missing required parameters for proof verification");let r=["challenge","timestamp","nonce","responseTimestamp","publicKeyHash","signature"];for(let h of r)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(i);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(i,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(r){throw s.secureLog.log("error","Authentication proof verification failed",{error:r.message}),new Error(`Failed to verify cryptographic proof: ${r.message}`)}}static async hashPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),i=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(i)).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,i="";for(let r=0;r<6;r++){let n;do n=crypto.getRandomValues(new Uint8Array(1))[0];while(n>=256-256%t);i+=e[n%t]}return i.match(/.{1,2}/g).join("-")}static async encryptMessage(e,t,i,r,n,a=0){try{if(!e||typeof e!="string")throw new Error("Invalid message format");s.assertCryptoKey(t,"AES-GCM",["encrypt"]),s.assertCryptoKey(i,"HMAC",["sign"]),s.assertCryptoKey(r,"AES-GCM",["encrypt"]);let o=new TextEncoder,c=o.encode(e),l=crypto.getRandomValues(new Uint8Array(12)),h=crypto.getRandomValues(new Uint8Array(12)),u=Date.now(),p=16-c.length%16,S=new Uint8Array(c.length+p);S.set(c);let w=crypto.getRandomValues(new Uint8Array(p));S.set(w,c.length);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:l},t,S),m={id:n,timestamp:u,sequenceNumber:a,originalLength:c.length,version:"4.0"},I=JSON.stringify(s.sortObjectKeys(m)),b=await crypto.subtle.encrypt({name:"AES-GCM",iv:h},r,o.encode(I)),D={messageIv:Array.from(l),messageData:Array.from(new Uint8Array(g)),metadataIv:Array.from(h),metadataData:Array.from(new Uint8Array(b)),version:"4.0"},_=s.sortObjectKeys(D),R=JSON.stringify(_),E=await crypto.subtle.sign("HMAC",i,o.encode(R));return D.mac=Array.from(new Uint8Array(E)),D}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,i,r,n=null){try{s.assertCryptoKey(t,"AES-GCM",["decrypt"]),s.assertCryptoKey(i,"HMAC",["verify"]),s.assertCryptoKey(r,"AES-GCM",["decrypt"]);let a=["messageIv","messageData","metadataIv","metadataData","mac","version"];for(let M of a)if(!e[M])throw new Error(`Missing required field: ${M}`);let o={...e};delete o.mac;let c=s.sortObjectKeys(o),l=JSON.stringify(c);if(!await crypto.subtle.verify("HMAC",i,new Uint8Array(e.mac),new TextEncoder().encode(l)))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),p=new Uint8Array(e.metadataData),S=await crypto.subtle.decrypt({name:"AES-GCM",iv:u},r,p),w=new TextDecoder().decode(S),g=JSON.parse(w);if(!g.id||!g.timestamp||g.sequenceNumber===void 0||!g.originalLength)throw new Error("Invalid metadata structure");let m=Date.now()-g.timestamp;if(m>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 I=new Uint8Array(e.messageIv),b=new Uint8Array(e.messageData),D=await crypto.subtle.decrypt({name:"AES-GCM",iv:I},t,b),R=new Uint8Array(D).slice(0,g.originalLength),C=new TextDecoder().decode(R);return s.secureLog.log("info","Message decrypted successfully",{messageId:g.id,sequenceNumber:g.sequenceNumber,messageAge:Math.round(m/1e3)+"s"}),{message:C,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=Rr(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,i=new Uint8Array(e),r=await crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(r)).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 i=typeof e=="string"?e:JSON.stringify(e),r=typeof t=="string"?t:JSON.stringify(t);if(i.length!==r.length){let a=0;for(let o=0;oa.toLowerCase()===t);if(i)return i;let r=t.split("-")[0],n=Ke.find(a=>a.toLowerCase().split("-")[0]===r);if(n)return n}return null}function Vs({pathname:s="/",stored:e=null,languages:t=[]}={}){let i=Dr(s);return i||(Bs(s)?"en":e&&Ke.includes(e)?e:zs(t)||"en")}function Bs(s){return s==="/"||s==="/index.html"}function Hs(s,e="/"){let t=Dr(e),r=(t?String(e).slice(t.length+1):String(e)).replace(/^\/+/,"");return s==="en"?`/${r}`:`/${s}/${r}`}function Pr(s){try{localStorage.setItem(Lr,s)}catch{}}function $s(){try{return localStorage.getItem(Lr)}catch{return null}}var Rt=null;function Ge(){if(Rt)return Rt;let s=typeof window>"u"?null:window;return!s||!s.location?"en":(Rt=Vs({pathname:s.location.pathname||"/",stored:$s(),languages:s.navigator?.languages||[]}),Rt)}function Gs(s=Ge()){return rt[s]?.dir==="rtl"?"rtl":"ltr"}function qs(s=Ge()){return Gs(s)==="rtl"}function Fr(s=Ge()){return qs(s)?-1:1}function Oe(s,e=Ge()){let t=Mt(e)?.[s]??Mt("en")?.[s];return Array.isArray(t)?t:[]}function Kr({pathname:s="/",active:e="en"}={}){return Ke.map(t=>({code:t,href:Hs(t,s),hrefLang:rt[t]?.htmlLang||t,label:rt[t]?.nativeName||t,abbr:rt[t]?.abbr||t.toUpperCase(),dir:rt[t]?.dir||"ltr",isCurrent:t===e}))}function f(s,e,t=Ge()){let i=Mt(t)?.[s]??Mr[t]?.[s]??Mt("en")?.[s]??s;return e?String(i).replace(/\{(\w+)\}/g,(r,n)=>Object.prototype.hasOwnProperty.call(e,n)?String(e[n]):r):i}var Ie=class s{static#e=null;static#n=Symbol("SecureFileTransferContext");static getInstance(){return this.#e||(this.#e=new s),this.#e}#t=null;#i=!1;#r="high";setFileTransferSystem(e){if(!(e instanceof je))throw new Error("Invalid file transfer system instance");this.#t=e,this.#i=!0}getFileTransferSystem(){return this.#t}isActive(){return this.#i&&this.#t!==null}deactivate(){this.#i=!1,this.#t=null}getSecurityLevel(){return this.#r}setSecurityLevel(e){["low","medium","high"].includes(e)&&(this.#r=e)}},Q=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 i of this.#e)if(t.includes(i))return i;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})}},Lt=class{static async signFileMetadata(e,t){try{let r=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,r);return Array.from(new Uint8Array(n))}catch(i){throw Q.logSecurityEvent("signature_failed",{error:i.message}),new Error("Failed to sign file metadata")}}static async verifyFileMetadata(e,t,i){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",i,a,n);return o||Q.logSecurityEvent("invalid_signature",{fileId:e.fileId}),o}catch(r){return Q.logSecurityEvent("verification_failed",{error:r.message}),!1}}},Dt=class{static MAX_MESSAGE_SIZE=1024*1024;static isMessageSizeValid(e){let t=JSON.stringify(e),i=new Blob([t]).size;if(i>this.MAX_MESSAGE_SIZE)throw Q.logSecurityEvent("message_too_large",{size:i,limit:this.MAX_MESSAGE_SIZE}),new Error("Message too large");return!0}},wi=class{constructor(){this.locks=new Map}async withLock(e,t){for(;this.locks.has(e);)await this.locks.get(e);let i,r=new Promise(n=>{i=n});this.locks.set(e,r);try{return await t()}finally{this.locks.delete(e),i()}}},nt=class{constructor(e,t){this.maxRequests=e,this.windowMs=t,this.requests=new Map}isAllowed(e){let t=Date.now(),i=t-this.windowMs;this.requests.has(e)||this.requests.set(e,[]);let n=this.requests.get(e).filter(a=>a>i);return this.requests.set(e,n),n.length>=this.maxRequests?(Q.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,i,r,n,a){if(this.webrtcManager=e,this.onProgress=t,this.onComplete=i,this.onError=r,this.onFileReceived=n,this.onIncomingFileRequest=a,!e)throw new Error("webrtcManager is required for EnhancedSecureFileTransfer");Ie.getInstance().setFileTransferSystem(this),this.atomicOps=new wi,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(),i=t.lastIndexOf("."),r=i>=0?t.substring(i):"",n=String(e?.type||"").toLowerCase();for(let[a,o]of Object.entries(this.FILE_TYPE_RESTRICTIONS)){if(!o.extensions.includes(r))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:r,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:r,mimeType:n}}validateFile(e){let t=this.getFileType(e),i=[],n=String(e?.name||"").toLowerCase(),a=n.lastIndexOf("."),o=a>=0?n.substring(a):"";return this.BLOCKED_EXTENSIONS.has(o)&&i.push(`File rejected: ${o} files are not allowed for security reasons.`),e.size>t.maxSize&&i.push(`File size (${this.formatFileSize(e.size)}) exceeds maximum allowed for ${t.category} (${this.formatFileSize(t.maxSize)})`),!t.allowed&&!this.BLOCKED_EXTENSIONS.has(o)&&i.push(`File rejected: unsupported file type. Supported types: ${t.description}`),e.size>this.MAX_FILE_SIZE&&i.push(`File size (${this.formatFileSize(e.size)}) exceeds general limit (${this.formatFileSize(this.MAX_FILE_SIZE)})`),{isValid:i.length===0,errors:i,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 i=typeof e?.fileName=="string"?e.fileName:"",r=this.normalizeDisplayFileName(i);if((!i||i!==i.trim()||/[\u0000-\u001F\u007F]/.test(i)||/[\\/]/.test(i)||i==="."||i===".."||r.length===0)&&t.push("Dangerous file name"),t.length===0){let c=this.validateFile({name:r,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:r,isVoice:a&&!o,voiceRejection:o}}rejectVoiceAutoAcceptReason(e){let t=String(e?.fileType||"").toLowerCase(),i=e?.fileSize;return t.startsWith("audio/")?this.FILE_TYPE_RESTRICTIONS.voice.mimeTypes.includes(t)?!Number.isSafeInteger(i)||i<=0||i>this.MAX_AUTO_ACCEPT_VOICE_SIZE?`too large to auto-accept (${this.formatFileSize(i||0)} > ${this.formatFileSize(this.MAX_AUTO_ACCEPT_VOICE_SIZE)})`:this.autoAcceptedVoiceBytes+i>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,i=["B","KB","MB","GB"],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,r)).toFixed(2))+" "+i[r]}getSupportedFileTypes(){let e={};for(let[t,i]of Object.entries(this.FILE_TYPE_RESTRICTIONS))e[t]={category:i.category,description:i.description,extensions:i.extensions,maxSize:this.formatFileSize(i.maxSize),maxSizeBytes:i.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),i="",r=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>Dt.MAX_MESSAGE_SIZE){console.warn("\u{1F512} Message too large, ignoring"),Q.logSecurityEvent("oversized_message_blocked");return}if(typeof e.data=="string")try{let t=JSON.parse(e.data);if(Dt.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,i=50;for(;!this.webrtcManager.fileTransferSystem&&tsetTimeout(r,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 i={type:"file_transfer_error",fileId:e.fileId,error:"File transfer system not available",timestamp:Date.now()};await this.sendSecureMessage(i)}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 i={type:"file_transfer_error",fileId:e.fileId,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(i)}}}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)),i=new TextEncoder,r=i.encode(this.webrtcManager.keyFingerprint),n=i.encode(e),a=new Uint8Array(this.webrtcManager.sessionSalt),o=new Uint8Array(r.length+a.length+t.length+n.length),c=0;o.set(r,c),c+=r.length,o.set(a,c),c+=a.length,o.set(t,c),c+=t.length,o.set(n,c);let l=await crypto.subtle.digest("SHA-256",o),h=await crypto.subtle.importKey("raw",l,{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 i=new TextEncoder,r=i.encode(this.webrtcManager.keyFingerprint),n=i.encode(e),a=new Uint8Array(t),o=new Uint8Array(this.webrtcManager.sessionSalt),c=new Uint8Array(r.length+o.length+a.length+n.length),l=0;c.set(r,l),l+=r.length,c.set(o,l),l+=o.length,c.set(a,l),l+=a.length,c.set(n,l);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(i){throw console.error("\u274C Failed to derive session key from salt:",i),i}}_emitTransferProgress(e,t){if(typeof this.onProgress!="function"||!e)return;let i=e.totalChunks||0,r=t==="up"?e.sentChunks||0:e.receivedCount||0,n=i>0?Math.min(100,Math.round(r/i*100)):0;try{this.onProgress({fileId:e.fileId,uiId:e.uiId||null,direction:t,progress:n,transferredChunks:r,totalChunks:i,isVoice:!!e.isVoice,voice:e.voice||null})}catch{}}async sendFile(e,t={}){try{if(!this.webrtcManager)throw new Error("WebRTC Manager not initialized");let i=this.getClientIdentifier();if(!this.rateLimiter.isAllowed(i))throw Q.logSecurityEvent("rate_limit_exceeded",{clientId:i}),new Error("Rate limit exceeded. Please wait before sending another file.");if(!e||!e.size)throw new Error("Invalid file object");let r=this.validateFile(e);if(!r.isValid){let p=r.errors.join(". ");throw new Error(p)}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,l=o.salt,h={fileId:n,file:e,fileHash:a,sessionKey:c,salt:l,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((p,S)=>{h.resolveConsent=p,h.rejectConsent=S,h.consentTimeout=setTimeout(()=>{h.consentTimeout=null,S(new Error("Transfer timeout"))},3e4)});return await this.sendFileMetadata(h),await u,await this.startChunkTransmission(h),n}catch(i){let r=Q.sanitizeError(i);throw console.error("\u274C File sending failed:",r),this.onError&&this.onError(r),new Error(r)}}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 Lt.signFileMetadata(t,this.signingKey),console.log("\u{1F512} File metadata signed successfully")}catch(i){Q.logSecurityEvent("signature_failed",{fileId:e.fileId,error:i.message})}await this.sendSecureMessage(t),e.status="metadata_sent"}catch(t){let i=Q.sanitizeError(t);throw console.error("\u274C Failed to send file metadata:",i),e.status="failed",new Error(i)}}async startChunkTransmission(e){try{e.status="transmitting";let t=e.file,i=e.totalChunks;for(let r=0;r{let i=this.activeTransfers.get(e.fileId);i&&i.status!=="completed"&&this.cleanupTransfer(e.fileId)},18e4)}async handleChunkRequest(e){let t=this.activeTransfers.get(e?.fileId);if(!t||!t.file)return;let i=Array.isArray(e.missing)?e.missing:[];if(i.length===0)return;this._armSenderIdleTimeout(t),t.status="transmitting";let n=i.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),l=await this.readFileChunk(t.file,o,c);await this.sendFileChunk(t,a,l),await this.waitForBackpressure()}catch(o){console.warn("\u26A0\uFE0F Failed to retransmit chunk",a,Q.sanitizeError(o))}t.status==="transmitting"&&(t.status="waiting_confirmation"),this._armSenderIdleTimeout(t)}async readFileChunk(e,t,i){try{return await e.slice(t,i).arrayBuffer()}catch(r){let n=Q.sanitizeError(r);throw console.error("\u274C Failed to read file chunk:",n),new Error(n)}}async sendFileChunk(e,t,i){try{let r=e.sessionKey,n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},r,i),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:i.byteLength,timestamp:Date.now()};await this.waitForBackpressure(),await this.sendSecureMessage(c)}catch(r){let n=Q.sanitizeError(r);throw console.error("\u274C Failed to send file chunk:",n),new Error(n)}}async sendSecureMessage(e){let t=JSON.stringify(e),i=this.webrtcManager?.dataChannel,r=10,n=0,a=o=>new Promise(c=>setTimeout(c,o));for(;;)try{if(!i||i.readyState!=="open")throw new Error("Data channel not ready");await this.waitForBackpressure(),i.send(t);return}catch(o){let c=String(o?.message||""),l=c.includes("send queue is full")||c.includes("bufferedAmount"),h=o?.name==="OperationError";if((l||h)&&ne.bufferedAmountLowThreshold&&await new Promise(i=>{let r=()=>{e.removeEventListener("bufferedamountlow",r),i()};e.addEventListener("bufferedamountlow",r,{once:!0})});return}let t=4*1024*1024;for(;e.bufferedAmount>t;)await new Promise(i=>setTimeout(i,20))}catch{}}async calculateFileHash(e){try{let t=await e.arrayBuffer(),i=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(i)).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 i=this.validateIncomingMetadata(e);if(!i.isValid)throw new Error(i.errors.join(". "));if(e.signature&&this.verificationKey)try{if(!await Lt.verifyFileMetadata(e,e.signature,this.verificationKey))throw Q.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 Q.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");i.voiceRejection&&console.warn(`Voice auto-accept declined, falling back to consent: ${i.voiceRejection}`);let r={...e,isVoice:i.isVoice,fileName:i.displayName,receivedAt:Date.now()};this.pendingIncomingTransfers.set(e.fileId,r),i.isVoice&&(this.autoAcceptedVoiceBytes+=e.fileSize),typeof this.onIncomingFileRequest=="function"?this.onIncomingFileRequest({fileId:r.fileId,fileName:r.fileName,fileSize:r.fileSize,mimeType:r.fileType||"application/octet-stream",isVoice:i.isVoice,voice:r.voice||null}):await this.rejectIncomingFile(e.fileId,f("file.consentUnavailable"))}catch(t){let i=Q.sanitizeError(t);console.error("\u274C Failed to handle file transfer start:",i);let r={type:"file_transfer_response",fileId:e.fileId,accepted:!1,error:i,timestamp:Date.now()};await this.sendSecureMessage(r)}}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 i=new Uint8Array(e.nonce),r;if(e.encryptedDataB64)r=this.base64ToUint8Array(e.encryptedDataB64);else if(e.encryptedData)r=new Uint8Array(e.encryptedData);else throw new Error("Missing encrypted data");let n=await crypto.subtle.decrypt({name:"AES-GCM",iv:i},t.sessionKey,r);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 i=Q.sanitizeError(t);console.warn("\u26A0\uFE0F Dropping unprocessable file chunk (will be re-requested):",e.chunkIndex,i)}})}_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:(Q.logSecurityEvent("incoming_chunk_transfer_rate_limit_exceeded",{clientId:t,fileId:e}),!1)):(Q.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(i!==e.fileSize)throw new Error(`File size mismatch: expected ${e.fileSize}, got ${i}`);let r=new Uint8Array(i),n=0;for(let h of t)r.set(h,n),n+=h.length;if(await this.calculateFileHashFromData(r)!==e.fileHash)throw new Error("File integrity check failed - hash mismatch");let o=r.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 S=await this.getBlob(e.fileId);if(!S)throw new Error("This file is no longer available for download.");return S},u=async()=>{let S=await h();return URL.createObjectURL(S)},p=S=>{try{URL.revokeObjectURL(S)}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:p})}let l={type:"file_transfer_complete",fileId:e.fileId,success:!0,timestamp:Date.now()};await this.sendSecureMessage(l),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 i={type:"file_transfer_complete",fileId:e.fileId,success:!1,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(i),this.cleanupReceivingTransfer(e.fileId)}}}async calculateFileHashFromData(e){try{let t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(r=>r.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 i=this.receivingTransfers.get(e.fileId);i&&(i.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 i=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:i,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 i=256,r=[];for(let n=0;nthis.MAX_RETAINED_RECEIVED_FILE_BUFFERS;){let i=this.receivedFileBuffers.keys().next().value;this._discardReceivedFileBuffer(i)}}_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 i=this.receivingTransfers.get(e);i&&(i.status==="completed"||i._assembled)&&(i._stallTimer&&(clearInterval(i._stallTimer),i._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 i=this.receivedFileBuffers.get(e);if(i)try{i.buffer&&(qe.secureWipe(i.buffer),new Uint8Array(i.buffer).fill(0));for(let[n,a]of Object.entries(i))a&&typeof a=="object"&&((a instanceof ArrayBuffer||a instanceof Uint8Array)&&qe.secureWipe(a),i[n]=null);this.receivedFileBuffers.delete(e)}catch(n){console.warn("\u26A0\uFE0F Failed to securely clear file buffer:",n),this.receivedFileBuffers.delete(e)}let r=[];for(let n of this.processedChunks)n.startsWith(e)&&r.push(n);for(let n of r)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),i=await this.deriveFileSessionKeyFromSalt(e,t.salt),r=new TextEncoder().encode("test data"),n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},t.key,r),o=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},i,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 i=JSON.parse(t.data);if(e.isFileTransferMessage(i))return await e.handleFileMessage(i),!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=Q.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"}},xe={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"},Nr={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}},Ei={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 js(s){return s.indexOf(`\r +var en=Object.create;var fi=Object.defineProperty;var tn=Object.getOwnPropertyDescriptor;var rn=Object.getOwnPropertyNames;var sn=Object.getPrototypeOf,nn=Object.prototype.hasOwnProperty;var pi=(n,e)=>()=>{try{return e||n((e={exports:{}}).exports,e),e.exports}catch(t){throw e=0,t}};var an=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of rn(e))!nn.call(n,i)&&i!==t&&fi(n,i,{get:()=>e[i],enumerable:!(r=tn(e,i))||r.enumerable});return n};var yi=(n,e,t)=>(t=n!=null?en(sn(n)):{},an(e||!n||!n.__esModule?fi(t,"default",{value:n,enumerable:!0}):t,n));var Cs=pi((xo,qt)=>{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"),s=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:s.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(u){console.error("[Notifications] Error in onClick handler:",u)}},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}}},jt=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 s=document.createElement("span");s.textContent=e.text,s.style.wordWrap="break-word",s.style.overflowWrap="break-word",s.style.whiteSpace="normal";let a=document.createElement("small");a.textContent=new Date(e.timestamp).toLocaleTimeString(),r.appendChild(i),r.appendChild(s),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 qt<"u"&&qt.exports&&(qt.exports={SecureChatNotificationManager:wt,SecureP2PChat:jt});typeof window<"u"&&(window.SecureChatNotificationManager=wt,window.SecureP2PChat=jt)});var As=pi((Io,Wt)=>{var ks=yi(Cs());var Yt=class{constructor(e){this.webrtcManager=e,this.notificationManager=new ks.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(u=>this.processedMessages.add(u))}if(t==="system"||t==="file-transfer"||t==="heartbeat")return;let s=this.extractMessageInfo(e,t);if(!s)return;let o=!!r&&typeof r=="object"&&(r.once===!0||Number.isFinite(r.ttl)&&r.ttl>0)?"Sent you a private message":s.text,c=this.notificationManager.notify(s.senderName,o,{icon:s.senderAvatar,senderId:s.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 Wt<"u"&&Wt.exports&&(Wt.exports={NotificationIntegration:Yt});typeof window<"u"&&(window.NotificationIntegration=Yt)});function gi(n,e){(e==null||e>n.length)&&(e=n.length);for(var t=0,r=Array(e);t2?r-2:0),s=2;s1?t-1:0),i=1;i"u"?null:te(BigInt.prototype.toString),Ei=typeof Symbol>"u"?null:te(Symbol.prototype.toString),he=te(Object.prototype.hasOwnProperty),pt=te(Object.prototype.toString),se=te(RegExp.prototype.test),$e=bn(TypeError);function te(n){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(mi&&mi(n,null),!Fe(e))return n;let r=e.length;for(;r--;){let i=e[r];if(typeof i=="string"){let s=t(i);s!==i&&(hn(e)||(e[r]=s),i=s)}n[i]=!0}return n}function wn(n){for(let e=0;e/g),xn=ae(/\${[\w\W]*/g),In=ae(/^data-[\-\w.\u00B7-\uFFFF]+$/),Rn=ae(/^aria-[\-\w]+$/),Ai=ae(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Mn=ae(/^(?:\w+script|data):/i),Ln=ae(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Dn=ae(/^html$/i),Pn=ae(/^[a-z][.\w]*(-[.\w]+)+$/i),xi=ae(/<[/\w!]/g),Fn=ae(/<[/\w]/g),Kn=ae(/<\/no(script|embed|frames)/i),Nn=ae(/\/>/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},On=function(){return typeof window>"u"?null:window},Un=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 s="dompurify"+(r?"#"+r:"");try{return e.createPolicy(s,{createHTML(a){return a},createScriptURL(a){return a}})}catch{return console.warn("TrustedTypes policy "+s+" could not be created."),null}},Ii=function(){return{afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},Pe=function(e,t,r,i){return he(e,t)&&Fe(e[t])?V(i.base?ue(i.base):{},e[t],i.transform):r};function Li(){let n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:On(),e=A=>Li(A);if(e.version="3.4.10",e.removed=[],!n||!n.document||n.document.nodeType!==ke.document||!n.Element)return e.isSupported=!1,e;let t=n.document,r=t,i=r.currentScript;n.DocumentFragment;let s=n.HTMLTemplateElement,a=n.Node,o=n.Element,c=n.NodeFilter,d=n.NamedNodeMap;d===void 0&&(n.NamedNodeMap||n.MozNamedAttrMap),n.HTMLFormElement;let u=n.DOMParser,h=n.trustedTypes,m=o.prototype,p=Ae(m,"cloneNode"),S=Ae(m,"remove"),g=Ae(m,"nextSibling"),_=Ae(m,"childNodes"),I=Ae(m,"parentNode"),w=Ae(m,"shadowRoot"),D=Ae(m,"attributes"),T=a&&a.prototype?Ae(a.prototype,"nodeType"):null,v=a&&a.prototype?Ae(a.prototype,"nodeName"):null;if(typeof s=="function"){let A=t.createElement("template");A.content&&A.content.ownerDocument&&(t=A.content.ownerDocument)}let b,C="",x,k=!1,j=0,z=function(){if(j>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.')},M=function(l){z(),j++;try{return b.createHTML(l)}finally{j--}},fe=function(l){z(),j++;try{return b.createScriptURL(l)}finally{j--}},re=function(){return k||(x=Un(h,i),k=!0),x},pe=t,me=pe.implementation,ce=pe.createNodeIterator,ve=pe.createDocumentFragment,G=pe.getElementsByTagName,N=r.importNode,R=Ii();e.isSupported=typeof Ri=="function"&&typeof I=="function"&&me&&me.createHTMLDocument!==void 0;let P=kn,K=An,O=xn,q=In,Y=Rn,Se=Mn,_e=Ln,ye=Pn,Ye=Ai,W=null,Qt=V({},[...vi,...yr,...gr,...mr,...Ti]),Z=null,Jt=V({},[...Ci,...Sr,...ki,...It]),Q=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,Gr=null,Me=Object.seal(rt(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}})),qr=!0,Zt=!0,jr=!1,Wr=!0,Le=!1,lt=!0,Be=!1,er=!1,tr=!1,Xe=!1,Et=!1,vt=!1,Yr=!0,Xr=!1,Qr="user-content-",rr=!0,ir=!1,Qe={},Te=null,sr=V({},["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"]),Jr=null,Zr=V({},["audio","video","img","source","image","track"]),nr=null,ei=V({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Tt="http://www.w3.org/1998/Math/MathML",Ct="http://www.w3.org/2000/svg",Ce="http://www.w3.org/1999/xhtml",Je=Ce,ar=!1,or=null,Os=V({},[Tt,Ct,Ce],pr),ti=ne(["mi","mo","mn","ms","mtext"]),cr=V({},ti),ri=ne(["annotation-xml"]),lr=V({},ri),Us=V({},["title","style","font","a","script"]),dt=null,zs=["application/xhtml+xml","text/html"],Vs="text/html",J=null,Ze=null,Bs=t.createElement("form"),ii=function(l){return l instanceof RegExp||l instanceof Function},dr=function(){let l=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(Ze&&Ze===l)return;(!l||typeof l!="object")&&(l={}),l=ue(l),dt=zs.indexOf(l.PARSER_MEDIA_TYPE)===-1?Vs:l.PARSER_MEDIA_TYPE,J=dt==="application/xhtml+xml"?pr:yt,W=Pe(l,"ALLOWED_TAGS",Qt,{transform:J}),Z=Pe(l,"ALLOWED_ATTR",Jt,{transform:J}),or=Pe(l,"ALLOWED_NAMESPACES",Os,{transform:pr}),nr=Pe(l,"ADD_URI_SAFE_ATTR",ei,{transform:J,base:ei}),Jr=Pe(l,"ADD_DATA_URI_TAGS",Zr,{transform:J,base:Zr}),Te=Pe(l,"FORBID_CONTENTS",sr,{transform:J}),ct=Pe(l,"FORBID_TAGS",ue({}),{transform:J}),Gr=Pe(l,"FORBID_ATTR",ue({}),{transform:J}),Qe=he(l,"USE_PROFILES")?l.USE_PROFILES&&typeof l.USE_PROFILES=="object"?ue(l.USE_PROFILES):l.USE_PROFILES:!1,qr=l.ALLOW_ARIA_ATTR!==!1,Zt=l.ALLOW_DATA_ATTR!==!1,jr=l.ALLOW_UNKNOWN_PROTOCOLS||!1,Wr=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,Et=l.RETURN_DOM_FRAGMENT||!1,vt=l.RETURN_TRUSTED_TYPE||!1,tr=l.FORCE_BODY||!1,Yr=l.SANITIZE_DOM!==!1,Xr=l.SANITIZE_NAMED_PROPS||!1,rr=l.KEEP_CONTENT!==!1,ir=l.IN_PLACE||!1,Ye=vn(l.ALLOWED_URI_REGEXP)?l.ALLOWED_URI_REGEXP:Ai,Je=typeof l.NAMESPACE=="string"?l.NAMESPACE:Ce,cr=he(l,"MATHML_TEXT_INTEGRATION_POINTS")&&l.MATHML_TEXT_INTEGRATION_POINTS&&typeof l.MATHML_TEXT_INTEGRATION_POINTS=="object"?ue(l.MATHML_TEXT_INTEGRATION_POINTS):V({},ti),lr=he(l,"HTML_INTEGRATION_POINTS")&&l.HTML_INTEGRATION_POINTS&&typeof l.HTML_INTEGRATION_POINTS=="object"?ue(l.HTML_INTEGRATION_POINTS):V({},ri);let y=he(l,"CUSTOM_ELEMENT_HANDLING")&&l.CUSTOM_ELEMENT_HANDLING&&typeof l.CUSTOM_ELEMENT_HANDLING=="object"?ue(l.CUSTOM_ELEMENT_HANDLING):rt(null);if(Q=rt(null),he(y,"tagNameCheck")&&ii(y.tagNameCheck)&&(Q.tagNameCheck=y.tagNameCheck),he(y,"attributeNameCheck")&&ii(y.attributeNameCheck)&&(Q.attributeNameCheck=y.attributeNameCheck),he(y,"allowCustomizedBuiltInElements")&&typeof y.allowCustomizedBuiltInElements=="boolean"&&(Q.allowCustomizedBuiltInElements=y.allowCustomizedBuiltInElements),ae(Q),Le&&(Zt=!1),Et&&(Xe=!0),Qe&&(W=V({},Ti),Z=rt(null),Qe.html===!0&&(V(W,vi),V(Z,Ci)),Qe.svg===!0&&(V(W,yr),V(Z,Sr),V(Z,It)),Qe.svgFilters===!0&&(V(W,gr),V(Z,Sr),V(Z,It)),Qe.mathMl===!0&&(V(W,mr),V(Z,ki),V(Z,It))),Me.tagCheck=null,Me.attributeCheck=null,he(l,"ADD_TAGS")&&(typeof l.ADD_TAGS=="function"?Me.tagCheck=l.ADD_TAGS:Fe(l.ADD_TAGS)&&(W===Qt&&(W=ue(W)),V(W,l.ADD_TAGS,J))),he(l,"ADD_ATTR")&&(typeof l.ADD_ATTR=="function"?Me.attributeCheck=l.ADD_ATTR:Fe(l.ADD_ATTR)&&(Z===Jt&&(Z=ue(Z)),V(Z,l.ADD_ATTR,J))),he(l,"ADD_URI_SAFE_ATTR")&&Fe(l.ADD_URI_SAFE_ATTR)&&V(nr,l.ADD_URI_SAFE_ATTR,J),he(l,"FORBID_CONTENTS")&&Fe(l.FORBID_CONTENTS)&&(Te===sr&&(Te=ue(Te)),V(Te,l.FORBID_CONTENTS,J)),he(l,"ADD_FORBID_CONTENTS")&&Fe(l.ADD_FORBID_CONTENTS)&&(Te===sr&&(Te=ue(Te)),V(Te,l.ADD_FORBID_CONTENTS,J)),rr&&(W["#text"]=!0),Be&&V(W,["html","head","body"]),W.table&&(V(W,["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 E=b;b=l.TRUSTED_TYPES_POLICY;try{C=M("")}catch(L){throw b=E,L}}else l.TRUSTED_TYPES_POLICY===null?(b=void 0,C=""):(b===void 0&&(b=re()),b&&typeof C=="string"&&(C=M("")));(R.uponSanitizeElement.length>0||R.uponSanitizeAttribute.length>0)&&W===Qt&&(W=ue(W)),R.uponSanitizeAttribute.length>0&&Z===Jt&&(Z=ue(Z)),ne&&ne(l),Ze=l},si=V({},[...yr,...gr,...Tn]),ni=V({},[...mr,...Cn]),Hs=function(l,y,E){return y.namespaceURI===Ce?l==="svg":y.namespaceURI===Tt?l==="svg"&&(E==="annotation-xml"||cr[E]):!!si[l]},$s=function(l,y,E){return y.namespaceURI===Ce?l==="math":y.namespaceURI===Ct?l==="math"&&lr[E]:!!ni[l]},Gs=function(l,y,E){return y.namespaceURI===Ct&&!lr[E]||y.namespaceURI===Tt&&!cr[E]?!1:!ni[l]&&(Us[l]||!si[l])},qs=function(l){let y=I(l);(!y||!y.tagName)&&(y={namespaceURI:Je,tagName:"template"});let E=yt(l.tagName),L=yt(y.tagName);return or[l.namespaceURI]?l.namespaceURI===Ct?Hs(E,y,L):l.namespaceURI===Tt?$s(E,y,L):l.namespaceURI===Ce?Gs(E,y,L):!!(dt==="application/xhtml+xml"&&or[l.namespaceURI]):!1},De=function(l){tt(e.removed,{element:l});try{I(l).removeChild(l)}catch{if(S(l),!I(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")}},ai=function(l){let y=_(l);if(y){let L=[];ht(y,U=>{tt(L,U)}),ht(L,U=>{try{S(U)}catch{}})}let E=D(l);if(E)for(let L=E.length-1;L>=0;--L){let U=E[L],B=U&&U.name;if(typeof B=="string")try{l.removeAttribute(B)}catch{}}},He=function(l,y){try{tt(e.removed,{attribute:y.getAttributeNode(l),from:y})}catch{tt(e.removed,{attribute:null,from:y})}if(y.removeAttribute(l),l==="is")if(Xe||Et)try{De(y)}catch{}else try{y.setAttribute(l,"")}catch{}},js=function(l){let y=D(l);if(y)for(let E=y.length-1;E>=0;--E){let L=y[E],U=L&&L.name;if(!(typeof U!="string"||Z[J(U)]))try{l.removeAttribute(U)}catch{}}},Ws=function(l){let y=[l];for(;y.length>0;){let E=y.pop();(T?T(E):E.nodeType)===ke.element&&js(E);let U=_(E);if(U)for(let B=U.length-1;B>=0;--B)y.push(U[B])}},oi=function(l){let y=null,E=null;if(tr)l=""+l;else{let B=_i(l,/^[\r\n\t ]+/);E=B&&B[0]}dt==="application/xhtml+xml"&&Je===Ce&&(l=''+l+"");let L=b?M(l):l;if(Je===Ce)try{y=new u().parseFromString(L,dt)}catch{}if(!y||!y.documentElement){y=me.createDocument(Je,"template",null);try{y.documentElement.innerHTML=ar?C:L}catch{}}let U=y.body||y.documentElement;return l&&E&&U.insertBefore(t.createTextNode(E),U.childNodes[0]||null),Je===Ce?G.call(y,Be?"html":"body")[0]:Be?y.documentElement:U},ci=function(l){return ce.call(l.ownerDocument||l,l,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT|c.SHOW_PROCESSING_INSTRUCTION|c.SHOW_CDATA_SECTION,null)},kt=function(l){return l=ft(l,P," "),l=ft(l,K," "),l=ft(l,O," "),l},ur=function(l){var y;l.normalize();let E=ce.call(l.ownerDocument||l,l,c.SHOW_TEXT|c.SHOW_COMMENT|c.SHOW_CDATA_SECTION|c.SHOW_PROCESSING_INSTRUCTION,null),L=E.nextNode();for(;L;)L.data=kt(L.data),L=E.nextNode();let U=(y=l.querySelectorAll)===null||y===void 0?void 0:y.call(l,"template");U&&ht(U,B=>{et(B.content)&&ur(B.content)})},At=function(l){let y=v?v(l):null;return typeof y!="string"||J(y)!=="form"?!1:typeof l.nodeName!="string"||typeof l.textContent!="string"||typeof l.removeChild!="function"||l.attributes!==D(l)||typeof l.removeAttribute!="function"||typeof l.setAttribute!="function"||typeof l.namespaceURI!="string"||typeof l.insertBefore!="function"||typeof l.hasChildNodes!="function"||l.nodeType!==T(l)||l.childNodes!==_(l)},et=function(l){if(!T||typeof l!="object"||l===null)return!1;try{return T(l)===ke.documentFragment}catch{return!1}},ut=function(l){if(!T||typeof l!="object"||l===null)return!1;try{return typeof T(l)=="number"}catch{return!1}};function xe(A,l,y){A.length!==0&&ht(A,E=>{E.call(e,l,y,Ze)})}let Ys=function(l,y){return!!(lt&&l.hasChildNodes()&&!ut(l.firstElementChild)&&se(xi,l.textContent)&&se(xi,l.innerHTML)||lt&&l.namespaceURI===Ce&&y==="style"&&ut(l.firstElementChild)||l.nodeType===ke.processingInstruction||lt&&l.nodeType===ke.comment&&se(Fn,l.data))},Xs=function(l,y){if(!ct[y]&&ui(y)&&(Q.tagNameCheck instanceof RegExp&&se(Q.tagNameCheck,y)||Q.tagNameCheck instanceof Function&&Q.tagNameCheck(y)))return!1;if(rr&&!Te[y]){let E=I(l),L=_(l);if(L&&E){let U=L.length;for(let B=U-1;B>=0;--B){let ie=ir?L[B]:p(L[B],!0);E.insertBefore(ie,g(l))}}}return De(l),!0},li=function(l){if(xe(R.beforeSanitizeElements,l,null),At(l))return De(l),!0;let y=J(v?v(l):l.nodeName);if(xe(R.uponSanitizeElement,l,{tagName:y,allowedTags:W}),Ys(l,y))return De(l),!0;if(ct[y]||!(Me.tagCheck instanceof Function&&Me.tagCheck(y))&&!W[y])return Xs(l,y);if((T?T(l):l.nodeType)===ke.element&&!qs(l)||(y==="noscript"||y==="noembed"||y==="noframes")&&se(Kn,l.innerHTML))return De(l),!0;if(Le&&l.nodeType===ke.text){let L=kt(l.textContent);l.textContent!==L&&(tt(e.removed,{element:l.cloneNode()}),l.textContent=L)}return xe(R.afterSanitizeElements,l,null),!1},di=function(l,y,E){if(Gr[y]||Yr&&(y==="id"||y==="name")&&(E in t||E in Bs))return!1;let L=Z[y]||Me.attributeCheck instanceof Function&&Me.attributeCheck(y,l);if(!(Zt&&se(q,y))){if(!(qr&&se(Y,y))){if(L){if(!nr[y]){if(!se(Ye,ft(E,_e,""))){if(!((y==="src"||y==="xlink:href"||y==="href")&&l!=="script"&&bi(E,"data:")===0&&Jr[l])){if(!(jr&&!se(Se,ft(E,_e,"")))){if(E)return!1}}}}}else if(!(ui(l)&&(Q.tagNameCheck instanceof RegExp&&se(Q.tagNameCheck,l)||Q.tagNameCheck instanceof Function&&Q.tagNameCheck(l))&&(Q.attributeNameCheck instanceof RegExp&&se(Q.attributeNameCheck,y)||Q.attributeNameCheck instanceof Function&&Q.attributeNameCheck(y,l))||y==="is"&&Q.allowCustomizedBuiltInElements&&(Q.tagNameCheck instanceof RegExp&&se(Q.tagNameCheck,E)||Q.tagNameCheck instanceof Function&&Q.tagNameCheck(E))))return!1}}return!0},Qs=V({},["annotation-xml","color-profile","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","missing-glyph"]),ui=function(l){return!Qs[yt(l)]&&se(ye,l)},Js=function(l,y,E,L){if(b&&typeof h=="object"&&typeof h.getAttributeType=="function"&&!E)switch(h.getAttributeType(l,y)){case"TrustedHTML":return M(L);case"TrustedScriptURL":return fe(L)}return L},Zs=function(l,y,E,L){try{E?l.setAttributeNS(E,y,L):l.setAttribute(y,L),At(l)?De(l):Si(e.removed)}catch{He(y,l)}},hi=function(l){xe(R.beforeSanitizeAttributes,l,null);let y=l.attributes;if(!y||At(l))return;let E={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Z,forceKeepAttr:void 0},L=y.length,U=J(l.nodeName);for(;L--;){let B=y[L],ie=B.name,ee=B.namespaceURI,be=B.value,we=J(ie),fr=be,de=ie==="value"?fr:mn(fr);if(E.attrName=we,E.attrValue=de,E.keepAttr=!0,E.forceKeepAttr=void 0,xe(R.uponSanitizeAttribute,l,E),de=E.attrValue,Xr&&(we==="id"||we==="name")&&bi(de,Qr)!==0&&(He(ie,l),de=Qr+de),lt&&se(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,de)){He(ie,l);continue}if(we==="attributename"&&_i(de,"href")){He(ie,l);continue}if(!E.forceKeepAttr){if(!E.keepAttr){He(ie,l);continue}if(!Wr&&se(Nn,de)){He(ie,l);continue}if(Le&&(de=kt(de)),!di(U,we,de)){He(ie,l);continue}de=Js(U,we,ee,de),de!==fr&&Zs(l,ie,ee,de)}}xe(R.afterSanitizeAttributes,l,null)},xt=function(l){let y=null,E=ci(l);for(xe(R.beforeSanitizeShadowDOM,l,null);y=E.nextNode();)if(xe(R.uponSanitizeShadowNode,y,null),li(y),hi(y),et(y.content)&&xt(y.content),(T?T(y):y.nodeType)===ke.element){let U=w(y);et(U)&&(hr(U),xt(U))}xe(R.afterSanitizeShadowDOM,l,null)},hr=function(l){let y=[{node:l,shadow:null}];for(;y.length>0;){let E=y.pop();if(E.shadow){xt(E.shadow);continue}let L=E.node,B=(T?T(L):L.nodeType)===ke.element,ie=_(L);if(ie)for(let ee=ie.length-1;ee>=0;--ee)y.push({node:ie[ee],shadow:null});if(B){let ee=v?v(L):null;if(typeof ee=="string"&&J(ee)==="template"){let be=L.content;et(be)&&y.push({node:be,shadow:null})}}if(B){let ee=w(L);et(ee)&&y.push({node:null,shadow:ee},{node:ee,shadow:null})}}};return e.sanitize=function(A){let l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},y=null,E=null,L=null,U=null;if(ar=!A,ar&&(A=""),typeof A!="string"&&!ut(A)&&(A=En(A),typeof A!="string"))throw $e("dirty is not a string, aborting");if(!e.isSupported)return A;er||dr(l),e.removed=[];let B=ir&&typeof A!="string"&&ut(A);if(B){let be=v?v(A):A.nodeName;if(typeof be=="string"){let we=J(be);if(!W[we]||ct[we])throw $e("root node is forbidden and cannot be sanitized in-place")}if(At(A))throw $e("root node is clobbered and cannot be sanitized in-place");try{hr(A)}catch(we){throw ai(A),we}}else if(ut(A))y=oi(""),E=y.ownerDocument.importNode(A,!0),E.nodeType===ke.element&&E.nodeName==="BODY"||E.nodeName==="HTML"?y=E:y.appendChild(E),hr(E);else{if(!Xe&&!Le&&!Be&&A.indexOf("<")===-1)return b&&vt?M(A):A;if(y=oi(A),!y)return Xe?null:vt?C:""}y&&tr&&De(y.firstChild);let ie=ci(B?A:y);try{for(;L=ie.nextNode();)li(L),hi(L),et(L.content)&&xt(L.content)}catch(be){throw B&&ai(A),be}if(B)return ht(e.removed,be=>{be.element&&Ws(be.element)}),Le&&ur(A),A;if(Xe){if(Le&&ur(y),Et)for(U=ve.call(y.ownerDocument);y.firstChild;)U.appendChild(y.firstChild);else U=y;return(Z.shadowroot||Z.shadowrootmode)&&(U=N.call(r,U,!0)),U}let ee=Be?y.outerHTML:y.innerHTML;return Be&&W["!doctype"]&&y.ownerDocument&&y.ownerDocument.doctype&&y.ownerDocument.doctype.name&&se(Dn,y.ownerDocument.doctype.name)&&(ee=" +`+ee),Le&&(ee=kt(ee)),b&&vt?M(ee):ee},e.setConfig=function(){let A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};dr(A),er=!0},e.clearConfig=function(){Ze=null,er=!1,b=x,C=""},e.isValidAttribute=function(A,l,y){Ze||dr({});let E=J(A),L=J(l);return di(E,L,y)},e.addHook=function(A,l){typeof l=="function"&&tt(R[A],l)},e.removeHook=function(A,l){if(l!==void 0){let y=yn(R[A],l);return y===-1?void 0:gn(R[A],y,1)[0]}return Si(R[A])},e.removeHooks=function(A){R[A]=[]},e.removeAllHooks=function(){R=Ii()},e}var Di=Li();var Rt=class n{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(n.sortObjectKeys);let t={};return Object.keys(e).sort().forEach(r=>{t[r]=n.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 s=0;s=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 s="full",a=!1;try{let h=await n.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 n.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 n.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 n.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 n.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 n.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 n.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 n.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 n.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 n.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:s,maxPossibleScore:100}}catch(s){return console.error("Security level calculation failed:",s.message),{level:"UNKNOWN",score:0,color:"red",verificationResults:{},timestamp:Date.now(),details:`Verification failed: ${s.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 s=new TextEncoder().encode(r),a=crypto.getRandomValues(new Uint8Array(12)),o=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e.encryptionKey,s),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 s=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.privateKey,s);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.publicKey,a,s))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 s=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"HMAC",hash:"SHA-256"},e.macKey,s);if(!await crypto.subtle.verify({name:"HMAC",hash:"SHA-256"},e.macKey,a,s))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=n.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"),s=Math.floor(Math.random()*(e.paddingConfig.maxPadding-e.paddingConfig.minPadding))+e.paddingConfig.minPadding,a=new Uint8Array(i.byteLength+s);return a.set(new Uint8Array(i),0),a.byteLength>=i.byteLength+e.paddingConfig.minPadding}catch(t){return n.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 n.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 n.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 n.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 n.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 n.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(s=>setTimeout(s,Math.floor(Math.random()*10)+5)),this.checkMessageRate(e,t,r);this.locks.set(i,!0);try{let s=Date.now();this.messages.has(i)||this.messages.set(i,[]);let o=this.messages.get(i).filter(c=>s-c=t?!1:(o.push(s),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(s=>setTimeout(s,Math.floor(Math.random()*10)+5)),this.checkConnectionRate(e,t,r);this.locks.set(i,!0);try{let s=Date.now();this.connections.has(i)||this.connections.set(i,[]);let o=this.connections.get(i).filter(c=>s-c=t?!1:(o.push(s),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 s=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),s={timestamp:Date.now(),level:e,message:t,context:i,id:crypto.getRandomValues(new Uint32Array(1))[0]};if(this.logs.push(s),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,s]of Object.entries(e))t.some(o=>o.test(i)||typeof s=="string"&&o.test(s))?r[i]="[REDACTED]":typeof s=="string"&&s.length>100?r[i]=s.substring(0,100)+"...[TRUNCATED]":s instanceof ArrayBuffer||s instanceof Uint8Array?r[i]=`[${s.constructor.name}(${s.byteLength||s.length} bytes)]`:s&&typeof s=="object"&&!Array.isArray(s)?r[i]=this.sanitizeContext(s):r[i]=s;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 n.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 n.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 n.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 n.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 s=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},e,i);return Array.from(new Uint8Array(s))}catch(s){n.secureLog.log("warn","SHA-384 signing failed, trying SHA-256",{error:s.message});let a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e,i);return Array.from(new Uint8Array(a))}}catch(r){throw n.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,s=typeof r=="string"?i.encode(r):r,a=new Uint8Array(t);try{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},e,a,s)}catch{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e,a,s)}}catch(i){throw n.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=n.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 s=i.children[0];if(s.tag!==48)throw new Error("Invalid AlgorithmIdentifier - not a SEQUENCE");let a=s.children[0];if(a.tag!==6)throw new Error("Invalid algorithm OID - not an OBJECT IDENTIFIER");let o=a.value,c=n.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(s.children.length<2)throw new Error("Missing curve parameters for EC key");let m=s.children[1];if(m.tag!==6)throw new Error("Invalid curve OID - not an OBJECT IDENTIFIER");let p=n.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=n.oidToString(s.children[1].value)==="1.2.840.10045.3.1.7"?"P-256":"P-384",_=p[g];if(m.length!==_)throw new Error(`Invalid EC point size for ${g}: expected ${_}, 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 n.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 s=e[i],a=i+1;if(s&128){let d=s&127;if(d>4)throw new Error("ASN.1 length too large");s=0;for(let u=0;u=e.length)throw new Error("Truncated ASN.1 length");s=s<<8|e[a+u]}a+=d}if(a+s>e.length)throw new Error("ASN.1 structure extends beyond data");let o=e.slice(a,a+s),c={tag:r,length:s,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),s=Array.from(new Uint8Array(i));await n.validateKeyStructure(s,r);let a={keyType:r,keyData:s,timestamp:Date.now(),version:"4.0"},o=JSON.stringify(a),c=await n.signData(t,o);return{...a,signature:c}}catch(i){throw n.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:s,timestamp:a,version:o,signature:c}=e;if(!i||!s||!a||!c)throw new Error("Missing required fields in signed package");if(!n.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 n.validateKeyStructure(s,i);let h=JSON.stringify({keyType:i,keyData:s,timestamp:a,version:o});if(!await n.verifySignature(t,c,h))throw new Error("Invalid signature on key package - possible MITM attack");let p=new Uint8Array(s);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){n.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"},_=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,g,!1,_)}}catch(i){throw n.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 n.validateKeyStructure(r,"ECDH"),r}catch(t){throw n.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 n.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 n.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 n.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=n._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 s=["keyData","signature","keyType","timestamp","version"].filter(m=>!e[m]);if(s.length>0)throw n.secureLog.log("error","Missing required fields in signed package",{missingFields:s,availableFields:Object.keys(e)}),new Error(`Required fields are missing in the signed package: ${s.join(", ")}`);if(!t)throw n.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 n.validateKeyStructure(e.keyData,e.keyType||"ECDH");let a={...e};delete a.signature;let o=JSON.stringify(a);if(!await n.verifySignature(t,e.signature,o))throw n.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 n.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 n._keyMetadata.set(m,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),m}catch(m){n.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 n._keyMetadata.set(p,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),p}}catch(i){throw n.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 n.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 n.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),s=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(_){throw n.secureLog.log("error","ECDH derivation failed",{error:_.message}),_}finally{o&&(n.zeroizeBuffer(o),o=null)}let c;c=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:s.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:s.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:s.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:s.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:s.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:s.encode("fingerprint-generation-v4")},a,256),g=await n.generateKeyFingerprint(new Uint8Array(S))}finally{S&&(n.zeroizeBuffer(S),S=null)}if(!(c instanceof CryptoKey))throw n.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 n.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 n.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 n.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 n.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(s=>s.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 s={challenge:e.challenge,timestamp:e.timestamp,nonce:e.nonce,responseTimestamp:Date.now(),publicKeyHash:await n.hashPublicKey(r)},a=JSON.stringify(s),o=await n.signData(t,a),c={...s,signature:o,version:"4.0"};return n.secureLog.log("info","Authentication proof created",{challengeAge:Math.round(i/1e3)+"s"}),c}catch(i){throw n.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)),n.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(!n.constantTimeCompareArrays(e.challenge,t.challenge)||e.timestamp!==t.timestamp||!n.constantTimeCompareArrays(e.nonce,t.nonce))throw new Error("Challenge mismatch - possible replay attack");let s=Date.now()-e.responseTimestamp;if(s>18e5)throw new Error("Proof response expired");let a=await n.hashPublicKey(r);if(!n.constantTimeCompare(e.publicKeyHash,a))throw new Error("Public key hash mismatch");let o={...e};delete o.signature;let c=JSON.stringify(o);if(!await n.verifySignature(r,e.signature,c))throw new Error("Invalid proof signature");return n.secureLog.log("info","Authentication proof verified successfully",{responseAge:Math.round(s/1e3)+"s"}),!0}catch(i){throw n.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(s=>s.toString(16).padStart(2,"0")).join("")}catch(t){throw n.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 s;do s=crypto.getRandomValues(new Uint8Array(1))[0];while(s>=256-256%t);r+=e[s%t]}return r.match(/.{1,2}/g).join("-")}static async encryptMessage(e,t,r,i,s,a=0){try{if(!e||typeof e!="string")throw new Error("Invalid message format");n.assertCryptoKey(t,"AES-GCM",["encrypt"]),n.assertCryptoKey(r,"HMAC",["sign"]),n.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),_={id:s,timestamp:h,sequenceNumber:a,originalLength:c.length,version:"4.0"},I=JSON.stringify(n.sortObjectKeys(_)),w=await crypto.subtle.encrypt({name:"AES-GCM",iv:u},i,o.encode(I)),D={messageIv:Array.from(d),messageData:Array.from(new Uint8Array(g)),metadataIv:Array.from(u),metadataData:Array.from(new Uint8Array(w)),version:"4.0"},T=n.sortObjectKeys(D),v=JSON.stringify(T),b=await crypto.subtle.sign("HMAC",r,o.encode(v));return D.mac=Array.from(new Uint8Array(b)),D}catch(o){throw n.secureLog.log("error","Message encryption failed",{error:o.message,messageId:s}),new Error(`Failed to encrypt the message: ${o.message}`)}}static async decryptMessage(e,t,r,i,s=null){try{n.assertCryptoKey(t,"AES-GCM",["decrypt"]),n.assertCryptoKey(r,"HMAC",["verify"]),n.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=n.sortObjectKeys(o),d=JSON.stringify(c);if(!await crypto.subtle.verify("HMAC",r,new Uint8Array(e.mac),new TextEncoder().encode(d)))throw n.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 _=Date.now()-g.timestamp;if(_>18e5)throw new Error("Message expired (older than 30 minutes)");if(s!==null){if(g.sequenceNumbers+10)throw new Error(`Sequence number gap too large: expected around ${s}, got ${g.sequenceNumber}`)}let I=new Uint8Array(e.messageIv),w=new Uint8Array(e.messageData),D=await crypto.subtle.decrypt({name:"AES-GCM",iv:I},t,w),v=new Uint8Array(D).slice(0,g.originalLength),C=new TextDecoder().decode(v);return n.secureLog.log("info","Message decrypted successfully",{messageId:g.id,sequenceNumber:g.sequenceNumber,messageAge:Math.round(_/1e3)+"s"}),{message:C,messageId:g.id,timestamp:g.timestamp,sequenceNumber:g.sequenceNumber}}catch(a){throw n.secureLog.log("error","Message decryption failed",{error:a.message}),new Error(`Failed to decrypt the message: ${a.message}`)}}static _getMessageSanitizer(){if(n._messageSanitizer)return n._messageSanitizer;if(typeof window>"u"||!window?.document)throw new Error("DOMPurify requires a browser-like window for message sanitization");return n._messageSanitizer=Di(window),n._messageSanitizer}static sanitizeMessage(e){if(typeof e!="string")throw new Error("Message must be a string");let t=n._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 n.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],s=Ke.find(a=>a.toLowerCase().split("-")[0]===i);if(s)return s}return null}function $n({pathname:n="/",stored:e=null,languages:t=[]}={}){let r=Ki(n);return r||(Gn(n)?"en":e&&Ke.includes(e)?e:Hn(t)||"en")}function Gn(n){return n==="/"||n==="/index.html"}function qn(n,e="/"){let t=Ki(e),i=(t?String(e).slice(t.length+1):String(e)).replace(/^\/+/,"");return n==="en"?`/${i}`:`/${n}/${i}`}function Ni(n){try{localStorage.setItem(Fi,n)}catch{}}function jn(){try{return localStorage.getItem(Fi)}catch{return null}}var Mt=null;function Ge(){if(Mt)return Mt;let n=typeof window>"u"?null:window;return!n||!n.location?"en":(Mt=$n({pathname:n.location.pathname||"/",stored:jn(),languages:n.navigator?.languages||[]}),Mt)}function Wn(n=Ge()){return it[n]?.dir==="rtl"?"rtl":"ltr"}function Yn(n=Ge()){return Wn(n)==="rtl"}function Oi(n=Ge()){return Yn(n)?-1:1}function Oe(n,e=Ge()){let t=Lt(e)?.[n]??Lt("en")?.[n];return Array.isArray(t)?t:[]}function Ui({pathname:n="/",active:e="en"}={}){return Ke.map(t=>({code:t,href:qn(t,n),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(n,e,t=Ge()){let r=Lt(t)?.[n]??Pi[t]?.[n]??Lt("en")?.[n]??n;return e?String(r).replace(/\{(\w+)\}/g,(i,s)=>Object.prototype.hasOwnProperty.call(e,s)?String(e[s]):i):r}var Ie=class n{static#e=null;static#s=Symbol("SecureFileTransferContext");static getInstance(){return this.#e||(this.#e=new n),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)}},X=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})}},Dt=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"})),s=await crypto.subtle.sign("RSASSA-PKCS1-v1_5",t,i);return Array.from(new Uint8Array(s))}catch(r){throw X.logSecurityEvent("signature_failed",{error:r.message}),new Error("Failed to sign file metadata")}}static async verifyFileMetadata(e,t,r){try{let s=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,s);return o||X.logSecurityEvent("invalid_signature",{fileId:e.fileId}),o}catch(i){return X.logSecurityEvent("verification_failed",{error:i.message}),!1}}},Pt=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 X.logSecurityEvent("message_too_large",{size:r,limit:this.MAX_MESSAGE_SIZE}),new Error("Message too large");return!0}},wr=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(s=>{r=s});this.locks.set(e,i);try{return await t()}finally{this.locks.delete(e),r()}}},st=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 s=this.requests.get(e).filter(a=>a>r);return this.requests.set(e,s),s.length>=this.maxRequests?(X.logSecurityEvent("rate_limit_exceeded",{identifier:e,requestCount:s.length,limit:this.maxRequests}),!1):(s.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,s,a){if(this.webrtcManager=e,this.onProgress=t,this.onComplete=r,this.onError=i,this.onFileReceived=s,this.onIncomingFileRequest=a,!e)throw new Error("webrtcManager is required for EnhancedSecureFileTransfer");Ie.getInstance().setFileTransferSystem(this),this.atomicOps=new wr,this.rateLimiter=new st(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 st(5,6e4),this.incomingChunkLimiter=new st(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):"",s=String(e?.type||"").toLowerCase();for(let[a,o]of Object.entries(this.FILE_TYPE_RESTRICTIONS)){if(!o.extensions.includes(i))continue;if(!s||this._genericMimeTypes.has(s)||this._allowedMimeTypes.has(s))return{type:a,category:o.category,description:o.description,maxSize:o.maxSize,allowed:!0,extension:i,mimeType:s}}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:s}}validateFile(e){let t=this.getFileType(e),r=[],s=String(e?.name||"").toLowerCase(),a=s.lastIndexOf("."),o=a>=0?s.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 s=0;s{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>Pt.MAX_MESSAGE_SIZE){console.warn("\u{1F512} Message too large, ignoring"),X.logSecurityEvent("oversized_message_blocked");return}if(typeof e.data=="string")try{let t=JSON.parse(e.data);if(Pt.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),s=r.encode(e),a=new Uint8Array(this.webrtcManager.sessionSalt),o=new Uint8Array(i.length+a.length+t.length+s.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(s,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),s=r.encode(e),a=new Uint8Array(t),o=new Uint8Array(this.webrtcManager.sessionSalt),c=new Uint8Array(i.length+o.length+a.length+s.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(s,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,s=r>0?Math.min(100,Math.round(i/r*100)):0;try{this.onProgress({fileId:e.fileId,uiId:e.uiId||null,direction:t,progress:s,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 X.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 s=`file_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,a=await this.calculateFileHash(e),o=await this.deriveFileSessionKey(s),c=o.key,d=o.salt,u={fileId:s,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(s,u),this.transferNonces.set(s,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),s}catch(r){let i=X.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 Dt.signFileMetadata(t,this.signingKey),console.log("\u{1F512} File metadata signed successfully")}catch(r){X.logSecurityEvent("signature_failed",{fileId:e.fileId,error:r.message})}await this.sendSecureMessage(t),e.status="metadata_sent"}catch(t){let r=X.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 s=r.slice(0,512);for(let a of s)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,X.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 s=X.sanitizeError(i);throw console.error("\u274C Failed to read file chunk:",s),new Error(s)}}async sendFileChunk(e,t,r){try{let i=e.sessionKey,s=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:s},i,r),o=this.arrayBufferToBase64(new Uint8Array(a)),c={type:"file_chunk",fileId:e.fileId,chunkIndex:t,totalChunks:e.totalChunks,nonce:Array.from(s),encryptedDataB64:o,chunkSize:r.byteLength,timestamp:Date.now()};await this.waitForBackpressure(),await this.sendSecureMessage(c)}catch(i){let s=X.sanitizeError(i);throw console.error("\u274C Failed to send file chunk:",s),new Error(s)}}async sendSecureMessage(e){let t=JSON.stringify(e),r=this.webrtcManager?.dataChannel,i=10,s=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)&&se.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(s=>s.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 Dt.verifyFileMetadata(e,e.signature,this.verificationKey))throw X.logSecurityEvent("invalid_metadata_signature",{fileId:e.fileId}),new Error("Invalid file metadata signature");console.log("\u{1F512} File metadata signature verified successfully")}catch(s){throw X.logSecurityEvent("verification_failed",{fileId:e.fileId,error:s.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=X.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 s=await crypto.subtle.decrypt({name:"AES-GCM",iv:r},t.sessionKey,i);if(s.byteLength!==e.chunkSize)throw new Error(`Chunk size mismatch: expected ${e.chunkSize}, got ${s.byteLength}`);t.receivedChunks.set(e.chunkIndex,s),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=X.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 st(this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE,6e4)),this.incomingTransferChunkLimiters.get(e).isAllowed(e)?!0:(X.logSecurityEvent("incoming_chunk_transfer_rate_limit_exceeded",{clientId:t,fileId:e}),!1)):(X.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),s=0;for(let u of t)i.set(u,s),s+=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 s=this.receivingTransfers.get(e);s&&(s._stallTimer&&clearInterval(s._stallTimer),s._lastProgressCount=s.receivedCount||0,s._lastProgressTime=Date.now(),s._stallTimer=setInterval(async()=>{let a=this.receivingTransfers.get(e);if(!a||a._stallTimer!==s._stallTimer){clearInterval(s._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 s=0;sthis.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[s,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(s){console.warn("\u26A0\uFE0F Failed to clear session key:",s)}if(t.salt)try{Array.isArray(t.salt)&&t.salt.fill(0),t.salt=null}catch(s){console.warn("\u26A0\uFE0F Failed to clear salt:",s)}for(let[s,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[s]=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[s,a]of Object.entries(r))a&&typeof a=="object"&&((a instanceof ArrayBuffer||a instanceof Uint8Array)&&qe.secureWipe(a),r[s]=null);this.receivedFileBuffers.delete(e)}catch(s){console.warn("\u26A0\uFE0F Failed to securely clear file buffer:",s),this.receivedFileBuffers.delete(e)}let i=[];for(let s of this.processedChunks)s.startsWith(e)&&i.push(s);for(let s of i)this.processedChunks.delete(s);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"),s=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:s},t.key,i),o=await crypto.subtle.decrypt({name:"AES-GCM",iv:s},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=X.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),nt={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"},zi={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}},Er={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 Xn(n){return n.indexOf(`\r `)!==-1?`\r `:` -`}function Ur(s){let e=js(s),t=s.split(/\r\n|\n/),i=[],r=[],n=null;for(let a of t)a.startsWith("m=")?(n={lines:[a]},r.push(n)):n?n.lines.push(a):i.push(a);return{eol:e,session:i,media:r}}function zr(s){let e=[...s.session];for(let t of s.media)e.push(...t.lines);return e.join(s.eol)}function Vr(s){let e=s.lines[0].match(/^m=(\w+)/);return e?e[1]:null}function Ws(s,e){let t=new RegExp("^a=rtpmap:(\\d+)\\s+"+e+"\\/","i"),i=[];for(let r of s.lines){let n=r.match(t);n&&i.push(n[1])}return i}function Ys(s){let e=new Map;for(let t of s.split(";")){let i=t.trim();if(!i)continue;let r=i.indexOf("=");r===-1?e.set(i,void 0):e.set(i.slice(0,r).trim(),i.slice(r+1).trim())}return e}function Or(s){let e=[];for(let[t,i]of s)e.push(i===void 0?t:`${t}=${i}`);return e.join(";")}function Xs(s,e,t){let i=s.lines.findIndex(o=>o.startsWith(`a=fmtp:${e} `)||o===`a=fmtp:${e}`);if(i!==-1){let o=s.lines[i].slice(`a=fmtp:${e} `.length),c=Ys(o);for(let[l,h]of Object.entries(t))c.set(l,String(h));s.lines[i]=`a=fmtp:${e} ${Or(c)}`;return}let r=new Map;for(let[o,c]of Object.entries(t))r.set(o,String(c));let n=`a=fmtp:${e} ${Or(r)}`,a=s.lines.findIndex(o=>o.startsWith(`a=rtpmap:${e} `));a!==-1?s.lines.splice(a+1,0,n):s.lines.push(n)}function bi(s,e){if(!s||typeof s!="string")return s;let t=Ur(s),i=!1;for(let r of t.media)if(Vr(r)==="audio")for(let n of Ws(r,"opus"))Xs(r,n,e),i=!0;return i?zr(t):s}var Qs=/^(rtx|red|ulpfec|flexfec-03|telephone-event|CN)$/i;function Js(s){let e=[];for(let t of s.lines){let i=t.match(/^a=rtpmap:(\d+)\s+([^/]+)\//);i&&!Qs.test(i[2])&&e.push(i[1])}return e}function Zs(s,e){for(let t of Js(s))for(let i of e){let r=`a=rtcp-fb:${t} ${i}`;if(s.lines.includes(r))continue;let n=-1;for(let a=0;ar.startsWith("a=extmap:")&&r.includes(e)))return;let t=0,i=-1;for(let r=0;rr.startsWith("a=mid:")),i===-1&&(i=s.lines.length-1)),s.lines.splice(i+1,0,`a=extmap:${t+1} ${e}`)}function Br(s,e){if(!s||typeof s!="string"||!e)return s;let t=Ur(s),i=!1;for(let r of t.media){let n=Vr(r),a=n==="video"?e.video:n==="audio"?e.audio:null;a&&(Array.isArray(a.rtcpFb)&&(Zs(r,a.rtcpFb),i=!0),a.twcc&&e.twccUri&&(ea(r,e.twccUri),i=!0))}return i?zr(t):s}function Hr(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),i=o=>/opus$/i.test(o.mimeType);if(!e.codecs.some(t))return!1;let r=e.codecs.filter(t),n=e.codecs.filter(i),a=e.codecs.filter(o=>!t(o)&&!i(o));return s.setCodecPreferences([...r,...n,...a]),!0}catch{return!1}}async function $r(s,e={}){try{if(Ue||!s||typeof s.getParameters!="function")return!1;let t={...st.sender,...e},i=s.getParameters();(!i.encodings||i.encodings.length===0)&&(i.encodings=[{}]);for(let r of i.encodings)r.maxBitrate=t.maxBitrate,r.priority=t.priority,r.networkPriority=t.networkPriority;return await s.setParameters(i),!0}catch{return!1}}var Gr={VP9:0,AV1:1,H264:2,VP8:3};function qr(s){return(String(s||"").split("/")[1]||"").toUpperCase()}function ta(s){let e=t=>{let i=qr(t.mimeType);return Object.prototype.hasOwnProperty.call(Gr,i)?Gr[i]:99};return s.map((t,i)=>({c:t,i})).sort((t,i)=>e(t.c)-e(i.c)||t.i-i.i).map(t=>t.c)}function jr(s){if(!s||!Array.isArray(s.codecs))return null;let e=new Set(s.codecs.map(t=>qr(t.mimeType)));for(let t of xe.codecPreferenceOrder)if(e.has(t))return t;return null}function Wr(){return typeof RTCRtpSender<"u"&&RTCRtpSender.getCapabilities?RTCRtpSender.getCapabilities("video"):null}function Yr(s){try{if(Ue||!s||typeof s.setCodecPreferences!="function")return!1;let e=Wr();return!e||!Array.isArray(e.codecs)?!1:(s.setCodecPreferences(ta(e.codecs)),jr(e))}catch{return!1}}function ia(s){return s==="VP9"?{scalabilityMode:xe.vp9.preferredScalabilityMode,maxBitrate:15e5,degradationPreference:xe.vp9.degradationPreference}:s==="AV1"?{scalabilityMode:xe.av1.scalabilityMode,maxBitrate:xe.av1.maxBitrate,degradationPreference:xe.av1.degradationPreference}:{scalabilityMode:void 0,maxBitrate:15e5,degradationPreference:"balanced"}}async function Xr(s,e={}){try{if(Ue||!s||typeof s.getParameters!="function")return!1;let t=jr(Wr())||"VP8",i={...ia(t),...e},r=s.getParameters();(!r.encodings||r.encodings.length===0)&&(r.encodings=[{}]);let n=r.encodings.length>1;if(n)for(let a of r.encodings)a.networkPriority=xe.networkPriority;else{let a=r.encodings[0];a.maxBitrate=i.maxBitrate,a.networkPriority=xe.networkPriority,i.scalabilityMode&&(a.scalabilityMode=i.scalabilityMode)}i.degradationPreference&&(r.degradationPreference=i.degradationPreference);try{return await s.setParameters(r),!0}catch{if(!n&&i.scalabilityMode){delete r.encodings[0].scalabilityMode;try{return await s.setParameters(r),!0}catch{return!1}}return!1}}catch{return!1}}function Qr(s,e={}){let t=null,i=null,r=null;for(let m of s)!m||typeof m.type!="string"||(m.type==="outbound-rtp"&&!m.isRemote?(!t||m.kind==="video")&&(t=m):m.type==="remote-inbound-rtp"?(!i||m.kind==="video")&&(i=m):m.type==="candidate-pair"&&(m.nominated||m.selected||m.state==="succeeded")&&(!r||m.nominated)&&(r=m));let n=Number(t?.packetsSent??0),a=Number(i?.packetsLost??0),o=n-(e.packetsSent??n),c=a-(e.packetsLost??a),l=o+c,h=l>0?Math.min(1,Math.max(0,c/l)):0,u=r?.currentRoundTripTime??i?.roundTripTime??0,p=Number(u)*1e3,S=Number(i?.jitter??0)*1e3,w=r?.availableOutgoingBitrate!=null?Number(r.availableOutgoingBitrate):null,g=t?.qualityLimitationReason??"none";return{lossPct:h,rttMs:p,jitterMs:S,availableOutgoingBitrate:w,qualityLimitationReason:g,counters:{packetsSent:n,packetsLost:a},hasData:!!(t&&(i||r))}}function Jr(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 ra(s,e,t=Ei){let{targetBitrate:i,ceilingBitrate:r,scaleResolutionDownBy:n,goodTicks:a}=e,o=!1,c="steady";if(s.qualityLimitationReason==="cpu"){let l=Math.min(4,+(n*t.cpuScaleStep).toFixed(3));l!==n&&(n=l,o=!0),a=0,c="cpu"}else if(s.lossPct>t.loss.highPct||s.rttMs>t.rtt.highMs){let l=Math.max(t.minVideoBitrate,Math.round(i*(1-t.stepDownPct)));l!==i&&(i=l,o=!0),a=0,c="backoff"}else if(s.lossPct=t.recoverStableTicks){let l=Math.min(r,Math.round(i*(1+t.stepUpPct)));l!==i&&(i=l,o=!0,c="rampup"),a=0}}else a=0;return{targetBitrate:i,scaleResolutionDownBy:n,goodTicks:a,changed:o,reason:c}}var Pt=class{constructor(e,t={}){this.pc=e,this.getVideoSender=t.getVideoSender||(()=>null),this.onQuality=t.onQuality||(()=>{}),this.cfg=t.cfg||Ei,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,i=Qr(t,this._prevCounters);this._prevCounters=i.counters;let r=Jr(i);if(r&&r!==this._lastQuality){this._lastQuality=r;try{this.onQuality(r,i)}catch{}}if(!i.hasData)return;let n=ra(i,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 i=t.encodings[t.encodings.length-1];i.maxBitrate=this.state.targetBitrate}await e.setParameters(t)}catch{}}};var na="SecureBit-DR-Root-v1",sa="SecureBit-DR-Message-v1",aa="SecureBit-DR-Init-v1",oa=Uint8Array.of(1),ca=Uint8Array.of(2),Kt=new TextEncoder,la=new TextDecoder,Ft=Object.freeze({MAX_SKIP_PER_CHAIN:512,MAX_SKIPPED_KEYS:1024,SKIPPED_KEY_TTL_MS:300*1e3});function Zr(s){let e="",t=new Uint8Array(s);for(let i=0;i{o&&o.apply(),this._receivingChainKey&&this._receivingChainKey!==S&&$(this._receivingChainKey);for(let w of a)$(w);this._receivingChainKey=S,this._receiveCount=i+1,this._remotePublicKeyB64=h;for(let{id:w,key:g}of n)this._rememberSkipped(w,g);$(p)},discard:()=>{o&&o.discard();for(let{key:w}of n)$(w);for(let w of a)$(w);$(S),$(p)}}}async _collectSkipped(e,t,i,r){if(iFt.MAX_SKIP_PER_CHAIN)throw new Error(`DoubleRatchet: refusing to skip ${i-t} messages (limit ${Ft.MAX_SKIP_PER_CHAIN})`);let n=[],a=e;for(let o=t;o=Ft.MAX_SKIPPED_KEYS;){let i=this._skipped.keys().next().value,r=this._skipped.get(i);this._skipped.delete(i),r&&$(r.key)}this._skipped.set(e,{key:t,storedAt:Date.now()})}_pruneSkipped(){let e=Date.now()-Ft.SKIPPED_KEY_TTL_MS;for(let[t,i]of this._skipped)i.storedAt{$(this._rootKey),$(r.nextRoot),this._sendingChainKey&&$(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:()=>{$(r.nextRoot),$(r.chainKey),$(o.nextRoot),$(o.chainKey)}}}destroy(){$(this._rootKey),$(this._sendingChainKey),$(this._receivingChainKey);for(let e of this._skipped.values())$(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 G=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}),sn=Date.UTC(2024,0,1),da=16777215,le=Object.freeze({OFFER:0,ANSWER:1}),an=Object.freeze(["actpass","active","passive"]),xi=Object.freeze([262144,1073741823,65536,null]),on=3,mt=Object.freeze({MAX_MESSAGE_SIZE:1}),me=Object.freeze({HOST_V4:0,HOST_MDNS:1,SRFLX_V4:2,RELAY_V4:3,HOST_V6:4,SRFLX_V6:5,RELAY_V6:6}),cn=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"}),ki=Object.freeze({0:"v4",1:"mdns",2:"v4",3:"v4",4:"v6",5:"v6",6:"v6"}),Ri=Object.freeze([null,"passive","active","so"]),ua=Object.freeze({host:126,srflx:100,relay:0}),Ot=/^[A-Za-z0-9+/]+$/,Ai=class extends Error{constructor(e,t="malformed"){super(e),this.name="DescriptorError",this.code=t}},P=(s,e)=>{throw new Ai(s,e)},ha=/^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\.local$/i,fa=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;function ln(s){let e=fa.exec(s);if(!e)return null;let t=new Uint8Array(4);for(let i=0;i<4;i++){let r=Number(e[i+1]);if(!Number.isInteger(r)||r<0||r>255)return null;t[i]=r}return t}function pa(s){if(!/^[0-9a-fA-F:.]+$/.test(s)||s.length>45)return null;let e=s,t=null,i=e.lastIndexOf(":");if(e.includes(".")){if(t=ln(e.slice(i+1)),!t)return null;e=e.slice(0,i+1)+"0:0"}let r=e.split("::");if(r.length>2)return null;let n=h=>h===""?[]:h.split(":").map(u=>u.length===0||u.length>4?NaN:parseInt(u,16)),a=n(r[0]),o=r.length===2?n(r[1]):[];if([...a,...o].some(h=>!Number.isInteger(h)||h<0||h>65535))return null;let c;if(r.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 l=new Uint8Array(16);return c.forEach((h,u)=>{l[u*2]=h>>8,l[u*2+1]=h&255}),t&&l.set(t,12),l}function ya(s){let e=ha.exec(s);if(!e)return null;let t=(e[1]+e[2]+e[3]+e[4]+e[5]).toLowerCase(),i=new Uint8Array(16);for(let r=0;r<16;r++)i[r]=parseInt(t.substr(r*2,2),16);return i}function ga(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 yt(s,e){let t=`a=${e}:`;for(let i of s)if(i.startsWith(t))return i.slice(t.length).trim();return null}function dn(s){let e=ga(s),t=yt(e,"ice-ufrag"),i=yt(e,"ice-pwd");(!t||!i)&&P("SDP is missing ICE credentials");let r=yt(e,"fingerprint");r||P("SDP is missing a DTLS fingerprint");let[n,a]=r.split(/\s+/);(!n||n.toLowerCase()!=="sha-256")&&P(`unsupported DTLS fingerprint algorithm: ${String(n).slice(0,16)}`);let o=String(a).split(":");o.length!==G.FINGERPRINT_BYTES&&P("DTLS fingerprint has the wrong length");let c=new Uint8Array(G.FINGERPRINT_BYTES);o.forEach((w,g)=>{/^[0-9a-fA-F]{2}$/.test(w)||P("DTLS fingerprint is not hex"),c[g]=parseInt(w,16)});let l=yt(e,"setup")||"actpass",h=an.indexOf(l);h<0&&P(`unsupported DTLS setup role: ${l.slice(0,16)}`);let u=yt(e,"max-message-size"),p=u===null?65536:Number(u);(!Number.isInteger(p)||p<0)&&P("invalid a=max-message-size");let S=[];for(let w of e){if(!w.startsWith("a=candidate:"))continue;let g=w.slice(12).split(/\s+/);if(g.length<8||g[6]!=="typ"||g[1]!=="1")continue;let m=g[2].toLowerCase(),I=Number(g[3]),b=g[4],D=Number(g[5]),_=g[7];if(!Number.isInteger(D)||D<1||D>65535)continue;let R=0;if(m==="tcp"){let v=g.indexOf("tcptype"),q=v>=0?Ri.indexOf(g[v+1]):-1;if(q<=0)continue;R=q}else if(m!=="udp")continue;let E=null,C=null,M=ya(b);if(M&&_==="host")E=me.HOST_MDNS,C=M;else{let v=ln(b),q=v?null:pa(b),O=v||q;if(!O)continue;if(_==="host")E=v?me.HOST_V4:me.HOST_V6;else if(_==="srflx"||_==="prflx")E=v?me.SRFLX_V4:me.SRFLX_V6;else if(_==="relay")E=v?me.RELAY_V4:me.RELAY_V6;else continue;C=O}S.push({kind:E,tcptype:R,addr:C,port:D,priority:Number.isFinite(I)?I:0})}return{ufrag:t,pwd:i,fingerprint:c,setup:h,maxMessageSize:p,candidates:S}}function rn(s){return 1+cn[s.kind]+2}var ma=s=>s.tcptype!==2&&s.tcptype!==3;function Mi(s,{maxCandidates:e=G.MAX_CANDIDATES,maxBytes:t=G.SURPLUS_CANDIDATE_BYTES,keepMdns:i=!0,maxRelays:r=2}={}){let n=s.filter(m=>i||m.kind!==me.HOST_MDNS),a=[],o=new Set;for(let m of n){let I=`${m.kind}:${m.tcptype}:${Array.from(m.addr).join(".")}:${m.port}`;o.has(I)||(o.add(I),a.push(m))}let c=(m,I)=>(I.priority||0)-(m.priority||0),l=m=>`${ki[m.kind]}/${at[m.kind]}/${m.tcptype===0?"udp":"tcp"}`,h=new Map;for(let m of[...a].sort(c)){if(!ma(m))continue;let I=l(m);h.has(I)||h.set(I,[]),h.get(I).push(m)}let u=[],p=new Set,S=0,w=0,g=m=>{u.push(m),p.add(m),S+=rn(m),at[m.kind]==="relay"&&w++};for(let m of h.values())g(m[0]);for(let m of[...a].sort(c))if(!p.has(m)){if(u.length>=e)break;S+rn(m)>t||at[m.kind]==="relay"&&w>=r||g(m)}return u.sort(c)}var St=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=xi.indexOf(s);if(t<0){t=on;let i=new St;i.u32(s),e.push({type:mt.MAX_MESSAGE_SIZE,value:i.done()})}return{mmsIndex:t,records:e}}function un(s){let{type:e,bindingTag:t=null,expiresAtMs:i,sdpFields:r,commitment:n=null}=s;e!==le.OFFER&&e!==le.ANSWER&&P("invalid descriptor type"),e===le.ANSWER?(!(t instanceof Uint8Array)||t.length!==G.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!==G.COMMITMENT_BYTES)&&P("commitment must be 16 bytes");let{ufrag:a,pwd:o,fingerprint:c,setup:l,maxMessageSize:h,candidates:u}=r;(a.lengthG.MAX_UFRAG||!Ot.test(a))&&P("invalid ice-ufrag"),(o.lengthG.MAX_PWD||!Ot.test(o))&&P("invalid ice-pwd"),u.length>G.MAX_CANDIDATES&&P("too many candidates");let p=Math.ceil((i-sn)/6e4);(!Number.isInteger(p)||p<0||p>da)&&P("expiry out of range");let{mmsIndex:S,records:w}=Sa(h),g=new St;for(let _ of w)_.value.length>255&&P("extension value is too long"),g.u8(_.type),g.u8(_.value.length),g.bytes(_.value);let m=g.done();m.length>G.MAX_EXT_BYTES&&P("extension area is too long");let I=e&3|(l&3)<<2|(S&3)<<4|(n?64:0)|(m.length?128:0),b=new St;b.u8(2),b.u8(I),b.u24(p),e===le.ANSWER&&b.bytes(t),b.bytes(c),b.u8(a.length),b.ascii(a),b.u8(o.length),b.ascii(o),b.u8(u.length);for(let _ of u)b.u8((_.kind&15)<<4|_.tcptype&15),b.bytes(_.addr),b.u16(_.port);n&&b.bytes(n),m.length&&(b.u8(m.length),b.bytes(m));let D=b.done();return D.length>G.MAX_PAYLOAD_BYTES&&P("descriptor exceeds the payload limit"),D}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 i=0;i126)&&P("non-printable byte in a text field"),t+=String.fromCharCode(r)}return this.i+=e,t}get rest(){return this.buf.length-this.i}};function _a(s){let e=new _t(s),t=new Map,i=-1;for(;e.rest>0;){let r=e.u8(),n=e.u8(),a=e.bytes(n);if(r<=i&&P("extension records must be in ascending type order without duplicates"),i=r,r===mt.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"),xi.includes(o)&&P("extension 0x01 duplicates a value the flags already encode"),t.set(r,o)}else P(`unknown extension type 0x${r.toString(16).padStart(2,"0")}`,"unknown_extension")}return t}function Li(s,{nowMs:e=Date.now()}={}){s instanceof Uint8Array||P("descriptor must be a Uint8Array"),s.length===0&&P("descriptor is empty"),s.length>G.MAX_PAYLOAD_BYTES&&P("descriptor exceeds the payload limit");let t=new _t(s),i=t.u8();i!==2&&P(`unsupported descriptor version 0x${i.toString(16)}`,"version");let r=t.u8(),n=r&3;n!==le.OFFER&&n!==le.ANSWER&&P("reserved descriptor type");let a=r>>2&3;a>2&&P("reserved DTLS setup role");let o=r>>4&3,c=(r&64)!==0,l=(r&128)!==0,h=t.u24(),u=sn+h*6e4;if(e-G.CLOCK_SKEW_MS>u){let C=Math.round((e-u)/6e4);P(`this code expired ${C} 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>G.MAX_LIFETIME_MINUTES*6e4+G.CLOCK_SKEW_MS&&P("descriptor lifetime is implausibly long","lifetime");let p=n===le.ANSWER?t.bytes(G.BINDING_BYTES):null,S=t.bytes(G.FINGERPRINT_BYTES),w=t.u8();(wG.MAX_UFRAG)&&P("ice-ufrag length out of range");let g=t.ascii(w);Ot.test(g)||P("ice-ufrag contains characters outside the ICE alphabet");let m=t.u8();(mG.MAX_PWD)&&P("ice-pwd length out of range");let I=t.ascii(m);Ot.test(I)||P("ice-pwd contains characters outside the ICE alphabet");let b=t.u8();b>G.MAX_CANDIDATES&&P("too many candidates");let D=[];for(let C=0;C>4&15,q=M&15,O=cn[v];O===void 0&&P(`reserved candidate kind ${v}`),q>=Ri.length&&P("reserved TCP candidate type");let x=t.bytes(O),ue=t.u16();ue<1&&P("candidate port must be non-zero"),D.push({kind:v,tcptype:q,addr:x,port:ue})}let _=null;c&&(_=t.bytes(G.COMMITMENT_BYTES));let R=new Map;if(l){let C=t.u8();C===0&&P("extension area is flagged but empty"),R=_a(t.bytes(C))}t.rest!==0&&P(`${t.rest} trailing byte(s) after the descriptor`);let E;return o===on?(R.has(mt.MAX_MESSAGE_SIZE)||P("flags promise an explicit max-message-size but no extension carries it"),E=R.get(mt.MAX_MESSAGE_SIZE)):(R.has(mt.MAX_MESSAGE_SIZE)&&P("extension 0x01 present but the flags do not select it"),E=xi[o]),{version:i,type:n,setup:a,maxMessageSize:E,expiresAtMs:u,bindingTag:p,fingerprint:S,ufrag:g,pwd:I,candidates:D,commitment:_,extensions:R}}var hn=s=>s.toString(16).padStart(2,"0");function nn(s,e){switch(s){case me.HOST_MDNS:{let t=Array.from(e,hn).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}.local`}case me.HOST_V4:case me.SRFLX_V4:case me.RELAY_V4:return`${e[0]}.${e[1]}.${e[2]}.${e[3]}`;default:{let t=[];for(let i=0;i<16;i+=2)t.push((e[i]<<8|e[i+1]).toString(16));return t.join(":")}}}function Di(s,{sessionId:e="1"}={}){let t=s.type===le.OFFER,i={relay:0,srflx:1,host:2},r=s.candidates.filter(u=>u.kind!==me.HOST_MDNS&&u.tcptype===0).sort((u,p)=>i[at[u.kind]]-i[at[p.kind]])[0],n=r&&ki[r.kind]==="v6",a=r?r.port:9,o=r?`c=IN IP${n?"6":"4"} ${nn(r.kind,r.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=>hn(u).toUpperCase()).join(":"),"a=setup:"+an[s.setup],"a=mid:0","a=sctp-port:5000","a=max-message-size:"+s.maxMessageSize],l=s.candidates.map((u,p)=>{let S=at[u.kind],w=u.tcptype===0?"udp":"tcp",g=Math.max(0,65535-p),m=ua[S]*16777216+g*256+255,b=`a=candidate:${String(u.kind*4+u.tcptype+1)} 1 ${w} ${m} ${nn(u.kind,u.addr)} ${u.port} typ ${S}`;return S!=="host"&&(b+=ki[u.kind]==="v6"?" raddr :: rport 0":" raddr 0.0.0.0 rport 0"),w==="tcp"&&(b+=` tcptype ${Ri[u.tcptype]}`),b});l.push("a=end-of-candidates");let h=c.indexOf(o)+1;return c.splice(h,0,...l),{type:t?"offer":"answer",sdp:c.join(`\r +`}function Bi(n){let e=Xn(n),t=n.split(/\r\n|\n/),r=[],i=[],s=null;for(let a of t)a.startsWith("m=")?(s={lines:[a]},i.push(s)):s?s.lines.push(a):r.push(a);return{eol:e,session:r,media:i}}function Hi(n){let e=[...n.session];for(let t of n.media)e.push(...t.lines);return e.join(n.eol)}function $i(n){let e=n.lines[0].match(/^m=(\w+)/);return e?e[1]:null}function Qn(n,e){let t=new RegExp("^a=rtpmap:(\\d+)\\s+"+e+"\\/","i"),r=[];for(let i of n.lines){let s=i.match(t);s&&r.push(s[1])}return r}function Jn(n){let e=new Map;for(let t of n.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 Vi(n){let e=[];for(let[t,r]of n)e.push(r===void 0?t:`${t}=${r}`);return e.join(";")}function Zn(n,e,t){let r=n.lines.findIndex(o=>o.startsWith(`a=fmtp:${e} `)||o===`a=fmtp:${e}`);if(r!==-1){let o=n.lines[r].slice(`a=fmtp:${e} `.length),c=Jn(o);for(let[d,u]of Object.entries(t))c.set(d,String(u));n.lines[r]=`a=fmtp:${e} ${Vi(c)}`;return}let i=new Map;for(let[o,c]of Object.entries(t))i.set(o,String(c));let s=`a=fmtp:${e} ${Vi(i)}`,a=n.lines.findIndex(o=>o.startsWith(`a=rtpmap:${e} `));a!==-1?n.lines.splice(a+1,0,s):n.lines.push(s)}function vr(n,e){if(!n||typeof n!="string")return n;let t=Bi(n),r=!1;for(let i of t.media)if($i(i)==="audio")for(let s of Qn(i,"opus"))Zn(i,s,e),r=!0;return r?Hi(t):n}var ea=/^(rtx|red|ulpfec|flexfec-03|telephone-event|CN)$/i;function ta(n){let e=[];for(let t of n.lines){let r=t.match(/^a=rtpmap:(\d+)\s+([^/]+)\//);r&&!ea.test(r[2])&&e.push(r[1])}return e}function ra(n,e){for(let t of ta(n))for(let r of e){let i=`a=rtcp-fb:${t} ${r}`;if(n.lines.includes(i))continue;let s=-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=n.lines.length-1)),n.lines.splice(r+1,0,`a=extmap:${t+1} ${e}`)}function Gi(n,e){if(!n||typeof n!="string"||!e)return n;let t=Bi(n),r=!1;for(let i of t.media){let s=$i(i),a=s==="video"?e.video:s==="audio"?e.audio:null;a&&(Array.isArray(a.rtcpFb)&&(ra(i,a.rtcpFb),r=!0),a.twcc&&e.twccUri&&(ia(i,e.twccUri),r=!0))}return r?Hi(t):n}function qi(n){try{if(Ue||!n||typeof n.setCodecPreferences!="function"||!nt.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),s=e.codecs.filter(r),a=e.codecs.filter(o=>!t(o)&&!r(o));return n.setCodecPreferences([...i,...s,...a]),!0}catch{return!1}}async function ji(n,e={}){try{if(Ue||!n||typeof n.getParameters!="function")return!1;let t={...nt.sender,...e},r=n.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 n.setParameters(r),!0}catch{return!1}}var Wi={VP9:0,AV1:1,H264:2,VP8:3};function Yi(n){return(String(n||"").split("/")[1]||"").toUpperCase()}function sa(n){let e=t=>{let r=Yi(t.mimeType);return Object.prototype.hasOwnProperty.call(Wi,r)?Wi[r]:99};return n.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 Xi(n){if(!n||!Array.isArray(n.codecs))return null;let e=new Set(n.codecs.map(t=>Yi(t.mimeType)));for(let t of Re.codecPreferenceOrder)if(e.has(t))return t;return null}function Qi(){return typeof RTCRtpSender<"u"&&RTCRtpSender.getCapabilities?RTCRtpSender.getCapabilities("video"):null}function Ji(n){try{if(Ue||!n||typeof n.setCodecPreferences!="function")return!1;let e=Qi();return!e||!Array.isArray(e.codecs)?!1:(n.setCodecPreferences(sa(e.codecs)),Xi(e))}catch{return!1}}function na(n){return n==="VP9"?{scalabilityMode:Re.vp9.preferredScalabilityMode,maxBitrate:15e5,degradationPreference:Re.vp9.degradationPreference}:n==="AV1"?{scalabilityMode:Re.av1.scalabilityMode,maxBitrate:Re.av1.maxBitrate,degradationPreference:Re.av1.degradationPreference}:{scalabilityMode:void 0,maxBitrate:15e5,degradationPreference:"balanced"}}async function Zi(n,e={}){try{if(Ue||!n||typeof n.getParameters!="function")return!1;let t=Xi(Qi())||"VP8",r={...na(t),...e},i=n.getParameters();(!i.encodings||i.encodings.length===0)&&(i.encodings=[{}]);let s=i.encodings.length>1;if(s)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 n.setParameters(i),!0}catch{if(!s&&r.scalabilityMode){delete i.encodings[0].scalabilityMode;try{return await n.setParameters(i),!0}catch{return!1}}return!1}}catch{return!1}}function es(n,e={}){let t=null,r=null,i=null;for(let _ of n)!_||typeof _.type!="string"||(_.type==="outbound-rtp"&&!_.isRemote?(!t||_.kind==="video")&&(t=_):_.type==="remote-inbound-rtp"?(!r||_.kind==="video")&&(r=_):_.type==="candidate-pair"&&(_.nominated||_.selected||_.state==="succeeded")&&(!i||_.nominated)&&(i=_));let s=Number(t?.packetsSent??0),a=Number(r?.packetsLost??0),o=s-(e.packetsSent??s),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:s,packetsLost:a},hasData:!!(t&&(r||i))}}function ts(n){if(!n||!n.hasData)return null;let e=n.lossPct,t=n.rttMs;return e<.03&&t<150?"excellent":e<.07&&t<250?"good":e<.15&&t<400?"fair":"poor"}function aa(n,e,t=Er){let{targetBitrate:r,ceilingBitrate:i,scaleResolutionDownBy:s,goodTicks:a}=e,o=!1,c="steady";if(n.qualityLimitationReason==="cpu"){let d=Math.min(4,+(s*t.cpuScaleStep).toFixed(3));d!==s&&(s=d,o=!0),a=0,c="cpu"}else if(n.lossPct>t.loss.highPct||n.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(n.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:s,goodTicks:a,changed:o,reason:c}}var Ft=class{constructor(e,t={}){this.pc=e,this.getVideoSender=t.getVideoSender||(()=>null),this.onQuality=t.onQuality||(()=>{}),this.cfg=t.cfg||Er,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=es(t,this._prevCounters);this._prevCounters=r.counters;let i=ts(r);if(i&&i!==this._lastQuality){this._lastQuality=i;try{this.onQuality(i,r)}catch{}}if(!r.hasData)return;let s=aa(r,this.state,this.cfg);this.state={targetBitrate:s.targetBitrate,ceilingBitrate:this.state.ceilingBitrate,scaleResolutionDownBy:s.scaleResolutionDownBy,goodTicks:s.goodTicks},s.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 oa="SecureBit-DR-Root-v1",ca="SecureBit-DR-Message-v1",la="SecureBit-DR-Init-v1",da=Uint8Array.of(1),ua=Uint8Array.of(2),Nt=new TextEncoder,ha=new TextDecoder,Kt=Object.freeze({MAX_SKIP_PER_CHAIN:512,MAX_SKIPPED_KEYS:1024,SKIPPED_KEY_TTL_MS:300*1e3});function rs(n){let e="",t=new Uint8Array(n);for(let r=0;r{o&&o.apply(),this._receivingChainKey&&this._receivingChainKey!==p&&H(this._receivingChainKey);for(let S of a)H(S);this._receivingChainKey=p,this._receiveCount=r+1,this._remotePublicKeyB64=u;for(let{id:S,key:g}of s)this._rememberSkipped(S,g);H(m)},discard:()=>{o&&o.discard();for(let{key:S}of s)H(S);for(let S of a)H(S);H(p),H(m)}}}async _collectSkipped(e,t,r,i){if(rKt.MAX_SKIP_PER_CHAIN)throw new Error(`DoubleRatchet: refusing to skip ${r-t} messages (limit ${Kt.MAX_SKIP_PER_CHAIN})`);let s=[],a=e;for(let o=t;o=Kt.MAX_SKIPPED_KEYS;){let r=this._skipped.keys().next().value,i=this._skipped.get(r);this._skipped.delete(r),i&&H(i.key)}this._skipped.set(e,{key:t,storedAt:Date.now()})}_pruneSkipped(){let e=Date.now()-Kt.SKIPPED_KEY_TTL_MS;for(let[t,r]of this._skipped)r.storedAt{H(this._rootKey),H(i.nextRoot),this._sendingChainKey&&H(this._sendingChainKey),this._rootKey=o.nextRoot,this._sendingChainKey=o.chainKey,this._selfKeyPair=s,this._remotePublicKey=t,this._remotePublicKeyB64=e,this._previousSendCount=this._sendCount,this._sendCount=0},discard:()=>{H(i.nextRoot),H(i.chainKey),H(o.nextRoot),H(o.chainKey)}}}destroy(){H(this._rootKey),H(this._sendingChainKey),H(this._receivingChainKey);for(let e of this._skipped.values())H(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 $=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}),os=Date.UTC(2024,0,1),fa=16777215,oe=Object.freeze({OFFER:0,ANSWER:1}),cs=Object.freeze(["actpass","active","passive"]),Rr=Object.freeze([262144,1073741823,65536,null]),ls=3,St=Object.freeze({MAX_MESSAGE_SIZE:1}),ge=Object.freeze({HOST_V4:0,HOST_MDNS:1,SRFLX_V4:2,RELAY_V4:3,HOST_V6:4,SRFLX_V6:5,RELAY_V6:6}),ds=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"}),Ar=Object.freeze({0:"v4",1:"mdns",2:"v4",3:"v4",4:"v6",5:"v6",6:"v6"}),Mr=Object.freeze([null,"passive","active","so"]),pa=Object.freeze({host:126,srflx:100,relay:0}),Ut=/^[A-Za-z0-9+/]+$/,xr=class extends Error{constructor(e,t="malformed"){super(e),this.name="DescriptorError",this.code=t}},F=(n,e)=>{throw new xr(n,e)},ya=/^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\.local$/i,ga=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;function us(n){let e=ga.exec(n);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 ma(n){if(!/^[0-9a-fA-F:.]+$/.test(n)||n.length>45)return null;let e=n,t=null,r=e.lastIndexOf(":");if(e.includes(".")){if(t=us(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 s=u=>u===""?[]:u.split(":").map(h=>h.length===0||h.length>4?NaN:parseInt(h,16)),a=s(i[0]),o=i.length===2?s(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 Sa(n){let e=ya.exec(n);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 _a(n){return typeof n!="string"&&F("SDP must be a string"),n.length>64*1024&&F("SDP is too large"),n.split(/\r\n|\n/).filter(e=>e.length>0)}function gt(n,e){let t=`a=${e}:`;for(let r of n)if(r.startsWith(t))return r.slice(t.length).trim();return null}function hs(n){let e=_a(n),t=gt(e,"ice-ufrag"),r=gt(e,"ice-pwd");(!t||!r)&&F("SDP is missing ICE credentials");let i=gt(e,"fingerprint");i||F("SDP is missing a DTLS fingerprint");let[s,a]=i.split(/\s+/);(!s||s.toLowerCase()!=="sha-256")&&F(`unsupported DTLS fingerprint algorithm: ${String(s).slice(0,16)}`);let o=String(a).split(":");o.length!==$.FINGERPRINT_BYTES&&F("DTLS fingerprint has the wrong length");let c=new Uint8Array($.FINGERPRINT_BYTES);o.forEach((S,g)=>{/^[0-9a-fA-F]{2}$/.test(S)||F("DTLS fingerprint is not hex"),c[g]=parseInt(S,16)});let d=gt(e,"setup")||"actpass",u=cs.indexOf(d);u<0&&F(`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)&&F("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 _=g[2].toLowerCase(),I=Number(g[3]),w=g[4],D=Number(g[5]),T=g[7];if(!Number.isInteger(D)||D<1||D>65535)continue;let v=0;if(_==="tcp"){let k=g.indexOf("tcptype"),j=k>=0?Mr.indexOf(g[k+1]):-1;if(j<=0)continue;v=j}else if(_!=="udp")continue;let b=null,C=null,x=Sa(w);if(x&&T==="host")b=ge.HOST_MDNS,C=x;else{let k=us(w),j=k?null:ma(w),z=k||j;if(!z)continue;if(T==="host")b=k?ge.HOST_V4:ge.HOST_V6;else if(T==="srflx"||T==="prflx")b=k?ge.SRFLX_V4:ge.SRFLX_V6;else if(T==="relay")b=k?ge.RELAY_V4:ge.RELAY_V6;else continue;C=z}p.push({kind:b,tcptype:v,addr:C,port:D,priority:Number.isFinite(I)?I:0})}return{ufrag:t,pwd:r,fingerprint:c,setup:u,maxMessageSize:m,candidates:p}}function ns(n){return 1+ds[n.kind]+2}var ba=n=>n.tcptype!==2&&n.tcptype!==3;function Lr(n,{maxCandidates:e=$.MAX_CANDIDATES,maxBytes:t=$.SURPLUS_CANDIDATE_BYTES,keepMdns:r=!0,maxRelays:i=2}={}){let s=n.filter(_=>r||_.kind!==ge.HOST_MDNS),a=[],o=new Set;for(let _ of s){let I=`${_.kind}:${_.tcptype}:${Array.from(_.addr).join(".")}:${_.port}`;o.has(I)||(o.add(I),a.push(_))}let c=(_,I)=>(I.priority||0)-(_.priority||0),d=_=>`${Ar[_.kind]}/${at[_.kind]}/${_.tcptype===0?"udp":"tcp"}`,u=new Map;for(let _ of[...a].sort(c)){if(!ba(_))continue;let I=d(_);u.has(I)||u.set(I,[]),u.get(I).push(_)}let h=[],m=new Set,p=0,S=0,g=_=>{h.push(_),m.add(_),p+=ns(_),at[_.kind]==="relay"&&S++};for(let _ of u.values())g(_[0]);for(let _ of[...a].sort(c))if(!m.has(_)){if(h.length>=e)break;p+ns(_)>t||at[_.kind]==="relay"&&S>=i||g(_)}return h.sort(c)}var _t=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)&&F("max-message-size must be an integer between 1024 and 2^31-1");let e=[],t=Rr.indexOf(n);if(t<0){t=ls;let r=new _t;r.u32(n),e.push({type:St.MAX_MESSAGE_SIZE,value:r.done()})}return{mmsIndex:t,records:e}}function fs(n){let{type:e,bindingTag:t=null,expiresAtMs:r,sdpFields:i,commitment:s=null}=n;e!==oe.OFFER&&e!==oe.ANSWER&&F("invalid descriptor type"),e===oe.ANSWER?(!(t instanceof Uint8Array)||t.length!==$.BINDING_BYTES)&&F("answer needs an 8-byte binding tag"):t!==null&&F("offers do not carry a binding tag"),s!==null&&(!(s instanceof Uint8Array)||s.length!==$.COMMITMENT_BYTES)&&F("commitment must be 16 bytes");let{ufrag:a,pwd:o,fingerprint:c,setup:d,maxMessageSize:u,candidates:h}=i;(a.length<$.MIN_UFRAG||a.length>$.MAX_UFRAG||!Ut.test(a))&&F("invalid ice-ufrag"),(o.length<$.MIN_PWD||o.length>$.MAX_PWD||!Ut.test(o))&&F("invalid ice-pwd"),h.length>$.MAX_CANDIDATES&&F("too many candidates");let m=Math.ceil((r-os)/6e4);(!Number.isInteger(m)||m<0||m>fa)&&F("expiry out of range");let{mmsIndex:p,records:S}=wa(u),g=new _t;for(let T of S)T.value.length>255&&F("extension value is too long"),g.u8(T.type),g.u8(T.value.length),g.bytes(T.value);let _=g.done();_.length>$.MAX_EXT_BYTES&&F("extension area is too long");let I=e&3|(d&3)<<2|(p&3)<<4|(s?64:0)|(_.length?128:0),w=new _t;w.u8(2),w.u8(I),w.u24(m),e===oe.ANSWER&&w.bytes(t),w.bytes(c),w.u8(a.length),w.ascii(a),w.u8(o.length),w.ascii(o),w.u8(h.length);for(let T of h)w.u8((T.kind&15)<<4|T.tcptype&15),w.bytes(T.addr),w.u16(T.port);s&&w.bytes(s),_.length&&(w.u8(_.length),w.bytes(_));let D=w.done();return D.length>$.MAX_PAYLOAD_BYTES&&F("descriptor exceeds the payload limit"),D}var bt=class{constructor(e){this.buf=e,this.i=0}need(e){this.i+e>this.buf.length&&F("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)&&F("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 Ea(n){let e=new bt(n),t=new Map,r=-1;for(;e.rest>0;){let i=e.u8(),s=e.u8(),a=e.bytes(s);if(i<=r&&F("extension records must be in ascending type order without duplicates"),r=i,i===St.MAX_MESSAGE_SIZE){s!==4&&F("extension 0x01 must be 4 bytes");let o=new bt(a).u32();(o<1024||o>2147483647)&&F("extension 0x01 value is out of range"),Rr.includes(o)&&F("extension 0x01 duplicates a value the flags already encode"),t.set(i,o)}else F(`unknown extension type 0x${i.toString(16).padStart(2,"0")}`,"unknown_extension")}return t}function Dr(n,{nowMs:e=Date.now()}={}){n instanceof Uint8Array||F("descriptor must be a Uint8Array"),n.length===0&&F("descriptor is empty"),n.length>$.MAX_PAYLOAD_BYTES&&F("descriptor exceeds the payload limit");let t=new bt(n),r=t.u8();r!==2&&F(`unsupported descriptor version 0x${r.toString(16)}`,"version");let i=t.u8(),s=i&3;s!==oe.OFFER&&s!==oe.ANSWER&&F("reserved descriptor type");let a=i>>2&3;a>2&&F("reserved DTLS setup role");let o=i>>4&3,c=(i&64)!==0,d=(i&128)!==0,u=t.u24(),h=os+u*6e4;if(e-$.CLOCK_SKEW_MS>h){let C=Math.round((e-h)/6e4);F(`this code expired ${C} 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>$.MAX_LIFETIME_MINUTES*6e4+$.CLOCK_SKEW_MS&&F("descriptor lifetime is implausibly long","lifetime");let m=s===oe.ANSWER?t.bytes($.BINDING_BYTES):null,p=t.bytes($.FINGERPRINT_BYTES),S=t.u8();(S<$.MIN_UFRAG||S>$.MAX_UFRAG)&&F("ice-ufrag length out of range");let g=t.ascii(S);Ut.test(g)||F("ice-ufrag contains characters outside the ICE alphabet");let _=t.u8();(_<$.MIN_PWD||_>$.MAX_PWD)&&F("ice-pwd length out of range");let I=t.ascii(_);Ut.test(I)||F("ice-pwd contains characters outside the ICE alphabet");let w=t.u8();w>$.MAX_CANDIDATES&&F("too many candidates");let D=[];for(let C=0;C>4&15,j=x&15,z=ds[k];z===void 0&&F(`reserved candidate kind ${k}`),j>=Mr.length&&F("reserved TCP candidate type");let M=t.bytes(z),fe=t.u16();fe<1&&F("candidate port must be non-zero"),D.push({kind:k,tcptype:j,addr:M,port:fe})}let T=null;c&&(T=t.bytes($.COMMITMENT_BYTES));let v=new Map;if(d){let C=t.u8();C===0&&F("extension area is flagged but empty"),v=Ea(t.bytes(C))}t.rest!==0&&F(`${t.rest} trailing byte(s) after the descriptor`);let b;return o===ls?(v.has(St.MAX_MESSAGE_SIZE)||F("flags promise an explicit max-message-size but no extension carries it"),b=v.get(St.MAX_MESSAGE_SIZE)):(v.has(St.MAX_MESSAGE_SIZE)&&F("extension 0x01 present but the flags do not select it"),b=Rr[o]),{version:r,type:s,setup:a,maxMessageSize:b,expiresAtMs:h,bindingTag:m,fingerprint:p,ufrag:g,pwd:I,candidates:D,commitment:T,extensions:v}}var ps=n=>n.toString(16).padStart(2,"0");function as(n,e){switch(n){case ge.HOST_MDNS:{let t=Array.from(e,ps).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}.local`}case ge.HOST_V4:case ge.SRFLX_V4:case ge.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 Pr(n,{sessionId:e="1"}={}){let t=n.type===oe.OFFER,r={relay:0,srflx:1,host:2},i=n.candidates.filter(h=>h.kind!==ge.HOST_MDNS&&h.tcptype===0).sort((h,m)=>r[at[h.kind]]-r[at[m.kind]])[0],s=i&&Ar[i.kind]==="v6",a=i?i.port:9,o=i?`c=IN IP${s?"6":"4"} ${as(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:"+n.ufrag,"a=ice-pwd:"+n.pwd,"a=fingerprint:sha-256 "+Array.from(n.fingerprint,h=>ps(h).toUpperCase()).join(":"),"a=setup:"+cs[n.setup],"a=mid:0","a=sctp-port:5000","a=max-message-size:"+n.maxMessageSize],d=n.candidates.map((h,m)=>{let p=at[h.kind],S=h.tcptype===0?"udp":"tcp",g=Math.max(0,65535-m),_=pa[p]*16777216+g*256+255,w=`a=candidate:${String(h.kind*4+h.tcptype+1)} 1 ${S} ${_} ${as(h.kind,h.addr)} ${h.port} typ ${p}`;return p!=="host"&&(w+=Ar[h.kind]==="v6"?" raddr :: rport 0":" raddr 0.0.0.0 rport 0"),S==="tcp"&&(w+=` tcptype ${Mr[h.tcptype]}`),w});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 `)+`\r -`}}var Pi=new TextEncoder;function Ut(...s){let e=s.reduce((r,n)=>r+n.length,0),t=new Uint8Array(e),i=0;for(let r of s)t.set(r,i),i+=r.length;return t}async function Fi(s,e){return(await s(Ut(Pi.encode("sbq2/bind\0"),e))).slice(0,G.BINDING_BYTES)}async function zt(s,e){return(await s(Ut(Pi.encode("sbq2/blob\0"),e))).slice(0,G.COMMITMENT_BYTES)}function fn(s,e,t,i){let r=n=>{let a=new Uint8Array(4);return new DataView(a.buffer).setUint32(0,n.length),Ut(a,n)};return Ut(Pi.encode("sbq2/sas/v1\0"),r(s),r(e),r(t),r(i))}var gt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function wa(s){let e="";for(let t=0;t>2],e+=gt[(i&3)<<4|(r??0)>>4],r===void 0||(e+=gt[(r&15)<<2|(n??0)>>6],n===void 0))break;e+=gt[n&63]}return e}function Ea(s){typeof s!="string"&&P("payload must be a string");let e=s.replace(/\s+/g,"");e.length>Math.ceil(G.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)),i=0,r=0,n=0;for(let a of e)r=r<<6|gt.indexOf(a),n+=6,n>=8&&(n-=8,t[i++]=r>>n&255);return r&(1<{throw new Ni(s,e)};function gn({role:s,ecdhSpki:e,ecdsaSpki:t}){s!==be.OFFER&&s!==be.ANSWER&&de("invalid role");for(let[a,o]of[["ecdh",e],["ecdsa",t]])o instanceof Uint8Array||de(`${a} SPKI must be a Uint8Array`),(o.lengthWe.MAX_SPKI)&&de(`${a} SPKI length out of range`);let i=new Uint8Array(4+e.length+2+t.length),r=new DataView(i.buffer),n=0;return i[n++]=yn,i[n++]=s,r.setUint16(n,e.length),n+=2,i.set(e,n),n+=e.length,r.setUint16(n,t.length),n+=2,i.set(t,n),i}function mn(s){s instanceof Uint8Array||de("key blob must be a Uint8Array"),s.length===0&&de("key blob is empty"),s.length>We.MAX_BLOB_BYTES&&de("key blob exceeds the size limit");let e=new DataView(s.buffer,s.byteOffset,s.byteLength),t=0,i=h=>{t+h>s.length&&de("key blob is truncated")};i(1);let r=s[t++];r!==yn&&de(`unsupported key blob version 0x${r.toString(16)}`,"version"),i(1);let n=s[t++];n!==be.OFFER&&n!==be.ANSWER&&de("reserved key blob role"),i(2);let a=e.getUint16(t);t+=2,(aWe.MAX_SPKI)&&de("ECDH SPKI length out of range"),i(a);let o=s.slice(t,t+a);t+=a,i(2);let c=e.getUint16(t);t+=2,(cWe.MAX_SPKI)&&de("ECDSA SPKI length out of range"),i(c);let l=s.slice(t,t+c);return t+=c,t!==s.length&&de(`${s.length-t} trailing byte(s) after the key blob`),{version:r,role:n,ecdhSpki:o,ecdsaSpki:l}}function Sn({offerDescriptor:s,answerDescriptor:e,offerBlob:t,answerBlob:i}){for(let[r,n]of Object.entries({offerDescriptor:s,answerDescriptor:e,offerBlob:t,answerBlob:i}))(!(n instanceof Uint8Array)||n.length===0)&&de(`transcript component ${r} is missing`);return fn(s,e,t,i)}async function _n(s,e){let t=await s.digest("SHA-512",e);return Array.from(new Uint8Array(t))}var wn=new TextEncoder;function Oi(s){let e=wn.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 En(s,{ecdhPrivateKey:e,peerEcdhPublicKey:t,transcript:i,digits:r=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",i)),c=await s.deriveBits({name:"HKDF",hash:"SHA-256",salt:o,info:wn.encode("sbq2-sas-v1")},a,64),l=new DataView(c),h=(l.getUint32(0)^l.getUint32(4))>>>0,u=10**r;return String(h%u).padStart(r,"0")}finally{try{new Uint8Array(n).fill(0)}catch{}}}async function bn(s,e,t){(!(t instanceof Uint8Array)||t.length!==G.COMMITMENT_BYTES)&&de("descriptor carried no usable commitment","commitment_missing");let r=await zt(async a=>new Uint8Array(await s.digest("SHA-256",a)),e);r.length!==t.length&&de("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=i,this.onVerificationStateChange=a,this.onVerificationRequired=r,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,i=!1){try{let r={sessionId:this.currentSession?.sessionId||this.sessionId||"unknown",keyFingerprint:this.keyFingerprint||"unknown",sequenceNumber:this._generateNextSequenceNumber(),messageType:e,timestamp:Date.now(),connectionId:this.connectionId||"unknown",isFileMessage:i};return t&&typeof t=="object"&&(t.fileId&&(r.fileId=t.fileId),t.chunkIndex!==void 0&&(r.chunkIndex=t.chunkIndex),t.totalChunks!==void 0&&(r.totalChunks=t.totalChunks)),JSON.stringify(r)}catch(r){return this._secureLog("error","\u274C Failed to create message AAD",{errorType:r.constructor.name,message:r.message,messageType:e}),JSON.stringify({sessionId:"unknown",keyFingerprint:"unknown",sequenceNumber:Date.now(),messageType:e,timestamp:Date.now(),connectionId:"unknown",isFileMessage:i})}}_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 i;if(e instanceof ArrayBuffer)i=new Uint8Array(e);else if(e instanceof Uint8Array)i=e;else if(e instanceof CryptoKey){let a=`${e.type}_${e.algorithm?.name||"unknown"}_${e.extractable}`;i=new TextEncoder().encode(a)}else if(typeof e=="string")i=new TextEncoder().encode(e);else if(typeof e=="object"&&e!==null){let a={type:e.kty||"unknown",use:e.use||"unknown"};i=new TextEncoder().encode(JSON.stringify(a))}else i=new TextEncoder().encode(String(e));let r=await crypto.subtle.digest("SHA-256",i),n=new Uint8Array(r);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(i=>{setTimeout(async()=>{try{await e(),i(!0)}catch(r){this._secureLog("error","Async cleanup failed",{errorType:r?.constructor?.name||"Unknown"}),i(!1)}},t)})}async _batchAsyncOperation(e,t=10,i=5){let r=[];for(let n=0;n{let r=` +`}}var Fr=new TextEncoder;function zt(...n){let e=n.reduce((i,s)=>i+s.length,0),t=new Uint8Array(e),r=0;for(let i of n)t.set(i,r),r+=i.length;return t}async function Kr(n,e){return(await n(zt(Fr.encode("sbq2/bind\0"),e))).slice(0,$.BINDING_BYTES)}async function Vt(n,e){return(await n(zt(Fr.encode("sbq2/blob\0"),e))).slice(0,$.COMMITMENT_BYTES)}function ys(n,e,t,r){let i=s=>{let a=new Uint8Array(4);return new DataView(a.buffer).setUint32(0,s.length),zt(a,s)};return zt(Fr.encode("sbq2/sas/v1\0"),i(n),i(e),i(t),i(r))}var mt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function va(n){let e="";for(let t=0;t>2],e+=mt[(r&3)<<4|(i??0)>>4],i===void 0||(e+=mt[(i&15)<<2|(s??0)>>6],s===void 0))break;e+=mt[s&63]}return e}function Ta(n){typeof n!="string"&&F("payload must be a string");let e=n.replace(/\s+/g,"");e.length>Math.ceil($.MAX_PAYLOAD_BYTES*4/3)+4&&F("payload is too long"),/^[A-Za-z0-9_-]*$/.test(e)||F("payload contains characters outside base64url"),e.length%4===1&&F("payload has an impossible length");let t=new Uint8Array(Math.floor(e.length*3/4)),r=0,i=0,s=0;for(let a of e)i=i<<6|mt.indexOf(a),s+=6,s>=8&&(s-=8,t[r++]=i>>s&255);return i&(1<{throw new Or(n,e)};function Ss({role:n,ecdhSpki:e,ecdsaSpki:t}){n!==Ee.OFFER&&n!==Ee.ANSWER&&le("invalid role");for(let[a,o]of[["ecdh",e],["ecdsa",t]])o instanceof Uint8Array||le(`${a} SPKI must be a Uint8Array`),(o.lengthWe.MAX_SPKI)&&le(`${a} SPKI length out of range`);let r=new Uint8Array(4+e.length+2+t.length),i=new DataView(r.buffer),s=0;return r[s++]=ms,r[s++]=n,i.setUint16(s,e.length),s+=2,r.set(e,s),s+=e.length,i.setUint16(s,t.length),s+=2,r.set(t,s),r}function _s(n){n instanceof Uint8Array||le("key blob must be a Uint8Array"),n.length===0&&le("key blob is empty"),n.length>We.MAX_BLOB_BYTES&&le("key blob exceeds the size limit");let e=new DataView(n.buffer,n.byteOffset,n.byteLength),t=0,r=u=>{t+u>n.length&&le("key blob is truncated")};r(1);let i=n[t++];i!==ms&&le(`unsupported key blob version 0x${i.toString(16)}`,"version"),r(1);let s=n[t++];s!==Ee.OFFER&&s!==Ee.ANSWER&&le("reserved key blob role"),r(2);let a=e.getUint16(t);t+=2,(aWe.MAX_SPKI)&&le("ECDH SPKI length out of range"),r(a);let o=n.slice(t,t+a);t+=a,r(2);let c=e.getUint16(t);t+=2,(cWe.MAX_SPKI)&&le("ECDSA SPKI length out of range"),r(c);let d=n.slice(t,t+c);return t+=c,t!==n.length&&le(`${n.length-t} trailing byte(s) after the key blob`),{version:i,role:s,ecdhSpki:o,ecdsaSpki:d}}function bs({offerDescriptor:n,answerDescriptor:e,offerBlob:t,answerBlob:r}){for(let[i,s]of Object.entries({offerDescriptor:n,answerDescriptor:e,offerBlob:t,answerBlob:r}))(!(s instanceof Uint8Array)||s.length===0)&&le(`transcript component ${i} is missing`);return ys(n,e,t,r)}async function ws(n,e){let t=await n.digest("SHA-512",e);return Array.from(new Uint8Array(t))}var Es=new TextEncoder;function Ur(n){let e=Es.encode("sbq2/proof/v1\0"),t=new Uint8Array(e.length+n.length);return t.set(e,0),t.set(n,e.length),t}async function vs(n,{ecdhPrivateKey:e,peerEcdhPublicKey:t,transcript:r,digits:i=7}){let s=await n.deriveBits({name:"ECDH",public:t},e,256),a=null;try{a=await n.importKey("raw",s,"HKDF",!1,["deriveBits"]);let o=new Uint8Array(await n.digest("SHA-256",r)),c=await n.deriveBits({name:"HKDF",hash:"SHA-256",salt:o,info:Es.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(s).fill(0)}catch{}}}async function Ts(n,e,t){(!(t instanceof Uint8Array)||t.length!==$.COMMITMENT_BYTES)&&le("descriptor carried no usable commitment","commitment_missing");let i=await Vt(async a=>new Uint8Array(await n.digest("SHA-256",a)),e);i.length!==t.length&&le("commitment length mismatch","commitment_mismatch");let s=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=s,this.isInitiator=!1,this.connectionAttempts=0,this.maxConnectionAttempts=n.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=n.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:n.SIZES.CHUNK_SIZE_MAX,minDelay:n.SIZES.CHUNK_DELAY_MIN,maxDelay:n.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:n.LIMITS.MAX_OUT_OF_ORDER_PACKETS,reorderTimeout:n.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),s=new Uint8Array(i);return Array.from(s.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 s=0;s{let i=` self.onmessage = function(e) { const { type, data } = e.data; @@ -39,44 +39,44 @@ Please wait for real-time cryptographic verification to complete.`,"sec.verifica self.postMessage({ success: false, error: error.message }); } }; - `,n=new Blob([r],{type:"application/javascript"}),a=new Worker(URL.createObjectURL(n)),o=setTimeout(()=>{a.terminate(),i(new Error("Worker cleanup timeout"))},5e3);a.onmessage=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),c.data.success?t(c.data):i(new Error(c.data.error))},a.onerror=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),i(c)},a.postMessage(e)})}async _cleanupInMainThread(e){let{type:t,data:i}=e;switch(t){case"cleanup_arrays":let r=0,n=100;for(;rc++),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",i=typeof this.verificationCode=="string"&&this.verificationCode.trim().length>0,r=typeof this._sasLocalFingerprint=="string"&&this._sasLocalFingerprint.trim().length>0&&typeof this._sasRemoteFingerprint=="string"&&this._sasRemoteFingerprint.trim().length>0;return e&&t&&i&&r}_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 i of e.match(/^a=candidate:.*$/gm)||[]){t.total+=1;let n=i.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 i=t.slice(12).trim().split(/\s+/),r=i.findIndex(h=>h.toLowerCase()==="typ"),n=i[4]||"",a=i[5]||"",o=r>=0&&i[r+1]||"unknown",c=(i[2]||"unknown").toLowerCase(),l="unknown";return/\.local$/i.test(n)?l="mdns":/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(n)?l="private-ipv4":/^\d{1,3}(\.\d{1,3}){3}$/.test(n)?l="public-ipv4":n.includes(":")&&(l="ipv6"),{candidateType:o,protocol:c,addressKind:l,portPresent:!!a,tcpType:(()=>{let h=i.findIndex(u=>u.toLowerCase()==="tcptype");return h>=0&&i[h+1]||null})()}})}_logIceCandidateDiagnostics(e,t,i={}){let r=this._summarizeIceCandidatesInSDP(t),n=this._describeIceCandidatesInSDP(t);return console.info(`[SecureBit ICE] ${e}`,{candidateSummary:r,candidateDetails:n,candidateDetailsJson:JSON.stringify(n),...i}),{candidateSummary:r,candidateDetails:n}}_hasOnlyMdnsHostCandidates(e){let t=this._summarizeIceCandidatesInSDP(e),i=this._describeIceCandidatesInSDP(e);return t.total>0&&t.srflx===0&&t.relay===0&&t.prflx===0&&i.every(r=>r.candidateType==="host"&&r.addressKind==="mdns")}_warnIfRemoteCandidatesNeedRelay(e,t){if(!this._hasOnlyMdnsHostCandidates(t))return!1;let i=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(i,"system"),!0}async _collectIceFailureDiagnostics(){if(!this.peerConnection?.getStats)return null;try{let e=await this.peerConnection.getStats(),t=new Map,i=[];return e.forEach(r=>{(r.type==="local-candidate"||r.type==="remote-candidate")&&t.set(r.id,{type:r.type,candidateType:r.candidateType,protocol:r.protocol,address:r.address||r.ip||null,port:r.port||null,networkType:r.networkType||null})}),e.forEach(r=>{r.type==="candidate-pair"&&i.push({state:r.state,nominated:!!r.nominated,writable:!!r.writable,bytesSent:r.bytesSent||0,bytesReceived:r.bytesReceived||0,currentRoundTripTime:r.currentRoundTripTime??null,local:t.get(r.localCandidateId)||null,remote:t.get(r.remoteCandidateId)||null})}),{pairCount:i.length,states:i.reduce((r,n)=>(r[n.state||"unknown"]=(r[n.state||"unknown"]||0)+1,r),{}),pairs:i}}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 i={isValid:!1,sanitizedData:null,errors:[],warnings:[]};try{if(e==null)return i.errors.push("Data cannot be null or undefined"),i;if(typeof e=="string")return e.length>this._inputValidationLimits.maxStringLength?(i.errors.push(`String too long: ${e.length} > ${this._inputValidationLimits.maxStringLength}`),i):(i.sanitizedData=this._sanitizeInputString(e),i.isValid=!0,i);if(typeof e=="object"){let r=new WeakSet,n=(o,c="")=>{if(!(o===null||typeof o!="object")){if(r.has(o)){i.errors.push(`Circular reference detected at path: ${c}`);return}if(r.add(o),c.split(".").length>this._inputValidationLimits.maxObjectDepth){i.errors.push(`Object too deep: ${c.split(".").length} > ${this._inputValidationLimits.maxObjectDepth}`);return}if(Array.isArray(o)&&o.length>this._inputValidationLimits.maxArrayLength){i.errors.push(`Array too long: ${o.length} > ${this._inputValidationLimits.maxArrayLength}`);return}for(let l in o)o.hasOwnProperty(l)&&n(o[l],c?`${c}.${l}`:l)}};if(n(e),i.errors.length>0)return i;let a=this._calculateObjectSize(e);return a>this._inputValidationLimits.maxMessageSize?(i.errors.push(`Object too large: ${a} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),i):(i.sanitizedData=this._sanitizeInputObject(e),i.isValid=!0,i)}return e instanceof ArrayBuffer?e.byteLength>this._inputValidationLimits.maxMessageSize?(i.errors.push(`ArrayBuffer too large: ${e.byteLength} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),i):(i.sanitizedData=e,i.isValid=!0,i):(i.errors.push(`Unsupported data type: ${typeof e}`),i)}catch(r){return i.errors.push(`Validation error: ${r.message}`),this._secureLog("error","\u274C Input validation failed",{context:t,errorType:r?.constructor?.name||"Unknown",message:r?.message||"Unknown error"}),i}}_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,` + `,s=new Blob([i],{type:"application/javascript"}),a=new Worker(URL.createObjectURL(s)),o=setTimeout(()=>{a.terminate(),r(new Error("Worker cleanup timeout"))},5e3);a.onmessage=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(s),c.data.success?t(c.data):r(new Error(c.data.error))},a.onerror=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(s),r(c)},a.postMessage(e)})}async _cleanupInMainThread(e){let{type:t,data:r}=e;switch(t){case"cleanup_arrays":let i=0,s=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 s=r.match(/\btyp\s+(host|srflx|relay|prflx)\b/i)?.[1]?.toLowerCase();s&&Object.prototype.hasOwnProperty.call(t,s)?t[s]+=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"),s=r[4]||"",a=r[5]||"",o=i>=0&&r[i+1]||"unknown",c=(r[2]||"unknown").toLowerCase(),d="unknown";return/\.local$/i.test(s)?d="mdns":/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(s)?d="private-ipv4":/^\d{1,3}(\.\d{1,3}){3}$/.test(s)?d="public-ipv4":s.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),s=this._describeIceCandidatesInSDP(t);return console.info(`[SecureBit ICE] ${e}`,{candidateSummary:i,candidateDetails:s,candidateDetailsJson:JSON.stringify(s),...r}),{candidateSummary:i,candidateDetails:s}}_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,s)=>(i[s.state||"unknown"]=(i[s.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:n.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,s=(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)&&s(o[d],c?`${c}.${d}`:d)}};if(s(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(i=>this._sanitizeInputObject(i));let t={};for(let i in e)if(e.hasOwnProperty(i)){let r=e[i];typeof r=="string"?t[i]=this._sanitizeInputString(r):typeof r=="object"?t[i]=this._sanitizeInputObject(r):t[i]=r}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 $t,this._secureKeyStorage=new Bt(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(i,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 i=await this._secureKeyStorage.storeKey(e,t,{version:this.currentKeyVersion,type:t.algorithm.name});return i&&this._secureLog("info",`\u{1F511} Key ${e} stored securely with encryption`),i}_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 Bt}_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 i=e instanceof CryptoKey;t+=i?1:0}catch{t+=0}try{let i=!!(e&&e.algorithm);t+=i?1:0}catch{t+=0}try{let i=!!(e&&e.type);t+=i?1:0}catch{t+=0}try{let i=e&&e.extractable!==void 0;t+=i?1:0}catch{t+=0}return t===4}_validateKeyPairConstantTime(e){if(!e||typeof e!="object")return!1;let t=this._validateKeyConstantTime(e.privateKey),i=this._validateKeyConstantTime(e.publicKey);return t&&i}_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[i,r]of this._logCounts.entries())r>this._maxLogCount*2&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Excessive log count detected: ${i}`));let t=Array.from(this._logCounts.keys());for(let i of t)this._containsSensitiveContent(i)&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Sensitive content in log key: ${i}`));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],i=e.slice(1);if(i.length===0){this._secureLog("info",String(t||""));return}if(i.length===1){this._secureLog("info",String(t||""),i[0]);return}this._secureLog("info",String(t||""),{additionalArgs:i,argCount:i.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,i=null){if(i&&!this._auditLogMessage(t,i)){this._originalConsole?.error?.("SECURITY: Logging blocked due to potential data leakage");return}if(this._logLevels[e]>this._currentLogLevel)return;let r=`${e}:${t.substring(0,50)}`,n=this._logCounts.get(r)||0;if(n>=this._maxLogCount)return;this._logCounts.set(r,n+1);let a=null;if(i&&(a=this._sanitizeLogData(i),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[r,n]of Object.entries(e)){let a=r.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(r)||o.some(l=>a.includes(l))){t[r]="[SENSITIVE_DATA_BLOCKED]";continue}if(this._safeFieldsWhitelist.has(r)){typeof n=="string"?t[r]=this._sanitizeString(n):t[r]=n;continue}if(typeof n=="boolean"||typeof n=="number")t[r]=n;else if(typeof n=="string")t[r]=this._sanitizeString(n);else if(n instanceof ArrayBuffer||n instanceof Uint8Array)t[r]=`[${n.constructor.name}( bytes)]`;else if(n&&typeof n=="object")try{t[r]=this._sanitizeLogData(n)}catch{t[r]="[RECURSIVE_SANITIZATION_FAILED]"}else t[r]=`[${typeof n}]`}let i=JSON.stringify(t);return this._containsSensitiveContent(i)?{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 i of t)if(i.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(i=>i.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 i=e.length,r=0;for(let n of Object.values(t)){let a=n/i;r-=a*Math.log2(a)}return r>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(i=>typeof window.secureBitChat[i]!="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(i){this._secureMemoryManager.memoryStats.failedCleanups++,this._secureLog("error","\u274C Secure memory wipe failed",{context:t,errorType:i.constructor.name,errorMessage:i.message})}}_secureWipeArrayBuffer(e,t){if(!(!e||e.byteLength===0))try{let i=new Uint8Array(e);crypto.getRandomValues(i),i.fill(0),i.fill(255),i.fill(0),this._secureLog("debug","\u{1F512} ArrayBuffer securely wiped",{context:t,size:e.byteLength})}catch(i){this._secureLog("error","\u274C Failed to wipe ArrayBuffer",{context:t,errorType:i.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(i){this._secureLog("error","\u274C Failed to wipe Uint8Array",{context:t,errorType:i.constructor.name})}}_secureWipeArray(e,t){if(!(!Array.isArray(e)||e.length===0))try{e.forEach((i,r)=>{i!=null&&this._secureWipeMemory(i,`${t}[${r}]`)}),e.fill(null),this._secureLog("debug","\u{1F512} Array securely wiped",{context:t,size:e.length})}catch(i){this._secureLog("error","\u274C Failed to wipe array",{context:t,errorType:i.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[i,r]of Object.entries(e))r!=null&&this._secureWipeMemory(r,`${t}.${i}`),e[i]=null;this._secureLog("debug","\u{1F512} Object securely wiped",{context:t,properties:Object.keys(e).length})}catch(i){this._secureLog("error","\u274C Failed to wipe object",{context:t,errorType:i.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,i=!!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 i=this._categorizeError(e),r=this._getSafeErrorMessage(i,t);return this._secureLog("error","Internal error occurred",{category:i,context:t,errorType:e?.constructor?.name||"Unknown",timestamp:Date.now()}),this._trackErrorFrequency(i),r}catch(i){return this._secureLog("error","Error handling failed",{originalError:e?.message||"Unknown",handlingError:i.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 i={[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"}},r=i[e]||i[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"),r[n]||r.default}_trackErrorFrequency(e){let t=Date.now();t-this._secureErrorHandler.lastErrorTime>6e4&&this._secureErrorHandler.errorCounts.clear();let i=this._secureErrorHandler.errorCounts.get(e)||0;this._secureErrorHandler.errorCounts.set(e,i+1),this._secureErrorHandler.lastErrorTime=t;let r=Array.from(this._secureErrorHandler.errorCounts.values()).reduce((n,a)=>n+a,0);r>this._secureErrorHandler.errorThreshold&&(this._secureErrorHandler.isInErrorMode=!0,this._secureLog("warn","\u26A0\uFE0F High error frequency detected - entering error mode",{totalErrors:r,threshold:this._secureErrorHandler.errorThreshold}))}_throwSecureError(e,t="unknown"){let i=this._createSecureErrorMessage(e,t);throw new Error(i)}_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 i={test:!0},n=e.map(a=>{try{return window.secureBitChat[a].bind(i)}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 i=Object.keys(this.securityFeatures).filter(n=>this.securityFeatures[n]),r=["hasEncryption","hasECDH","hasECDSA"].filter(n=>this.securityFeatures[n]);return this._secureLog("info","\u2705 Cryptographic security validation passed",{criticalFeatures:e.length,availableFeatures:i.length,encryptionFeatures:r.length,totalSecurityFeatures:i.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",i=this.isVerified,r=t&&i;if(!r&&e){if(!t)throw new Error("Data channel not ready");if(!i)throw new Error("Connection not verified")}return r}_enforceVerificationGate(e="unknown",t=!0){if(!this.isVerified){let i=`SECURITY VIOLATION: ${e} blocked - connection not cryptographically verified`;if(this._secureLog("error",i,{operation:e,isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey),timestamp:Date.now()}),t)throw new Error(i);return!1}return!0}_setVerifiedStatus(e,t="unknown",i=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:i?"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 i=JSON.parse(e);if(i.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(i.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(t&&i.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${i.messageType}`);if(Date.now()-i.timestamp>18e5)throw new Error("AAD timestamp too old - possible replay attack");return i}catch(i){throw this._secureLog("error","AAD validation failed",{error:i.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${i.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 i=Math.min(...this.replayWindow);this.replayWindow.delete(i)}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(i){return this._secureLog("error","Sequence number validation failed",{error:i.message,context:t,timestamp:Date.now()}),!1}}_validateMessageAAD(e,t=null){try{let i=JSON.parse(e);if(i.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(i.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(!this._validateIncomingSequenceNumber(i.sequenceNumber,i.messageType))throw new Error("Sequence number validation failed - possible replay or DoS attack");if(t&&i.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${i.messageType}`);return i}catch(i){throw this._secureLog("error","AAD validation failed",{error:i.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${i.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,i)=>t-i)};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,i=[],r;for(;(r=t.exec(e))!==null;)i.push({algorithm:r[1].toLowerCase(),fingerprint:r[2].trim()});if(i.length===0){let a=/fingerprint\s*=\s*([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/gi;for(;(r=a.exec(e))!==null;)i.push({algorithm:r[1].toLowerCase(),fingerprint:r[2].trim()})}if(i.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[...i].sort((a,o)=>{let c=a.algorithm==="sha-256",l=o.algorithm==="sha-256";if(c!==l)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,i="unknown"){try{if(!e||!t)throw new Error("Missing fingerprint for validation");let r=e.toLowerCase().replace(/:/g,""),n=t.toLowerCase().replace(/:/g,"");if(r!==n)throw this._secureLog("error","DTLS fingerprint mismatch - possible MITM attack",{context:i,timestamp:Date.now()}),new Error(`DTLS fingerprint mismatch - possible MITM attack in ${i}`);return this._secureLog("info","DTLS fingerprint validation successful",{context:i,timestamp:Date.now()}),!0}catch(r){throw this._secureLog("error","DTLS fingerprint validation failed",{error:r.message,context:i}),r}}async _computeSAS(e,t,i){try{if(!e){let m=[];throw e||m.push("keyMaterialRaw"),new Error(`Missing required parameters for SAS computation: ${m.join(", ")}`)}let r=new TextEncoder,n=(m,I)=>{if(typeof m!="string"||m.trim().length===0)throw new Error(`Security error: ${I} must be a non-empty DTLS fingerprint string for SAS computation`);return m.trim().toLowerCase()},a=n(t,"localFP"),o=n(i,"remoteFP"),c=r.encode("webrtc-sas|"+[a,o].sort().join("|")),l;if(e instanceof ArrayBuffer)l=e;else if(e instanceof Uint8Array)l=e.buffer;else if(typeof e=="string"){let m=e.replace(/:/g,"").replace(/\s/g,""),I=new Uint8Array(m.length/2);for(let b=0;b>>0,g=String(w%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(r){throw this._secureLog("error","SAS computation failed",{error:r.message,keyMaterialType:typeof e,hasLocalFP:!!t,hasRemoteFP:!!i,timestamp:Date.now()}),new Error(`SAS computation failed: ${r.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 i=this._sbq2;i?.timer&&(clearTimeout(i.timer),i.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=gn({role:e,ecdhSpki:await this._exportSpki(this.ecdhKeyPair.publicKey),ecdsaSpki:await this._exportSpki(this.ecdsaKeyPair.publicKey)}),r=await zt(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:r}}async _sbq2BuildDescriptor(e,{bindingTag:t=null,lifetimeMs:i=600*1e3}={}){let r=this.peerConnection?.localDescription?.sdp;if(!r)throw new Error("SBQ2: no local description to encode");let n=e===le.OFFER?be.OFFER:be.ANSWER,{commitment:a}=await this._sbq2BuildLocalBlob(n),o=dn(r),c=un({type:e,expiresAtMs:Date.now()+i,sdpFields:{...o,candidates:Mi(o.candidates)},commitment:a,...e===le.ANSWER?{bindingTag:t}:{}}),l=this._sbq2State();return l.localDescriptor=c,this._secureLog("info","SBQ2 descriptor built",{type:e===le.OFFER?"offer":"answer",bytes:c.length,candidates:Mi(o.candidates).length}),{bytes:c,text:pn(c)}}_sbq2AdoptRemoteDescriptor(e,t){let i=Li(e);if(i.type!==t)throw new Error(`expected an ${t===le.OFFER?"invitation":"answer"}, got the other kind`);if(!i.commitment)throw new Error("the invitation carries no key commitment");let r=this._sbq2State();return r.remoteDescriptor=e,r.remoteCommitment=i.commitment,i}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,i=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(i.remoteBlob){this._sbq2Abort("duplicate_blob","The secure handshake was sent twice. The connection has been closed for safety.");return}let r=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.blob||"")));await bn(crypto.subtle,r,i.remoteCommitment);let n=mn(r),a=i.role===be.OFFER?be.ANSWER:be.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}i.remoteBlob=r,i.peerEcdhKey=await crypto.subtle.importKey("spki",n.ecdhSpki,{name:"ECDH",namedCurve:"P-384"},!1,[]),i.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 r=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.sig||"")));if(!i.transcript||!i.peerEcdsaKey){i.pendingProof=r;return}await this._sbq2VerifyProof(r);return}}catch(r){let n=r?.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===be.OFFER;e.transcript=Sn({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 _n(crypto.subtle,e.transcript),this.peerPublicKey=e.peerEcdhKey,this.peerECDHPublicKey=e.peerEcdhKey;let i=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,e.peerEcdhKey,this.sessionSalt);await this._setEncryptionKeys(i.messageKey,i.macKey,i.metadataKey,i.fingerprint),await this._initializeRatchet(i,t),e.keysDerived=!0;let r=new Uint8Array(await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},this.ecdsaKeyPair.privateKey,Oi(e.transcript)));if(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_PROOF,sig:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(r.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,Oi(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 En(crypto.subtle,{ecdhPrivateKey:this.ecdhKeyPair.privateKey,peerEcdhPublicKey:t.peerEcdhKey,transcript:t.transcript});let r=this.expectedDTLSFingerprint,n=this._peerDTLSFingerprint;r&&n&&this._setSASMaterialReady(r,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 i=e?.ratchetRoot;if(!i)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(i),!1;try{let r=this.peerPublicKey||this.peerECDHPublicKey;if(!r||!this.ecdhKeyPair?.privateKey)throw new Error("handshake ECDH keys unavailable");let n=new Nt;return await n.init({sharedSecret:i,sessionSalt:new Uint8Array(this.sessionSalt||[]),selfPrivateKey:this.ecdhKeyPair.privateKey,remotePublicKey:r,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(r){return this._ratchet=null,this.securityFeatures.hasPFS=!1,this._secureLog("error","Double Ratchet initialisation failed \u2014 continuing with static session keys",{errorType:r?.constructor?.name||"Unknown"}),!1}finally{window.EnhancedSecureCryptoUtils.zeroizeBuffer(i)}}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 i=typeof e=="string"?e:JSON.stringify(e),n={type:"encrypted_file_message",encryptedData:await window.EnhancedSecureCryptoUtils.encryptDataWithAAD(i,this.encryptionKey,t),aad:t,timestamp:Date.now(),keyFingerprint:this.keyFingerprint};return JSON.stringify(n)}catch(i){throw this._secureLog("error","Failed to encrypt file message",{error:i.message}),new Error(`File message encryption failed: ${i.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 i=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:i}}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 i=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,t,this.sessionSalt);return await this._setEncryptionKeys(i.messageKey,i.macKey,i.metadataKey,i.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 i=JSON.parse(e);return t.includes(i.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,i=null){try{return e()}catch(r){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:r?.constructor?.name||"Unknown"}),i}}async _withAsyncErrorHandling(e,t,i=null){try{return await e()}catch(r){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:r?.constructor?.name||"Unknown"}),i}}_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,i=0;for(let[r,n]of this._logCounts.entries())n>10&&i++;i>20&&(this._logCounts.clear(),this._secureLog("warn","\u{1F6A8} Emergency log cleanup due to suspicious patterns")),this._logSecurityViolations>0&&i<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(r=>{this._secureLog("error","Periodic cleanup failed",{errorType:r?.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[i,r]of Object.entries(e))typeof r=="string"&&this._containsSensitiveContent(r)?t[i]="[SENSITIVE_DATA_REDACTED]":t[i]=r;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 i=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(i))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log data"),!1;let r=["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=i.toLowerCase();for(let a of r)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 r=()=>{this._secureLog("info","\u{1F504} DataChannel opened, initializing file transfer..."),this.initializeFileTransfer()};this.dataChannel.addEventListener("open",r,{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=r=>{try{this._secureLog("info","\u{1F3C1} Sender transfer summary",{summary:r}),this.onFileProgress&&this.onFileProgress({type:"complete",...r})}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 i=this.fileTransferSystem.getSystemStatus();this._secureLog("info","\u{1F50D} File transfer system status after init",{status:i})}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 i=t-e+1,r=Math.ceil(Math.log2(i)),n=Math.ceil(r/8),a=(1<=i);return e+o}getSafeRandomFloat(e,t,i=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 r=this.getSafeRandomInt(0,i),n=(t-e)/i;return e+r*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",i=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 r=t==="received"?this._sanitizeIncomingChatMessage(e):e;if(this.onMessage){let n=i&&typeof this._sanitizeMessageMeta=="function"?this._sanitizeMessageMeta(i):null;this._secureLog("debug","\u{1F4E4} Calling this.onMessage callback",{message:r,type:t}),this.onMessage(r,t,n||void 0)}else this._secureLog("warn","\u26A0\uFE0F this.onMessage callback is null or undefined")}catch(r){this._secureLog("error","\u274C Failed to deliver message to UI:",{errorType:r?.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(([i,r])=>r===!0).map(([i])=>i.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"),i=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this.nestedEncryptionKey,e),r=new Uint8Array(s.SIZES.NESTED_ENCRYPTION_IV_SIZE+i.byteLength);return r.set(t,0),r.set(new Uint8Array(i),s.SIZES.NESTED_ENCRYPTION_IV_SIZE),this._secureLog("debug","\u2705 Nested encryption applied with secure IV",{ivSize:t.length,dataSize:e.byteLength,encryptedSize:i.byteLength}),r.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+r).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,i=Math.min(this.fakeTrafficConfig.maxInterval,3e4),r=this.getUnbiasedRandomInRange(t,i);this.fakeTrafficTimer=setTimeout(e,r)}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],i=this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minSize,this.fakeTrafficConfig.maxSize),r=crypto.getRandomValues(new Uint8Array(i));return{type:s.MESSAGE_TYPES.FAKE,pattern:t,data:Array.from(r).map(n=>n.toString(16).padStart(2,"0")).join(""),timestamp:Date.now(),size:i,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()}),i=new TextEncoder().encode(t),r=await this.applySecurityLayers(i,!0);this.dataChannel.send(r),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 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 applySecurityLayersWithoutMutex:",{errorType:i?.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 i=new DataView(t.buffer,0,16),r=i.getUint32(0,!1),n=i.getUint32(4,!1),a=i.getUint32(8,!1),o=i.getUint32(12,!1),c=t.slice(16,16+o);this.chunkQueue[r]||(this.chunkQueue[r]={chunks:new Array(a),received:0,timestamp:Date.now()});let l=this.chunkQueue[r];if(l.chunks[n]=c,l.received++,this._secureLog("debug",`\u{1F4E6} Received chunk ${n+1}/${a} for message ${r}`),l.received===a){let h=l.chunks.reduce((S,w)=>S+w.length,0),u=new Uint8Array(h),p=0;for(let S of l.chunks)u.set(S,p),p+=S.length;await this.processMessage(u.buffer),delete this.chunkQueue[r],this._secureLog("info",`\u{1F4E6} Chunked message ${r} 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(r,i),this.decoyChannels.set(i,r)}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=i=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Received decoy message on "${t}": ${i.data?.length||"undefined"} bytes`)},e.onclose=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" closed`),this.stopDecoyTraffic(t)},e.onerror=i=>{this._debugMode&&this._secureLog("error",`\u274C Decoy channel "${t}" error`,{error:i.message})}}startDecoyTraffic(e,t){let i=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(()=>i(),a))}catch(n){this._debugMode&&this._secureLog("error",`\u274C Failed to send decoy data on "${t}"`,{error:n.message})}},r=Math.random()*1e4+5e3;this.decoyTimers.set(t,setTimeout(()=>i(),r))}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(i=>i.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(i=>i.toString(16).padStart(2,"0")).join("")}),heartbeat:()=>JSON.stringify({type:"heartbeat",timestamp:Date.now(),data:Array.from(crypto.getRandomValues(new Uint8Array(24))).map(i=>i.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(i=>i.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(i=>i.toString(16).padStart(2,"0")).join("")})};return t[e]?t[e]():Array.from(crypto.getRandomValues(new Uint8Array(64))).map(i=>i.toString(16).padStart(2,"0")).join("")}addReorderingHeaders(e){if(!this.reorderingConfig.enabled)return e;try{let t=new Uint8Array(e),i=this.reorderingConfig.useTimestamps?12:8,r=new ArrayBuffer(i),n=new DataView(r);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(i+t.length);return a.set(new Uint8Array(r),0),a.set(t,i),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),i=this.reorderingConfig.useTimestamps?12:8;if(t.lengtht.length-i||o<=0)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid reordered packet data size, processing directly"),this.processMessage(e);let c=t.slice(i,i+o);try{let l=new TextDecoder().decode(c),h=JSON.parse(l);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 i=this.lastProcessedSequence+1,r=this.packetBuffer.get(i);if(r){try{let n=new TextDecoder().decode(r.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(i),this.lastProcessedSequence=i;continue}}catch{}await this.processMessage(r.data),this.packetBuffer.delete(i),this.lastProcessedSequence=i}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,i]of this.packetBuffer.entries())(!e||i.timestampt&&(this._secureLog("warn","\u26A0\uFE0F \u{1F5D1}\uFE0F Removing timed out packet ${sequence}"),this.packetBuffer.delete(i))}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),i=this.getUnbiasedRandomInRange(8,40),r=crypto.getRandomValues(new Uint8Array(i)),n=new Uint8Array(t.length+i);return n.set(t,0),n.set(r,t.length),n.buffer}randomizeSize(e){let t=new Uint8Array(e),i=this.fingerprintMask.sizeVariation,r=Math.floor(t.length*i);if(r>t.length){let n=crypto.getRandomValues(new Uint8Array(r-t.length)),a=new Uint8Array(r);return a.set(t,0),a.set(n,t.length),a.buffer}else if(r=256-256%this.fingerprintMask.headerVariations.length);let l=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)),p=new DataView(n.buffer,a);p.setUint32(0,u.length+8,!1),p.setUint32(4,this.hashString(l),!1),n.set(u,a+8);let S=this.calculateChecksum(n.slice(a,a+8+u.length));new DataView(n.buffer,a+8+u.length).setUint32(0,S,!1),a+=8+u.length+4}return n.set(t,a),n.buffer}hashString(e){let t=0;for(let i=0;i50)try{if(/^[A-Za-z0-9+/=]+$/.test(i.trim())&&(this._debugMode&&this._secureLog("debug","\u{1F513} Applying standard decryption..."),i=await window.EnhancedSecureCryptoUtils.decryptData(i,this.encryptionKey),this._debugMode&&this._secureLog("debug","\u2705 Standard decryption successful"),typeof i=="string")){try{let n=JSON.parse(i);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{}i=new TextEncoder().encode(i).buffer}}catch(r){return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Standard decryption failed:",{details:r.message}),e}if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&i instanceof ArrayBuffer&&i.byteLength>12)try{if(i=await this.removeNestedEncryption(i),i instanceof ArrayBuffer)try{let r=new TextDecoder().decode(i),n=JSON.parse(r);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(r){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Nested decryption failed - skipping this layer:",{details:r.message})}if(this.securityFeatures.hasPacketReordering&&this.reorderingConfig.enabled&&i instanceof ArrayBuffer)try{let r=this.reorderingConfig.useTimestamps?12:8;if(i.byteLength>r)return await this.processReorderedPacket(i)}catch(r){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Reordering processing failed - using direct processing:",{details:r.message})}if(this.securityFeatures.hasPacketPadding&&i instanceof ArrayBuffer)try{i=this.removePacketPadding(i)}catch(r){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Padding removal failed:",{details:r.message})}if(this.securityFeatures.hasAntiFingerprinting&&i instanceof ArrayBuffer)try{i=this.removeAntiFingerprinting(i)}catch(r){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Anti-fingerprinting removal failed:",{details:r.message})}if(i instanceof ArrayBuffer&&(i=new TextDecoder().decode(i)),typeof i=="string")try{let r=JSON.parse(i);if(r.type==="fake"||r.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Final check fake message: ${r.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}return i}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 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}}_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 i=Math.floor(e.onceTtl);i>=1&&i<=3600&&(t.onceTtl=i)}if(Number.isFinite(e.ttl)){let i=Math.floor(e.ttl);i>=5&&i<=86400&&(t.ttl=i)}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 i=this._validateInputData(e,"sendMessage");if(!i.isValid){let r=`Input validation failed: ${i.errors.join(", ")}`;throw this._secureLog("error","\u274C Input validation failed in sendMessage",{errors:i.errors,dataType:typeof e,dataLength:e?.length||e?.byteLength||0}),new Error(r)}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 i.sanitizedData,isString:typeof i.sanitizedData=="string",isArrayBuffer:i.sanitizedData instanceof ArrayBuffer,dataLength:i.sanitizedData?.length||i.sanitizedData?.byteLength||0}),typeof i.sanitizedData=="string")try{let n=JSON.parse(i.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(i.sanitizedData,a);return this.dataChannel.send(o),!0}}catch{}if(typeof i.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:i.sanitizedData}),a={type:"message",data:i.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 r=await this._applySecurityLayersWithLimitedMutex(i.sanitizedData,!1);return this.dataChannel.send(r),!0}catch(r){throw this._secureLog("error","\u274C Failed to send message",{error:r.message,errorType:r.constructor.name}),r}}async _applySecurityLayersWithLimitedMutex(e,t=!1){return this._withMutex("cryptoOperation",async i=>{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}},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 i=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(i),!0}catch(i){return this._secureLog("error","\u274C Failed to send system message:",{errorType:i?.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 r=JSON.parse(e),n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(r.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(r.type&&n.includes(r.type)){this._secureLog("warn","\u26A0\uFE0F Unencrypted file message detected - this should not happen in secure mode",{type:r.type}),this._secureLog("error","\u274C Dropping unencrypted file message for security",{type:r.type});return}if(r.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(r.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(r.type===s.MESSAGE_TYPES.MESSAGE){this._secureLog("error","Rejected unencrypted frame in processMessage",{messageType:"message"});return}if(r.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(r.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:r.type});return}let a=s.MESSAGE_TYPES;if(r.type===a.MESSAGE_DELETE){let o=r?.data?.messageId??r?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelete?.(o.slice(0,64))}catch{}return}if(r.type===a.MESSAGE_RECEIPT){let o=r?.data?.messageId??r?.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(r.type)){try{await this._handleCallSignal(r.type,r.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(r.type)){try{await this._handleIceRestartSignal(r.type,r.data||{})}catch(o){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:o?.constructor?.name})}return}return}if(r.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(r.type)){this.handleSystemMessage(r);return}if(r.type==="fake"){this._secureLog("warn","\u{1F3AD} Fake message blocked in processMessage",{pattern:r.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 i;if(typeof t=="string")try{let r=JSON.parse(t);if(r.type&&fileMessageTypes.includes(r.type)){this._secureLog("debug","\u{1F4C1} File message detected after decryption",{type:r.type}),this.fileTransferSystem&&await this.fileTransferSystem.handleFileMessage(r);return}if(r.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(r.type)){this.handleSystemMessage(r);return}if(r.type==="fake"){this._secureLog("warn",`\u{1F3AD} Post-decryption fake message blocked: ${r.pattern}`);return}r.type==="message"&&r.data?i=r.data:i=t}catch{i=t}else if(t instanceof ArrayBuffer)i=new TextDecoder().decode(t);else if(t&&typeof t=="object"&&t.message)i=t.message;else{this._secureLog("warn","\u26A0\uFE0F Unexpected data type after processing:",{details:typeof t});return}if(i&&i.trim().startsWith("{"))try{let r=JSON.parse(i);if(r.type==="fake"){this._secureLog("warn",`\u{1F3AD} Final fake message check blocked: ${r.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(r.type&&n.includes(r.type)){this._secureLog("warn",`\u{1F4C1} Final system/file message check blocked: ${r.type}`);return}}catch{}i&&this._secureLog("error","Rejected unauthenticated payload at the end of processMessage",{messageLength:typeof i=="string"?i.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(i){return this._secureLog("error","\u274C Error processing encrypted data",{operationId:t,errorType:i.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(([i,r])=>r===!0).map(([i])=>i);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"},i=`\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(i,"system")),this.dataChannel&&this.dataChannel.readyState==="open")try{let n={type:"security_upgrade",stage:e,stageName:t[e],message:i,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 r=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(i=>{this.pendingRotation={newVersion:this.currentKeyVersion+1,operationId:e,resolve:i,timeout:setTimeout(()=>{this._secureLog("error"," Key rotation timeout",{operationId:e}),this._keySystemState.isRotating=!1,this.pendingRotation=null,i(!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,i=0;for(let[r,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(r),i++,this._secureLog("info","\u{1F9F9} Old PFS keys hard wiped and cleaned up",{version:r,age:Math.round((e-n.timestamp)/1e3)+"s",timestamp:Date.now()}));i>0&&this._secureLog("info",`PFS cleanup completed: ${i} 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(i=>typeof i=="string"&&i.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 i of e||[]){t.serverCount+=1,(i?.username||i?.credential)&&(t.hasCredentials=!0);let r=Array.isArray(i?.urls)?i.urls:[i?.urls];for(let n of r){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(),i=null;e&&!t?i="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?i="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||(i="Privacy warning: relay-only mode is disabled. Direct WebRTC connectivity may expose host or server-reflexive IP addresses even when TURN is available."),i&&this.deliverMessageToUI(i,"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(i=>{console.warn("[SecureBit ICE] failure diagnostics",i),this._noteIceFailureDiagnostics(i)}),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(i){this._secureLog("warn","\u26A0\uFE0F ontrack handling failed",{errorType:i?.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,i=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(r){this._secureLog("error","SBQ2 key exchange failed to start",{errorType:r?.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(r){this._secureLog("error","Error in establishConnection:",{errorType:r?.constructor?.name||"Unknown"})}if(this.pendingSASCode&&this.dataChannel&&this.dataChannel.readyState==="open")try{let r={type:"sas_code",data:{code:this.pendingSASCode,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(r)),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=i,this.dataChannel.readyState==="open"&&Promise.resolve().then(()=>i()).catch(r=>{this._secureLog("error","Deferred data channel open handling failed",{errorType:r?.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 r=>{try{if(this._noteInboundActivity?.(),typeof r.data=="string")try{let n=JSON.parse(r.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(l,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 r.data=="string"?r.data.length:0});return}else r.data instanceof ArrayBuffer&&await this._processBinaryDataWithoutMutex(r.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 i=new TextDecoder().decode(t);try{let r=JSON.parse(i);if(r.type==="fake"||r.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 i=JSON.parse(t);if(i.type==="fake"||i.isFakeTraffic===!0)return;if(i&&i.type==="message"&&typeof i.data=="string"){this.deliverMessageToUI(i.data,"received",i.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 i=JSON.parse(t.message);if(i.type==="fake"||i.isFakeTraffic===!0)return;if(i&&i.type==="message"&&typeof i.data=="string"){this.onMessage&&this.deliverMessageToUI(i.data,"received",i.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,i=5e3){let r=`_${e}Mutex`,n=this[r];if(!n)throw this._secureLog("error",`Unknown mutex: ${e}`,{mutexPropertyName:r,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,i)},i),a();else{let l={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}'`)))},i)};n.queue.push(l),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 i=`_${e}Mutex`,r=this[i];if(!r)throw this._secureLog("error",`Unknown mutex for release: ${e}`,{mutexPropertyName:i,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex for release: ${e}`);if(r.lockId!==t)throw this._secureLog("error","CRITICAL: Invalid mutex release attempt - potential race condition",{mutexName:e,expectedLockId:r.lockId,providedOperationId:t,mutexState:{locked:r.locked,lockTime:r.lockTime,queueLength:r.queue.length}}),new Error(`Invalid mutex release attempt for '${e}': expected '${r.lockId}', got '${t}'`);if(!r.locked)throw this._secureLog("error","CRITICAL: Attempting to release unlocked mutex",{mutexName:e,operationId:t,mutexState:{locked:r.locked,lockId:r.lockId,lockTime:r.lockTime}}),new Error(`Attempting to release unlocked mutex: ${e}`);try{r.lockTimeout&&(clearTimeout(r.lockTimeout),r.lockTimeout=null);let n=r.lockTime?Date.now()-r.lockTime:0;r.locked=!1,r.lockId=null,r.lockTime=null,this._secureLog("debug",`Mutex released successfully: ${e}`,{operationId:t,lockDuration:n,queueLength:r.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}),r.locked=!1,r.lockId=null,r.lockTime=null,r.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 i=t.queue.shift();if(!i){this._secureLog("warn",`Empty queue item for mutex '${e}'`);return}if(!i.operationId||!i.resolve||!i.reject){this._secureLog("error",`Invalid queue item structure for mutex '${e}'`,{hasOperationId:!!i.operationId,hasResolve:!!i.resolve,hasReject:!!i.reject});return}try{i.timeout&&clearTimeout(i.timeout),this._secureLog("debug",`Processing next operation in queue for mutex '${e}'`,{operationId:i.operationId,queueRemaining:t.queue.length,timestamp:Date.now()}),setTimeout(async()=>{try{await this._acquireMutex(e,i.operationId,5e3),this._secureLog("debug",`Queued operation acquired mutex '${e}'`,{operationId:i.operationId,acquisitionTime:Date.now()}),i.resolve()}catch(r){this._secureLog("error",`Queued operation failed to acquire mutex '${e}'`,{operationId:i.operationId,errorType:r.constructor.name,errorMessage:r.message,timestamp:Date.now()}),i.reject(new Error(`Queue processing failed for '${e}': ${r.message}`)),setTimeout(()=>{this._processNextInQueue(e)},50)}},10)}catch(r){this._secureLog("error",`Critical error during queue processing for mutex '${e}'`,{operationId:i.operationId,errorType:r.constructor.name,errorMessage:r.message});try{i.reject(new Error(`Queue processing critical error: ${r.message}`))}catch(n){this._secureLog("error","Failed to reject queue item",{originalError:r.message,rejectError:n.message})}setTimeout(()=>{this._processNextInQueue(e)},100)}}_getAvailableMutexes(){let e=[],t=Object.getOwnPropertyNames(this);for(let i of t)if(i.endsWith("Mutex")&&i.startsWith("_")){let r=i.slice(1,-5);e.push(r)}return e}async _withMutex(e,t,i=5e3){let r=this._generateOperationId();if(!this._validateMutexSystem())throw this._secureLog("error","Mutex system not properly initialized",{operationId:r,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,r,i),a=!0;let o=`${e}Operations`;this._operationCounters&&this._operationCounters[o]!==void 0&&this._operationCounters[o]++;let c=await t(r);return c===void 0&&t.name!=="cleanup"&&this._secureLog("warn","Mutex operation returned undefined result",{operationId:r,mutexName:e,operationName:t.name}),c}catch(o){throw this._secureLog("error","Error in mutex operation",{operationId:r,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,r),(o.message.includes("timeout")||o.message.includes("race condition"))&&this._emergencyUnlockAllMutexes("errorHandler"),o}finally{if(a)try{await this._releaseMutex(e,r),n.locked&&n.lockId===r&&(this._secureLog("error","Mutex release verification failed",{operationId:r,mutexName:e}),n.locked=!1,n.lockId=null,n.lockTimeout=null)}catch(o){this._secureLog("error","Error releasing mutex in finally block",{operationId:r,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 i=`_${t}Mutex`,r=this[i];if(!r||typeof r!="object")return this._secureLog("error",`Missing or invalid mutex: ${t}`,{mutexPropertyName:i,mutexType:typeof r}),!1;let n=["locked","queue","lockId","lockTimeout"];for(let a of n)if(!(a in r))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 i=0,r=50;for(;t.isInitializing&&isetTimeout(n,100)),i++;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 i=null,r=null;try{if(i=await this._generateEphemeralECDHKeys(),!i||!i.privateKey||!i.publicKey)throw new Error("Ephemeral ECDH key pair validation failed");if(!this._validateKeyPairConstantTime(i))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:i.privateKey.algorithm?.name,publicKeyType:i.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(r=await window.EnhancedSecureCryptoUtils.generateECDSAKeyPair(),!r||!r.privateKey||!r.publicKey)throw new Error("ECDSA key pair validation failed");if(!this._validateKeyPairConstantTime(r))throw new Error("ECDSA keys are not valid CryptoKey instances");this._secureLog("debug","ECDSA keys generated and validated",{operationId:e,privateKeyType:r.privateKey.algorithm?.name,publicKeyType:r.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(!i||!r)throw new Error("One or both key pairs failed to generate");return this._enableSecurityFeaturesAfterKeyGeneration(i,r),this._secureLog("info","Encryption keys generated successfully with atomic protection",{operationId:e,hasECDHKeys:!!(i?.privateKey&&i?.publicKey),hasECDSAKeys:!!(r?.privateKey&&r?.publicKey),generationTime:Date.now()-t.lastOperationTime}),{ecdhKeyPair:i,ecdsaKeyPair:r}}catch(i){throw this._secureLog("error","Key generation failed, resetting state",{operationId:e,errorType:i.constructor.name}),i}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(i){this._secureLog("error","Failed to enable security features after key generation",{errorType:i.constructor.name,errorMessage:i.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 i=["keyOperation","cryptoOperation","connectionOperation"];this._secureLog("error","EMERGENCY: Unlocking all mutexes with authorization and state cleanup",{callerContext:e,timestamp:Date.now()});let r=0,n=0;if(i.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 l=0;o.queue.forEach(h=>{try{h.reject&&typeof h.reject=="function"&&(h.reject(new Error(`Emergency mutex unlock for ${a} by ${e}`)),l++)}catch(u){this._secureLog("warn","Failed to reject queue item during emergency unlock",{mutexName:a,errorType:u.constructor.name})}}),o.queue=[],r++,this._secureLog("debug",`Emergency unlocked mutex: ${a}`,{previousState:c,queueRejectCount:l,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:r,errorCount:n,totalMutexes:i.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 i=0,r=100;for(;io.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:i,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:i,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:i}),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:i,ivSize:e,totalIVs:this._ivTrackingSystem.usedIVs.size}),n}throw this._secureLog("error",`Failed to generate unique IV after ${r} attempts`,{context:t,totalIVs:this._ivTrackingSystem.usedIVs.size}),new Error(`Failed to generate unique IV after ${r} attempts`)}_validateIVEntropy(e){this._ivTrackingSystem.entropyValidation.entropyTests++;let t=new Array(256).fill(0);for(let w=0;w0){let g=t[w]/n;r-=g*Math.log2(g)}i.shannon=r;let o=Math.max(...t)/n;i.min=-Math.log2(o);let c=0;for(let w=0;w<256;w++)if(t[w]>0){let g=t[w]/n;c+=g*g}i.collision=-Math.log2(c);let l=Array.from(e).map(w=>String.fromCharCode(w)).join(""),h=this._estimateCompressedLength(l);i.compression=(1-h/n)*8,i.quantum=this._calculateQuantumResistantEntropy(e);let u=this._detectAdvancedSuspiciousPatterns(e),p=this._ivTrackingSystem.entropyValidation.minEntropy,S=i.shannon>=p&&i.min>=p*.8&&i.collision>=p*.9&&i.compression>=p*.7&&i.quantum>=p*.6&&!u;return S||this._secureLog("warn","Enhanced IV entropy validation failed",{shannon:i.shannon.toFixed(2),min:i.min.toFixed(2),collision:i.collision.toFixed(2),compression:i.compression.toFixed(2),quantum:i.quantum.toFixed(2),minThreshold:p,hasSuspiciousPatterns:u}),S}_estimateCompressedLength(e){let t=0,i=0;for(;ir&&(r=o,n=i-a)}r>=3?(t+=3,i+=r):(t+=1,i+=1)}return t}_calculateQuantumResistantEntropy(e){let t=0;this._detectQuantumVulnerablePatterns(e)&&(t-=2);let r=this._analyzeBitDistribution(e);t+=r.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 i of t)for(let r=0;r<=e.length-i.length;r++){let n=!0;for(let a=0;a>>0).toString(2).split("1").length-1;let r=(i-t)/i,n=t/i,a=Math.abs(.5-n);return{score:Math.max(0,8-a*16),zeroRatio:r,oneRatio:n,deviation:a}}_detectPeriodicity(e){if(e.length<16)return 0;let t=0;for(let i=2;i<=e.length/2;i++){let r=0,n=0;for(let a=0;a0){let a=r/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 i=[];for(let r=0;r<=e.length-8;r++){let n=e.slice(r,r+8),a={};for(let c of n)a[c]=(a[c]||0)+1;let o=0;for(let c of Object.values(a)){let l=c/8;o-=l*Math.log2(l)}i.push(o)}return i}_detectSuspiciousIVPatterns(e){let t=e.every(n=>n===0),i=e.every(n=>n===255);if(t||i)return!0;let r=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((l,h)=>l===c[h]))return!0}return!1}async _cleanupOldIVs(){let e=Date.now(),t=18e5,i=0,r=[];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)r.push(o),i++,r.length>=100&&(this._processCleanupBatch(r),r.length=0)}for(let[n,a]of this._ivTrackingSystem.ivHistory.entries())e-a.timestamp>t&&(r.push(n),i++,r.length>=100&&(this._processCleanupBatch(r),r.length=0));r.length>0&&this._processCleanupBatch(r);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 l of c)a.delete(l),this._ivTrackingSystem.usedIVs.delete(l),this._ivTrackingSystem.ivHistory.delete(l),i++}i>50&&await this._performNaturalCleanup(),i>0&&this._secureLog("debug",`Enhanced cleanup: ${i} old IVs removed`,{cleanedCount:i,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 i=t.map(n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("")),r=new Set(i);r.size<95&&(this._ivTrackingSystem.rngValidation.weakRngDetected=!0,this._secureLog("error","CRITICAL: Weak RNG detected in validation test",{uniqueIVs:r.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,i){let r=this[`_${e}Mutex`];if(!r){this._secureLog("error",`Mutex '${e}' not found during timeout handling`);return}if(r.lockId!==t){this._secureLog("warn",`Timeout for different operation ID on mutex '${e}'`,{expectedOperationId:t,actualLockId:r.lockId,locked:r.locked});return}if(!r.locked){this._secureLog("warn",`Timeout for already unlocked mutex '${e}'`,{operationId:t});return}try{let n=r.lockTime?Date.now()-r.lockTime:0;this._secureLog("warn",`Mutex '${e}' auto-released due to timeout`,{operationId:t,lockDuration:n,timeout:i,queueLength:r.queue.length}),r.locked=!1,r.lockId=null,r.lockTimeout=null,r.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(i=>{let r=this[`_${i}Mutex`];if(!r){t++,this._secureLog("error",`Mutex '${i}' not found after emergency unlock`);return}r.locked&&(t++,this._secureLog("error",`Mutex '${i}' still locked after emergency unlock`,{lockId:r.lockId,lockTime:r.lockTime})),r.lockId!==null&&(t++,this._secureLog("error",`Mutex '${i}' still has lock ID after emergency unlock`,{lockId:r.lockId})),r.lockTimeout!==null&&(t++,this._secureLog("error",`Mutex '${i}' still has timeout after emergency unlock`)),r.queue.length>0&&(t++,this._secureLog("error",`Mutex '${i}' still has queue items after emergency unlock`,{queueLength:r.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(i=>{let r=`_${i}Mutex`,n=this[r];n?e.mutexes[i]={locked:n.locked,lockId:n.lockId,queueLength:n.queue.length,hasTimeout:!!n.lockTimeout}:e.mutexes[i]={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 i=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdhKeyPair.publicKey)),r=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdsaKeyPair.publicKey));if(!i||!r)throw new Error("Failed to generate key fingerprints");this._secureLog("info","Generated unique key pairs for MITM protection",{operationId:e,hasECDHFingerprint:!!i,hasECDSAFingerprint:!!r,fingerprintLength:i.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 m=this._extractDTLSFingerprintFromSDP(o.sdp);this.expectedDTLSFingerprint=m,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:m,context:"offer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${m}`,"system")}catch(m){this._secureLog("error","Failed to extract DTLS fingerprint from offer",{error:m.message})}let c=Date.now(),l=await this.waitForIceGathering(),h=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),u=h.total;if(!l&&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:l}),this._logIceCandidateDiagnostics("offer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:l}),l||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.lengthm.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(m=>m.toString(16).padStart(2,"0")).join(""),this._storePendingOfferContext();let S={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},w=Date.now(),g={t:"offer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:w,e:n,d:a,sl:this.sessionSalt,si:this.sessionId,ci:this.connectionId,vc:this.verificationCode,ac:p,slv:"MAX",dr:s.RATCHET_VERSION,kf:{e:i.substring(0,12),d:r.substring(0,12)}};try{let m=this.validateEnhancedOfferData(g)}catch(m){throw new Error(`Offer package validation error: ${m.message}`)}if(this._secureLog("info","Enhanced secure offer created successfully",{operationId:e,version:g.version,hasECDSA:!0,hasMutualAuth:!0,hasSessionId:!!g.sessionId,securityLevel:S.level,timestamp:w,capabilitiesCount:10}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"offer",timestamp:w,securityLevel:S.level,operationId:e}})),s.SBQ2_SEND_ENABLED){this._latchHandshakeMode("sbq2");let{text:m}=await this._sbq2BuildDescriptor(le.OFFER);return{t:"offer",sbq2:m}}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(i){throw this.securityFeatures=t,this._secureLog("error","Security features update failed, rolled back",{errorType:i.constructor.name}),i}}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 i=Ki(String(e.sbq2)),r=this._sbq2AdoptRemoteDescriptor(i,le.OFFER),{sdp:n}=Di(r);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(r.fingerprint,l=>l.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 l=>new Uint8Array(await crypto.subtle.digest("SHA-256",l)),{text:c}=await this._sbq2BuildDescriptor(le.ANSWER,{bindingTag:await Fi(o,i)});return this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:Date.now(),operationId:t}})),{t:"answer",sbq2:c}}catch(i){throw this._secureLog("error","SBQ2 answer creation failed",{operationId:t,errorType:i?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),i}},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 i=e.ts||e.timestamp,r=e.v||e.version;if(!i||!r)throw new Error("Missing required security fields in offer data \u2013 possible MITM attack");let n=Date.now()-i,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=r;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 l=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);this._secureLog("info","Session salt validated successfully",{operationId:t,saltLength:this.sessionSalt.length,saltFingerprint:l.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 x=e.d||e.ecdsaPublicKey;u=await crypto.subtle.importKey("spki",new Uint8Array(x.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"])}catch(x){this._throwSecureError(x,"ecdsa_key_import")}let p;try{let x=e.e||e.ecdhPublicKey;p=await window.EnhancedSecureCryptoUtils.importSignedPublicKey(x,u,"ECDH")}catch(x){this._secureLog("error","Failed to import signed ECDH public key",{operationId:t,errorType:x.constructor.name}),this._throwSecureError(x,"ecdh_key_import")}if(!(p instanceof CryptoKey))throw this._secureLog("error","Peer ECDH public key is not a CryptoKey",{operationId:t,publicKeyType:typeof p,publicKeyAlgorithm:p?.algorithm?.name}),new Error("Peer ECDH public key is not a valid CryptoKey");this.peerPublicKey=p;let S;try{this._secureLog("debug","About to call deriveSharedKeys",{operationId:t,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof p,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:p?.algorithm?.name}),S=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,p,this.sessionSalt),this._secureLog("debug","deriveSharedKeys completed successfully",{operationId:t,hasMessageKey:!!S.messageKey,hasMacKey:!!S.macKey,hasPfsKey:!!S.pfsKey,hasMetadataKey:!!S.metadataKey,hasFingerprint:!!S.fingerprint})}catch(x){this._secureLog("error","Failed to derive shared keys",{operationId:t,errorType:x.constructor.name,errorMessage:x.message,errorStack:x.stack,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof p,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:p?.algorithm?.name}),this._throwSecureError(x,"key_derivation")}if(await this._setEncryptionKeys(S.messageKey,S.macKey,S.metadataKey,S.fingerprint),await this._initializeRatchet(S,!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 w;if(e.authChallenge)try{w=await window.EnhancedSecureCryptoUtils.createAuthProof(e.authChallenge,this.ecdsaKeyPair.privateKey,this.ecdsaKeyPair.publicKey)}catch(x){this._secureLog("error","Failed to create authentication proof",{operationId:t,errorType:x.constructor.name}),this._throwSecureError(x,"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(x){this._secureLog("warn","Could not extract peer DTLS fingerprint from offer",{error:x.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(x){this._secureLog("error","Failed to set remote description",{error:x.message,operationId:t}),this._throwSecureError(x,"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(x){this._throwSecureError(x,"webrtc_create_answer")}try{await this.peerConnection.setLocalDescription(g)}catch(x){this._throwSecureError(x,"webrtc_local_description")}try{let x=this._extractDTLSFingerprintFromSDP(g.sdp);this.expectedDTLSFingerprint=x,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:x,context:"answer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${x}`,"system")}catch(x){this._secureLog("error","Failed to extract DTLS fingerprint from answer",{error:x.message})}try{let x=this._extractDTLSFingerprintFromSDP(e.s||e.sdp),ue=this.expectedDTLSFingerprint,ne=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(ne,ue,x),this._setSASMaterialReady(ue,x)}catch(x){throw this._secureLog("error","SAS computation failed in createSecureAnswer (Answer side)",{errorType:x?.constructor?.name||"Unknown"}),new Error(`SAS computation failed: ${x.message}`)}let m=Date.now(),I=await this.waitForIceGathering(),b=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),D=b.total;if(!I&&D===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(D>0?"info":"warn","ICE candidates captured for answer export",{candidateSummary:b,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-m,iceGatheringCompleted:I}),this._logIceCandidateDiagnostics("answer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-m,iceGatheringCompleted:I}),I||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the response. Connectivity may still fail on restrictive networks.","system"),D===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 _=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),R=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!_||typeof _!="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(!_.keyData||!_.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!_.keyData,hasSignature:!!_.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!R||typeof R!="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(!R.keyData||!R.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!R.keyData,hasSignature:!!R.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");let E={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},C=Date.now(),M={t:"answer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:C,e:_,d:R,ap:w,slv:"MAX",dr:s.RATCHET_VERSION,sc:{sf:l.substring(0,12),kd:!0,ma:!0}},v=M.s||M.sdp,q=M.e||M.ecdhPublicKey,O=M.d||M.ecdsaPublicKey;if(!v||!q||!O)throw new Error("Generated answer package is incomplete");return this._secureLog("info","Enhanced secure answer created successfully",{operationId:t,version:M.version,hasECDSA:!0,hasMutualAuth:!!w,hasSessionConfirmation:!!M.sessionConfirmation,securityLevel:E.level,timestamp:C,processingTime:C-e.timestamp}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:C,securityLevel:E.level,operationId:t}})),setTimeout(async()=>{try{let x=await this.calculateAndReportSecurityLevel();x&&(this.notifySecurityUpdate(),this._secureLog("info","Post-connection security level calculated",{operationId:t,level:x.level}))}catch(x){this._secureLog("error","Error calculating post-connection security",{operationId:t,errorType:x.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(),M}catch(i){throw this._secureLog("error","Enhanced secure answer creation failed in critical section",{operationId:t,errorType:i.constructor.name,errorMessage:i.message,phase:this._determineAnswerErrorPhase(i),offerAge:e?.timestamp?Date.now()-e.timestamp:"unknown"}),this._cleanupFailedAnswerCreation(),this.onStatusChange("disconnected"),this.onAnswerError&&(i.message.includes("too old")||i.message.includes("replay")?this.onAnswerError("replay_attack",i.message):i.message.includes("MITM")||i.message.includes("signature")?this.onAnswerError("security_violation",i.message):i.message.includes("validation")||i.message.includes("format")?this.onAnswerError("invalid_format",i.message):this.onAnswerError("general_error",i.message)),i}},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,i,r){return this._withMutex("keyOperation",async n=>{if(this._secureLog("info","Setting encryption keys with mutex",{operationId:n}),!(e instanceof CryptoKey)||!(t instanceof CryptoKey)||!(i instanceof CryptoKey))throw new Error("Invalid key types provided");if(!r||typeof r!="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=i,this.keyFingerprint=r,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(),i=Ki(String(e.sbq2)),r=Li(i);if(r.type!==le.ANSWER)throw new Error("That code is an invitation, not a response to one.");if(!r.commitment)throw new Error("The response carries no key commitment");let a=await Fi(async l=>new Uint8Array(await crypto.subtle.digest("SHA-256",l)),t.localDescriptor),o=0;for(let l=0;ll.toString(16).padStart(2,"0").toUpperCase()).join(":");let{sdp:c}=Di(r);await this.peerConnection.setRemoteDescription({type:"answer",sdp:c}),this._secureLog("info","SBQ2 answer accepted; awaiting in-band key exchange",{bytes:i.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,i=e.type==="enhanced_secure_answer"&&e.sdp;if(!t&&!i)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 r=e.v||e.version;if(r!==s.PROTOCOL_VERSION)throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${r||"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 l=Date.now()-e.timestamp;if(l>36e5)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Answer data is too old - possible replay attack",{answerAge:l,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");r!==s.PROTOCOL_VERSION&&window.EnhancedSecureCryptoUtils.secureLog.log("warn","Incompatible protocol version in answer",{expectedVersion:s.PROTOCOL_VERSION,receivedVersion:r});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 p=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);if(window.EnhancedSecureCryptoUtils.secureLog.log("info","Session salt integrity verified",{saltFingerprint:p.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(g=>g.toString(16).padStart(2,"0")).join(""));let S=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,u,this.sessionSalt);if(this.encryptionKey=S.messageKey,this.macKey=S.macKey,this.metadataKey=S.metadataKey,this.keyFingerprint=S.fingerprint,await this._initializeRatchet(S,!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),m=this.expectedDTLSFingerprint,I=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(I,m,g),this._setSASMaterialReady(m,g),this.pendingSASCode=this.verificationCode,this._secureLog("info","SAS verification code generated for MITM protection (Offer side)",{sasCode:this.verificationCode,localFP:m.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 w=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:w?.length||0,usingCompactSDP:!e.sdp&&!!e.s}),await this.peerConnection.setRemoteDescription({type:"answer",sdp:w}),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(),i=this.verificationCode.replace(/[-\s]/g,"").toUpperCase();return t.length!==i.length?!1:window.EnhancedSecureCryptoUtils.constantTimeCompare(t,i)}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,i=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(i){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 i=`Input validation failed: ${t.errors.join(", ")}`;throw this._secureLog("error","Input validation failed in sendSecureMessage",{errors:t.errors,messageType:typeof e}),new Error(i)}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 i=>{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 r=typeof t.sanitizedData=="string"?t.sanitizedData:JSON.stringify(t.sanitizedData),n=window.EnhancedSecureCryptoUtils.sanitizeMessage(r),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:l,ciphertext:h}=await this._ratchet.encrypt(n);c={type:s.MESSAGE_TYPES.RATCHET_MESSAGE,h:l,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:i,messageLength:n.length,keyVersion:this.currentKeyVersion})}catch(r){throw this._secureLog("error","Secure message sending failed",{operationId:i,errorType:r.constructor.name}),r.message.includes("Session expired")?new Error("Session expired. Please enter your password to unlock."):r.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):r.message.includes("Connection lost")?new Error("Connection lost. Please check your Internet connection."):r.message.includes("Rate limit exceeded")?new Error("Message rate limit exceeded. Please wait before sending another message."):r}},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&&i>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:i,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(r){this._secureLog("warn","\u26A0\uFE0F ICE restart attempt failed to send",{errorType:r?.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,i=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()},i),this._trackActiveTimer(e.retryTimer)}async _sendIceRestartOffer(){let e=this.peerConnection;if(!e)return;if(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 i=this._currentRemoteDtlsFingerprint();if(!i)throw new Error(`Cannot verify peer identity for ${t}`);let r=this._extractDTLSFingerprintFromSDP(e);await this._validateDTLSFingerprint(r,i,t)}async _handleIceRestartSignal(e,t){let i=s.MESSAGE_TYPES,r=this.peerConnection;if(r)switch(this._noteInboundActivity(),e){case i.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 i.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",await r.setRemoteDescription({type:"offer",sdp:t.sdp});let n=await r.createAnswer();await r.setLocalDescription(n),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:i.ICE_RESTART_ANSWER,sdp:r.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart answer sent");return}case i.ICE_RESTART_ANSWER:{if(!t.sdp)return;if(r.signalingState!=="have-local-offer"){this._secureLog("warn","\u26A0\uFE0F Ignoring restart answer in unexpected state",{signalingState:r.signalingState});return}await this._assertSameRemoteIdentity(t.sdp,"ice_restart_answer"),await r.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(i=>{let r=this.peerConnection;if(!r){i(!1);return}if(r.iceGatheringState==="complete"){i(!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}},l=u=>{if(!n){n=!0,a&&(clearTimeout(a),this._untrackActiveTimer?.(a)),o&&(clearTimeout(o),this._untrackActiveTimer?.(o));try{r.removeEventListener("icegatheringstatechange",h)}catch{}i(u)}},h=()=>{this.peerConnection?.iceGatheringState==="complete"&&l(!0)};r.addEventListener("icegatheringstatechange",h),a=setTimeout(()=>{c()&&l(!1)},e),this._trackActiveTimer?.(a),o=setTimeout(()=>l(!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,i=this.dataChannel?.readyState==="open",r=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(i){t===2&&window.EnhancedSecureCryptoUtils.secureLog.log("error","Failed to send disconnect notification",{error:i.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",i=t==="user_disconnect"?"manually disconnected.":"connection lost.";this.peerDisconnectNotificationSent||(this.peerDisconnectNotificationSent=!0,this.deliverMessageToUI(`Peer ${i}`,"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 r=this._peerDisconnectCleanupTimer;this._peerDisconnectCleanupTimer=null,this._untrackActiveTimer(r),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(i=>setTimeout(i,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(i){throw this._secureLog("error","File transfer error:",{errorType:i?.constructor?.name||"Unknown"}),i.message.includes("Connection not ready")?new Error("Connection not ready for file transfer. Check connection status."):i.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):i.message.includes("Transfer timeout")?new Error("File transfer timeout. Check connection and try again."):i}}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,i,r=null){this.onFileProgress=e,this.onFileReceived=t,this.onFileError=i,this.onIncomingFileRequest=r,this.fileTransferSystem&&(this.fileTransferSystem.onProgress=e,this.fileTransferSystem.onFileReceived=t,this.fileTransferSystem.onError=i,this.fileTransferSystem.onIncomingFileRequest=r)}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(r){this._secureLog("warn","File transfer initialization failed during session activation:",{details:r.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:i=t.signal,timeout:r=6e3}=e;i&&i!==t.signal&&i.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,l=new Promise((h,u)=>{let p=()=>{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(p,o)};p()});if(await Promise.race([l,new Promise((h,u)=>setTimeout(()=>u(new Error(`Global timeout after ${r}ms`)),r))]),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((r,n)=>r===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"),i=this.remoteMediaStream?this.remoteMediaStream.getTracks():[];i.length===t.length&&i.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 i of this._callStateListeners)try{i(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 i=this.peerConnection,r=t.getAudioTracks()[0]||null,n=t.getVideoTracks()[0]||null;return r&&(this._callAudioSender?await this._callAudioSender.replaceTrack(r):this._callAudioSender=i.addTrack(r,t)),n&&(this._callVideoSender?await this._callVideoSender.replaceTrack(n):this._callVideoSender=i.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(r=>r.sender&&r.sender===this._callAudioSender);t&&Hr(t);let i=e.find(r=>r.sender&&r.sender===this._callVideoSender);i&&Yr(i)}catch{}}_mungeCallSdp(e){try{let t=bi(e,st.opusFmtp);return t=Br(t,Nr),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:bi(e.sdp,st.opusFmtp)});return}catch{await t.setLocalDescription(e)}}}async _applyCallSenderParams(){try{this._callAudioSender&&await $r(this._callAudioSender,{}),this._callVideoSender&&await Xr(this._callVideoSender,{})}catch{}}_startAdaptation(){if(!(this._adaptationController||!this.peerConnection))try{this._adaptationController=new Pt(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 i=e?.name||"",r=t?"camera/microphone":"microphone",n,a;i==="NotAllowedError"?(a="permission_denied",n=`\u26A0\uFE0F Call not started \u2014 ${r} 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.`):i==="NotFoundError"||i==="OverconstrainedError"?(a="device_not_found",n=`\u26A0\uFE0F Call not started \u2014 no ${r} found on this device.`):i==="NotReadableError"||i==="AbortError"?(a="device_busy",n=`\u26A0\uFE0F Call not started \u2014 your ${r} is in use by another app. Close it and try again.`):(a="media_failed",n=`\u26A0\uFE0F Call not started \u2014 could not access ${r}${i?" ("+i+")":""}.`);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 i=await this.peerConnection.createOffer();await this._setLocalMunged(i),this._callMakingOffer=!1,await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:t,withVideo:e,sdp:this.peerConnection.localDescription.sdp})}catch(i){this._callMakingOffer=!1,this._secureLog("error","\u274C startCall failed",{errorType:i?.constructor?.name});let r=this._notifyCallMediaError(i,e);throw await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:r}),i}}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 i=await this.peerConnection.createAnswer();await this._setLocalMunged(i),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 i=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:i})}}}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(i=>{i.enabled=!1}),this._updateCallState({cameraEnabled:!1});return}let t=this.localMediaStream?.getVideoTracks?.()||[];if(t.length){t.forEach(i=>{i.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],i=this.localMediaStream.getVideoTracks()[0];if(i){this.localMediaStream.removeTrack(i);try{i.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 i=s.MESSAGE_TYPES;switch(e){case i.CALL_OFFER:{await this._onIncomingCallOffer(t);return}case i.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(r){this._secureLog("warn","\u26A0\uFE0F Failed to apply call answer",{errorType:r?.constructor?.name})}return}case i.CALL_ICE:{try{t.candidate&&await this.peerConnection.addIceCandidate(t.candidate)}catch{}return}case i.CALL_DECLINE:{await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1,error:"declined"});return}case i.CALL_END:{await this.endCall(!1);return}default:return}}},Bt=class{constructor(e=null){this._keyStore=new WeakMap,this._keyMetadata=new Map,this._keyReferences=new Map,this._masterKeyManager=e||new $t,this._persistentStorage=new Ui(this._masterKeyManager),this._setupMasterKeyCallbacks(),setTimeout(()=>{this.validateStorageIntegrity()||this._secureLog("error","CRITICAL: Key storage integrity check failed")},100)}_secureLog(e,t,i={}){try{let r=typeof window<"u"&&window.EnhancedSecureCryptoUtils?.secureLog||null;if(r&&typeof r.log=="function"){r.log(e,`[KeyStorage] ${t}`,i);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,i={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");try{return t.extractable?(await this._persistentStorage.storeExtractableKey(e,t,i),this._keyReferences.set(e,t),this._keyMetadata.set(e,{...i,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0,encrypted:!0}),!0):(this._keyReferences.set(e,t),this._keyMetadata.set(e,{...i,created:Date.now(),lastAccessed:Date.now(),extractable:!1,persistent:!1,encrypted:!1}),!0)}catch(r){return this._secureLog("error","Failed to store key securely",{errorType:r?.constructor?.name||"Unknown"}),!1}}async retrieveKey(e){try{if(this._keyReferences.has(e)){let i=this._keyMetadata.get(e);return i&&(i.lastAccessed=Date.now()),this._keyReferences.get(e)}let t=await this._persistentStorage.retrieveKey(e);if(t){this._keyReferences.set(e,t);let i=this._keyMetadata.get(e);return this._keyMetadata.set(e,{...i,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,r=new TextEncoder().encode(t);await this._ensureMasterKeyUnlocked();let{encryptedData:n,iv:a}=await this._masterKeyManager.encryptBytes(r),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),i=e.slice(12);await this._ensureMasterKeyUnlocked();let r=await this._masterKeyManager.decryptBytes(i,t),a=new TextDecoder().decode(r);try{return JSON.parse(a)}catch{return r}}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,i]of this._keyMetadata.entries())i.extractable===!0&&i.encrypted!==!0&&e.push({keyId:t,type:"EXTRACTABLE_KEY_NOT_ENCRYPTED",metadata:i}),i.extractable===!1&&i.encrypted===!0&&e.push({keyId:t,type:"NON_EXTRACTABLE_KEY_ENCRYPTED",metadata:i});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,i])=>({id:t,created:i.created,lastAccessed:i.lastAccessed,age:Date.now()-i.created,persistent:i.persistent||!1})),persistent:e}}async listAllKeys(){try{let e=Array.from(this._keyMetadata.entries()).map(([r,n])=>({keyId:r,...n,location:"memory"})),i=(await this._persistentStorage.listStoredKeys()).map(r=>({...r,location:"persistent"}));return{memoryKeys:e,persistentKeys:i,totalCount:e.length+i.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}}},Ht=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 i=indexedDB.open(this.dbName,this.version);i.onerror=()=>{t(new Error(`Failed to open IndexedDB: ${i.error}`))},i.onsuccess=()=>{this.db=i.result,e()},i.onupgradeneeded=r=>{let n=r.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,i,r,n,a,o={}){if(!this.db)throw new Error("Database not initialized");let c=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite"),l={keyId:e,encryptedData:Array.from(new Uint8Array(t)),iv:Array.from(new Uint8Array(i)),algorithm:r,usages:n,type:a},h={keyId:e,...o};return new Promise((u,p)=>{let S=c.objectStore(this.KEYS_STORE).put(l),w=c.objectStore(this.METADATA_STORE).put(h);c.oncomplete=()=>u(),c.onerror=()=>p(new Error(`Failed to store key: ${c.error}`))})}async getEncryptedKey(e){if(!this.db)throw new Error("Database not initialized");let i=this.db.transaction([this.KEYS_STORE],"readonly").objectStore(this.KEYS_STORE);return new Promise((r,n)=>{let a=i.get(e);a.onsuccess=()=>{let o=a.result;o&&(o.encryptedData=new Uint8Array(o.encryptedData),o.iv=new Uint8Array(o.iv)),r(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 r=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((n,a)=>{let o=r.get(e);o.onsuccess=()=>{let c=o.result;if(c){Object.assign(c,t);let l=r.put(c);l.onsuccess=()=>n(),l.onerror=()=>a(new Error(`Failed to update metadata: ${l.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 i=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((r,n)=>{let a=i.get(e);a.onsuccess=()=>r(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 i=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((r,n)=>{let a=i.put(e);a.onsuccess=()=>r(),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((i,r)=>{let n=t.objectStore(this.KEYS_STORE).delete(e),a=t.objectStore(this.METADATA_STORE).delete(e);t.oncomplete=()=>i(),t.onerror=()=>r(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((i,r)=>{let n=t.getAll();n.onsuccess=()=>i(n.result),n.onerror=()=>r(new Error(`Failed to list keys: ${n.error}`))})}async storeMasterSalt(e){if(!this.db)throw new Error("Database not initialized");let i=this.db.transaction([this.SALT_STORE],"readwrite").objectStore(this.SALT_STORE),r={id:"master_salt",salt:Array.from(new Uint8Array(e))};return new Promise((n,a)=>{let o=i.put(r);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((i,r)=>{let n=t.get("master_salt");n.onsuccess=()=>{let a=n.result;i(a?new Uint8Array(a.salt):null)},n.onerror=()=>r(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,i)=>{let r=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=()=>i(new Error(`Failed to clear database: ${e.error}`))})}close(){this.db&&(this.db.close(),this.db=null)}},Ui=class{constructor(e,t=null){this._masterKeyManager=e,this._indexedDB=t||new Ht,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,i={}){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 r=await crypto.subtle.exportKey("jwk",t),{encryptedData:n,iv:a}=await this._encryptKeyData(r),o=await this._encryptMetadata({...i,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(r,t.algorithm,t.usages);return this._keyReferences.set(e,c),!0}catch(r){throw new Error(`Failed to store extractable key: ${r.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 i=await this._decryptKeyData(t.encryptedData,t.iv),r=await this._importAsNonExtractable(i,t.algorithm,t.usages);return this._keyReferences.set(e,r),await this._updateEncryptedMetadata(e,{lastAccessed:Date.now()}),r}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 i of e){let r=await this._readMetadataWithMigration(i);r&&t.push({keyId:i.keyId,...r})}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),i=new TextEncoder().encode(t);return await this._ensureMasterKeyUnlocked(),await this._masterKeyManager.encryptBytes(i)}async _decryptKeyData(e,t){await this._ensureMasterKeyUnlocked();let i=await this._masterKeyManager.decryptBytes(e,t),r=new TextDecoder().decode(i);return JSON.parse(r)}async _encryptMetadata(e){let t=new TextEncoder().encode(JSON.stringify(e));await this._ensureMasterKeyUnlocked();let{encryptedData:i,iv:r}=await this._masterKeyManager.encryptBytes(t);return{metadataVersion:1,encryptedMetadata:Array.from(i),metadataIv:Array.from(r)}}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,...i}=e,r={keyId:t,...await this._encryptMetadata(i)};return await this._indexedDB.putKeyMetadataRecord(r),i}async _updateEncryptedMetadata(e,t){let i=await this._indexedDB.getKeyMetadataRecord(e);if(!i)throw new Error(`Key metadata not found: ${e}`);let r=await this._readMetadataWithMigration(i);if(!r)throw new Error(`Key metadata corrupted: ${e}`);await this._indexedDB.putKeyMetadataRecord({keyId:e,...await this._encryptMetadata({...r,...t})})}async _importAsNonExtractable(e,t,i){return await crypto.subtle.importKey("jwk",e,t,!1,i)}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,i)=>Math.max(t,i.lastAccessed||0),0)}}catch(e){return{totalKeys:0,memoryKeys:this._keyReferences.size,persistentKeys:0,lastAccessed:0,error:e.message}}}},$t=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 Ht,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 i=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"},i,{name:"AES-GCM",length:256},!1,["encrypt","decrypt","wrapKey","unwrapKey"])}catch(i){throw new Error(`Key derivation failed: ${i.message}`)}}async _requestPassword(e=!1){if(!this._onPasswordRequired)throw new Error("Password callback not set");return new Promise((t,i)=>{this._onPasswordRequired(e,r=>{r?t(r):i(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)),i=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return{encryptedData:new Uint8Array(i),iv:t}}async decryptBytes(e,t){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let i=await crypto.subtle.decrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return new Uint8Array(i)}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 Fn=hr(vn());var kn="6.7.3";var zi=()=>{if(Ke.length<2)return null;let[s,e]=React.useState(!1),t=React.useRef(null),i=typeof window<"u"?window.location.pathname:"/",r=Kr({pathname:i,active:Ge()}),n=r.find(c=>c.isCurrent)||r[0];React.useEffect(()=>{if(!s)return;let c=h=>{t.current&&!t.current.contains(h.target)&&e(!1)},l=h=>{h.key==="Escape"&&e(!1)};return document.addEventListener("pointerdown",c),document.addEventListener("keydown",l),()=>{document.removeEventListener("pointerdown",c),document.removeEventListener("keydown",l)}},[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(255,255,255,0.07)",background:s?"rgba(255,255,255,0.06)":"rgba(255,255,255,0.02)",color:"#cfcfd4",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(255,255,255,0.08)",background:"#161618",boxShadow:"0 14px 34px rgba(0,0,0,0.45)",maxHeight:"min(62vh, 420px)",overflowY:"auto",overscrollBehavior:"contain"}},r.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:()=>Pr(c.code),style:{display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",fontSize:"13px",fontWeight:c.isCurrent?600:500,color:c.isCurrent?"#e8e8eb":"#9a9aa2",background:c.isCurrent?"rgba(255,255,255,0.06)":"transparent",textDecoration:"none",whiteSpace:"nowrap"}},[React.createElement("span",{key:"a",style:{fontSize:"11px",fontWeight:700,letterSpacing:"0.4px",color:"#6b6b73",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=zi;var Ta=`v${kn}`,Ca=({status:s,fingerprint:e,verificationCode:t,onDisconnect:i,isConnected:r,securityLevel:n,webrtcManager:a})=>{let[o,c]=React.useState(null),[l,h]=React.useState(0),[u,p]=React.useState(!1),[S,w]=React.useState(0),[g,m]=React.useState("unknown");React.useEffect(()=>{let U=!1,H=0,A=async()=>{let K=Date.now();if(!(K-H<1e4)&&!U){U=!0,H=K;try{if(!a||!r)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 X=o?.score||0,Se=W.score||0;X!==Se||!o?(c(W),h(K)):window.DEBUG_MODE}}catch{}finally{U=!1}}};if(r&&(A(),!o||o.score<50)){let K=setInterval(()=>{!o||o.score<50?A():clearInterval(K)},5e3);setTimeout(()=>clearInterval(K),3e4)}let F=setInterval(A,3e4);return()=>clearInterval(F)},[a,r]),React.useEffect(()=>{let U=A=>{setTimeout(()=>{h(0)},100)},H=A=>{A.detail&&A.detail.securityData&&(c(A.detail.securityData),h(Date.now()))};return document.addEventListener("security-level-updated",U),document.addEventListener("real-security-calculated",H),window.forceHeaderSecurityUpdate=A=>{A&&window.EnhancedSecureCryptoUtils?window.EnhancedSecureCryptoUtils.calculateSecurityLevel(A).then(F=>{F&&F.isRealData!==!1&&(c(F),h(Date.now()))}).catch(F=>{}):h(0)},()=>{document.removeEventListener("security-level-updated",U),document.removeEventListener("real-security-calculated",H)}},[]),React.useEffect(()=>{p(!0),w(0),m("premium")},[]),React.useEffect(()=>{p(!0),w(0),m("premium")},[]),React.useEffect(()=>{let U=K=>{p(!0),w(0),m("premium")},H=()=>{c(null),h(0),p(!1),w(0),m("unknown")},A=()=>{c(null),h(0)},F=()=>{c(null),h(0),p(!1),w(0),m("unknown")};return document.addEventListener("force-header-update",U),document.addEventListener("peer-disconnect",A),document.addEventListener("connection-cleaned",H),document.addEventListener("disconnected",F),()=>{document.removeEventListener("force-header-update",U),document.removeEventListener("peer-disconnect",A),document.removeEventListener("connection-cleaned",H),document.removeEventListener("disconnected",F)}},[]);let I=async U=>{if(U&&(U.button===2||U.ctrlKey||U.metaKey)&&i&&typeof i=="function"){i();return}U.preventDefault(),U.stopPropagation();let H=null;if(a&&window.EnhancedSecureCryptoUtils)try{H=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(a)}catch{}if(!H&&!o){alert(f("sec.verificationWait"));return}let A=H||o;A||(A={level:"UNKNOWN",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:f("sec.verificationUnavailable"),isRealData:!1,passedChecks:0,totalChecks:0});let F=`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 Gt,this._secureKeyStorage=new Ht(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 Ht}_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)},n.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)}`,s=this._logCounts.get(i)||0;if(s>=this._maxLogCount)return;this._logCounts.set(i,s+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,s]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 s=="string"?t[i]=this._sanitizeString(s):t[i]=s;continue}if(typeof s=="boolean"||typeof s=="number")t[i]=s;else if(typeof s=="string")t[i]=this._sanitizeString(s);else if(s instanceof ArrayBuffer||s instanceof Uint8Array)t[i]=`[${s.constructor.name}( bytes)]`;else if(s&&typeof s=="object")try{t[i]=this._sanitizeLogData(s)}catch{t[i]="[RECURSIVE_SANITIZATION_FAILED]"}else t[i]=`[${typeof s}]`}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 s of e)t[s]=(t[s]||0)+1;let r=e.length,i=0;for(let s of Object.values(t)){let a=s/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],s="default";return t.includes("key")||t.includes("crypto")?s=e===this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC?"key_generation":"default":t.includes("connection")||t.includes("peer")?s=e===this._secureErrorHandler.errorCategories.NETWORK?"connection":"default":(t.includes("validation")||t.includes("format"))&&(s=e===this._secureErrorHandler.errorCategories.VALIDATION?"format":"default"),i[s]||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((s,a)=>s+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},s=e.map(a=>{try{return window.secureBitChat[a].bind(r)}catch{return null}}).filter(a=>a===null);if(s.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - method binding issues",{unboundMethods:s.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(s=>!this.securityFeatures[s]);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(s=>{this.securityFeatures[s]=!0,this._secureLog("warn",`\u26A0\uFE0F Forced enable critical: ${s} = true`)}));let r=Object.keys(this.securityFeatures).filter(s=>this.securityFeatures[s]),i=["hasEncryption","hasECDH","hasECDSA"].filter(s=>this.securityFeatures[s]);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,""),s=t.toLowerCase().replace(/:/g,"");if(i!==s)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 _=[];throw e||_.push("keyMaterialRaw"),new Error(`Missing required parameters for SAS computation: ${_.join(", ")}`)}let i=new TextEncoder,s=(_,I)=>{if(typeof _!="string"||_.trim().length===0)throw new Error(`Security error: ${I} must be a non-empty DTLS fingerprint string for SAS computation`);return _.trim().toLowerCase()},a=s(t,"localFP"),o=s(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 _=e.replace(/:/g,"").replace(/\s/g,""),I=new Uint8Array(_.length/2);for(let w=0;w<_.length;w+=2)I[w/2]=parseInt(_.substr(w,2),16);d=I.buffer}else throw new Error("Invalid keyMaterialRaw type");let u=await crypto.subtle.importKey("raw",d,"HKDF",!1,["deriveBits"]),h=i.encode("p2p-sas-v1"),m=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:c,info:h},u,64),p=new DataView(m),S=(p.getUint32(0)^p.getUint32(4))>>>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=Ss({role:e,ecdhSpki:await this._exportSpki(this.ecdhKeyPair.publicKey),ecdsaSpki:await this._exportSpki(this.ecdsaKeyPair.publicKey)}),i=await Vt(async a=>new Uint8Array(await crypto.subtle.digest("SHA-256",a)),t),s=this._sbq2State();return s.role=e,s.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 s=e===oe.OFFER?Ee.OFFER:Ee.ANSWER,{commitment:a}=await this._sbq2BuildLocalBlob(s),o=hs(i),c=fs({type:e,expiresAtMs:Date.now()+r,sdpFields:{...o,candidates:Lr(o.candidates)},commitment:a,...e===oe.ANSWER?{bindingTag:t}:{}}),d=this._sbq2State();return d.localDescriptor=c,this._secureLog("info","SBQ2 descriptor built",{type:e===oe.OFFER?"offer":"answer",bytes:c.length,candidates:Lr(o.candidates).length}),{bytes:c,text:gs(c)}}_sbq2AdoptRemoteDescriptor(e,t){let r=Dr(e);if(r.type!==t)throw new Error(`expected an ${t===oe.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.")},n.SBQ2_KEY_EXCHANGE_TIMEOUT_MS);try{this.dataChannel.send(JSON.stringify({type:n.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=n.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 Ts(crypto.subtle,i,r.remoteCommitment);let s=_s(i),a=r.role===Ee.OFFER?Ee.ANSWER:Ee.OFFER;if(s.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",s.ecdhSpki,{name:"ECDH",namedCurve:"P-384"},!1,[]),r.peerEcdsaKey=await crypto.subtle.importKey("spki",s.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 s=i?.code||"handshake_failed",a=s==="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(s,a)}}async _sbq2CompleteExchange(){let e=this._sbq2State();if(e.keysDerived||!e.remoteBlob||!e.localBlob)return;this._peerSupportsRatchet=!0;let t=e.role===Ee.OFFER;e.transcript=bs({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 ws(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,Ur(e.transcript)));if(this.dataChannel.send(JSON.stringify({type:n.MESSAGE_TYPES.KEY_PROOF,sig:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(i.buffer)})),e.proofSent=!0,e.pendingProof){let s=e.pendingProof;e.pendingProof=null,await this._sbq2VerifyProof(s)}}async _sbq2VerifyProof(e){let t=this._sbq2State();if(t.proofVerified)return;if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},t.peerEcdsaKey,e,Ur(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 vs(crypto.subtle,{ecdhPrivateKey:this.ecdhKeyPair.privateKey,peerEcdhPublicKey:t.peerEcdhKey,transcript:t.transcript});let i=this.expectedDTLSFingerprint,s=this._peerDTLSFingerprint;i&&s&&this._setSASMaterialReady(i,s),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:n.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 s=new Ot;return await s.init({sharedSecret:r,sessionSalt:new Uint8Array(this.sessionSalt||[]),selfPrivateKey:this.ecdhKeyPair.privateKey,remotePublicKey:i,isInitiator:t}),this._ratchet=s,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),s={type:"encrypted_file_message",encryptedData:await window.EnhancedSecureCryptoUtils.encryptDataWithAAD(r,this.encryptionKey,t),aad:t,timestamp:Date.now(),keyFingerprint:this.keyFingerprint};return JSON.stringify(s)}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=[n.MESSAGE_TYPES.HEARTBEAT,n.MESSAGE_TYPES.VERIFICATION,n.MESSAGE_TYPES.VERIFICATION_RESPONSE,n.MESSAGE_TYPES.VERIFICATION_CONFIRMED,n.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,n.MESSAGE_TYPES.PEER_DISCONNECT,n.MESSAGE_TYPES.SECURITY_UPGRADE,n.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,n.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===n.MESSAGE_TYPES.FAKE||t.isFakeTraffic===!0}catch{return!1}return typeof e=="object"&&e!==null?e.type===n.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(n.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,s]of this._logCounts.entries())s>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"],s=r.toLowerCase();for(let a of i)if(s.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(s){this._secureLog("warn","\u26A0\uFE0F onComplete handler failed:",{details:s.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)),s=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),s=(t-e)/r;return e+i*s}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()},n.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&&[n.MESSAGE_TYPES.FILE_TRANSFER_START,n.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,n.MESSAGE_TYPES.FILE_CHUNK,n.MESSAGE_TYPES.CHUNK_CONFIRMATION,n.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,n.MESSAGE_TYPES.FILE_TRANSFER_ERROR,n.MESSAGE_TYPES.HEARTBEAT,n.MESSAGE_TYPES.VERIFICATION,n.MESSAGE_TYPES.VERIFICATION_RESPONSE,n.MESSAGE_TYPES.VERIFICATION_CONFIRMED,n.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,n.MESSAGE_TYPES.PEER_DISCONNECT,n.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,n.MESSAGE_TYPES.KEY_ROTATION_READY,n.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 s=JSON.parse(e);if(s.type&&[n.MESSAGE_TYPES.FILE_TRANSFER_START,n.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,n.MESSAGE_TYPES.FILE_CHUNK,n.MESSAGE_TYPES.CHUNK_CONFIRMATION,n.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,n.MESSAGE_TYPES.FILE_TRANSFER_ERROR,n.MESSAGE_TYPES.HEARTBEAT,n.MESSAGE_TYPES.VERIFICATION,n.MESSAGE_TYPES.VERIFICATION_RESPONSE,n.MESSAGE_TYPES.VERIFICATION_CONFIRMED,n.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,n.MESSAGE_TYPES.PEER_DISCONNECT,n.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,n.MESSAGE_TYPES.KEY_ROTATION_READY,n.MESSAGE_TYPES.SECURITY_UPGRADE].includes(s.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI (string): ${s.type}`);return}}catch{}let i=t==="received"?this._sanitizeIncomingChatMessage(e):e;if(this.onMessage){let s=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,s||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(n.SIZES.NESTED_ENCRYPTION_IV_SIZE,"nestedEncryption"),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this.nestedEncryptionKey,e),i=new Uint8Array(n.SIZES.NESTED_ENCRYPTION_IV_SIZE+r.byteLength);return i.set(t,0),i.set(new Uint8Array(r),n.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 s=this.generateFakeMessage();await this.sendFakeMessage(s);let a=this.fakeTrafficConfig.randomDecoyIntervals?this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minInterval,Math.min(this.fakeTrafficConfig.maxInterval,6e4)):this.fakeTrafficConfig.minInterval,o=Math.max(a,n.TIMEOUTS.FAKE_TRAFFIC_MIN_INTERVAL);this.fakeTrafficTimer=setTimeout(e,o)}catch(s){this._debugMode&&this._secureLog("error","\u274C Fake traffic generation failed:",{errorType:s?.constructor?.name||"Unknown"}),this.stopFakeTrafficGeneration()}},t=n.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:n.MESSAGE_TYPES.FAKE,pattern:t,data:Array.from(i).map(s=>s.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:n.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),s=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[s]=c,d.received++,this._secureLog("debug",`\u{1F4E6} Received chunk ${s+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 s=this.generateDecoyData(t);e.send(s);let a=this.decoyChannelConfig.randomDecoyIntervals?Math.random()*15e3+1e4:2e4;this.decoyTimers.set(t,setTimeout(()=>r(),a))}catch(s){this._debugMode&&this._secureLog("error",`\u274C Failed to send decoy data on "${t}"`,{error:s.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),s=new DataView(i);this.reorderingConfig.useSequenceNumbers&&s.setUint32(0,this.sequenceNumber++,!1),this.reorderingConfig.useTimestamps&&s.setUint32(4,Date.now(),!1),s.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(s,{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 s=new TextDecoder().decode(i.data),a=JSON.parse(s);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 s=this.findOldestPacket();if(s&&e-s.timestamp>t){this._secureLog("warn","\u26A0\uFE0F Packet ${oldestPacket.sequence} timed out, processing out of order");try{let a=new TextDecoder().decode(s.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(s.sequence),this.lastProcessedSequence=s.sequence;continue}}catch{}await this.processMessage(s.data),this.packetBuffer.delete(s.sequence),this.lastProcessedSequence=s.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)),s=new Uint8Array(t.length+r);return s.set(t,0),s.set(i,t.length),s.buffer}randomizeSize(e){let t=new Uint8Array(e),r=this.fingerprintMask.sizeVariation,i=Math.floor(t.length*r);if(i>t.length){let s=crypto.getRandomValues(new Uint8Array(i-t.length)),a=new Uint8Array(i);return a.set(t,0),a.set(s,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(s.buffer,a);m.setUint32(0,h.length+8,!1),m.setUint32(4,this.hashString(d),!1),s.set(h,a+8);let p=this.calculateChecksum(s.slice(a,a+8+h.length));new DataView(s.buffer,a+8+h.length).setUint32(0,p,!1),a+=8+h.length+4}return s.set(t,a),s.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 s=JSON.parse(r);if(s.type==="fake"||s.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Legacy fake message: ${s.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),s=JSON.parse(i);if(s.type==="fake"||s.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Nested fake message: ${s.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:n.MESSAGE_TYPES.MESSAGE_DELETE,messageId:e.slice(0,64)})}sendDeliveryReceipt(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:n.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 s=JSON.parse(r.sanitizedData);if(s.type&&s.type.startsWith("file_")){this._secureLog("debug","\u{1F4C1} File message detected - applying full encryption with AAD",{type:s.type});let a=this._createFileMessageAAD(s.type,s.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 s=this._createMessageAAD("message",{content:r.sanitizedData}),a={type:"message",data:r.sanitizedData,timestamp:Date.now(),aad:s};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),s=["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&&s.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===n.MESSAGE_TYPES.MESSAGE){this._secureLog("error","Rejected unencrypted frame in processMessage",{messageType:"message"});return}if(i.type&&n.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=n.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 s=["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&&s.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 s={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:s.type,stage:s.stage}),this.dataChannel.send(JSON.stringify(s))}catch(s){this._secureLog("warn","\u26A0\uFE0F Failed to send security upgrade notification to peer:",{details:s.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=n.LIMITS.MAX_KEY_AGE,r=0;for(let[i,s]of this.oldKeys.entries())e-s.timestamp>t&&(s.encryptionKey&&this._secureWipeMemory(s.encryptionKey,"pfs_cleanup_wipe"),s.macKey&&this._secureWipeMemory(s.macKey,"pfs_cleanup_wipe"),s.metadataKey&&this._secureWipeMemory(s.metadataKey,"pfs_cleanup_wipe"),s.encryptionKey=null,s.macKey=null,s.metadataKey=null,s.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-s.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 s of i){let a=String(s||"").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 s=JSON.parse(i.data),a=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(s.type&&a.includes(s.type)){if(!this._enforceVerificationGate("file_message_receive",!1)){this._secureLog("error","Dropped file message received before verification",{messageType:s.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(s);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(s);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:s.type?.constructor?.name||"Unknown"});return}if(s.type&&n.POST_VERIFICATION_CONTROL_TYPES.has(s.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:s.type});return}let o=n.MESSAGE_TYPES;if(s.type===o.MESSAGE_DELETE){let c=s?.data?.messageId??s?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelete?.(c.slice(0,64))}catch{}return}if(s.type===o.MESSAGE_RECEIPT){let c=s?.data?.messageId??s?.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(s.type)){try{await this._handleCallSignal(s.type,s.data||{})}catch{}return}if([o.ICE_RESTART_OFFER,o.ICE_RESTART_ANSWER,o.ICE_RESTART_REQUEST].includes(s.type)){try{await this._handleIceRestartSignal(s.type,s.data||{})}catch(c){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:c?.constructor?.name})}return}return}if(s.type===n.MESSAGE_TYPES.KEY_BLOB||s.type===n.MESSAGE_TYPES.KEY_PROOF){await this._sbq2HandleHandshakeFrame(s);return}if(s.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","sas_code","peer_disconnect","security_upgrade"].includes(s.type)){this.handleSystemMessage(s);return}if(s.type===n.MESSAGE_TYPES.RATCHET_MESSAGE){await this._processRatchetMessage(s);return}if(s.type==="enhanced_message"&&s.data){await this._processEnhancedMessageWithoutMutex(s);return}this._secureLog("error","Rejected unencrypted frame on the chat channel",{messageType:typeof s.type=="string"?s.type.slice(0,32):typeof s.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(s){this._secureLog("error","Failed to process message in onmessage:",{errorType:s?.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`,s=this[i];if(!s)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(s.lockId===t){this._secureLog("warn",`Mutex '${e}' already locked by same operation`,{operationId:t}),a();return}if(!s.locked)s.locked=!0,s.lockId=t,s.lockTime=Date.now(),this._secureLog("debug",`Mutex '${e}' acquired atomically`,{operationId:t,lockTime:s.lockTime}),s.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=s.queue.findIndex(h=>h.operationId===t);u!==-1&&(s.queue.splice(u,1),o(new Error(`Mutex acquisition timeout for '${e}'`)))},r)};s.queue.push(d),this._secureLog("debug",`Operation queued for mutex '${e}'`,{operationId:t,queueLength:s.queue.length,currentLockId:s.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 s=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:s,queueLength:i.queue.length}),this._processNextInQueue(e)}catch(s){throw this._secureLog("error","Error during mutex release queue processing",{mutexName:e,operationId:t,errorType:s.constructor.name,errorMessage:s.message}),i.locked=!1,i.lockId=null,i.lockTime=null,i.lockTimeout=null,s}}_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(s){this._secureLog("error","Failed to reject queue item",{originalError:i.message,rejectError:s.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 s=this[`_${e}Mutex`];if(!s)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:s?{locked:s.locked,lockId:s.lockId,queueLength:s.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),s.locked&&s.lockId===i&&(this._secureLog("error","Mutex release verification failed",{operationId:i,mutexName:e}),s.locked=!1,s.lockId=null,s.lockTimeout=null)}catch(o){this._secureLog("error","Error releasing mutex in finally block",{operationId:i,mutexName:e,releaseErrorType:o.constructor.name,releaseErrorMessage:o.message}),s.locked=!1,s.lockId=null,s.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 s=["locked","queue","lockId","lockTimeout"];for(let a of s)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(s,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(s){this._secureLog("error","Ephemeral ECDH key generation failed",{operationId:e,errorType:s.constructor.name}),this._throwSecureError(s,"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(s){this._secureLog("error","ECDSA key generation failed",{operationId:e,errorType:s.constructor.name}),this._throwSecureError(s,"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,s=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){s++,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:s,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(s)){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}),s}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]/s;i-=g*Math.log2(g)}r.shannon=i;let o=Math.max(...t)/s;r.min=-Math.log2(o);let c=0;for(let S=0;S<256;S++)if(t[S]>0){let g=t[S]/s;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/s)*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,s=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 s=this._detectPeriodicity(e);return t-=s*.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 s=!0;for(let a=0;a>>0).toString(2).split("1").length-1;let i=(r-t)/r,s=t/r,a=Math.abs(.5-s);return{score:Math.max(0,8-a*16),zeroRatio:i,oneRatio:s,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,s=0;for(let a=0;a0){let a=i/s;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 s of t)for(let a=0;a<=e.length-s.length;a++){let o=!0;for(let c=0;cs<3).length>e.length*.3}_calculateLocalEntropy(e){let r=[];for(let i=0;i<=e.length-8;i++){let s=e.slice(i,i+8),a={};for(let c of s)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(s=>s===0),r=e.every(s=>s===255);if(t||r)return!0;let i=0;for(let s=1;s=3)return!0;for(let s=2;s<=Math.floor(e.length/2);s++)for(let a=0;a<=e.length-s*2;a++){let o=e.slice(a,a+s),c=e.slice(a+s,a+s*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 s=Array.from(this._ivTrackingSystem.ivHistory.entries()),a=s.slice(0,s.length-this._ivTrackingSystem.maxIVHistorySize);for(let[o]of a)i.push(o),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0)}for(let[s,a]of this._ivTrackingSystem.ivHistory.entries())e-a.timestamp>t&&(i.push(s),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0));i.length>0&&this._processCleanupBatch(i);for(let[s,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 s=0;s<100;s++)t.push(crypto.getRandomValues(new Uint8Array(12)));let r=t.map(s=>Array.from(s).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 s=i.lockTime?Date.now()-i.lockTime:0;this._secureLog("warn",`Mutex '${e}' auto-released due to timeout`,{operationId:t,lockDuration:s,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(s){this._secureLog("error",`Critical error during mutex timeout handling for '${e}'`,{operationId:t,errorType:s.constructor.name,errorMessage:s.message});try{this._emergencyUnlockAllMutexes("timeoutHandler")}catch(a){this._secureLog("error","Emergency unlock failed during timeout handling",{originalError:s.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`,s=this[i];s?e.mutexes[r]={locked:s.locked,lockId:s.lockId,queueLength:s.queue.length,hasTimeout:!!s.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 s=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),a=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!s||typeof s!="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(!s.keyData||!s.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!s.keyData,hasSignature:!!s.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 _=this._extractDTLSFingerprintFromSDP(o.sdp);this.expectedDTLSFingerprint=_,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:_,context:"offer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${_}`,"system")}catch(_){this._secureLog("error","Failed to extract DTLS fingerprint from offer",{error:_.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.length_.toString(16).padStart(2,"0")).join(""),!this.sessionId||this.sessionId.length!==n.SIZES.SESSION_ID_LENGTH*2)throw new Error("Failed to generate valid session ID");this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(_=>_.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:n.PROTOCOL_VERSION,ts:S,e:s,d:a,sl:this.sessionSalt,si:this.sessionId,ci:this.connectionId,vc:this.verificationCode,ac:m,slv:"MAX",dr:n.RATCHET_VERSION,kf:{e:r.substring(0,12),d:i.substring(0,12)}};try{let _=this.validateEnhancedOfferData(g)}catch(_){throw new Error(`Offer package validation error: ${_.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}})),n.SBQ2_SEND_ENABLED){this._latchHandshakeMode("sbq2");let{text:_}=await this._sbq2BuildDescriptor(oe.OFFER);return{t:"offer",sbq2:_}}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=Nr(String(e.sbq2)),i=this._sbq2AdoptRemoteDescriptor(r,oe.OFFER),{sdp:s}=Pr(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:s}),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(oe.ANSWER,{bindingTag:await Kr(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 s=Date.now()-r,a=18e5;if(s>a)throw this._secureLog("error","Offer data is too old - possible replay attack",{operationId:t,offerAge:Math.round(s/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!==n.PROTOCOL_VERSION)throw this._secureLog("warn","Protocol version mismatch detected",{operationId:t,expectedVersion:n.PROTOCOL_VERSION,receivedVersion:o}),new Error(`Version mismatch: expected protocol ${n.PROTOCOL_VERSION}, received ${o}`);if(this.sessionSalt=e.sl||e.salt,this._peerSupportsRatchet=e.dr===n.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 M=e.d||e.ecdsaPublicKey;h=await crypto.subtle.importKey("spki",new Uint8Array(M.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"])}catch(M){this._throwSecureError(M,"ecdsa_key_import")}let m;try{let M=e.e||e.ecdhPublicKey;m=await window.EnhancedSecureCryptoUtils.importSignedPublicKey(M,h,"ECDH")}catch(M){this._secureLog("error","Failed to import signed ECDH public key",{operationId:t,errorType:M.constructor.name}),this._throwSecureError(M,"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(M){this._secureLog("error","Failed to derive shared keys",{operationId:t,errorType:M.constructor.name,errorMessage:M.message,errorStack:M.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(M,"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(M){this._secureLog("error","Failed to create authentication proof",{operationId:t,errorType:M.constructor.name}),this._throwSecureError(M,"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(M){this._secureLog("warn","Could not extract peer DTLS fingerprint from offer",{error:M.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(M){this._secureLog("error","Failed to set remote description",{error:M.message,operationId:t}),this._throwSecureError(M,"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(M){this._throwSecureError(M,"webrtc_create_answer")}try{await this.peerConnection.setLocalDescription(g)}catch(M){this._throwSecureError(M,"webrtc_local_description")}try{let M=this._extractDTLSFingerprintFromSDP(g.sdp);this.expectedDTLSFingerprint=M,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:M,context:"answer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${M}`,"system")}catch(M){this._secureLog("error","Failed to extract DTLS fingerprint from answer",{error:M.message})}try{let M=this._extractDTLSFingerprintFromSDP(e.s||e.sdp),fe=this.expectedDTLSFingerprint,re=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(re,fe,M),this._setSASMaterialReady(fe,M)}catch(M){throw this._secureLog("error","SAS computation failed in createSecureAnswer (Answer side)",{errorType:M?.constructor?.name||"Unknown"}),new Error(`SAS computation failed: ${M.message}`)}let _=Date.now(),I=await this.waitForIceGathering(),w=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),D=w.total;if(!I&&D===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(D>0?"info":"warn","ICE candidates captured for answer export",{candidateSummary:w,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-_,iceGatheringCompleted:I}),this._logIceCandidateDiagnostics("answer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-_,iceGatheringCompleted:I}),I||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the response. Connectivity may still fail on restrictive networks.","system"),D===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 T=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),v=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!T||typeof T!="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(!T.keyData||!T.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!T.keyData,hasSignature:!!T.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!v||typeof v!="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(!v.keyData||!v.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!v.keyData,hasSignature:!!v.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");let b={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},C=Date.now(),x={t:"answer",s:this.peerConnection.localDescription.sdp,v:n.PROTOCOL_VERSION,ts:C,e:T,d:v,ap:S,slv:"MAX",dr:n.RATCHET_VERSION,sc:{sf:d.substring(0,12),kd:!0,ma:!0}},k=x.s||x.sdp,j=x.e||x.ecdhPublicKey,z=x.d||x.ecdsaPublicKey;if(!k||!j||!z)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:b.level,timestamp:C,processingTime:C-e.timestamp}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:C,securityLevel:b.level,operationId:t}})),setTimeout(async()=>{try{let M=await this.calculateAndReportSecurityLevel();M&&(this.notifySecurityUpdate(),this._secureLog("info","Post-connection security level calculated",{operationId:t,level:M.level}))}catch(M){this._secureLog("error","Error calculating post-connection security",{operationId:t,errorType:M.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 s=>{if(this._secureLog("info","Setting encryption keys with mutex",{operationId:s}),!(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:s,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:s,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=Nr(String(e.sbq2)),i=Dr(r);if(i.type!==oe.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 Kr(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}=Pr(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!==n.PROTOCOL_VERSION)throw new Error(`Version mismatch: expected protocol ${n.PROTOCOL_VERSION}, received ${i||"unknown"}`);let s=e.ecdhPublicKey||e.e,a=e.ecdsaPublicKey||e.d;if(!s||typeof s!="object"||Array.isArray(s))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure in answer",{hasEcdhKey:!!s,ecdhKeyType:typeof s,isArray:Array.isArray(s),availableKeys:Object.keys(e)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDH public key structure");if(!s.keyData||!s.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature in answer",{hasKeyData:!!s.keyData,hasSignature:!!s.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!==n.PROTOCOL_VERSION&&window.EnhancedSecureCryptoUtils.secureLog.log("warn","Incompatible protocol version in answer",{expectedVersion:n.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(s,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===n.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),_=this.expectedDTLSFingerprint,I=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(I,_,g),this._setSASMaterialReady(_,g),this.pendingSASCode=this.verificationCode,this._secureLog("info","SAS verification code generated for MITM protection (Offer side)",{sasCode:this.verificationCode,localFP:_.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:n.MAX_SAS_ATTEMPTS}),this.sasValidationAttempts>=n.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===n.PROTOCOL_VERSION&&e.e&&e.d,r=e.version===n.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 ${n.PROTOCOL_VERSION}, received ${a}`)}let s=t?e.s:e.sdp;if(typeof s!="string"||!s.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),s=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:s}),c;if(this._ratchet?.canEncrypt){let{header:d,ciphertext:u}=await this._ratchet.encrypt(s);c={type:n.MESSAGE_TYPES.RATCHET_MESSAGE,h:d,c:u,version:"5.0"}}else c={type:"enhanced_message",data:await window.EnhancedSecureCryptoUtils.encryptMessage(s,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:s.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:n.TIMEOUTS.HEARTBEAT_INTERVAL,lastHeartbeat:0},this.stopHeartbeat(!0),this._heartbeatTimer=setInterval(()=>{this._heartbeatConfig?.enabled&&this.dataChannel?.readyState==="open"&&this._sendHeartbeat()},n.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:n.TIMEOUTS.HEARTBEAT_INTERVAL,probeAfterMs:n.TIMEOUTS.LIVENESS_PROBE_AFTER,probeTimeoutMs:n.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"})}},n.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=n.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()},n.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.barrenFailuresn.TIMEOUTS.RECONNECT_MAX_DURATION){this._giveUpAutoReconnect("timeout");return}if(e.inFlightAt&&Date.now()-e.inFlightAt=2&&r>n.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:n.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=n.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)}async _sendIceRestartOffer(){let e=this.peerConnection;if(!e)return;if(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(n.TIMEOUTS.ICE_RESTART_GATHERING,n.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:n.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=n.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",await i.setRemoteDescription({type:"offer",sdp:t.sdp});let s=await i.createAnswer();await i.setLocalDescription(s),await this.waitForIceGathering(n.TIMEOUTS.ICE_RESTART_GATHERING,n.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=n.TIMEOUTS.ICE_GATHERING_TIMEOUT,t=n.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 s=!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(!s){s=!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,s=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 s=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(s>=a){h(new Error(`Initialization timeout after ${c}ms`));return}s++,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(s){return s.name==="AbortError"||s.message.includes("cancelled")?(this._secureLog("info","File transfer initialization cancelled by user"),{cancelled:!0}):(this._secureLog("error","Force file transfer initialization failed:",{errorType:s?.constructor?.name||"Unknown",message:s.message,attempts}),{error:s.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(n.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest1"),t=this._generateSecureIV(n.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest2");return e.every((i,s)=>i===t[s])?(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(s=>s.track).filter(s=>s&&(s.kind==="audio"||s.kind==="video")&&s.readyState==="live"),r=this.remoteMediaStream?this.remoteMediaStream.getTracks():[];r.length===t.length&&r.every(s=>t.includes(s))||(this.remoteMediaStream=new MediaStream(t)),this._updateCallState({remoteHasVideo:t.some(s=>s.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,s=t.getVideoTracks()[0]||null;return i&&(this._callAudioSender?await this._callAudioSender.replaceTrack(i):this._callAudioSender=r.addTrack(i,t)),s&&(this._callVideoSender?await this._callVideoSender.replaceTrack(s):this._callVideoSender=r.addTrack(s,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&&qi(t);let r=e.find(i=>i.sender&&i.sender===this._callVideoSender);r&&Ji(r)}catch{}}_mungeCallSdp(e){try{let t=vr(e,nt.opusFmtp);return t=Gi(t,zi),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:vr(e.sdp,nt.opusFmtp)});return}catch{await t.setLocalDescription(e)}}}async _applyCallSenderParams(){try{this._callAudioSender&&await ji(this._callAudioSender,{}),this._callVideoSender&&await Zi(this._callVideoSender,{})}catch{}}_startAdaptation(){if(!(this._adaptationController||!this.peerConnection))try{this._adaptationController=new Ft(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",s,a;r==="NotAllowedError"?(a="permission_denied",s=`\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",s=`\u26A0\uFE0F Call not started \u2014 no ${i} found on this device.`):r==="NotReadableError"||r==="AbortError"?(a="device_busy",s=`\u26A0\uFE0F Call not started \u2014 your ${i} is in use by another app. Close it and try again.`):(a="media_failed",s=`\u26A0\uFE0F Call not started \u2014 could not access ${i}${r?" ("+r+")":""}.`);try{this.deliverMessageToUI(s,"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(n.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(n.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(n.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(n.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(n.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(n.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=n.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}}},Ht=class{constructor(e=null){this._keyStore=new WeakMap,this._keyMetadata=new Map,this._keyReferences=new Map,this._masterKeyManager=e||new Gt,this._persistentStorage=new zr(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:s,iv:a}=await this._masterKeyManager.encryptBytes(i),o=new Uint8Array(a.length+s.byteLength);return o.set(a,0),o.set(s,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,s])=>({keyId:i,...s,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}}},$t=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 s=i.target.result;if(!s.objectStoreNames.contains(this.KEYS_STORE)){let a=s.createObjectStore(this.KEYS_STORE,{keyPath:"keyId"});a.createIndex("timestamp","timestamp",{unique:!1}),a.createIndex("algorithm","algorithm",{unique:!1})}if(!s.objectStoreNames.contains(this.METADATA_STORE)){let a=s.createObjectStore(this.METADATA_STORE,{keyPath:"keyId"});a.createIndex("created","created",{unique:!1}),a.createIndex("lastAccessed","lastAccessed",{unique:!1})}s.objectStoreNames.contains(this.SALT_STORE)||s.createObjectStore(this.SALT_STORE,{keyPath:"id"})}})}async storeEncryptedKey(e,t,r,i,s,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:s,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,s)=>{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=()=>s(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((s,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=()=>s(),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,s)=>{let a=r.get(e);a.onsuccess=()=>i(a.result||null),a.onerror=()=>s(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,s)=>{let a=r.put(e);a.onsuccess=()=>i(),a.onerror=()=>s(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 s=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 s=t.getAll();s.onsuccess=()=>r(s.result),s.onerror=()=>i(new Error(`Failed to list keys: ${s.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((s,a)=>{let o=r.put(i);o.onsuccess=()=>s(),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 s=t.get("master_salt");s.onsuccess=()=>{let a=s.result;r(a?new Uint8Array(a.salt):null)},s.onerror=()=>i(new Error(`Failed to retrieve salt: ${s.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(),s=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)}},zr=class{constructor(e,t=null){this._masterKeyManager=e,this._indexedDB=t||new $t,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:s,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,s,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}}}},Gt=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 $t,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 Ns=yi(As());var xs="6.8.0";var Vr=()=>{if(Ke.length<2)return null;let[n,e]=React.useState(!1),t=React.useRef(null),r=typeof window<"u"?window.location.pathname:"/",i=Ui({pathname:r,active:Ge()}),s=i.find(c=>c.isCurrent)||i[0];React.useEffect(()=>{if(!n)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)}},[n]);let a=React.createElement("button",{key:"trigger",type:"button",onClick:()=>e(c=>!c),"aria-haspopup":"menu","aria-expanded":n?"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:n?"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"},s?s.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:n?"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:n?"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:()=>Ni(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=Vr;var ot={system:'',light:'',dark:''},Br=(n,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:n}}),Hr=()=>{let n=typeof window<"u"?window.SecureBitTheme:null;if(!n)return null;let[e,t]=React.useState(!1),[r,i]=React.useState(()=>n.get()),[s,a]=React.useState(()=>n.resolved()),o=React.useRef(null);React.useEffect(()=>n.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:s==="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"}},Br(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:()=>{n.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)"}},Br(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)"}},Br('',12,2.6))])}));return React.createElement("div",{ref:o,style:{position:"relative",display:"inline-flex"}},[h,m])};window.ThemeSwitcher=Hr;var ka=`v${xs}`,Aa=({status:n,fingerprint:e,verificationCode:t,onDisconnect:r,isConnected:i,securityLevel:s,webrtcManager:a})=>{let[o,c]=React.useState(null),[d,u]=React.useState(0),[h,m]=React.useState(!1),[p,S]=React.useState(0),[g,_]=React.useState("unknown");React.useEffect(()=>{let G=!1,N=0,R=async()=>{let K=Date.now();if(!(K-N<1e4)&&!G){G=!0,N=K;try{if(!a||!i)return;let O=a,q=null;if(typeof O.getRealSecurityLevel=="function"?q=await O.getRealSecurityLevel():typeof O.calculateAndReportSecurityLevel=="function"?q=await O.calculateAndReportSecurityLevel():q=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(O),q&&q.isRealData!==!1){let Y=o?.score||0,Se=q.score||0;Y!==Se||!o?(c(q),u(K)):window.DEBUG_MODE}}catch{}finally{G=!1}}};if(i&&(R(),!o||o.score<50)){let K=setInterval(()=>{!o||o.score<50?R():clearInterval(K)},5e3);setTimeout(()=>clearInterval(K),3e4)}let P=setInterval(R,3e4);return()=>clearInterval(P)},[a,i]),React.useEffect(()=>{let G=R=>{setTimeout(()=>{u(0)},100)},N=R=>{R.detail&&R.detail.securityData&&(c(R.detail.securityData),u(Date.now()))};return document.addEventListener("security-level-updated",G),document.addEventListener("real-security-calculated",N),window.forceHeaderSecurityUpdate=R=>{R&&window.EnhancedSecureCryptoUtils?window.EnhancedSecureCryptoUtils.calculateSecurityLevel(R).then(P=>{P&&P.isRealData!==!1&&(c(P),u(Date.now()))}).catch(P=>{}):u(0)},()=>{document.removeEventListener("security-level-updated",G),document.removeEventListener("real-security-calculated",N)}},[]),React.useEffect(()=>{m(!0),S(0),_("premium")},[]),React.useEffect(()=>{m(!0),S(0),_("premium")},[]),React.useEffect(()=>{let G=K=>{m(!0),S(0),_("premium")},N=()=>{c(null),u(0),m(!1),S(0),_("unknown")},R=()=>{c(null),u(0)},P=()=>{c(null),u(0),m(!1),S(0),_("unknown")};return document.addEventListener("force-header-update",G),document.addEventListener("peer-disconnect",R),document.addEventListener("connection-cleaned",N),document.addEventListener("disconnected",P),()=>{document.removeEventListener("force-header-update",G),document.removeEventListener("peer-disconnect",R),document.removeEventListener("connection-cleaned",N),document.removeEventListener("disconnected",P)}},[]);let I=async G=>{if(G&&(G.button===2||G.ctrlKey||G.metaKey)&&r&&typeof r=="function"){r();return}G.preventDefault(),G.stopPropagation();let N=null;if(a&&window.EnhancedSecureCryptoUtils)try{N=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(a)}catch{}if(!N&&!o){alert(f("sec.verificationWait"));return}let R=N||o;R||(R={level:"UNKNOWN",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:f("sec.verificationUnavailable"),isRealData:!1,passedChecks:0,totalChecks:0});let P=`REAL-TIME SECURITY VERIFICATION -`;if(F+=`Security Level: ${A.level} (${A.score}%) -`,F+=`Verification Time: ${new Date(A.timestamp).toLocaleTimeString()} -`,F+=`Data Source: ${A.isRealData?f("sec.realTests"):f("sec.simulatedData")} +`;if(P+=`Security Level: ${R.level} (${R.score}%) +`,P+=`Verification Time: ${new Date(R.timestamp).toLocaleTimeString()} +`,P+=`Data Source: ${R.isRealData?f("sec.realTests"):f("sec.simulatedData")} -`,A.verificationResults){F+=`DETAILED CRYPTOGRAPHIC TESTS: -`,F+="="+"=".repeat(40)+` -`;let X=Object.entries(A.verificationResults).filter(([_e,ge])=>ge.passed),Se=Object.entries(A.verificationResults).filter(([_e,ge])=>!ge.passed);X.length>0&&(F+=`PASSED TESTS: -`,X.forEach(([_e,ge])=>{let Ye=_e.replace(/([A-Z])/g," $1").replace(/^./,Y=>Y.toUpperCase());F+=` ${Ye}: ${ge.details||f("sec.testPassed")} -`}),F+=` -`),Se.length>0&&(F+=`FAILED/UNAVAILABLE TESTS: -`,Se.forEach(([_e,ge])=>{let Ye=_e.replace(/([A-Z])/g," $1").replace(/^./,Y=>Y.toUpperCase());F+=` ${Ye}: ${ge.details||f("sec.testFailed")} -`}),F+=` -`),F+=`SUMMARY: -`,F+=`Passed: ${A.passedChecks}/${A.totalChecks} tests -`,F+=`Score: ${A.score}/${A.maxPossibleScore||100} points +`,R.verificationResults){P+=`DETAILED CRYPTOGRAPHIC TESTS: +`,P+="="+"=".repeat(40)+` +`;let Y=Object.entries(R.verificationResults).filter(([_e,ye])=>ye.passed),Se=Object.entries(R.verificationResults).filter(([_e,ye])=>!ye.passed);Y.length>0&&(P+=`PASSED TESTS: +`,Y.forEach(([_e,ye])=>{let Ye=_e.replace(/([A-Z])/g," $1").replace(/^./,W=>W.toUpperCase());P+=` ${Ye}: ${ye.details||f("sec.testPassed")} +`}),P+=` +`),Se.length>0&&(P+=`FAILED/UNAVAILABLE TESTS: +`,Se.forEach(([_e,ye])=>{let Ye=_e.replace(/([A-Z])/g," $1").replace(/^./,W=>W.toUpperCase());P+=` ${Ye}: ${ye.details||f("sec.testFailed")} +`}),P+=` +`),P+=`SUMMARY: +`,P+=`Passed: ${R.passedChecks}/${R.totalChecks} tests +`,P+=`Score: ${R.score}/${R.maxPossibleScore||100} points -`}if(F+=`SECURITY FEATURES STATUS: -`,F+="="+"=".repeat(40)+` -`,A.verificationResults){let X={"ECDSA Digital Signatures":A.verificationResults.verifyECDSASignatures?.passed||!1,"ECDH Key Exchange":A.verificationResults.verifyECDHKeyExchange?.passed||!1,"AES-GCM Encryption":A.verificationResults.verifyEncryption?.passed||!1,[f("sec.messageIntegrity")]:A.verificationResults.verifyMessageIntegrity?.passed||!1,[f("sec.forwardSecrecy")]:A.verificationResults.verifyPerfectForwardSecrecy?.passed||!1,[f("sec.replayProtection")]:A.verificationResults.verifyReplayProtection?.passed||!1,"DTLS Fingerprint":A.verificationResults.verifyDTLSFingerprint?.passed||!1,"SAS Verification":A.verificationResults.verifySASVerification?.passed||!1,[f("sec.metadataProtection")]:A.verificationResults.verifyMetadataProtection?.passed||!1,[f("sec.trafficObfuscation")]:A.verificationResults.verifyTrafficObfuscation?.passed||!1};Object.entries(X).forEach(([Se,_e])=>{F+=`${_e?"\u2705":"\u274C"} ${Se} -`})}else F+=`\u2705 ECDSA Digital Signatures -`,F+=`\u2705 ECDH Key Exchange -`,F+=`\u2705 AES-GCM Encryption -`,F+=`\u2705 Message Integrity (HMAC) -`,F+=`\u2705 Perfect Forward Secrecy -`,F+=`\u2705 Replay Protection -`,F+=`\u2705 DTLS Fingerprint -`,F+=`\u2705 SAS Verification -`,F+=`\u2705 Metadata Protection -`,F+=`\u2705 Traffic Obfuscation -`;F+=` -${A.details||f("sec.verificationDone")}`,A.isRealData?F+=` +`}if(P+=`SECURITY FEATURES STATUS: +`,P+="="+"=".repeat(40)+` +`,R.verificationResults){let Y={"ECDSA Digital Signatures":R.verificationResults.verifyECDSASignatures?.passed||!1,"ECDH Key Exchange":R.verificationResults.verifyECDHKeyExchange?.passed||!1,"AES-GCM Encryption":R.verificationResults.verifyEncryption?.passed||!1,[f("sec.messageIntegrity")]:R.verificationResults.verifyMessageIntegrity?.passed||!1,[f("sec.forwardSecrecy")]:R.verificationResults.verifyPerfectForwardSecrecy?.passed||!1,[f("sec.replayProtection")]:R.verificationResults.verifyReplayProtection?.passed||!1,"DTLS Fingerprint":R.verificationResults.verifyDTLSFingerprint?.passed||!1,"SAS Verification":R.verificationResults.verifySASVerification?.passed||!1,[f("sec.metadataProtection")]:R.verificationResults.verifyMetadataProtection?.passed||!1,[f("sec.trafficObfuscation")]:R.verificationResults.verifyTrafficObfuscation?.passed||!1};Object.entries(Y).forEach(([Se,_e])=>{P+=`${_e?"\u2705":"\u274C"} ${Se} +`})}else P+=`\u2705 ECDSA Digital Signatures +`,P+=`\u2705 ECDH Key Exchange +`,P+=`\u2705 AES-GCM Encryption +`,P+=`\u2705 Message Integrity (HMAC) +`,P+=`\u2705 Perfect Forward Secrecy +`,P+=`\u2705 Replay Protection +`,P+=`\u2705 DTLS Fingerprint +`,P+=`\u2705 SAS Verification +`,P+=`\u2705 Metadata Protection +`,P+=`\u2705 Traffic Obfuscation +`;P+=` +${R.details||f("sec.verificationDone")}`,R.isRealData?P+=` -\u2705 This is REAL-TIME verification using actual cryptographic functions.`:F+=` +\u2705 This is REAL-TIME verification using actual cryptographic functions.`:P+=` \u26A0\uFE0F Warning: This data may be simulated. Connection may not be fully established.`;let K=document.createElement("div");K.style.cssText=` position: fixed; @@ -84,27 +84,27 @@ ${A.details||f("sec.verificationDone")}`,A.isRealData?F+=` left: 0; width: 100%; height: 100%; - background: rgba(0,0,0,0.8); + background: rgba(var(--sb-scrim-rgb), 0.8); z-index: 10000; display: flex; align-items: center; justify-content: center; font-family: monospace; - `;let z=document.createElement("div");z.style.cssText=` - background: #1a1a1a; - color: #fff; + `;let O=document.createElement("div");O.style.cssText=` + background: var(--sb-legacy-panel); + color: var(--sb-text-1); padding: 20px; border-radius: 8px; max-width: 80%; max-height: 80%; overflow-y: auto; white-space: pre-line; - border: 1px solid #333; - `,z.textContent=F,K.appendChild(z),K.addEventListener("click",X=>{X.target===K&&document.body.removeChild(K)});let W=X=>{X.key==="Escape"&&(document.body.removeChild(K),document.removeEventListener("keydown",W))};document.addEventListener("keydown",W),document.body.appendChild(K)},D=(()=>{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"}}})(),_=r?o||n:null,E=(()=>{if(!_)return{tooltip:f("sec.verificationInProgress"),isVerified:!1,dataSource:"loading"};let U=_.isRealData!==!1,H=`${_.level} (${_.score}%)`;return U?{tooltip:`${H} - Real-time verification \u2705 -Right-click or Ctrl+click to disconnect`,isVerified:!0,dataSource:"real"}:{tooltip:`${H} - Estimated (connection establishing...) -Right-click or Ctrl+click to disconnect`,isVerified:!1,dataSource:"estimated"}})();React.useEffect(()=>(window.debugHeaderSecurity=void 0,()=>{delete window.debugHeaderSecurity}),[o,l,r,a,_,E]);let C=_?_.color==="green"?"#3ecf8e":_.color==="orange"?"#f0892a":_.color==="yellow"?"#e3c84e":"#e5727a":"#3ecf8e",M=r?"#3ecf8e":["connecting","verifying","retrying","reconnecting"].includes(s)?"#e3c84e":s==="failed"?"#e5727a":"#6b6b73",v=M==="#3ecf8e"?"rgba(62,207,142,0.16)":M==="#e3c84e"?"rgba(227,200,78,0.16)":M==="#e5727a"?"rgba(229,114,122,0.16)":"rgba(107,107,115,0.16)",q="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",O=!r,[x,ue]=React.useState(!1);React.useEffect(()=>{let U=()=>ue((window.scrollY||window.pageYOffset||0)>8);return U(),window.addEventListener("scroll",U,{passive:!0}),()=>window.removeEventListener("scroll",U)},[]);let ne="blur(20px) saturate(180%)",te="background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease, border-color .25s ease",ye={paddingTop:"var(--sb-safe-top, 0px)",paddingBottom:"var(--sb-bar-extra, 0px)"},Re={position:"fixed",top:0,left:0,right:0,...ye},j=O?x?{...Re,background:"rgba(15,15,17,0.72)",backdropFilter:ne,WebkitBackdropFilter:ne,borderBottom:"1px solid rgba(255,255,255,0.06)",transition:te}:{...Re,background:"transparent",backdropFilter:"blur(0px) saturate(100%)",WebkitBackdropFilter:"blur(0px) saturate(100%)",borderBottom:"1px solid transparent",transition:te}:{...ye,background:"rgba(18,18,20,0.72)",backdropFilter:ne,WebkitBackdropFilter:ne,borderBottom:"1px solid rgba(255,255,255,0.06)"};return React.createElement("header",{className:O?"header-minimal z-50":"header-minimal sticky top-0 z-50",style:j},[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:"#e8e8eb"}},"SecureBit"),React.createElement("span",{key:"v",style:{fontFamily:q,fontSize:"10px",fontWeight:500,color:"#56565e"}},Ta)]),React.createElement("div",{key:"r2",className:"hidden sm:block",style:{fontSize:"11px",color:"#6b6b73",fontWeight:500}},f("hdr.tagline"))])]),React.createElement("div",{key:"right",style:{display:"flex",alignItems:"center",gap:"9px"}},[O&&React.createElement(zi,{key:"lang"}),!O&&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(255,255,255,0.07)",background:"rgba(255,255,255,0.02)",color:"#9a9aa2",cursor:"pointer",transition:"all .15s"}},React.createElement("i",{className:"fas fa-network-wired",style:{fontSize:"13px"}})),!O&&_&&React.createElement("div",{key:"sec",onClick:I,onContextMenu:U=>{U.preventDefault(),typeof i=="function"&&i()},title:E.tooltip,className:"sb-secpill",style:{display:"flex",alignItems:"center",gap:"8px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(255,255,255,0.07)",background:"rgba(255,255,255,0.02)",cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-shield-halved",style:{fontSize:"13px",color:C}}),React.createElement("span",{key:"l",className:"hidden sm:inline",style:{fontSize:"12.5px",fontWeight:600,color:"#e8e8eb"}},f(`secLevel.${_.level}`)===`secLevel.${_.level}`?String(_.level):f(`secLevel.${_.level}`)),React.createElement("span",{key:"s",style:{fontFamily:q,fontSize:"11.5px",color:"#8a8a92"}},_.score+"%")]),!O&&React.createElement("div",{key:"status",style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 13px",borderRadius:"9px",border:"1px solid rgba(255,255,255,0.07)",background:"rgba(255,255,255,0.02)"}},[React.createElement("span",{key:"dot",style:{width:"7px",height:"7px",borderRadius:"50%",background:M,boxShadow:"0 0 0 3px "+v}}),React.createElement("span",{key:"t",className:"hidden sm:inline",style:{fontSize:"13px",fontWeight:600,color:"#cfcfd4"}},D.text)]),r&&React.createElement("button",{key:"dc",onClick:i,className:"sb-disconnect",style:{display:"flex",alignItems:"center",gap:"7px",padding:"8px 14px",borderRadius:"9px",border:"1px solid rgba(255,255,255,0.08)",background:"transparent",color:"#9a9aa2",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=Ca;var Yt="1.0.1",Vi=`https://github.com/SecureBitChat/securebit-desktop/releases/download/v${Yt}`,va=()=>{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:`${Vi}/SecureBit.Chat_${Yt}_x64-setup.exe`,color:"blue"},{id:"macos",name:"macOS",subtitle:"Desktop App",icon:"fab fa-safari",platform:"Desktop",isActive:!0,url:`${Vi}/SecureBit.Chat_${Yt}_x64.dmg`,color:"gray"},{id:"linux",name:"Linux",subtitle:"Desktop App",icon:"fab fa-linux",platform:"Desktop",isActive:!0,url:`${Vi}/SecureBit.Chat_${Yt}_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"),i=s.filter(c=>c.platform==="Mobile"),r=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"},i.map(o)),React.createElement("div",{key:"browser-row",className:"flex justify-center gap-6"},r.map(o))])};window.DownloadApps=va;var ka=()=>{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="#f0892a",i="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",r="'Manrope', system-ui, -apple-system, sans-serif",n="https://docs.google.com/forms/d/e/1FAIpQLSc9ijV9PCoyXkus6vEx1OWwvwAsLq8fKS6-H5BmX-c-bvia6w/viewform?usp=dialog",a=[{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"}],o=(p,S,w,g,m)=>React.createElement("svg",{className:m,width:S,height:S,viewBox:"0 0 24 24",fill:"none",stroke:w,strokeWidth:g,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:p}}),c=p=>React.createElement("span",{key:"role",style:{fontFamily:i,fontSize:"10.5px",fontWeight:600,color:"#6b6b73",textTransform:"uppercase",letterSpacing:"1.2px",padding:"6px 11px",borderRadius:"8px",border:"1px solid rgba(255,255,255,0.07)",background:"rgba(255,255,255,0.025)",whiteSpace:"nowrap"}},p),l=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:"#141416",border:"1px solid rgba(255,255,255,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(255,255,255,0.13)"},onMouseLeave:S=>{S.currentTarget.style.transform="none",S.currentTarget.style.borderColor="rgba(255,255,255,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:"#f4f4f6"}},p.name),React.createElement("p",{key:"desc",style:{margin:"0 0 22px",fontSize:"14.5px",lineHeight:1.6,color:"#9a9aa2"}},p.desc),React.createElement("div",{key:"foot",style:{marginTop:"auto",paddingTop:"6px",display:"flex",alignItems:"center",gap:"12px"}},[c(p.role)])]),h=React.createElement("a",{key:"invite",href:n,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"#111113",border:"1px dashed rgba(255,255,255,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(240,137,42,0.4)"},onMouseLeave:p=>{p.currentTarget.style.borderColor="rgba(255,255,255,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(240,137,42,0.12)",border:"1px solid rgba(240,137,42,0.28)",marginBottom:"24px"}},o('',23,t,1.9)),React.createElement("h3",{key:"title",style:{margin:"0 0 8px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"#f4f4f6"}},f("partners.inviteTitle")),React.createElement("p",{key:"desc",style:{margin:0,fontSize:"14.5px",lineHeight:1.6,color:"#8a8a92"}},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:t,color:"#1a0f04",fontFamily:r,fontSize:"15px",fontWeight:700,cursor:"pointer",boxShadow:"0 8px 24px rgba(240,137,42,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"),o('',17,"currentColor",2.2,"sb-mirror-rtl")])]),u=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:"#6b6b73",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:"#f4f4f6"}},f("partners.heading"))]),React.createElement("div",{key:"cards",style:{display:"flex",gap:"18px",alignItems:"stretch",flexWrap:"wrap"}},[...a.map(l),h])]);return React.createElement("section",{style:{width:"100%",color:"#e8e8eb",fontFamily:r,padding:s?"48px 0":"72px 0",background:"radial-gradient(1100px 640px at 50% -6%, rgba(240,137,42,0.055), transparent 62%), #0f0f11"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ptUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),u])};window.BecomePartner=ka;var Aa=()=>{let[s,e]=React.useState(0),[t,i]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let _=window.matchMedia("(max-width:767px)"),R=()=>i(_.matches);return _.addEventListener?_.addEventListener("change",R):_.addListener(R),()=>{_.removeEventListener?_.removeEventListener("change",R):_.removeListener(R)}},[]);let r="#f0892a",n="radial-gradient(130% 90% at 28% 0%, rgba(240,137,42,0.11), transparent 60%), #141416",a="rgba(240,137,42,0.3)",o="#111113",c="rgba(255,255,255,0.06)",l="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",h="'Manrope', system-ui, -apple-system, sans-serif",u=[{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=(_,R,E,C)=>React.createElement("svg",{width:R,height:R,viewBox:"0 0 24 24",fill:"none",stroke:E,strokeWidth:C,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:_}}),S=_=>e(R=>(R+_+u.length)%u.length),w=(_,R,E)=>React.createElement("button",{key:_,onClick:R,"aria-label":_,className:"sb-mirror-rtl",style:{width:"46px",height:"46px",display:"grid",placeItems:"center",borderRadius:"50%",border:"1px solid rgba(255,255,255,0.1)",background:"rgba(255,255,255,0.025)",color:"#cfcfd4",cursor:"pointer",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:C=>{C.currentTarget.style.borderColor=a,C.currentTarget.style.color=r},onMouseLeave:C=>{C.currentTarget.style.borderColor="rgba(255,255,255,0.1)",C.currentTarget.style.color="#cfcfd4"}},p(E,18,"currentColor",2.1)),g=_=>React.createElement("span",{key:_,style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(255,255,255,0.07)",background:"rgba(255,255,255,0.025)",fontFamily:l,fontSize:"11.5px",fontWeight:500,color:"#9a9aa2"}},[React.createElement("span",{key:"dot",style:{width:"5px",height:"5px",borderRadius:"50%",background:"#3ecf8e"}}),_]),m=_=>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(240,137,42,0.13)",border:"1px solid rgba(240,137,42,0.3)"}},p(_.icon,26,r,1.9)),React.createElement("span",{key:"n",style:{fontFamily:l,fontSize:"13px",fontWeight:600,color:"#6b6b73"}},_.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:"#f4f4f6"}},[_.title[0],React.createElement("br",{key:"br"}),_.title[1]]),React.createElement("p",{key:"p",style:{margin:0,fontSize:"15px",lineHeight:1.6,color:"#9a9aa2",maxWidth:"380px"}},_.desc)]),React.createElement("div",{key:"tags",style:{display:"flex",flexWrap:"wrap",gap:"8px"}},_.tags.map(g))]),I=_=>t?React.createElement("div",{key:"col",style:{display:"flex",alignItems:"center",gap:"16px",padding:"20px 22px"}},[React.createElement("span",{key:"n",style:{fontFamily:l,fontSize:"12px",fontWeight:600,color:"#56565e"}},_.num),React.createElement("span",{key:"l",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.2px",color:"#cfcfd4"}},_.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:l,fontSize:"12px",fontWeight:600,color:"#56565e"}},_.num),React.createElement("span",{key:"l",style:{writingMode:"vertical-rl",transform:"rotate(180deg)",fontSize:"17px",fontWeight:800,letterSpacing:"-0.2px",color:"#cfcfd4",whiteSpace:"nowrap"}},_.collapsed),p(_.icon,22,"#56565e",1.8)]),b=u.map((_,R)=>{let E=s===R;return React.createElement("div",{key:R,onClick:()=>e(R),onMouseEnter:C=>{E||(C.currentTarget.style.filter="brightness(1.18)")},onMouseLeave:C=>{C.currentTarget.style.filter="none"},style:{flex:t?"none":E?6.2:1,minWidth:t?"auto":"72px",position:"relative",borderRadius:"18px",overflow:"hidden",cursor:"pointer",background:E?n:o,border:"1px solid "+(E?a:c),color:"#8a8a92",transition:"flex .46s cubic-bezier(.2,.7,.3,1), background .3s ease, border-color .3s ease, filter .2s ease"}},E?m(_):I(_))}),D=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:l,fontSize:"11px",fontWeight:600,color:"#6b6b73",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:"#f4f4f6"}},f("unique.heading"))]),React.createElement("div",{key:"nav",style:{display:"flex",alignItems:"center",gap:"10px",flex:"none"}},[w("prev",()=>S(-1),''),w("next",()=>S(1),'')])]),React.createElement("div",{key:"accordion",style:{display:"flex",flexDirection:t?"column":"row",gap:t?"12px":"14px",height:t?"auto":"440px"}},b)]);return React.createElement("section",{style:{width:"100%",color:"#e8e8eb",fontFamily:h,padding:t?"44px 0":"64px 0",background:"radial-gradient(1100px 700px at 18% 8%, rgba(240,137,42,0.05), transparent 60%), #0f0f11"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes wuUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}"}}),D])};window.UniqueFeatureSlider=Aa;function Ia(){let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let b=window.matchMedia("(max-width:767px)"),D=()=>e(b.matches);return b.addEventListener?b.addEventListener("change",D):b.addListener(D),()=>{b.removeEventListener?b.removeEventListener("change",D):b.removeListener(D)}},[]);let t="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",i="'Manrope', system-ui, -apple-system, sans-serif",r=[{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(b=>({...b,title:f(`roadmap.${b.k}.title`),sub:f(`roadmap.${b.k}.sub`),date:f(`roadmap.${b.k}.date`),features:Oe(`roadmap.${b.k}.features`)})),n={released:{word:f("roadmap.status.released"),color:"#3ecf8e",line:"rgba(62,207,142,0.32)"},current:{word:f("roadmap.status.current"),color:"#f0892a",line:"rgba(240,137,42,0.32)"},dev:{word:f("roadmap.status.dev"),color:"#e3b341",line:"rgba(255,255,255,0.08)"},planned:{word:f("roadmap.status.planned"),color:"#8a8a92",line:"rgba(255,255,255,0.08)"},research:{word:f("roadmap.status.research"),color:"#6b6b73",line:"rgba(255,255,255,0.08)"}},[a,o]=React.useState({}),c=b=>a[b]===void 0?r[b].status==="current":a[b],l=b=>o(D=>({...D,[b]:!c(b)})),h=(b,D)=>{let _=parseInt(b.slice(1),16);return`rgba(${_>>16&255},${_>>8&255},${_&255},${D})`},u=r.length,p=r.filter(b=>b.status==="released"||b.status==="current").length,S=u-p,w=(p/u*100).toFixed(1)+"%",[g,m]=f("roadmap.progress",{total:u}).split("{shipped}"),I=b=>b==="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(62,207,142,0.16),rgba(62,207,142,0.16)), #0f0f11",border:"1px solid rgba(62,207,142,0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"#3ecf8e",strokeWidth:"2.4",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M5 13l4 4 10-11"}))):b==="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(240,137,42,0.2),rgba(240,137,42,0.2)), #0f0f11",border:"1px solid #f0892a",zIndex:2,animation:"rmPulse 2.4s ease-out infinite"}},React.createElement("span",{style:{width:"9px",height:"9px",borderRadius:"50%",background:"#f0892a"}})):b==="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(227,179,65,0.15),rgba(227,179,65,0.15)), #0f0f11",border:"1px solid rgba(227,179,65,0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"#e3b341",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:"#0f0f11",border:`1px ${b==="research"?"dashed":"solid"} rgba(255,255,255,0.18)`,zIndex:2}},React.createElement("span",{style:{width:"7px",height:"7px",borderRadius:"50%",background:n[b].color}}));return React.createElement("section",{style:{width:"100%",color:"#e8e8eb",fontFamily:i,padding:s?"48px 0":"64px 0",background:"radial-gradient(1200px 720px at 50% -8%, rgba(240,137,42,0.05), transparent 60%), #0f0f11"}},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(240,137,42,0.18)}60%{box-shadow:0 0 0 9px rgba(240,137,42,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:"#6b6b73",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:"#f4f4f6"}},f("roadmap.heading")),React.createElement("p",{style:{margin:0,fontSize:"15.5px",lineHeight:1.6,color:"#8a8a92",maxWidth:"660px"}},f("roadmap.subheading"))),React.createElement("div",{style:{display:"flex",alignItems:"center",gap:"18px",flexWrap:"wrap",padding:"18px 22px",borderRadius:"14px",background:"#141416",border:"1px solid rgba(255,255,255,0.06)",marginBottom:"36px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"12px",fontWeight:600,color:"#e8e8eb",whiteSpace:"nowrap"}},g,React.createElement("span",{style:{color:"#3ecf8e"}},p),m),React.createElement("div",{style:{flex:"1 1 240px",minWidth:"200px",height:"8px",borderRadius:"99px",background:"#0c0c0e",border:"1px solid rgba(255,255,255,0.06)",overflow:"hidden"}},React.createElement("div",{style:{height:"100%",width:w,background:"linear-gradient(90deg, #3ecf8e, #f0892a)"}})),React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"#6b6b73",textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},f("roadmap.upcoming",{upcoming:S}))),r.map((b,D)=>{let _=n[b.status],R=c(D),E=Dl(D),style:{display:"flex",alignItems:"center",gap:s?"11px":"16px",padding:s?"16px 16px":"18px 22px",cursor:"pointer",transition:"background .18s ease"},onMouseEnter:C=>{C.currentTarget.style.background="rgba(255,255,255,0.018)"},onMouseLeave:C=>{C.currentTarget.style.background="transparent"}},React.createElement("div",{style:{flex:"none",minWidth:"52px",textAlign:"center",padding:"7px 10px",borderRadius:"9px",background:"#0c0c0e",border:"1px solid rgba(255,255,255,0.07)",fontFamily:t,fontSize:"13px",fontWeight:700,color:b.status==="current"?"#f0892a":"#cfcfd4"}},b.v),React.createElement("div",{style:{flex:1,minWidth:0}},React.createElement("div",{style:{fontSize:s?"15.5px":"17px",fontWeight:800,letterSpacing:"-0.4px",color:"#f4f4f6"}},b.title),!s&&React.createElement("div",{style:{marginTop:"3px",fontSize:"13.5px",color:"#9a9aa2"}},b.sub)),React.createElement("div",{style:{flex:"none",display:"flex",alignItems:"center",gap:s?"8px":"14px"}},React.createElement("span",{style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"6px 11px",borderRadius:"8px",background:h(_.color,.1),border:`1px solid ${h(_.color,.22)}`,fontFamily:t,fontSize:"10.5px",fontWeight:600,color:_.color,textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},React.createElement("span",{style:{width:"6px",height:"6px",borderRadius:"50%",background:_.color}}),!s&&_.word),!s&&React.createElement("span",{style:{fontFamily:t,fontSize:"12px",fontWeight:500,color:"#8a8a92",whiteSpace:"nowrap",minWidth:"74px",textAlign:"end"}},b.date),React.createElement("span",{style:{color:"#6b6b73",display:"inline-flex",transition:"transform .22s cubic-bezier(.2,.7,.3,1)",transform:R?"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"}))))),R&&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:"#56565e",textTransform:"uppercase",letterSpacing:"1.2px",marginBottom:"14px",paddingTop:"14px",borderTop:"1px solid rgba(255,255,255,0.05)"}},f("roadmap.keyFeatures")),React.createElement("div",{style:{display:"grid",gridTemplateColumns:s?"1fr":"1fr 1fr",gap:"11px 28px"}},b.features.map((C,M)=>React.createElement("div",{key:M,style:{display:"flex",alignItems:"flex-start",gap:"10px"}},React.createElement("span",{style:{flex:"none",marginTop:"7px",width:"5px",height:"5px",borderRadius:"50%",background:_.color}}),React.createElement("span",{style:{fontSize:"13.5px",lineHeight:1.5,color:"#cfcfd4"}},C)))))))})))}window.Roadmap=Ia;var xa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let l=window.matchMedia("(max-width:767px)"),h=()=>e(l.matches);return l.addEventListener?l.addEventListener("change",h):l.addListener(h),()=>{l.removeEventListener?l.removeEventListener("change",h):l.removeListener(h)}},[]);let t="#f0892a",i="'Manrope', system-ui, -apple-system, sans-serif",r="https://github.com/SecureBitChat/securebit-chat/",n="mailto:lockbitchat@tutanota.com",a=React.createElement("a",{key:"gh",href:r,target:"_blank",rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:t,color:"#1a0f04",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",boxShadow:"0 8px 24px rgba(240,137,42,0.28)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:l=>{l.currentTarget.style.background="#ff9637",l.currentTarget.style.transform="translateY(-2px)"},onMouseLeave:l=>{l.currentTarget.style.background=t,l.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")]),o=React.createElement("a",{key:"fb",href:n,rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:"rgba(255,255,255,0.03)",color:"#e8e8eb",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",border:"1px solid rgba(255,255,255,0.1)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:l=>{l.currentTarget.style.borderColor="rgba(255,255,255,0.24)",l.currentTarget.style.background="rgba(255,255,255,0.06)"},onMouseLeave:l=>{l.currentTarget.style.borderColor="rgba(255,255,255,0.1)",l.currentTarget.style.background="rgba(255,255,255,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")]),c=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(240,137,42,0.1), transparent 65%), #121214",border:"1px solid rgba(255,255,255,0.07)",padding:s?"40px 24px 36px":"56px 56px 48px",textAlign:"center",boxShadow:"0 24px 60px rgba(0,0,0,0.4)"}},[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(240,137,42,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:"#f4f4f6"}},f("community.title")),React.createElement("p",{key:"desc",style:{margin:"0 auto 32px",maxWidth:"560px",fontSize:"16px",lineHeight:1.65,color:"#9a9aa2"}},f("community.description")),React.createElement("div",{key:"btns",style:{display:"flex",gap:"14px",justifyContent:"center",flexWrap:"wrap"}},[a,o]),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:l=>{l.currentTarget.style.opacity=1},onMouseLeave:l=>{l.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:"#0f0f11",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)}}"}}),c])};window.CommunityCTA=xa;var Ra=({webrtcManager:s,isConnected:e,pendingIncomingFiles:t=[],onIncomingDecision:i,showDropzone:r=!0})=>{let[n,a]=React.useState(!1),[o,c]=React.useState({sending:[],receiving:[]}),l=React.useRef(null);React.useEffect(()=>{if(!e||!s)return;let C=setInterval(()=>{let M=s.getFileTransfers();c(M)},500);return()=>clearInterval(C)},[e,s]),React.useEffect(()=>{e||c({sending:[],receiving:[]})},[e]);let h=async E=>{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 C of E)try{let M=s.validateFile(C);if(!M.isValid){let v=M.errors.join(". ");alert(`\u0424\u0430\u0439\u043B ${C.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${v}`);continue}await s.sendFile(C)}catch(M){M.message.includes(f("file.notReady"))?alert(`\u0424\u0430\u0439\u043B ${C.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.`):M.message.includes(f("file.tooLarge"))||M.message.includes("exceeds maximum")?alert(`\u0424\u0430\u0439\u043B ${C.name} \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439: ${M.message}`):M.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."):M.message.includes(f("file.typeNotAllowed"))?alert(`\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 ${C.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F: ${M.message}`):alert(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${C.name}: ${M.message}`)}},u=E=>{E.preventDefault(),a(!1);let C=Array.from(E.dataTransfer.files);h(C)},p=E=>{E.preventDefault(),a(!0)},S=E=>{E.preventDefault(),a(!1)},w=E=>{let C=Array.from(E.target.files);h(C),E.target.value=""},g=E=>{if(E===0)return"0 B";let C=1024,M=["B","KB","MB","GB"],v=Math.floor(Math.log(E)/Math.log(C));return parseFloat((E/Math.pow(C,v)).toFixed(2))+" "+M[v]},m=E=>{switch(E){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"}},I=E=>{switch(E){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 E}},b=(E,C)=>{let M=E.totalChunks||0,v=E.transferredChunks||0,q=E.status==="completed",O=M>0?Math.min(M,32):24,x;return q?x=O:M>0?x=Math.floor(v/M*O):x=Math.floor((E.progress||0)/100*O),x=Math.max(0,Math.min(O,x)),React.createElement("div",{key:"progress"},[React.createElement("div",{key:"squares",style:{display:"flex",flexWrap:"wrap",gap:"3px",marginBottom:"7px"}},Array.from({length:O},(ue,ne)=>React.createElement("div",{key:ne,style:{width:"11px",height:"11px",borderRadius:"2px",background:ne0?`${Math.min(v,M)} / ${M} chunks`:`${(E.progress||0).toFixed(0)}%`)])])},D=E=>E.status==="completed",_=async(E,C)=>{typeof i=="function"&&await i(E,C),c(s.getFileTransfers())};return e?s&&s.isConnected()&&s.isVerified?React.createElement("div",{className:"file-transfer-component"},[r&&React.createElement("div",{key:"drop-zone",onDrop:u,onDragOver:p,onDragLeave:S,style:{position:"relative",border:"1.5px dashed "+(n?"rgba(240,137,42,0.7)":"rgba(255,255,255,0.14)"),borderRadius:"14px",background:n?"rgba(240,137,42,0.07)":"#141416",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(255,255,255,0.04)",border:"1px solid rgba(255,255,255,0.08)"}},React.createElement("i",{className:"fas fa-arrow-up-from-bracket",style:{color:"#9a9aa2",fontSize:"18px"}})),React.createElement("div",{key:"title",style:{fontSize:"14px",fontWeight:700,color:"#e8e8eb"}},f("file.drop")),React.createElement("div",{key:"sub",style:{fontSize:"12px",color:"#7b7b83",marginTop:"4px"}},f("file.dropHint")),React.createElement("button",{key:"browse",type:"button",onClick:()=>l.current?.click(),className:"sb-send",style:{marginTop:"14px",display:"inline-flex",alignItems:"center",gap:"7px",padding:"9px 16px",borderRadius:"9px",border:"none",background:"#f0892a",color:"#1a0f04",fontFamily:"inherit",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-folder-open",style:{fontSize:"13px"}}),f("file.browse")])]),r&&React.createElement("input",{key:"file-input",ref:l,type:"file",multiple:!0,className:"hidden",onChange:w}),t.length>0&&React.createElement("div",{key:"incoming-consent",className:"mt-4 space-y-2"},t.map(E=>React.createElement("div",{key:E.fileId,style:{borderRadius:"12px",border:"1px solid rgba(255,255,255,0.08)",background:"#161618",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(240,137,42,0.12)",border:"1px solid rgba(240,137,42,0.22)"}},React.createElement("i",{className:"fas fa-file-arrow-down",style:{color:"#f0892a",fontSize:"15px"}})),React.createElement("div",{key:"text",style:{minWidth:0}},[React.createElement("div",{key:"title",style:{fontSize:"13px",fontWeight:600,color:"#e8e8eb"}},f("file.incoming")),React.createElement("div",{key:"meta",style:{fontSize:"11.5px",color:"#7b7b83",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},`${E.fileName} \xB7 ${g(E.fileSize)} \xB7 ${E.mimeType}`)])]),React.createElement("div",{key:"actions",style:{display:"flex",gap:"8px"}},[React.createElement("button",{key:"accept",onClick:()=>_(E.fileId,!0),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"none",background:"#f0892a",color:"#1a0f04",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:()=>_(E.fileId,!1),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"1px solid rgba(229,114,122,0.3)",background:"rgba(229,114,122,0.08)",color:"#e5727a",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:"#8a8a92",marginBottom:"10px"}},[React.createElement("i",{key:"icon",className:"fas fa-right-left",style:{fontSize:"12px"}}),f("file.title")]),...o.sending.map(E=>React.createElement("div",{key:`send-${E.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(255,255,255,0.07)",background:"#161618",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:"#f0892a",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"#e8e8eb"}},E.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"#7b7b83"}},g(E.fileSize))]),React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(E.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])]),b(E,"#f0892a")])),...o.receiving.map(E=>React.createElement("div",{key:`recv-${E.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(255,255,255,0.07)",background:"#161618",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:"#3ecf8e",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"#e8e8eb"}},E.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"#7b7b83"}},g(E.fileSize))]),React.createElement("div",{key:"actions",className:"flex items-center space-x-2"},[E.status==="completed"?React.createElement("button",{key:"download",className:"text-green-400 hover:text-green-300 text-xs flex items-center",onClick:async()=>{try{let C=await s.getReceivedFileObjectURL(E.fileId);if(!C){alert(f("file.gone"));return}let M=document.createElement("a");M.href=C,M.download=E.fileName||"file",M.click(),setTimeout(()=>s.revokeReceivedFileObjectURL(C),1e4)}catch(C){alert(C.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(E.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])])]),b(E,"#3ecf8e")]))])]):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=Ra;var ze=Object.freeze({MAX_SERVERS:10,MAX_URLS_PER_SERVER:8,MAX_STRING_LENGTH:512}),Uo=Object.freeze(["stun","stuns","turn","turns"]),Ma=/^(stuns?|turns?):/i,La=/^(\[[0-9a-f:]+\]|[a-z0-9.-]+)(:\d{1,5})?$/i,Da=/^transport=(udp|tcp)$/i;function xn(s){for(let e=0;eze.MAX_STRING_LENGTH)return f("iceUrl.tooLong");if(xn(e))return f("iceUrl.badChars");let t=e.match(Ma);if(!t)return f("iceUrl.badScheme");let i=e.slice(t[0].length),[r,n,...a]=i.split("?");return a.length>0?f("iceUrl.badQuery"):r?La.test(r)?n!==void 0&&!Da.test(n)?f("iceUrl.badTransport"):null:f("iceUrl.badHost"):f("iceUrl.noHost")}function Rn(s){return typeof s=="string"&&/^turns?:/i.test(s.trim())}function An(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`:xn(s)?`${e} contains invalid characters`:null}function In(s){let e=[],t=[],i=[];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((r,n)=>{let a=`Server #${n+1}`;if(!r||typeof r!="object"){e.push(f("iceErr.invalidEntry",{label:a}));return}let o=Array.isArray(r.urls)?r.urls:[r.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=[],l=!1;for(let S of o){let w=Pa(S);if(w){e.push(`${a}: ${w}`);continue}let g=S.trim();c.push(g),Rn(g)&&(l=!0)}if(c.length===0)return;let h=An(r.username,`${a} username`);h&&e.push(h);let u=An(r.credential,`${a} credential`);u&&e.push(u);let p={urls:c.length===1?c[0]:c};r.username&&(p.username=String(r.username)),r.credential&&(p.credential=String(r.credential)),l&&(!p.username||!p.credential)&&t.push(f("iceErr.turnCreds",{label:a})),i.push(p)}),{servers:i,errors:e,warnings:t}):{servers:[],errors:[f("iceErr.notArray")],warnings:[]}}function Mn(s){if(typeof s!="string"||!s.trim())return{servers:[],errors:[],warnings:[]};let e=s.trim();if(e.startsWith("[")||e.startsWith("{")){let i;try{i=JSON.parse(e)}catch{return{servers:[],errors:[f("iceErr.invalidJson")],warnings:[]}}let r=Array.isArray(i)?i:[i];return In(r)}let t=e.split(` -`).map(i=>i.trim()).filter(Boolean).map(i=>({urls:i}));return In(t)}function Ln(s){return Array.isArray(s)?s.some(e=>(Array.isArray(e?.urls)?e.urls:[e?.urls]).some(Rn)):!1}var Ve=window.React,Fa=["# 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 Ka(s,e=6e3){let t={host:0,srflx:0,relay:0};if(typeof RTCPeerConnection>"u")return{...t,error:f("ice.errUnavailable")};let i;try{i=new RTCPeerConnection({iceServers:s})}catch(r){return{...t,error:r.message||f("ice.errInvalid")}}return new Promise(r=>{let n=!1,a=()=>{if(!n){n=!0,clearTimeout(o);try{i.close()}catch{}r(t)}},o=setTimeout(a,e);i.onicecandidate=c=>{if(!c.candidate){a();return}let l=c.candidate.candidate||"";/ typ host/.test(l)?t.host++:/ typ srflx/.test(l)?t.srflx++:/ typ relay/.test(l)&&t.relay++};try{i.createDataChannel("securebit-ice-test"),i.createOffer().then(c=>i.setLocalDescription(c)).catch(()=>a())}catch{a()}})}var Na=({isOpen:s,onClose:e,initial:t,hasSaved:i,onApply:r,onForget:n,embedded:a})=>{if(!s)return null;let[o,c]=Ve.useState(t?.useCustom||!1),[l,h]=Ve.useState(t?.serversText||""),[u,p]=Ve.useState(t?.privacyMode==="relay-only"),[S,w]=Ve.useState(t?.persisted||!1),[g,m]=Ve.useState("idle"),[I,b]=Ve.useState(null),D=o?Mn(l):{servers:[],errors:[],warnings:[]},_=Ln(D.servers),R=!o||D.servers.length>0&&D.errors.length===0,E=async()=>{m("running"),b(null);let j=await Ka(D.servers);b(j),m("done")},C=()=>{R&&r({useCustom:o,servers:o?D.servers:[],privacyMode:u?"relay-only":"standard",serversText:l},S)},M=async()=>{n&&await n(),w(!1)},v=Ve.createElement,q="#f0892a",O="#3ecf8e",x="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",ue=(j,U,H,A,F)=>v("button",{type:"button",onClick:U,style:Object.assign({width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${j?"rgba(240,137,42,0.45)":"rgba(255,255,255,0.07)"}`,background:j?"rgba(240,137,42,0.06)":"#141416",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"},F||{})},[v("span",{key:"ring",style:{flex:"none",width:"18px",height:"18px",marginTop:"1px",borderRadius:"50%",border:`1.5px solid ${j?q:"rgba(255,255,255,0.22)"}`,display:"grid",placeItems:"center"}},v("span",{style:{width:"8px",height:"8px",borderRadius:"50%",background:j?q:"transparent"}})),v("span",{key:"tx",style:{flex:1}},[v("span",{key:"t",style:{display:"block",fontSize:"14px",fontWeight:700,color:"#f4f4f6"}},H),v("span",{key:"d",style:{display:"block",fontSize:"12.5px",color:"#8a8a92",marginTop:"2px"}},A)])]),ne=(j,U,H,A,F,K)=>v("button",{type:"button",onClick:U,style:{width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${j?"rgba(62,207,142,0.3)":"rgba(255,255,255,0.07)"}`,background:j?"rgba(62,207,142,0.05)":"#141416",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"}},[v("span",{key:"tx",style:{flex:1}},[v("span",{key:"r1",style:{display:"flex",alignItems:"center",gap:"8px"}},[v("span",{key:"t",style:{fontSize:"14px",fontWeight:700,color:"#f4f4f6"}},H),K&&v("span",{key:"b",style:{fontSize:"10px",fontWeight:700,color:O,padding:"2px 7px",borderRadius:"5px",background:"rgba(62,207,142,0.1)",border:"1px solid rgba(62,207,142,0.22)"}},K)]),v("span",{key:"d",style:{display:"block",fontSize:"12.5px",lineHeight:1.5,color:"#8a8a92",marginTop:"3px"}},A)]),v("span",{key:"tr",style:{flex:"none",width:"42px",height:"24px",borderRadius:"99px",background:j?F||O:"rgba(255,255,255,0.08)",border:`1px solid ${j?F||O:"rgba(255,255,255,0.12)"}`,position:"relative",transition:"all .18s",marginTop:"1px"}},v("span",{style:{position:"absolute",top:"2px",insetInlineStart:"2px",width:"18px",height:"18px",borderRadius:"50%",background:"#fff",transform:j?`translateX(${18*Fr()}px)`:"translateX(0)",transition:"transform .18s"}}))]),te=[];if(te.push(v("p",{key:"intro",style:{margin:"0 0 18px",fontSize:"13.5px",lineHeight:1.6,color:"#9a9aa2"}},f("ice.intro"))),te.push(ue(!o,()=>c(!1),f("ice.publicTitle"),f("ice.publicDesc"))),te.push(ue(o,()=>c(!0),f("ice.customTitle"),f("ice.customDesc",{max:ze.MAX_SERVERS}),o?{marginBottom:"14px"}:null)),o){let j=[];j.push(v("div",{key:"ta",style:{borderRadius:"13px",border:"1px solid rgba(255,255,255,0.08)",background:"#0c0c0e",overflow:"hidden",marginBottom:"12px"}},v("textarea",{dir:"ltr",value:l,onChange:H=>h(H.target.value),rows:5,spellCheck:!1,autoComplete:"off",placeholder:Fa,style:{width:"100%",resize:"vertical",border:"none",outline:"none",background:"transparent",color:"#c9ccd8",fontFamily:x,fontSize:"12px",lineHeight:1.65,padding:"13px 14px",minHeight:"104px"}}))),D.errors.length>0&&j.push(v("ul",{key:"err",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"#e5727a",fontSize:"12.5px"}},D.errors.slice(0,6).map((H,A)=>v("li",{key:A},H)))),D.warnings.length>0&&j.push(v("ul",{key:"warn",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"#e3c84e",fontSize:"12.5px"}},D.warnings.slice(0,6).map((H,A)=>v("li",{key:A},H)))),D.servers.length>0&&D.errors.length===0&&j.push(v("p",{key:"ok",style:{margin:"0 0 10px",fontSize:"12.5px",color:O}},`${D.servers.length} server(s) parsed${_?" (TURN present)":" (STUN only \u2014 does not hide IP)"}.`)),j.push(v("div",{key:"note",style:{display:"flex",alignItems:"flex-start",gap:"9px",padding:"12px 13px",borderRadius:"11px",border:"1px solid rgba(62,207,142,0.18)",background:"rgba(62,207,142,0.05)",marginBottom:"12px"}},[v("i",{key:"i",className:"fas fa-info-circle",style:{color:O,fontSize:"13px",marginTop:"2px",flex:"none"}}),v("span",{key:"t",style:{fontSize:"12px",lineHeight:1.55,color:"#a8b8ae"}},[f("ice.turnNote"),v("span",{key:"m",style:{fontFamily:x,color:O}},"turns:"),f("ice.turnNoteTls")])]));let U=g==="done"&&I&&!I.error?O:"#cfcfd4";j.push(v("div",{key:"test",style:{display:"flex",alignItems:"center",gap:"12px",flexWrap:"wrap",marginBottom:"4px"}},[v("button",{key:"btn",type:"button",disabled:!R||g==="running",onClick:E,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"10px 15px",borderRadius:"10px",border:`1px solid ${g==="done"&&I&&!I.error?"rgba(62,207,142,0.4)":"rgba(255,255,255,0.1)"}`,background:g==="done"&&I&&!I.error?"rgba(62,207,142,0.08)":"rgba(255,255,255,0.04)",color:U,fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:!R||g==="running"?"not-allowed":"pointer",opacity:!R||g==="running"?.6:1}},[v("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"&&I?v("span",{key:"res",style:{fontSize:"12px",color:I.error?"#e5727a":"#8a8a92"}},I.error?`Test failed: ${I.error}`:I.srflx>0||I.relay>0?`STUN ${I.srflx>0?"OK":"none"} \xB7 TURN ${I.relay>0?"OK":"none"} \xB7 host ${I.host}`:`host ${I.host} \xB7 this browser hides STUN/TURN candidates from the test \u2014 your servers still apply to real connections`):null])),te.push(v("div",{key:"custom",style:{marginBottom:"16px"}},j))}te.push(ne(u,()=>p(!u),f("ice.relayTitle"),f("ice.relayDesc"),O,f("ice.relayBadge"))),u&&o&&!_&&te.push(v("p",{key:"relaywarn",style:{margin:"-4px 0 10px",fontSize:"12.5px",color:"#e3c84e"}},f("ice.relayWarning"))),te.push(ne(S,()=>w(!S),f("ice.persist"),f("ice.persistDesc"),q));let ye=[];return i&&ye.push(v("button",{key:"forget",type:"button",onClick:M,style:{marginInlineEnd:"auto",padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(229,114,122,0.3)",background:"transparent",color:"#e5727a",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.forget"))),ye.push(v("button",{key:"cancel",type:"button",onClick:e,style:{padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(255,255,255,0.1)",background:"transparent",color:"#b3b3ba",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.cancel"))),ye.push(v("button",{key:"apply",type:"button",onClick:C,disabled:!R,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"11px 20px",borderRadius:"11px",border:"none",background:q,color:"#1a0f04",fontFamily:"inherit",fontSize:"13.5px",fontWeight:700,cursor:R?"pointer":"not-allowed",opacity:R?1:.5,boxShadow:"0 6px 18px rgba(240,137,42,0.28)"}},[v("i",{key:"i",className:"fas fa-check"}),f("ice.apply")])),v("div",{className:"sb-ice-overlay",style:a?{position:"absolute",inset:0,zIndex:60,display:"flex",flexDirection:"column",background:"#0f0f11",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}:{position:"fixed",inset:0,zIndex:60,display:"flex",flexDirection:"column",alignItems:"stretch",background:"#0f0f11",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}},[v(Ve.Fragment,{key:"panel"},[v("div",{key:"head",style:{display:"flex",alignItems:"center",gap:"12px",padding:"20px 24px",borderBottom:"1px solid rgba(255,255,255,0.06)"}},[v("div",{key:"ic",style:{width:"38px",height:"38px",flex:"none",display:"grid",placeItems:"center",borderRadius:"10px",background:"rgba(255,255,255,0.03)",border:"1px solid rgba(255,255,255,0.06)"}},v("i",{className:"fas fa-sliders-h",style:{color:"#cfcfd4",fontSize:"15px"}})),v("div",{key:"tx",style:{flex:1,lineHeight:1.25}},[v("div",{key:"t",style:{fontSize:"16.5px",fontWeight:800,letterSpacing:"-0.3px",color:"#f4f4f6"}},f("ice.title")),v("div",{key:"s",style:{fontSize:"12px",color:"#7b7b83"}},f("ice.subtitle"))]),v("button",{key:"x",type:"button",onClick:e,style:{width:"32px",height:"32px",flex:"none",display:"grid",placeItems:"center",borderRadius:"9px",border:"none",background:"rgba(255,255,255,0.04)",color:"#8a8a92",cursor:"pointer"}},v("i",{className:"fas fa-times"}))]),v("div",{key:"body",className:"custom-scrollbar",style:{flex:1,overflowY:"auto",padding:"20px 24px"}},te),v("div",{key:"foot",style:{display:"flex",alignItems:"center",justifyContent:"flex-end",gap:"10px",padding:"16px 24px",borderTop:"1px solid rgba(255,255,255,0.06)",background:"#0e0e10",borderRadius:"0"}},ye)])])};window.IceServerSettings=Na;var Oa=({webrtcManager:s,peerTitle:e})=>{let t=React.createElement,i="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",r={lock:'',minimize:'',expand:'',user:'',micOn:'',micOff:'',camOn:'',camOff:'',flip:'',phone:'',phoneHangup:''},n=(K,z,W)=>t("span",{style:{display:"grid",placeItems:"center",width:z+"px",height:z+"px"},dangerouslySetInnerHTML:{__html:`${K}`}}),[a,o]=React.useState(()=>s?.getCallState?.()||{phase:"idle",active:!1}),[c,l]=React.useState(!1),[h,u]=React.useState(0),p=React.useRef(null),S=React.useRef(null),w=React.useRef(null);React.useEffect(()=>{if(!s)return;let K=W=>o(W),z=s.onCallStateChanged;return s.onCallStateChanged=K,o(s.getCallState?s.getCallState():{phase:"idle",active:!1}),()=>{s.onCallStateChanged===K&&(s.onCallStateChanged=z||null)}},[s]);let g=a.phase||"idle",m=!!a.active,I=!!a.withVideo||!!a.remoteHasVideo;if(React.useEffect(()=>{let K=s?.getRemoteMediaStream?.(),z=s?.getLocalMediaStream?.(),W=(X,Se,_e)=>{if(!X||!Se)return;X.srcObject!==Se&&(X.muted=_e,X.srcObject=Se);let ge=X.play&&X.play();ge&&ge.catch&&ge.catch(()=>{})};W(S.current,K,!1,"remoteAudio"),W(p.current,K,!0,"remoteVideo"),W(w.current,z,!0,"selfVideo")}),React.useEffect(()=>{if(g!=="active"){u(0);return}let K=Date.now(),z=setInterval(()=>u(Math.floor((Date.now()-K)/1e3)),1e3);return()=>clearInterval(z)},[g]),React.useEffect(()=>{g==="idle"&&l(!1)},[g]),!m||g==="idle"||g==="ended"||a.groupCallId)return null;let b=K=>`${String(Math.floor(K/60)).padStart(2,"0")}:${String(K%60).padStart(2,"0")}`,D=g==="outgoing"||g==="connecting",_=g==="outgoing"?f("call.ringing"):g==="connecting"?f("call.connecting"):g==="active"?b(h):f("call.ringing"),R=e||f("call.peer"),E={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"1px solid rgba(255,255,255,0.1)",background:"rgba(255,255,255,0.05)",color:"#cfcfd4",cursor:"pointer",transition:"all .15s"},C={...E,background:"#e5484d",color:"#fff",border:"1px solid transparent"},M={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"#e5484d",color:"#fff",cursor:"pointer",boxShadow:"0 8px 24px rgba(229,72,77,0.35)",transition:"transform .15s"},v=K=>({width:"36px",height:"36px",borderRadius:"9px",display:"grid",placeItems:"center",border:"1px solid rgba(255,255,255,"+(K?"0.15":"0.1")+")",background:K?"rgba(0,0,0,0.35)":"rgba(255,255,255,0.04)",color:K?"#fff":"#cfcfd4",cursor:"pointer",transition:"all .15s"}),q=t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"4px",fontSize:"11px",fontWeight:600,color:"#3ecf8e"}},[n(r.lock,11,2),f("call.encryptedShort")]),O={excellent:{bars:4,color:"#3ecf8e",label:f("call.qualityExcellent")},good:{bars:3,color:"#3ecf8e",label:f("call.qualityGood")},fair:{bars:2,color:"#e3c84e",label:f("call.qualityFair")},poor:{bars:1,color:"#e5727a",label:f("call.qualityWeak")}},x=K=>{let z=O[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(X=>t("span",{key:X,style:{width:"3px",height:5+X*3+"px",borderRadius:"1px",background:Xs?.acceptCall?.(),ne=()=>s?.declineCall?.(),te=()=>{l(!1),s?.endCall?.()},ye=()=>s?.toggleMic?.(),Re=()=>s?.toggleCamera?.(),j=()=>s?.switchCamera?.(),U=()=>s?.upgradeToVideo?.(),H=t("audio",{key:"ra",ref:S,autoPlay:!0,playsInline:!0,style:{display:"none"}}),A=(K,z,W)=>t("div",{key:K,style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"}},[z,t("span",{key:"l",style:{fontFamily:i,fontSize:"10.5px",color:"#8a8a92"}},W)]),F=(K,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(240,137,42,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(240,137,42,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%, #2a2a30, #161618)",border:"1px solid rgba(255,255,255,0.1)",boxShadow:"0 12px 30px rgba(0,0,0,0.4)",color:"#8a8a92"}},n(r.user,K,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(240,137,42,0.08), transparent 70%), #0d0d0f",animation:"sbExpand .2s ease"}},[H,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:"#3ecf8e"}},[n(r.lock,13,2),f("call.encrypted")])),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[F(46,!0),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"#f4f4f6"}},R),t("div",{key:"st",style:{fontFamily:i,fontSize:"14px",fontWeight:500,color:"#9a9aa2",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"}},[A("dec",t("button",{onClick:ne,title:f("call.decline"),style:{...M,width:"62px",height:"62px"}},n(r.phoneHangup,24,1.9)),f("call.decline")),A("acc",t("button",{onClick:ue,title:f("call.accept"),style:{width:"62px",height:"62px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"#3ecf8e",color:"#06231a",cursor:"pointer",boxShadow:"0 8px 24px rgba(62,207,142,0.35)"}},n(r.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:"#161618",border:"1px solid rgba(255,255,255,0.1)",boxShadow:"0 18px 44px rgba(0,0,0,0.55)",animation:"sbExpand .18s ease"}},[H,I&&t("div",{key:"v",style:{position:"relative",height:"132px",background:"#111"}},[t("video",{key:"rv",ref:p,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,#15151b,#1d1a24)",color:"#6b6b73"}},n(r.camOff,22,1.8)),t("span",{key:"s",style:{position:"absolute",top:"8px",insetInlineStart:"9px",fontFamily:i,fontSize:"11px",fontWeight:600,color:"#fff",padding:"3px 7px",borderRadius:"6px",background:"rgba(0,0,0,0.5)"}},_)]),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(62,207,142,0.1)",border:"1px solid rgba(62,207,142,0.25)",color:"#3ecf8e"}},n(r.user,16,1.9)),t("div",{key:"tx",style:{flex:1,minWidth:0}},[t("div",{key:"n",style:{fontSize:"13px",fontWeight:700,color:"#f4f4f6",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},R),t("div",{key:"s",style:{display:"flex",alignItems:"center",gap:"7px",fontFamily:i,fontSize:"11px",color:"#9a9aa2"}},[(I?f("call.videoPrefix"):f("call.voicePrefix"))+_,g==="active"&&x(!0)])]),t("button",{key:"exp",onClick:()=>l(!1),title:f("call.expand"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"rgba(255,255,255,0.05)",color:"#cfcfd4",cursor:"pointer",transition:"all .15s"}},n(r.expand,15,2)),t("button",{key:"end",onClick:te,title:f("call.end"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"#e5484d",color:"#fff",cursor:"pointer",transition:"transform .15s"}},n(r.phoneHangup,15,2))])]):I?t("div",{style:{position:"absolute",inset:0,zIndex:40,overflow:"hidden",background:"#0a0a0c",animation:"sbExpand .2s ease"}},[H,a.remoteHasVideo?t("video",{key:"rv",ref:p,autoPlay:!0,muted:!0,playsInline:!0,style:{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",background:"#0a0a0c"}}):t("div",{key:"ph",style:{position:"absolute",inset:0,background:"linear-gradient(120deg, #15151b, #1d1a24, #161620)",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%, #2a2a30, #161618)",border:"1px solid rgba(255,255,255,0.1)",color:"#9a9aa2"}},n(r.user,54,1.5)),t("div",{key:"t",style:{fontSize:"15px",fontWeight:600,color:"#8a8a92"}},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"}},R),t("div",{key:"s",style:{display:"inline-flex",alignItems:"center",gap:"9px",marginTop:"4px"}},[t("span",{key:"st",style:{fontFamily:i,fontSize:"12.5px",fontWeight:500,color:"#e8e8eb"}},_),q,g==="active"&&x(!1)])]),t("button",{key:"min",onClick:()=>l(!0),title:f("call.minimize"),style:{flex:"none",...v(!0)}},n(r.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(255,255,255,0.16)",boxShadow:"0 12px 30px rgba(0,0,0,0.5)",background:"#111"}},[t("video",{key:"sv",ref:w,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:"#161618",color:"#6b6b73"}},[n(r.camOff,24,1.8),t("span",{key:"t",style:{fontSize:"10.5px",color:"#6b6b73",fontFamily:i}},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:ye,title:f("call.mute"),style:a.micEnabled?E:C},n(a.micEnabled?r.micOn:r.micOff,21,1.9)),t("button",{key:"cam",onClick:Re,title:f("call.camera"),style:a.cameraEnabled?E:C},n(a.cameraEnabled?r.camOn:r.camOff,21,1.8)),t("button",{key:"flip",onClick:j,title:f("call.flipCamera"),style:E},n(r.flip,21,1.8)),t("button",{key:"end",onClick:te,title:f("call.end"),style:M},n(r.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(240,137,42,0.08), transparent 70%), #0d0d0f",animation:"sbExpand .2s ease"}},[H,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:"#3ecf8e"}},[n(r.lock,13,2),f("call.encrypted")]),t("button",{key:"min",onClick:()=>l(!0),title:f("call.minimize"),style:v(!1)},n(r.minimize,16,2))]),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[F(46,D),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"#f4f4f6"}},R),t("div",{key:"st",style:{fontFamily:i,fontSize:"14px",fontWeight:500,color:"#9a9aa2",marginTop:"8px"}},_),g==="active"&&t("div",{key:"q",style:{marginTop:"12px"}},x(!1))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"26px",padding:"28px 24px 34px"}},[A("mute",t("button",{onClick:ye,title:f("call.mute"),style:a.micEnabled?E:C},n(a.micEnabled?r.micOn:r.micOff,22,1.9)),a.micEnabled?"Mute":f("call.muted")),A("video",t("button",{onClick:U,title:f("call.addVideo"),style:E},n(r.camOn,22,1.8)),f("call.video")),A("end",t("button",{onClick:te,title:f("call.end"),style:M},n(r.phoneHangup,22,1.9)),f("call.endShort"))])])};typeof window<"u"&&(window.CallUIComponent=Oa);window.EnhancedSecureCryptoUtils=xt;window.EnhancedSecureWebRTCManager=Vt;window.EnhancedSecureFileTransfer=je;window.NotificationIntegration=Fn.NotificationIntegration;var Ua=()=>{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),za=()=>{typeof window.requestIdleCallback=="function"?window.requestIdleCallback(Dn,{timeout:3e3}):setTimeout(Dn,1200)},Pn=()=>{Ua(),typeof window.initializeApp=="function"?window.initializeApp():window.DEBUG_MODE&&console.error("initializeApp is not defined on window"),za()};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Pn):Pn(); + border: 1px solid var(--sb-surface-5); + `,O.textContent=P,K.appendChild(O),K.addEventListener("click",Y=>{Y.target===K&&document.body.removeChild(K)});let q=Y=>{Y.key==="Escape"&&(document.body.removeChild(K),document.removeEventListener("keydown",q))};document.addEventListener("keydown",q),document.body.appendChild(K)},D=(()=>{switch(n){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"}}})(),T=i?o||s:null,b=(()=>{if(!T)return{tooltip:f("sec.verificationInProgress"),isVerified:!1,dataSource:"loading"};let G=T.isRealData!==!1,N=`${T.level} (${T.score}%)`;return G?{tooltip:`${N} - Real-time verification \u2705 +Right-click or Ctrl+click to disconnect`,isVerified:!0,dataSource:"real"}:{tooltip:`${N} - 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,T,b]);let C=T?T.color==="green"?"var(--sb-green)":T.color==="orange"?"var(--sb-orange)":T.color==="yellow"?"var(--sb-yellow)":"var(--sb-red)":"var(--sb-green)",x=i?"var(--sb-green-solid)":["connecting","verifying","retrying","reconnecting"].includes(n)?"var(--sb-yellow-solid)":n==="failed"?"var(--sb-red-solid)":"var(--sb-text-9)",k=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)",j="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",z=!i,[M,fe]=React.useState(!1);React.useEffect(()=>{let G=()=>fe((window.scrollY||window.pageYOffset||0)>8);return G(),window.addEventListener("scroll",G,{passive:!0}),()=>window.removeEventListener("scroll",G)},[]);let re="blur(20px) saturate(180%)",pe="background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease, border-color .25s ease",me={paddingTop:"var(--sb-safe-top, 0px)",paddingBottom:"var(--sb-bar-extra, 0px)"},ce={position:"fixed",top:0,left:0,right:0,...me},ve=z?M?{...ce,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:re,WebkitBackdropFilter:re,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)",transition:pe}:{...ce,background:"transparent",backdropFilter:"blur(0px) saturate(100%)",WebkitBackdropFilter:"blur(0px) saturate(100%)",borderBottom:"1px solid transparent",transition:pe}:{...me,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:re,WebkitBackdropFilter:re,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"};return React.createElement("header",{className:z?"header-minimal z-50":"header-minimal sticky top-0 z-50",style:ve},[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:j,fontSize:"10px",fontWeight:500,color:"var(--sb-text-faint)"}},ka)]),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"}},[z&&React.createElement(Vr,{key:"lang"}),z&&React.createElement(Hr,{key:"theme"}),!z&&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"}})),!z&&T&&React.createElement("div",{key:"sec",onClick:I,onContextMenu:G=>{G.preventDefault(),typeof r=="function"&&r()},title:b.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:C}}),React.createElement("span",{key:"l",className:"hidden sm:inline",style:{fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-2)"}},f(`secLevel.${T.level}`)===`secLevel.${T.level}`?String(T.level):f(`secLevel.${T.level}`)),React.createElement("span",{key:"s",style:{fontFamily:j,fontSize:"11.5px",color:"var(--sb-text-7)"}},T.score+"%")]),!z&&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 "+k}}),React.createElement("span",{key:"t",className:"hidden sm:inline",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-4)"}},D.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=Aa;var Xt="1.0.1",$r=`https://github.com/SecureBitChat/securebit-desktop/releases/download/v${Xt}`,xa=()=>{let n=[{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:`${$r}/SecureBit.Chat_${Xt}_x64-setup.exe`,color:"blue"},{id:"macos",name:"macOS",subtitle:"Desktop App",icon:"fab fa-safari",platform:"Desktop",isActive:!0,url:`${$r}/SecureBit.Chat_${Xt}_x64.dmg`,color:"gray"},{id:"linux",name:"Linux",subtitle:"Desktop App",icon:"fab fa-linux",platform:"Desktop",isActive:!0,url:`${$r}/SecureBit.Chat_${Xt}_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=n.filter(c=>c.platform==="Desktop"||c.platform==="Web"),r=n.filter(c=>c.platform==="Mobile"),i=n.filter(c=>c.platform==="Browser"),s="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 ${s} 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=xa;var Ia=()=>{let[n,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",s="'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,_,I)=>React.createElement("svg",{className:I,width:S,height:S,viewBox:"0 0 24 24",fill:"none",stroke:g,strokeWidth:_,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:n?"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:n?"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:s,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:n?"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:n?"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:s,padding:n?"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=Ia;var Ra=()=>{let[n,e]=React.useState(0),[t,r]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let v=window.matchMedia("(max-width:767px)"),b=()=>r(v.matches);return v.addEventListener?v.addEventListener("change",b):v.addListener(b),()=>{v.removeEventListener?v.removeEventListener("change",b):v.removeListener(b)}},[]);let i="var(--sb-orange)",s="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=(v,b,C,x)=>React.createElement("svg",{width:b,height:b,viewBox:"0 0 24 24",fill:"none",stroke:C,strokeWidth:x,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:v}}),S=v=>e(b=>(b+v+m.length)%m.length),g=(v,b,C)=>React.createElement("button",{key:v,onClick:b,"aria-label":v,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(C,18,"currentColor",2.1)),_=v=>React.createElement("span",{key:v,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)"}}),v]),I=v=>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(v.icon,26,s,1.9)),React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"13px",fontWeight:600,color:"var(--sb-text-9)"}},v.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)"}},[v.title[0],React.createElement("br",{key:"br"}),v.title[1]]),React.createElement("p",{key:"p",style:{margin:0,fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-6)",maxWidth:"380px"}},v.desc)]),React.createElement("div",{key:"tags",style:{display:"flex",flexWrap:"wrap",gap:"8px"}},v.tags.map(_))]),w=v=>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)"}},v.num),React.createElement("span",{key:"l",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)"}},v.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)"}},v.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"}},v.collapsed),p(v.icon,22,"var(--sb-text-faint)",1.8)]),D=m.map((v,b)=>{let C=n===b;return React.createElement("div",{key:b,onClick:()=>e(b),onMouseEnter:x=>{C||(x.currentTarget.style.filter="brightness(1.18)")},onMouseLeave:x=>{x.currentTarget.style.filter="none"},style:{flex:t?"none":C?6.2:1,minWidth:t?"auto":"72px",position:"relative",borderRadius:"18px",overflow:"hidden",cursor:"pointer",background:C?a:c,border:"1px solid "+(C?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"}},C?I(v):w(v))}),T=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"}},D)]);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)}}"}}),T])};window.UniqueFeatureSlider=Ra;function Ma(){let[n,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let w=window.matchMedia("(max-width:767px)"),D=()=>e(w.matches);return w.addEventListener?w.addEventListener("change",D):w.addListener(D),()=>{w.removeEventListener?w.removeEventListener("change",D):w.removeListener(D)}},[]);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`)})),s={released:{word:f("roadmap.status.released"),color:"var(--sb-green)",solid:"var(--sb-green-solid)",rgb:"var(--sb-green-rgb)",line:"rgba(var(--sb-green-rgb), 0.32)"},current:{word:f("roadmap.status.current"),color:"var(--sb-orange)",solid:"var(--sb-orange-solid)",rgb:"var(--sb-orange-rgb)",line:"rgba(var(--sb-orange-rgb), 0.32)"},dev:{word:f("roadmap.status.dev"),color:"var(--sb-yellow-2)",solid:"var(--sb-yellow-2-solid)",rgb:"var(--sb-yellow-2-rgb)",line:"rgba(var(--sb-ink), 0.08)"},planned:{word:f("roadmap.status.planned"),color:"var(--sb-text-7)",solid:"var(--sb-text-7)",rgb:"var(--sb-text-7-rgb)",line:"rgba(var(--sb-ink), 0.08)"},research:{word:f("roadmap.status.research"),color:"var(--sb-text-9)",solid:"var(--sb-text-9)",rgb:"var(--sb-text-9-rgb)",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(D=>({...D,[w]:!c(w)})),u=(w,D)=>`rgba(${w}, ${D})`,h=i.length,m=i.filter(w=>w.status==="released"||w.status==="current").length,p=h-m,S=(m/h*100).toFixed(1)+"%",[g,_]=f("roadmap.progress",{total:h}).split("{shipped}"),I=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:s[w].solid}}));return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:r,padding:n?"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:n?"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:n?"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"}},g,React.createElement("span",{style:{color:"var(--sb-green)"}},m),_),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:S,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:p}))),i.map((w,D)=>{let T=s[w.status],v=c(D),b=Dd(D),style:{display:"flex",alignItems:"center",gap:n?"11px":"16px",padding:n?"16px 16px":"18px 22px",cursor:"pointer",transition:"background .18s ease"},onMouseEnter:C=>{C.currentTarget.style.background="rgba(var(--sb-ink), 0.018)"},onMouseLeave:C=>{C.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:n?"15.5px":"17px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},w.title),!n&&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:n?"8px":"14px"}},!n&&React.createElement("span",{style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"6px 11px",borderRadius:"8px",background:u(T.rgb,.1),border:`1px solid ${u(T.rgb,.22)}`,fontFamily:t,fontSize:"10.5px",fontWeight:600,color:T.color,textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},React.createElement("span",{style:{width:"6px",height:"6px",borderRadius:"50%",background:T.solid}}),T.word),!n&&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:v?"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"}))))),v&&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:n?"1fr":"1fr 1fr",gap:"11px 28px"}},w.features.map((C,x)=>React.createElement("div",{key:x,style:{display:"flex",alignItems:"flex-start",gap:"10px"}},React.createElement("span",{style:{flex:"none",marginTop:"7px",width:"5px",height:"5px",borderRadius:"50%",background:T.solid}}),React.createElement("span",{style:{fontSize:"13.5px",lineHeight:1.5,color:"var(--sb-text-4)"}},C)))))))})))}window.Roadmap=Ma;var La=()=>{let[n,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",s="https://github.com/SecureBitChat/securebit-chat/",a="mailto:lockbitchat@tutanota.com",o=React.createElement("a",{key:"gh",href:s,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:n?"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:n?"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:n?"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:n?"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=La;var Da=({webrtcManager:n,isConnected:e,pendingIncomingFiles:t=[],onIncomingDecision:r,showDropzone:i=!0})=>{let[s,a]=React.useState(!1),[o,c]=React.useState({sending:[],receiving:[]}),d=React.useRef(null);React.useEffect(()=>{if(!e||!n)return;let C=setInterval(()=>{let x=n.getFileTransfers();c(x)},500);return()=>clearInterval(C)},[e,n]),React.useEffect(()=>{e||c({sending:[],receiving:[]})},[e]);let u=async b=>{if(!e||!n){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(!n.isConnected()||!n.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 C of b)try{let x=n.validateFile(C);if(!x.isValid){let k=x.errors.join(". ");alert(`\u0424\u0430\u0439\u043B ${C.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${k}`);continue}await n.sendFile(C)}catch(x){x.message.includes(f("file.notReady"))?alert(`\u0424\u0430\u0439\u043B ${C.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 ${C.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 ${C.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 ${C.name}: ${x.message}`)}},h=b=>{b.preventDefault(),a(!1);let C=Array.from(b.dataTransfer.files);u(C)},m=b=>{b.preventDefault(),a(!0)},p=b=>{b.preventDefault(),a(!1)},S=b=>{let C=Array.from(b.target.files);u(C),b.target.value=""},g=b=>{if(b===0)return"0 B";let C=1024,x=["B","KB","MB","GB"],k=Math.floor(Math.log(b)/Math.log(C));return parseFloat((b/Math.pow(C,k)).toFixed(2))+" "+x[k]},_=b=>{switch(b){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"}},I=b=>{switch(b){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 b}},w=(b,C)=>{let x=b.totalChunks||0,k=b.transferredChunks||0,j=b.status==="completed",z=x>0?Math.min(x,32):24,M;return j?M=z:x>0?M=Math.floor(k/x*z):M=Math.floor((b.progress||0)/100*z),M=Math.max(0,Math.min(z,M)),React.createElement("div",{key:"progress"},[React.createElement("div",{key:"squares",style:{display:"flex",flexWrap:"wrap",gap:"3px",marginBottom:"7px"}},Array.from({length:z},(fe,re)=>React.createElement("div",{key:re,style:{width:"11px",height:"11px",borderRadius:"2px",background:re0?`${Math.min(k,x)} / ${x} chunks`:`${(b.progress||0).toFixed(0)}%`)])])},D=b=>b.status==="completed",T=async(b,C)=>{typeof r=="function"&&await r(b,C),c(n.getFileTransfers())};return e?n&&n.isConnected()&&n.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 "+(s?"rgba(var(--sb-orange-rgb), 0.7)":"rgba(var(--sb-ink), 0.14)"),borderRadius:"14px",background:s?"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(b=>React.createElement("div",{key:b.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"}},`${b.fileName} \xB7 ${g(b.fileSize)} \xB7 ${b.mimeType}`)])]),React.createElement("div",{key:"actions",style:{display:"flex",gap:"8px"}},[React.createElement("button",{key:"accept",onClick:()=>T(b.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:()=>T(b.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(b=>React.createElement("div",{key:`send-${b.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)"}},b.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(b.fileSize))]),React.createElement("button",{key:"cancel",onClick:()=>n.cancelFileTransfer(b.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])]),w(b,"var(--sb-orange)")])),...o.receiving.map(b=>React.createElement("div",{key:`recv-${b.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)"}},b.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(b.fileSize))]),React.createElement("div",{key:"actions",className:"flex items-center space-x-2"},[b.status==="completed"?React.createElement("button",{key:"download",className:"text-green-400 hover:text-green-300 text-xs flex items-center",onClick:async()=>{try{let C=await n.getReceivedFileObjectURL(b.fileId);if(!C){alert(f("file.gone"));return}let x=document.createElement("a");x.href=C,x.download=b.fileName||"file",x.click(),setTimeout(()=>n.revokeReceivedFileObjectURL(C),1e4)}catch(C){alert(C.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:()=>n.cancelFileTransfer(b.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])])]),w(b,"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=Da;var ze=Object.freeze({MAX_SERVERS:10,MAX_URLS_PER_SERVER:8,MAX_STRING_LENGTH:512}),Go=Object.freeze(["stun","stuns","turn","turns"]),Pa=/^(stuns?|turns?):/i,Fa=/^(\[[0-9a-f:]+\]|[a-z0-9.-]+)(:\d{1,5})?$/i,Ka=/^transport=(udp|tcp)$/i;function Ms(n){for(let e=0;eze.MAX_STRING_LENGTH)return f("iceUrl.tooLong");if(Ms(e))return f("iceUrl.badChars");let t=e.match(Pa);if(!t)return f("iceUrl.badScheme");let r=e.slice(t[0].length),[i,s,...a]=r.split("?");return a.length>0?f("iceUrl.badQuery"):i?Fa.test(i)?s!==void 0&&!Ka.test(s)?f("iceUrl.badTransport"):null:f("iceUrl.badHost"):f("iceUrl.noHost")}function Ls(n){return typeof n=="string"&&/^turns?:/i.test(n.trim())}function Is(n,e){return n==null||n===""?null:typeof n!="string"?`${e} must be a string`:n.length>ze.MAX_STRING_LENGTH?`${e} is too long`:Ms(n)?`${e} contains invalid characters`:null}function Rs(n){let e=[],t=[],r=[];return Array.isArray(n)?n.length===0?{servers:[],errors:[],warnings:[]}:n.length>ze.MAX_SERVERS?(e.push(f("iceErr.tooMany",{max:ze.MAX_SERVERS})),{servers:[],errors:e,warnings:t}):(n.forEach((i,s)=>{let a=`Server #${s+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=Na(p);if(S){e.push(`${a}: ${S}`);continue}let g=p.trim();c.push(g),Ls(g)&&(d=!0)}if(c.length===0)return;let u=Is(i.username,`${a} username`);u&&e.push(u);let h=Is(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 Ds(n){if(typeof n!="string"||!n.trim())return{servers:[],errors:[],warnings:[]};let e=n.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 Rs(i)}let t=e.split(` +`).map(r=>r.trim()).filter(Boolean).map(r=>({urls:r}));return Rs(t)}function Ps(n){return Array.isArray(n)?n.some(e=>(Array.isArray(e?.urls)?e.urls:[e?.urls]).some(Ls)):!1}var Ve=window.React,Oa=["# 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 Ua(n,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:n})}catch(i){return{...t,error:i.message||f("ice.errInvalid")}}return new Promise(i=>{let s=!1,a=()=>{if(!s){s=!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 za=({isOpen:n,onClose:e,initial:t,hasSaved:r,onApply:i,onForget:s,embedded:a})=>{if(!n)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,_]=Ve.useState("idle"),[I,w]=Ve.useState(null),D=o?Ds(d):{servers:[],errors:[],warnings:[]},T=Ps(D.servers),v=!o||D.servers.length>0&&D.errors.length===0,b=async()=>{_("running"),w(null);let N=await Ua(D.servers);w(N),_("done")},C=()=>{v&&i({useCustom:o,servers:o?D.servers:[],privacyMode:h?"relay-only":"standard",serversText:d},p)},x=async()=>{s&&await s(),S(!1)},k=Ve.createElement,j="var(--sb-orange)",z="var(--sb-green)",M="var(--sb-orange-solid)",fe="var(--sb-green-solid)",re="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",pe=(N,R,P,K,O)=>k("button",{type:"button",onClick:R,style:Object.assign({width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${N?"rgba(var(--sb-orange-rgb), 0.45)":"rgba(var(--sb-ink), 0.07)"}`,background:N?"rgba(var(--sb-orange-rgb), 0.06)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"},O||{})},[k("span",{key:"ring",style:{flex:"none",width:"18px",height:"18px",marginTop:"1px",borderRadius:"50%",border:`1.5px solid ${N?j:"rgba(var(--sb-ink), 0.22)"}`,display:"grid",placeItems:"center"}},k("span",{style:{width:"8px",height:"8px",borderRadius:"50%",background:N?M:"transparent"}})),k("span",{key:"tx",style:{flex:1}},[k("span",{key:"t",style:{display:"block",fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},P),k("span",{key:"d",style:{display:"block",fontSize:"12.5px",color:"var(--sb-text-7)",marginTop:"2px"}},K)])]),me=(N,R,P,K,O,q)=>k("button",{type:"button",onClick:R,style:{width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${N?"rgba(var(--sb-green-rgb), 0.3)":"rgba(var(--sb-ink), 0.07)"}`,background:N?"rgba(var(--sb-green-rgb), 0.05)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"}},[k("span",{key:"tx",style:{flex:1}},[k("span",{key:"r1",style:{display:"flex",alignItems:"center",gap:"8px"}},[k("span",{key:"t",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},P),q&&k("span",{key:"b",style:{fontSize:"10px",fontWeight:700,color:z,padding:"2px 7px",borderRadius:"5px",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.22)"}},q)]),k("span",{key:"d",style:{display:"block",fontSize:"12.5px",lineHeight:1.5,color:"var(--sb-text-7)",marginTop:"3px"}},K)]),k("span",{key:"tr",style:{flex:"none",width:"42px",height:"24px",borderRadius:"99px",background:N?O||fe:"rgba(var(--sb-ink), 0.08)",border:`1px solid ${N?O||z:"rgba(var(--sb-ink), 0.12)"}`,position:"relative",transition:"all .18s",marginTop:"1px"}},k("span",{style:{position:"absolute",top:"2px",insetInlineStart:"2px",width:"18px",height:"18px",borderRadius:"50%",background:"#fff",transform:N?`translateX(${18*Oi()}px)`:"translateX(0)",transition:"transform .18s"}}))]),ce=[];if(ce.push(k("p",{key:"intro",style:{margin:"0 0 18px",fontSize:"13.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},f("ice.intro"))),ce.push(pe(!o,()=>c(!1),f("ice.publicTitle"),f("ice.publicDesc"))),ce.push(pe(o,()=>c(!0),f("ice.customTitle"),f("ice.customDesc",{max:ze.MAX_SERVERS}),o?{marginBottom:"14px"}:null)),o){let N=[];N.push(k("div",{key:"ta",style:{borderRadius:"13px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-bg-deep)",overflow:"hidden",marginBottom:"12px"}},k("textarea",{dir:"ltr",value:d,onChange:P=>u(P.target.value),rows:5,spellCheck:!1,autoComplete:"off",placeholder:Oa,style:{width:"100%",resize:"vertical",border:"none",outline:"none",background:"transparent",color:"var(--sb-text-code)",fontFamily:re,fontSize:"12px",lineHeight:1.65,padding:"13px 14px",minHeight:"104px"}}))),D.errors.length>0&&N.push(k("ul",{key:"err",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-red)",fontSize:"12.5px"}},D.errors.slice(0,6).map((P,K)=>k("li",{key:K},P)))),D.warnings.length>0&&N.push(k("ul",{key:"warn",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-yellow)",fontSize:"12.5px"}},D.warnings.slice(0,6).map((P,K)=>k("li",{key:K},P)))),D.servers.length>0&&D.errors.length===0&&N.push(k("p",{key:"ok",style:{margin:"0 0 10px",fontSize:"12.5px",color:z}},`${D.servers.length} server(s) parsed${T?" (TURN present)":" (STUN only \u2014 does not hide IP)"}.`)),N.push(k("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"}},[k("i",{key:"i",className:"fas fa-info-circle",style:{color:z,fontSize:"13px",marginTop:"2px",flex:"none"}}),k("span",{key:"t",style:{fontSize:"12px",lineHeight:1.55,color:"var(--sb-green-muted)"}},[f("ice.turnNote"),k("span",{key:"m",style:{fontFamily:re,color:z}},"turns:"),f("ice.turnNoteTls")])]));let R=g==="done"&&I&&!I.error?z:"var(--sb-text-4)";N.push(k("div",{key:"test",style:{display:"flex",alignItems:"center",gap:"12px",flexWrap:"wrap",marginBottom:"4px"}},[k("button",{key:"btn",type:"button",disabled:!v||g==="running",onClick:b,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"10px 15px",borderRadius:"10px",border:`1px solid ${g==="done"&&I&&!I.error?"rgba(var(--sb-green-rgb), 0.4)":"rgba(var(--sb-ink), 0.1)"}`,background:g==="done"&&I&&!I.error?"rgba(var(--sb-green-rgb), 0.08)":"rgba(var(--sb-ink), 0.04)",color:R,fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:!v||g==="running"?"not-allowed":"pointer",opacity:!v||g==="running"?.6:1}},[k("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"&&I?k("span",{key:"res",style:{fontSize:"12px",color:I.error?"var(--sb-red)":"var(--sb-text-7)"}},I.error?`Test failed: ${I.error}`:I.srflx>0||I.relay>0?`STUN ${I.srflx>0?"OK":"none"} \xB7 TURN ${I.relay>0?"OK":"none"} \xB7 host ${I.host}`:`host ${I.host} \xB7 this browser hides STUN/TURN candidates from the test \u2014 your servers still apply to real connections`):null])),ce.push(k("div",{key:"custom",style:{marginBottom:"16px"}},N))}ce.push(me(h,()=>m(!h),f("ice.relayTitle"),f("ice.relayDesc"),z,f("ice.relayBadge"))),h&&o&&!T&&ce.push(k("p",{key:"relaywarn",style:{margin:"-4px 0 10px",fontSize:"12.5px",color:"var(--sb-yellow)"}},f("ice.relayWarning"))),ce.push(me(p,()=>S(!p),f("ice.persist"),f("ice.persistDesc"),j));let ve=[];return r&&ve.push(k("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"))),ve.push(k("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"))),ve.push(k("button",{key:"apply",type:"button",onClick:C,disabled:!v,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"11px 20px",borderRadius:"11px",border:"none",background:M,color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:700,cursor:v?"pointer":"not-allowed",opacity:v?1:.5,boxShadow:"0 6px 18px rgba(var(--sb-orange-rgb), 0.28)"}},[k("i",{key:"i",className:"fas fa-check"}),f("ice.apply")])),k("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)"}},[k(Ve.Fragment,{key:"panel"},[k("div",{key:"head",style:{display:"flex",alignItems:"center",gap:"12px",padding:"20px 24px",borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"}},[k("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)"}},k("i",{className:"fas fa-sliders-h",style:{color:"var(--sb-text-4)",fontSize:"15px"}})),k("div",{key:"tx",style:{flex:1,lineHeight:1.25}},[k("div",{key:"t",style:{fontSize:"16.5px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-1)"}},f("ice.title")),k("div",{key:"s",style:{fontSize:"12px",color:"var(--sb-text-8)"}},f("ice.subtitle"))]),k("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"}},k("i",{className:"fas fa-times"}))]),k("div",{key:"body",className:"custom-scrollbar",style:{flex:1,overflowY:"auto",padding:"20px 24px"}},ce),k("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"}},ve)])])};window.IceServerSettings=za;var Va=({webrtcManager:n,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:''},s=(K,O,q)=>t("span",{style:{display:"grid",placeItems:"center",width:O+"px",height:O+"px"},dangerouslySetInnerHTML:{__html:`${K}`}}),[a,o]=React.useState(()=>n?.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(!n)return;let K=q=>o(q),O=n.onCallStateChanged;return n.onCallStateChanged=K,o(n.getCallState?n.getCallState():{phase:"idle",active:!1}),()=>{n.onCallStateChanged===K&&(n.onCallStateChanged=O||null)}},[n]);let g=a.phase||"idle",_=!!a.active,I=!!a.withVideo||!!a.remoteHasVideo;if(React.useEffect(()=>{let K=n?.getRemoteMediaStream?.(),O=n?.getLocalMediaStream?.(),q=(Y,Se,_e)=>{if(!Y||!Se)return;Y.srcObject!==Se&&(Y.muted=_e,Y.srcObject=Se);let ye=Y.play&&Y.play();ye&&ye.catch&&ye.catch(()=>{})};q(p.current,K,!1,"remoteAudio"),q(m.current,K,!0,"remoteVideo"),q(S.current,O,!0,"selfVideo")}),React.useEffect(()=>{if(g!=="active"){h(0);return}let K=Date.now(),O=setInterval(()=>h(Math.floor((Date.now()-K)/1e3)),1e3);return()=>clearInterval(O)},[g]),React.useEffect(()=>{g==="idle"&&d(!1)},[g]),!_||g==="idle"||g==="ended"||a.groupCallId)return null;let w=K=>`${String(Math.floor(K/60)).padStart(2,"0")}:${String(K%60).padStart(2,"0")}`,D=g==="outgoing"||g==="connecting",T=g==="outgoing"?f("call.ringing"):g==="connecting"?f("call.connecting"):g==="active"?w(u):f("call.ringing"),v=e||f("call.peer"),b={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"},C={...b,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"},k=K=>({width:"36px",height:"36px",borderRadius:"9px",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), "+(K?"0.15":"0.1")+")",background:K?"rgba(0,0,0,0.35)":"rgba(var(--sb-ink), 0.04)",color:K?"#fff":"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}),j=t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"4px",fontSize:"11px",fontWeight:600,color:"var(--sb-green)"}},[s(i.lock,11,2),f("call.encryptedShort")]),z={excellent:{bars:4,color:"var(--sb-green)",label:f("call.qualityExcellent")},good:{bars:3,color:"var(--sb-green)",label:f("call.qualityGood")},fair:{bars:2,color:"var(--sb-yellow)",label:f("call.qualityFair")},poor:{bars:1,color:"var(--sb-red)",label:f("call.qualityWeak")}},M=K=>{let O=z[a.quality];if(!O)return null;let q=t("span",{key:"bars",style:{display:"inline-flex",alignItems:"flex-end",gap:"2px",height:"14px"}},[0,1,2,3].map(Y=>t("span",{key:Y,style:{width:"3px",height:5+Y*3+"px",borderRadius:"1px",background:Yn?.acceptCall?.(),re=()=>n?.declineCall?.(),pe=()=>{d(!1),n?.endCall?.()},me=()=>n?.toggleMic?.(),ce=()=>n?.toggleCamera?.(),ve=()=>n?.switchCamera?.(),G=()=>n?.upgradeToVideo?.(),N=t("audio",{key:"ra",ref:p,autoPlay:!0,playsInline:!0,style:{display:"none"}}),R=(K,O,q)=>t("div",{key:K,style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"}},[O,t("span",{key:"l",style:{fontFamily:r,fontSize:"10.5px",color:"var(--sb-text-7)"}},q)]),P=(K,O)=>t("div",{key:"av",style:{position:"relative",width:"120px",height:"120px",marginBottom:"28px",display:"grid",placeItems:"center"}},[O&&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"}}),O&&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)"}},s(i.user,K,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"}},[N,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)"}},[s(i.lock,13,2),f("call.encrypted")])),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[P(46,!0),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},v),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"}},[R("dec",t("button",{onClick:re,title:f("call.decline"),style:{...x,width:"62px",height:"62px"}},s(i.phoneHangup,24,1.9)),f("call.decline")),R("acc",t("button",{onClick:fe,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)"}},s(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"}},[N,I&&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)"}},s(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)"}},T)]),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)"}},s(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"}},v),t("div",{key:"s",style:{display:"flex",alignItems:"center",gap:"7px",fontFamily:r,fontSize:"11px",color:"var(--sb-text-6)"}},[(I?f("call.videoPrefix"):f("call.voicePrefix"))+T,g==="active"&&M(!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"}},s(i.expand,15,2)),t("button",{key:"end",onClick:pe,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"}},s(i.phoneHangup,15,2))])]):I?t("div",{style:{position:"absolute",inset:0,zIndex:40,overflow:"hidden",background:"var(--sb-bg-deepest)",animation:"sbExpand .2s ease"}},[N,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)"}},s(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"}},v),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)"}},T),j,g==="active"&&M(!1)])]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:{flex:"none",...k(!0)}},s(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)"}},[s(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:me,title:f("call.mute"),style:a.micEnabled?b:C},s(a.micEnabled?i.micOn:i.micOff,21,1.9)),t("button",{key:"cam",onClick:ce,title:f("call.camera"),style:a.cameraEnabled?b:C},s(a.cameraEnabled?i.camOn:i.camOff,21,1.8)),t("button",{key:"flip",onClick:ve,title:f("call.flipCamera"),style:b},s(i.flip,21,1.8)),t("button",{key:"end",onClick:pe,title:f("call.end"),style:x},s(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"}},[N,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)"}},[s(i.lock,13,2),f("call.encrypted")]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:k(!1)},s(i.minimize,16,2))]),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[P(46,D),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},v),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},T),g==="active"&&t("div",{key:"q",style:{marginTop:"12px"}},M(!1))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"26px",padding:"28px 24px 34px"}},[R("mute",t("button",{onClick:me,title:f("call.mute"),style:a.micEnabled?b:C},s(a.micEnabled?i.micOn:i.micOff,22,1.9)),a.micEnabled?"Mute":f("call.muted")),R("video",t("button",{onClick:G,title:f("call.addVideo"),style:b},s(i.camOn,22,1.8)),f("call.video")),R("end",t("button",{onClick:pe,title:f("call.end"),style:x},s(i.phoneHangup,22,1.9)),f("call.endShort"))])])};typeof window<"u"&&(window.CallUIComponent=Va);window.EnhancedSecureCryptoUtils=Rt;window.EnhancedSecureWebRTCManager=Bt;window.EnhancedSecureFileTransfer=je;window.NotificationIntegration=Ns.NotificationIntegration;var Ba=()=>{try{let n=[];for(let e=0;e(window.__qrReady||(window.__qrReady=import("/dist/qr-local.js").then(()=>{window.dispatchEvent(new Event("securebit:qr-ready"))}).catch(n=>{console.warn("QR bundle failed to load:",n&&n.message),window.__qrReady=null})),window.__qrReady),Ha=()=>{typeof window.requestIdleCallback=="function"?window.requestIdleCallback(Fs,{timeout:3e3}):setTimeout(Fs,1200)},Ks=()=>{Ba(),typeof window.initializeApp=="function"?window.initializeApp():window.DEBUG_MODE&&console.error("initializeApp is not defined on window"),Ha()};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ks):Ks(); /** * 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 a01b866..8a26a86 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/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/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