Files
securebit-chat/dist/app-boot.js
T
lockbitchat 9e63cf65a4 v6.8.0: light theme
The palette lived as ~620 hex literals in inline styles plus a few hundred more in
the stylesheets, so there was no single thing to change. It is now 113 custom
properties in src/styles/theme.css, in two blocks.

src/scripts/theme-boot.js decides the theme before first paint — blocking, in <head>,
above the stylesheet, because a deferred script paints dark first and corrects itself.
It stores the mode ('system' | 'light' | 'dark'), never the colour it resolved to, and
stamps data-theme so an explicit choice can beat the media query. The switcher in the
header is a view onto it.

A filled accent stays the brand colour in both themes — the ink on it is near-black
either way — while an accent used as text darkens to clear 4.5:1 on white. A colour
reaches a fill by four routes (a style property, a constant, a helper argument, an SVG
source string), and tests/theme-switching.test.mjs covers all four.

The dark theme is unchanged: every colour declaration the previous build produced comes
out of this one identically once the properties are resolved.

Also: the roadmap drops its status chips on mobile, and Roadmap.jsx no longer splits a
colour with parseInt at runtime, which a var() reference cannot survive.
2026-09-04 17:38:41 -04:00

130 lines
588 KiB
JavaScript

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,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").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<this.rateLimitMs?!1:(this.lastNotificationTime=e,!0)}notify(e,t,r={}){if(typeof Notification>"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);t<e;t++)r[t]=n[t];return r}function on(n){if(Array.isArray(n))return n}function cn(n,e){var t=n==null?null:typeof Symbol<"u"&&n[Symbol.iterator]||n["@@iterator"];if(t!=null){var r,i,s,a,o=[],c=!0,d=!1;try{if(s=(t=t.call(n)).next,e!==0)for(;!(c=(r=s.call(t)).done)&&(o.push(r.value),o.length!==e);c=!0);}catch(u){d=!0,i=u}finally{try{if(!c&&t.return!=null&&(a=t.return(),Object(a)!==a))return}finally{if(d)throw i}}return o}}function ln(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function dn(n,e){return on(n)||cn(n,e)||un(n,e)||ln()}function un(n,e){if(n){if(typeof n=="string")return gi(n,e);var t={}.toString.call(n).slice(8,-1);return t==="Object"&&n.constructor&&(t=n.constructor.name),t==="Map"||t==="Set"?Array.from(n):t==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?gi(n,e):void 0}}var Ri=Object.entries,mi=Object.setPrototypeOf,hn=Object.isFrozen,fn=Object.getPrototypeOf,pn=Object.getOwnPropertyDescriptor,ne=Object.freeze,ae=Object.seal,rt=Object.create,Mi=typeof Reflect<"u"&&Reflect,_r=Mi.apply,br=Mi.construct;ne||(ne=function(e){return e});ae||(ae=function(e){return e});_r||(_r=function(e,t){for(var r=arguments.length,i=new Array(r>2?r-2:0),s=2;s<r;s++)i[s-2]=arguments[s];return e.apply(t,i)});br||(br=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),i=1;i<t;i++)r[i-1]=arguments[i];return new e(...r)});var ht=te(Array.prototype.forEach),yn=te(Array.prototype.lastIndexOf),Si=te(Array.prototype.pop),tt=te(Array.prototype.push),gn=te(Array.prototype.splice),Fe=Array.isArray,yt=te(String.prototype.toLowerCase),pr=te(String.prototype.toString),_i=te(String.prototype.match),ft=te(String.prototype.replace),bi=te(String.prototype.indexOf),mn=te(String.prototype.trim),Sn=te(Number.prototype.toString),_n=te(Boolean.prototype.toString),wi=typeof BigInt>"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;i<t;i++)r[i-1]=arguments[i];return _r(n,e,r)}}function bn(n){return function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return br(n,t)}}function V(n,e){let t=arguments.length>2&&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<n.length;e++)he(n,e)||(n[e]=null);return n}function ue(n){let e=rt(null);for(let r of Ri(n)){var t=dn(r,2);let i=t[0],s=t[1];he(n,i)&&(Fe(s)?e[i]=wn(s):s&&typeof s=="object"&&s.constructor===Object?e[i]=ue(s):e[i]=s)}return e}function En(n){switch(typeof n){case"string":return n;case"number":return Sn(n);case"boolean":return _n(n);case"bigint":return wi?wi(n):"0";case"symbol":return Ei?Ei(n):"Symbol()";case"undefined":return pt(n);case"function":case"object":{if(n===null)return pt(n);let e=n,t=Ae(e,"toString");if(typeof t=="function"){let r=t(e);return typeof r=="string"?r:pt(r)}return pt(n)}default:return pt(n)}}function Ae(n,e){for(;n!==null;){let r=pn(n,e);if(r){if(r.get)return te(r.get);if(typeof r.value=="function")return te(r.value)}n=fn(n)}function t(){return null}return t}function vn(n){try{return se(n,""),!0}catch{return!1}}var vi=ne(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),yr=ne(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),gr=ne(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),Tn=ne(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),mr=ne(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),Cn=ne(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),Ti=ne(["#text"]),Ci=ne(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","command","commandfor","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","exportparts","face","for","headers","height","hidden","high","href","hreflang","id","inert","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","part","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","slot","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns"]),Sr=ne(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mask-type","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),ki=ne(["accent","accentunder","align","bevelled","close","columnalign","columnlines","columnspacing","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lquote","lspace","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),It=ne(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),kn=ae(/{{[\w\W]*|^[\w\W]*}}/g),An=ae(/<%[\w\W]*|^[\w\W]*%>/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="<remove></remove>"+l;else{let B=_i(l,/^[\r\n\t ]+/);E=B&&B[0]}dt==="application/xhtml+xml"&&Je===Ce&&(l='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+l+"</body></html>");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="<!DOCTYPE "+y.ownerDocument.doctype.name+`>
`+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<i;s++)t+=String.fromCharCode(r[s]);return btoa(t)}static base64ToArrayBuffer(e){try{if(typeof e!="string"||!e)throw new Error("Invalid base64 input: must be a non-empty string");let t=e.trim();if(!/^[A-Za-z0-9+/]*={0,2}$/.test(t))throw new Error("Invalid base64 format");if(t==="")return new ArrayBuffer(0);let r=atob(t),i=r.length,s=new Uint8Array(i);for(let a=0;a<i;a++)s[a]=r.charCodeAt(a);return s.buffer}catch(t){throw console.error("Base64 to ArrayBuffer conversion failed:",t.message),new Error(`Base64 conversion error: ${t.message}`)}}static hexToUint8Array(e){try{if(!e||typeof e!="string")throw new Error("Invalid hex string input: must be a non-empty string");let t=e.replace(/:/g,"").replace(/\s/g,"");if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("Invalid hex format: contains non-hex characters");if(t.length%2!==0)throw new Error("Invalid hex format: odd length");let r=new Uint8Array(t.length/2);for(let i=0;i<t.length;i+=2)r[i/2]=parseInt(t.substr(i,2),16);return r}catch(t){throw console.error("Hex to Uint8Array conversion failed:",t.message),new Error(`Hex conversion error: ${t.message}`)}}static zeroizeBuffer(e){try{if(!e)return;let t=e instanceof Uint8Array?e:e instanceof ArrayBuffer?new Uint8Array(e):null;if(!t||t.length===0)return;crypto.getRandomValues(t),t.fill(0)}catch{}}static async encryptData(e,t){try{let r=typeof e=="string"?e:JSON.stringify(e),i=crypto.getRandomValues(new Uint8Array(16)),s=new TextEncoder,a=s.encode(t),o=await crypto.subtle.importKey("raw",a,{name:"PBKDF2"},!1,["deriveKey"]),c=await crypto.subtle.deriveKey({name:"PBKDF2",salt:i,iterations:31e4,hash:"SHA-256"},o,{name:"AES-GCM",length:256},!1,["encrypt"]),d=crypto.getRandomValues(new Uint8Array(12)),u=s.encode(r),h=await crypto.subtle.encrypt({name:"AES-GCM",iv:d},c,u),m={version:"1.0",salt:Array.from(i),iv:Array.from(d),data:Array.from(new Uint8Array(h)),timestamp:Date.now()},p=JSON.stringify(m);return n.arrayBufferToBase64(new TextEncoder().encode(p).buffer)}catch(r){throw console.error("Encryption failed:",r.message),new Error(`Encryption error: ${r.message}`)}}static async decryptData(e,t){try{let r=n.base64ToArrayBuffer(e),i=new TextDecoder().decode(r),s=JSON.parse(i);if(!s.version||!s.salt||!s.iv||!s.data)throw new Error("Invalid encrypted data format");let a=new Uint8Array(s.salt),o=new Uint8Array(s.iv),c=new Uint8Array(s.data),u=new TextEncoder().encode(t),h=await crypto.subtle.importKey("raw",u,{name:"PBKDF2"},!1,["deriveKey"]),m=await crypto.subtle.deriveKey({name:"PBKDF2",salt:a,iterations:31e4,hash:"SHA-256"},h,{name:"AES-GCM",length:256},!1,["decrypt"]),p=await crypto.subtle.decrypt({name:"AES-GCM",iv:o},m,c),S=new TextDecoder().decode(p);try{return JSON.parse(S)}catch{return S}}catch(r){throw console.error("Decryption failed:",r.message),new Error(`Decryption error: ${r.message}`)}}static generateSecurePassword(){let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?",t=e.length,r=32,i="";for(let s=0;s<r;s++){let a;do a=crypto.getRandomValues(new Uint32Array(1))[0];while(a>=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;a<i;a++)if(!await t.checkMessageRate(r,i,6e4))return{passed:!1,details:`Rate limiter refused message ${a+1} of ${i} while under the limit`};let s=await t.checkMessageRate(r,i,6e4);return t.messages.delete(`msg_${r}`),s?{passed:!1,details:"Rate limiter did not block a message over the limit"}:{passed:!0,details:`Rate limiting verified: ${i} allowed, the next refused`}}catch(t){return{passed:!1,details:`Rate limiting test failed: ${t.message}`}}}static async verifyMetadataProtection(e){try{let t=e?.metadataKey;if(!t||!(t instanceof CryptoKey))return{passed:!1,details:"Metadata encryption key not available"};if(t.algorithm?.name!=="AES-GCM")return{passed:!1,details:`Metadata key has the wrong algorithm: ${t.algorithm?.name}`};if(t.extractable)return{passed:!1,details:"Metadata key is extractable"};if(e.encryptionKey===t)return{passed:!1,details:"Metadata key is not separated from the message key"};let r=crypto.getRandomValues(new Uint8Array(12)),i=new TextEncoder().encode("metadata-protection-selftest"),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:r},t,i),a=await crypto.subtle.decrypt({name:"AES-GCM",iv:r},t,s);return new TextDecoder().decode(a)!=="metadata-protection-selftest"?{passed:!1,details:"Metadata encryption round-trip mismatch"}:{passed:!0,details:"Metadata is encrypted under a separate non-extractable key"}}catch(t){return{passed:!1,details:`Metadata protection test failed: ${t.message}`}}}static async verifyPerfectForwardSecrecy(e){try{if(!(!!e?.ecdhKeyPair?.privateKey&&e.ecdhKeyPair.privateKey.extractable===!1))return{passed:!1,details:"No non-extractable ephemeral ECDH key pair for this session"};if(e?.isRatchetActive?.()){let r=e._ratchet?.getState?.()||{};return{passed:!0,details:`Double Ratchet active: per-message keys destroyed after use, DH re-key on each reply (sent ${r.sendCount??0}, received ${r.receiveCount??0} on the current chain)`}}return{passed:!1,details:"Session-level PFS only: keys are ephemeral per session, but the Double Ratchet is not active for this connection (peer on an older version), so a compromised session key exposes the whole conversation"}}catch(t){return{passed:!1,details:`PFS test failed: ${t.message}`}}}static async verifyReplayProtection(e){try{return e.replayProtection?{passed:!0,details:"Replay protection is working correctly"}:{passed:!1,details:"Replay protection not enabled"}}catch(t){return{passed:!1,details:`Replay protection test failed: ${t.message}`}}}static async verifyDTLSFingerprint(e){try{return e.dtlsFingerprint?{passed:!0,details:"DTLS fingerprint is valid and available"}:{passed:!1,details:"DTLS fingerprint not available"}}catch(t){return{passed:!1,details:`DTLS fingerprint test failed: ${t.message}`}}}static async verifySASVerification(e){try{return e.sasCode?{passed:!0,details:"SAS verification code is valid and available"}:{passed:!1,details:"SAS code not available"}}catch(t){return{passed:!1,details:`SAS verification test failed: ${t.message}`}}}static async verifyTrafficObfuscation(e){try{return e.trafficObfuscation?{passed:!0,details:"Traffic obfuscation is working correctly"}:{passed:!1,details:"Traffic obfuscation not enabled"}}catch(t){return{passed:!1,details:`Traffic obfuscation test failed: ${t.message}`}}}static async verifyNestedEncryption(e){try{if(!e.nestedEncryptionKey||!(e.nestedEncryptionKey instanceof CryptoKey))return console.warn("Nested encryption key not available or invalid"),!1;let i=new TextEncoder().encode("Test nested encryption verification"),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:crypto.getRandomValues(new Uint8Array(12))},e.nestedEncryptionKey,i);return s&&s.byteLength>0}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<r);return o.length>=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<r);return o.length>=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-a<t);s.length===0?this.messages.delete(r):this.messages.set(r,s)}for(let[r,i]of this.connections.entries()){if(this.locks.has(r))continue;let s=i.filter(a=>e-a<t);s.length===0?this.connections.delete(r):this.connections.set(r,s)}for(let r of this.locks.keys()){let i=parseInt(r.split("_").pop())||0;e-i>3e4&&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<d;u++){if(a+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(;d<o.length;){let u=n.parseASN1(o,d);if(!u)break;c.children.push(u),d=d+1+u.lengthBytes+u.length}}return c.lengthBytes=a-i,c}static oidToString(e){if(!e||e.length===0)throw new Error("Empty OID");let t=[],r=Math.floor(e[0]/40),i=e[0]%40;t.push(r),t.push(i);let s=0;for(let a=1;a<e.length;a++)s=s<<7|e[a]&127,e[a]&128||(t.push(s),s=0);return t.join(".")}static validateOidString(e){if(!/^[0-9]+(\.[0-9]+)*$/.test(e))throw new Error(`Invalid OID format: ${e}`);let r=e.split(".").map(Number);if(r[0]>2)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.sequenceNumber<s)throw n.secureLog.log("error","Rejected message with stale sequence number - possible replay",{expected:s,received:g.sequenceNumber,messageId:g.id}),new Error(`Stale sequence number: expected at least ${s}, got ${g.sequenceNumber}`);if(g.sequenceNumber>s+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;o<Math.max(r.length,i.length);o++)a|=(r.charCodeAt(o%r.length)||0)^(i.charCodeAt(o%i.length)||0);return!1}let s=0;for(let a=0;a<r.length;a++)s|=r.charCodeAt(a)^i.charCodeAt(a);return s===0}static constantTimeCompareArrays(e,t){if(!Array.isArray(e)||!Array.isArray(t))return!1;if(e.length!==t.length){let i=0,s=Math.max(e.length,t.length);for(let a=0;a<s;a++)i|=(e[a%e.length]||0)^(t[a%t.length]||0);return!1}let r=0;for(let i=0;i<e.length;i++)r|=e[i]^t[i];return r===0}static async encryptDataWithAAD(e,t,r){try{let i=typeof e=="string"?e:JSON.stringify(e),s=new TextEncoder,a=s.encode(i),o=s.encode(r),c=crypto.getRandomValues(new Uint8Array(12)),d=await crypto.subtle.encrypt({name:"AES-GCM",iv:c,additionalData:o},t,a),u={version:"1.0",iv:Array.from(c),data:Array.from(new Uint8Array(d)),aad:r,timestamp:Date.now()},h=JSON.stringify(u),m=s.encode(h);return n.arrayBufferToBase64(m)}catch(i){throw new Error(`AAD encryption failed: ${i.message}`)}}static async decryptDataWithAAD(e,t,r){try{let i=n.base64ToArrayBuffer(e),s=new TextDecoder().decode(i),a=JSON.parse(s);if(!a.version||!a.iv||!a.data||!a.aad)throw new Error("Invalid encrypted data format");if(a.aad!==r)throw new Error("AAD mismatch - possible tampering or replay attack");let o=new Uint8Array(a.iv),c=new Uint8Array(a.data),d=new TextEncoder().encode(a.aad),u=await crypto.subtle.decrypt({name:"AES-GCM",iv:o,additionalData:d},t,c),h=new TextDecoder().decode(u);try{return JSON.parse(h)}catch{return h}}catch(i){throw new Error(`AAD decryption failed: ${i.message}`)}}static{n.secureLog&&typeof n.secureLog.init=="function"&&n.secureLog.init()}};var Ke=["en","de","fr","es","uk","ru","zh","ko","hi","ar","he","fa","ur"],it={en:{htmlLang:"en",nativeName:"English",abbr:"EN",dir:"ltr",path:"/"},de:{htmlLang:"de",nativeName:"Deutsch",abbr:"DE",dir:"ltr",path:"/de/"},fr:{htmlLang:"fr",nativeName:"Fran\xE7ais",abbr:"FR",dir:"ltr",path:"/fr/"},es:{htmlLang:"es",nativeName:"Espa\xF1ol",abbr:"ES",dir:"ltr",path:"/es/"},uk:{htmlLang:"uk",nativeName:"\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430",abbr:"UK",dir:"ltr",path:"/uk/"},ru:{htmlLang:"ru",nativeName:"\u0420\u0443\u0441\u0441\u043A\u0438\u0439",abbr:"RU",dir:"ltr",path:"/ru/"},zh:{htmlLang:"zh-Hans",nativeName:"\u7B80\u4F53\u4E2D\u6587",abbr:"ZH",dir:"ltr",path:"/zh/"},ko:{htmlLang:"ko",nativeName:"\uD55C\uAD6D\uC5B4",abbr:"KO",dir:"ltr",path:"/ko/"},hi:{htmlLang:"hi",nativeName:"\u0939\u093F\u0928\u094D\u0926\u0940",abbr:"HI",dir:"ltr",path:"/hi/"},ar:{htmlLang:"ar",nativeName:"\u0627\u0644\u0639\u0631\u0628\u064A\u0629",abbr:"AR",dir:"rtl",path:"/ar/"},he:{htmlLang:"he",nativeName:"\u05E2\u05D1\u05E8\u05D9\u05EA",abbr:"HE",dir:"rtl",path:"/he/"},fa:{htmlLang:"fa",nativeName:"\u0641\u0627\u0631\u0633\u06CC",abbr:"FA",dir:"rtl",path:"/fa/"},ur:{htmlLang:"ur",nativeName:"\u0627\u0631\u062F\u0648",abbr:"UR",dir:"rtl",path:"/ur/"}},Pi={en:{"language.suggest.text":"This page is also available in English.","language.suggest.cta":"Read in English","language.suggest.dismiss":"Dismiss"},de:{"language.suggest.text":"Diese Seite gibt es auch auf Deutsch.","language.suggest.cta":"Auf Deutsch lesen","language.suggest.dismiss":"Schlie\xDFen"},fr:{"language.suggest.text":"Cette page est aussi disponible en fran\xE7ais.","language.suggest.cta":"Lire en fran\xE7ais","language.suggest.dismiss":"Fermer"},es:{"language.suggest.text":"Esta p\xE1gina tambi\xE9n est\xE1 disponible en espa\xF1ol.","language.suggest.cta":"Leer en espa\xF1ol","language.suggest.dismiss":"Cerrar"},uk:{"language.suggest.text":"\u0426\u044F \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0430 \u0442\u0430\u043A\u043E\u0436 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u043E\u044E.","language.suggest.cta":"\u0427\u0438\u0442\u0430\u0442\u0438 \u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u043E\u044E","language.suggest.dismiss":"\u0417\u0430\u043A\u0440\u0438\u0442\u0438"},ru:{"language.suggest.text":"\u042D\u0442\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0442\u0430\u043A\u0436\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043D\u0430 \u0440\u0443\u0441\u0441\u043A\u043E\u043C.","language.suggest.cta":"\u0427\u0438\u0442\u0430\u0442\u044C \u043F\u043E-\u0440\u0443\u0441\u0441\u043A\u0438","language.suggest.dismiss":"\u0417\u0430\u043A\u0440\u044B\u0442\u044C"},zh:{"language.suggest.text":"\u672C\u9875\u9762\u4E5F\u6709\u7B80\u4F53\u4E2D\u6587\u7248\u672C\u3002","language.suggest.cta":"\u9605\u8BFB\u7B80\u4F53\u4E2D\u6587","language.suggest.dismiss":"\u5173\u95ED"},ko:{"language.suggest.text":"\uC774 \uD398\uC774\uC9C0\uB294 \uD55C\uAD6D\uC5B4\uB85C\uB3C4 \uBCFC \uC218 \uC788\uC2B5\uB2C8\uB2E4.","language.suggest.cta":"\uD55C\uAD6D\uC5B4\uB85C \uBCF4\uAE30","language.suggest.dismiss":"\uB2EB\uAE30"},hi:{"language.suggest.text":"\u092F\u0939 \u092A\u0943\u0937\u094D\u0920 \u0939\u093F\u0928\u094D\u0926\u0940 \u092E\u0947\u0902 \u092D\u0940 \u0909\u092A\u0932\u092C\u094D\u0927 \u0939\u0948\u0964","language.suggest.cta":"\u0939\u093F\u0928\u094D\u0926\u0940 \u092E\u0947\u0902 \u092A\u0922\u093C\u0947\u0902","language.suggest.dismiss":"\u092C\u0902\u0926 \u0915\u0930\u0947\u0902"},ar:{"language.suggest.text":"\u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062D\u0629 \u0645\u062A\u0648\u0641\u0631\u0629 \u0623\u064A\u0636\u064B\u0627 \u0628\u0627\u0644\u0639\u0631\u0628\u064A\u0629.","language.suggest.cta":"\u0627\u0642\u0631\u0623 \u0628\u0627\u0644\u0639\u0631\u0628\u064A\u0629","language.suggest.dismiss":"\u0625\u063A\u0644\u0627\u0642"},he:{"language.suggest.text":"\u05D4\u05D3\u05E3 \u05D4\u05D6\u05D4 \u05D6\u05DE\u05D9\u05DF \u05D2\u05DD \u05D1\u05E2\u05D1\u05E8\u05D9\u05EA.","language.suggest.cta":"\u05DC\u05E7\u05E8\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D1\u05E8\u05D9\u05EA","language.suggest.dismiss":"\u05E1\u05D2\u05D9\u05E8\u05D4"},fa:{"language.suggest.text":"\u0627\u06CC\u0646 \u0635\u0641\u062D\u0647 \u0628\u0647 \u0641\u0627\u0631\u0633\u06CC \u0647\u0645 \u062F\u0631 \u062F\u0633\u062A\u0631\u0633 \u0627\u0633\u062A.","language.suggest.cta":"\u062E\u0648\u0627\u0646\u062F\u0646 \u0628\u0647 \u0641\u0627\u0631\u0633\u06CC","language.suggest.dismiss":"\u0628\u0633\u062A\u0646"},ur:{"language.suggest.text":"\u06CC\u06C1 \u0635\u0641\u062D\u06C1 \u0627\u0631\u062F\u0648 \u0645\u06CC\u06BA \u0628\u06BE\u06CC \u062F\u0633\u062A\u06CC\u0627\u0628 \u06C1\u06D2\u06D4","language.suggest.cta":"\u0627\u0631\u062F\u0648 \u0645\u06CC\u06BA \u067E\u0691\u06BE\u06CC\u06BA","language.suggest.dismiss":"\u0628\u0646\u062F \u06A9\u0631\u06CC\u06BA"}};var zn={"language.label":"Language","language.suggest.text":"This page is also available in English.","language.suggest.cta":"Read in English","language.suggest.dismiss":"Dismiss","theme.label":"Theme","theme.system":"System","theme.light":"Light","theme.dark":"Dark","community.title":"Join the future of privacy","community.description":"SecureBit grows thanks to its community. Your ideas and feedback shape the future of secure communication - built in the open, with complete ASN.1 validation end-to-end.","community.github":"GitHub Repository","community.feedback":"Feedback","unique.eyebrow":"What sets us apart","unique.heading":"Why SecureBit is unique","unique.s1.titleTop":"Layered","unique.s1.titleBottom":"encryption core","unique.s1.collapsed":"Encryption core","unique.s1.desc":"ECDH P-384 key exchange, AES-256-GCM payloads, ECDSA signatures and full ASN.1 validation - composed into one hardened pipeline.","unique.s1.tags":["ECDH P-384","AES-256-GCM","ECDSA","ASN.1"],"unique.s2.titleTop":"Pure P2P","unique.s2.titleBottom":"WebRTC","unique.s2.collapsed":"Pure P2P WebRTC","unique.s2.desc":"Messages travel directly between devices over WebRTC. No relay holds your data - the server only helps two peers find each other.","unique.s2.tags":["DTLS 1.3","No relay"],"unique.s3.titleTop":"Perfect","unique.s3.titleBottom":"forward secrecy","unique.s3.collapsed":"Forward secrecy","unique.s3.desc":"Session keys rotate continuously and are discarded after use, so a single compromised key can never unlock past conversations.","unique.s3.tags":["Ephemeral keys","Auto-rotate"],"unique.s4.titleTop":"Traffic","unique.s4.titleBottom":"obfuscation","unique.s4.collapsed":"Traffic obfuscation","unique.s4.desc":"Packet sizes and timing are padded and randomized, hiding metadata patterns from anyone watching the wire.","unique.s4.tags":["Packet padding","Timing jitter"],"unique.s5.titleTop":"Zero data","unique.s5.titleBottom":"collection","unique.s5.collapsed":"Zero data collection","unique.s5.desc":"No accounts, no logs, no message storage. There is nothing on a server to leak, subpoena, or sell.","unique.s5.tags":["No accounts","No logs"],"partners.eyebrow":"Partners & ecosystem","partners.heading":"Trusted by our partners","partners.aegis.desc":"Capital partner securing confidential financial communications across its portfolio.","partners.aegis.role":"Strategic backer","partners.furilabs.desc":"Privacy-first Linux phones that ship SecureBit as a default secure channel.","partners.furilabs.role":"Technology partner","partners.inviteTitle":"Become a partner","partners.inviteDesc":"Building privacy hardware or infrastructure? Let's integrate SecureBit.","partners.inviteCta":"Start a conversation","roadmap.eyebrow":"Development Roadmap","roadmap.heading":"The evolution of SecureBit","roadmap.subheading":"From the first prototype to a quantum-resistant, decentralized network - with complete ASN.1 validation at every layer.","roadmap.progress":"{shipped} of {total} milestones shipped","roadmap.upcoming":"{upcoming} on the way","roadmap.keyFeatures":"Key features","roadmap.status.released":"Released","roadmap.status.current":"Current","roadmap.status.dev":"In development","roadmap.status.planned":"Planned","roadmap.status.research":"Research","hero.headlineTop":"A direct line","hero.headlineBottom":"only you two can read.","hero.subheading":"Keys are generated on your device and exchanged peer-to-peer. No accounts, no servers storing your messages.","hero.diagramAlt":"A direct encrypted line to one peer, with two more peers joining the mesh","intro.createTitle":"Create a new channel","intro.createDesc":"Your device generates the keys and a one-time invitation. Nothing touches a server.","intro.createCta":"Generate keys & invitation","intro.joinTitle":"Join a channel","intro.scanTitle":"Scan QR with camera","intro.scanSubtitle":"Fastest - point at your peer's screen","intro.orPasteCode":"or paste code","intro.pastePlaceholder":"Paste invitation code here\u2026","intro.connect":"Connect","intro.connecting":"Processing\u2026","roadmap.r1.title":"Start of Development","roadmap.r1.sub":"Idea, prototype, and infrastructure setup","roadmap.r1.date":"Early 2025","roadmap.r1.features":["Concept and requirements formation","Stack selection: WebRTC, P2P, cryptography","First messaging prototypes","Repository creation and CI","Basic encryption architecture","UX/UI design"],"roadmap.r2.title":"Alpha Release","roadmap.r2.sub":"First public alpha: basic chat and key exchange","roadmap.r2.date":"Spring 2025","roadmap.r2.features":["Basic P2P messaging via WebRTC","Simple E2E encryption (demo scheme)","Stable signaling and reconnection","Minimal UX for testing","Feedback collection from early testers"],"roadmap.r3.title":"Security Hardened","roadmap.r3.sub":"Security strengthening and stable branch release","roadmap.r3.date":"Summer 2025","roadmap.r3.features":["ECDH/ECDSA implementation in production","Perfect Forward Secrecy and key rotation","Improved authentication checks","File encryption and large payload transfers","Audit of basic cryptoprocesses"],"roadmap.r4.title":"Scaling & Stability","roadmap.r4.sub":"Network scaling and stability improvements","roadmap.r4.date":"Fall 2025","roadmap.r4.features":["Optimization of P2P connections and NAT traversal","Reconnection mechanisms and message queues","Reduced battery consumption on mobile","Multi-device synchronization support","Monitoring and logging tools for developers"],"roadmap.r5.title":"Privacy-first Release","roadmap.r5.sub":"Focus on privacy: minimizing metadata","roadmap.r5.date":"Winter 2025","roadmap.r5.features":["Metadata protection and fingerprint reduction","Experiments with onion routing and DHT","Options for anonymous connections","Preparation for open code audit","Improved user verification processes"],"roadmap.r6.title":"Enhanced Security Edition","roadmap.r6.sub":"18-layer military-grade cryptography with complete ASN.1 validation","roadmap.r6.date":"Late 2025","roadmap.r6.features":["ECDH + DTLS + SAS triple-layer security","ECDH P-384 + AES-GCM 256-bit encryption","DTLS fingerprint verification","SAS (Short Authentication String) verification","Perfect Forward Secrecy with key rotation","Enhanced MITM attack prevention","Complete ASN.1 DER validation","OID and EC point verification","SPKI structure validation","P2P WebRTC architecture","Metadata protection","100% open source code"],"roadmap.r7.title":"Desktop Edition","roadmap.r7.sub":"Native desktop apps for Windows, macOS, and Linux","roadmap.r7.date":"Early 2026","roadmap.r7.features":["Windows desktop app (Tauri v2)","macOS desktop app (Tauri v2)","Linux AppImage support (Tauri v2)","Real-time notifications","Automatic reconnection","Cross-device synchronization","Improved UX/UI","Support for files up to 100MB"],"roadmap.r8.title":"Secure Voice & Calls","roadmap.r8.sub":"Encrypted voice messages, audio calls, and video calls","roadmap.r8.date":"Early 2026","roadmap.r8.features":["End-to-end encrypted voice messages","1:1 encrypted audio calls (WebRTC)","1:1 encrypted video calls (WebRTC)","Perfect Forward Secrecy for live media","SRTP/DTLS-protected media streams","In-call SAS verification","Call notifications and auto-reconnection","Low-latency P2P media"],"roadmap.r9.title":"Group Communications","roadmap.r9.sub":"Group chats with preserved privacy","roadmap.r9.date":"Now","roadmap.r9.features":["P2P group chats up to 8 participants","Mesh delivery with signed relay fallback","One group safety code, compared by everyone","Commit-then-reveal ceremony against code grinding","Per-group identity keys, ephemeral by design","Signed membership with epoch ordering","Signed messages, so a split transcript is provable","No server, no shared group key, no history"],"roadmap.r10.title":"Mobile Edition","roadmap.r10.sub":"Native mobile apps for iOS and Android","roadmap.r10.date":"Q2 2027","roadmap.r10.features":["iOS native app (Swift/SwiftUI)","Android native app (Kotlin/Jetpack Compose)","PWA support for mobile browsers","Real-time push notifications","Battery optimization","Mobile-optimized UX/UI","Offline message queuing","Biometric authentication"],"roadmap.r11.title":"Quantum-Resistant Edition","roadmap.r11.sub":"Protection against quantum computers","roadmap.r11.date":"Q4 2027","roadmap.r11.features":["Post-quantum cryptography CRYSTALS-Kyber","SPHINCS+ digital signatures","Hybrid scheme: classic + PQ","Quantum-safe key exchange","Updated hashing algorithms","Migration of existing sessions","Compatibility with v5.x","Quantum-resistant protocols"],"roadmap.r12.title":"Decentralized Network","roadmap.r12.sub":"Fully decentralized network","roadmap.r12.date":"2028","roadmap.r12.features":["Node mesh network","DHT for peer discovery","Built-in onion routing","Tokenomics and node incentives","Governance via DAO","Interoperability with other networks","Cross-platform compatibility","Self-healing network"],"roadmap.r13.title":"AI Privacy Assistant","roadmap.r13.sub":"AI for privacy and security","roadmap.r13.date":"2028+","roadmap.r13.features":["Local AI threat analysis","Automatic MITM detection","Adaptive cryptography","Personalized security recommendations","Zero-knowledge machine learning","Private AI assistant","Predictive security","Autonomous attack protection"],"handshake.step1":"Generating ECDH P-384 key pair","handshake.step2":"Deriving verification code","handshake.step3":"Pinning Perfect Forward Secrecy","handshake.securingTitle":"Securing your channel","handshake.answerTitle":"Building your answer","handshake.securingDesc":"Forging keys strong enough to resist tampering.","handshake.shareTitle":"Share your invitation","handshake.sendAnswerTitle":"Send back your answer","handshake.shareDesc":"Show the QR or send the code to your peer. It is one-time and expires shortly.","handshake.sendAnswerDesc":"Give this answer to the channel creator so they can finish the handshake.","handshake.establish":"Establish connection","handshake.thenReceive":"Then receive the answer your peer sends back","handshake.pasteAnswerPlaceholder":"Paste peer's answer code\u2026","handshake.answerSentNote":"Send this answer to the creator, then wait - the chat opens once they connect.","handshake.qrHint":"Keep this open until your peer captures the code.","handshake.qrHintFrames":"The handshake is split across {frames} frames - keep this open until your peer captures all of them.","verify.title":"Security verification","verify.desc":"Compare this safety code with your peer over a separate channel (voice / in person), then type it to unlock the chat.","verify.enterLabel":"Enter the verified code","verify.placeholder":"Type code here","verify.confirm":"Confirm code","verify.confirmed":"Confirmed","verify.mismatch":"Don't match","verify.yours":"Your confirmation","verify.peer":"Peer confirmation","verify.pending":"Pending","verify.waiting":"Waiting for code\u2026","verify.verified":"Channel verified","verify.bothConfirmed":"Both parties confirmed. Opening the secure chat\u2026","pwa.bannerTitle":"Install SecureBit.chat","pwa.bannerDesc":"Get the native app experience with enhanced security","pwa.install":"Install","pwa.dismiss":"Dismiss","pwa.close":"Close","pwa.iosTitle":"Install on iOS","pwa.iosStep1":"Tap the Share button","pwa.iosStep1Hint":"Usually at the bottom of Safari","pwa.iosStep2":'Find "Add to Home Screen"',"pwa.iosStep2Hint":"Scroll down in the share menu","pwa.iosStep3":'Tap "Add"',"pwa.iosStep3Hint":"Confirm to install SecureBit.chat","pwa.genericTitle":"Install SecureBit","pwa.genericDesc":"Your browser handles installs its own way. Pick the steps that match yours.","pwa.androidChromeHint":"Tap \u22EE in the top corner, then \u201CInstall app\u201D","pwa.androidOtherHint":"Tap the menu, then \u201CAdd to Home screen\u201D","pwa.gotIt":"Got it","pwa.installedTitle":"App Installed!","pwa.installedIos":"iOS App installed! Open from home screen.","pwa.installedGeneric":"SecureBit.chat is now on your device","pwa.anytimeTitle":"Install Anytime","pwa.anytimeDesc":"You can still install SecureBit.chat from your browser's menu for the best experience.","pwa.ok":"OK","step.open":"Step 1 \xB7 open a channel","step.exchange":"Step 2 \xB7 exchange","step.verification":"Step 3 \xB7 verification","action.create":"Create","action.join":"Join","action.back":"Back","action.copy":"Copy","action.copied":"Copied","action.scan":"Scan","action.downloadDesktop":"Download desktop app","action.advancedSettings":"Advanced settings","cred.offerTag":"offer \xB7 or copy text","cred.answerTag":"answer \xB7 or copy text","cred.reveal":"Click to reveal - keep this code private","qr.title":"Scan QR code","qr.subtitle":"Point your camera at their QR","qr.scanning":"Scanning\u2026","qr.hint":"Hold steady until all parts are captured. Camera access is local - nothing is uploaded.","mesh.you":"you","mesh.peer":"peer \xB7 session 1","mesh.joined2":"mara joined \xB7 +2","mesh.joined3":"tobi joined \xB7 +3","ice.title":"Network settings","ice.subtitle":"Configured locally - never shared with your peer","ice.intro":"SecureBit uses public STUN servers by default to negotiate the peer-to-peer link. Point it at your own STUN/TURN if you self-host.","ice.publicTitle":"Public servers (default)","ice.publicDesc":"Zero-config. Good for most users.","ice.customTitle":"My own STUN/TURN servers","ice.customDesc":"Up to {max} servers.","ice.turnNote":"A TURN relay sees both peers' IP and traffic timing - but never message contents, which stay end-to-end encrypted. Prefer ","ice.turnNoteTls":" (TLS).","ice.test":"Test servers","ice.testing":"Testing\u2026","ice.relayTitle":"Relay-only mode","ice.relayBadge":"MAX PRIVACY","ice.relayDesc":"Routes all traffic through TURN so your IP is never exposed to the peer. Requires a TURN server.","ice.relayWarning":"Relay-only is enabled but no TURN server is configured. The connection will not be able to start.","ice.persist":"Save on this device","ice.persistDesc":"Stored encrypted in this browser. Leave off to use only for this session.","ice.forget":"Forget saved","ice.cancel":"Cancel","ice.apply":"Apply","ice.errUnavailable":"WebRTC is not available in this browser","ice.errInvalid":"Invalid server configuration","update.title":"Update available","update.desc":"A newer version of SecureBit has been detected.","update.currentVersion":"Current version","update.newVersion":"New version","update.now":"Update now","update.later":"Later","update.unknown":"N/A","update.stepSaving":"Saving data...","update.stepSwCaches":"Clearing Service Worker caches...","update.stepSwUnregister":"Unregistering Service Workers...","update.stepBrowserCache":"Clearing browser cache...","update.stepVersion":"Updating version...","update.stepReload":"Reloading application...","update.error":"Update error. Please refresh the page manually (Ctrl+F5 or Cmd+Shift+R)","update.confirmSkip":"New version available. Update is recommended for security and stability. Continue without update?","offline.backOnline":"Back online","offline.mode":"Offline mode","offline.dismiss":"Dismiss","offline.lostTitle":"Connection lost","offline.lostDesc":"SecureBit is now in offline mode. Some features are limited, but your data stays safe.","offline.point1":"Your session and keys are preserved","offline.point2":"No data is stored on servers","offline.point3":"Messages & files sync when you reconnect","offline.continue":"Continue offline","offline.restoredTitle":"When you reconnect","offline.restoredDesc":"A dropped connection costs you nothing. SecureBit queues everything locally and resumes the encrypted session the instant you're back online.","offline.r1Title":"Your messages get delivered","offline.r1Desc":"Everything you wrote while offline is sent to your contact automatically.","offline.r2Title":"Files finish transferring","offline.r2Desc":"Uploads resume from where they stopped - no need to resend.","offline.r3Title":"Their messages & files arrive","offline.r3Desc":"Whatever your contact sent during the outage is delivered to you in order.","offline.r4Title":"Nothing is lost","offline.r4Desc":"After reconnect there's no gap - the conversation continues exactly where it paused.","offline.gotIt":"Got it","qr.showTitle":"Show QR code","qr.showSubtitle":"Full-screen \xB7 let your peer scan","qr.showSubtitleFrames":"Full-screen \xB7 let your peer scan all {frames} frames","notify.enabledBody":"Notifications enabled! You will receive alerts for new messages.","notify.workingBody":"Notifications are working! You will receive alerts for new messages.","pw.label":"Password input","pw.placeholder":"Enter password...","pw.decrypt":"Decrypt","pw.cancel":"Cancel","file.title":"File transfers","file.drop":"Drag & drop files here","file.dropHint":"Encrypted end-to-end before transfer \xB7 up to 100 MB","file.browse":"Browse device","file.incoming":"Incoming file request","file.accept":"Accept","file.reject":"Reject","file.download":"Download","file.notReady":"Connection not ready","file.tooLarge":"File too large","file.typeNotAllowed":"File type not allowed","file.maxConcurrent":"Maximum concurrent transfers","file.gone":"This file is no longer available for download.","call.incoming":"Incoming call","call.incomingVideo":"Incoming video call","call.encrypted":"Encrypted call","call.encryptedShort":"Encrypted","call.peer":"Secure peer","call.connecting":"Connecting\u2026","call.ringing":"Ringing\u2026","call.accept":"Accept","call.decline":"Decline","call.end":"End call","call.camera":"Camera","call.cameraOff":"Camera off","call.peerCameraOff":"Peer's camera is off","call.flipCamera":"Flip camera","call.addVideo":"Add video","call.video":"Video","call.muted":"Muted","call.expand":"Expand","call.minimize":"Minimize","call.quality":"Connection quality","call.qualityExcellent":"Excellent","call.videoPrefix":"Video \xB7 ","call.voicePrefix":"Voice \xB7 ","group.new":"New group","group.create":"Create group","group.join":"Join group","group.name":"Group name","group.nameTooLong":"The group name is too long.","group.capacity":"Up to {max} people, peer to peer. Everyone will compare one safety code before the group opens.","group.invite":"Invite","group.inviteMore":"Invite more members","group.invitePeople":"Invite {count} people","group.invitation":"Group invitation","group.addMembers":"Add members","group.roomFor":"Room for {remaining} more. Everyone will compare a new group code once they join.","group.membersCount":"{count} members","group.member":"Member","group.members":"Members","group.remove":"Remove {name}","group.message":"Message {name}","group.leave":"Leave","group.leaveThis":"Leave this group","group.cancel":"Cancel group","group.close":"Close","group.cancelBtn":"Cancel","group.decline":"Decline","group.working":"Working\u2026","group.sasTitle":"Group safety code","group.sasEveryone":"Everyone sees this code","group.sasCompare":"Compare the group code with every member to open this group.","group.sasReadAloud":"Read these digits aloud to ","group.sasWarning":"If even one member reads a different code, someone is sitting between you. Cancel the group - do not confirm.","group.confirmFirst":"Confirm the group code first","group.codeSuffix":" \xB7 code {code}","group.exchangingNonces":"Exchanging nonces\u2026","group.waitingCommit":"Waiting for every member to commit\u2026","group.waitingJoin":"Waiting for the other members to join\u2026","group.emptyChat":"Nothing here yet. Messages are signed by their sender and travel over each member's own encrypted link.","group.noVerified":"No verified chats yet. Open a 1:1 chat and compare its safety code first - a group is built out of connections you have already checked.","group.noMoreToAdd":"No other verified chats to add. Open a 1:1 chat and compare its safety code first.","group.directLink":"Direct peer-to-peer link","group.noDirectLink":"No direct link yet - messages are relayed by another member while one is being built","group.relayNote":"Some members have no direct link to you yet. Their messages travel through another member, who can see that you are talking but cannot read past the signature or change what you said. The group keeps trying to connect them directly.","group.relayOnlyOff":"Relay-only mode is off, so each member connects to you directly and learns your IP address - including members somebody else invited. Turn it on in network settings if that matters here.","group.memberOffline":"{name} is offline and will not receive messages. They are still a member - removing them re-keys the group.","group.joinNote":"Other members will learn your presence in this group. There is no message history to catch up on - a group starts empty.","group.inviteSentNote":"The group keeps working until they accept. There is no history for them to catch up on - they will only see what is sent from now on.","group.errNotCreated":"Group not created","group.errNobodyAccepted":"Nobody accepted the invitation in time.","group.errNothingSent":"Nothing was sent and nothing was verified. Close this and try again once everyone is connected.","group.errNotFormed":"This group could not be formed.","group.errFull":"This group is full.","group.errInviteFailed":"The invitation could not be sent - that chat is not connected.","group.errNoMemberList":"The group owner never sent the member list.","group.errUnsignedList":"The member list was not signed by the group owner. Do not retry - tell them.","group.errNotOwner":"Someone other than the group owner tried to change the members.","hdr.tagline":"End-to-end encrypted","hdr.netSettings":"Advanced network settings","hdr.netSettingsTitle":"Advanced network settings (STUN/TURN)","hdr.disconnect":"Disconnect","status.connected":"Connected","status.connecting":"Connecting...","status.notConnected":"Not connected","status.reconnecting":"Reconnecting...","status.retrying":"Retrying...","status.verifying":"Verifying...","status.peerDisconnected":"Peer disconnected","sec.replayProtection":"Replay Protection","sec.messageIntegrity":"Message Integrity (HMAC)","sec.forwardSecrecy":"Perfect Forward Secrecy","sec.metadataProtection":"Metadata Protection","sec.trafficObfuscation":"Traffic Obfuscation","sec.realTests":"Real Cryptographic Tests","sec.simulatedData":"Simulated Data","sec.testPassed":"Test passed","sec.testFailed":"Test failed or unavailable","sec.verificationDone":"Real cryptographic verification completed","sec.verificationInProgress":"Security verification in progress...","sec.verificationWait":`Security verification in progress...
Please wait for real-time cryptographic verification to complete.`,"sec.verificationUnavailable":"Security verification not available","chat.placeholder":"Type an encrypted message\u2026","chat.send":"Send message","chat.sendFiles":"Send files","chat.hideFiles":"Hide files","chat.recordVoice":"Record voice message","chat.sendVoice":"Send voice message","chat.discard":"Discard","chat.codeBlock":"Send as a code block (expands the input)","chat.codeHint":"Code snippet \xB7 formatting preserved \xB7 \u2318\u21B5 to send","chat.viewOnce":"View once","chat.viewOnceTitle":"View once - vanishes after the peer reads it","chat.viewOncePrefix":"View once \xB7 ","chat.viewOnceTap":"View once \xB7 tap to reveal","chat.viewedOnce":"Viewed once","chat.disappearing":"Disappearing message - deletes on both sides","chat.disappearAfter":"Disappear after","chat.visibleFor":"Visible for","chat.timerPrefix":"Timer \xB7 ","chat.expired":"This message has expired","chat.deleteForEveryone":"Delete for everyone","chat.sending":"Sending","chat.delivered":"Delivered","chat.notSent":"Not sent","chat.notSentReason":"Not sent - the secure channel is not ready. Reconnect to continue.","chat.encrypted":"Encrypted","chat.decrypted":"Decrypted","chat.encryptedOnDevice":"Encrypted on your device","chat.uploading":"Uploading","chat.downloading":"Downloading","chat.transferring":"Transferring\u2026","chat.copied":"Copied!","chat.collapse":"Collapse","chat.closeMenu":"Close menu","chat.newChat":"New chat","chat.newGroup":"New group","chat.createGroup":"Create a group","chat.groupChats":"Group chats","chat.secureChat":"Secure chat","chat.nameThis":"Name this chat","chat.rename":"Rename chat (local only)","chat.renameHint":"Double-click to rename","chat.localLabel":"Local label \xB7 stored only on this device","chat.setStatus":"Set your status","chat.yourStatusPrefix":"Your status - ","chat.meshHint":"Up to 8 peers \xB7 P2P mesh","chat.offline":"Offline","chat.noNetwork":"No network \xB7 reconnecting","chat.startVoiceCall":"Start encrypted voice call","chat.startVideoCall":"Start encrypted video call","chat.verifyForCalls":"Verify the session to enable calls","chat.e2eeNote":"Every message is end-to-end encrypted on your device before it leaves.","chat.peersOnly":"Sent end-to-end to connected peers only - never stored on a server.","flow.invitationCreated":"Secure invitation created","flow.invitationCreatedBang":"Secure invitation created and encrypted!","flow.responseCreated":"Secure response created","flow.responseCreatedBang":"Secure response created!","flow.sendInvitation":"Send the invitation code to your interlocutor via a secure channel (voice call, SMS, etc.).","flow.sendResponse":"Send the response code to the initiator via a secure channel or let them scan the QR code below.","flow.sendEncryptedCode":"Send the encrypted code","flow.sendTheResponse":"Send the response","flow.pasteOrWrite":"Paste or write code\u2026","flow.processingInvitation":"Processing the secure invitation...","flow.processingResponse":"Processing the secure response...","flow.finalizing":"Finalizing the secure connection...","flow.channelEstablished":"Secure channel established","flow.channelReady":"Secure channel is ready","flow.restoring":"Restoring connection\u2026","flow.invitationCaptured":"Invitation captured.","err.needInvitation":"You need to insert the invitation code from your interlocutor.","err.needResponse":"You need to insert the response code from your interlocutor.","err.responseFormat":"Invalid response format - please check the code","err.responseNoKey":"Invalid response code - missing or corrupted cryptographic key. Please check the code and try again.","err.responseNoSignKey":"Invalid response code - missing signature verification key. Please check the code and try again.","err.responseOutdated":"Response data is outdated - please use a fresh invitation","err.setupError":"Connection setup error","err.notReady":"Connection not ready","err.securityBreach":"Security breach detected - connection rejected","err.securityValidation":"Security validation failed - possible attack detected","err.retiredQr":"This QR code uses a retired format that could not transfer the invitation. Ask your peer to generate a new one, or use copy/paste.","err.compressedQrNote":"Compressed QR may omit SDP for brevity. Use copy/paste if connection fails.","err.inviteNotConnected":"The invitation could not be sent. That chat is not connected right now.","err.inviteNotConnectedRetry":"The invitation could not be sent. That chat is not connected right now - reopen it and try again.","err.nobodyAccepted":"Nobody accepted the invitation. The group is unchanged.","err.noAudio":"No audio captured - check microphone permission and try again.","err.voiceNeedsConnection":"Voice message needs an active secure connection. Reconnect and try again.","err.voiceRestoring":"Restoring the connection - try sending the voice message again in a moment.","err.fileTooLarge":"File too large","sas.safetyNumber":"Safety number","sas.incorrect":"Incorrect code. Check it with your peer and try again.","sas.noMatch":"The codes do not match","sas.makeSure":"Make sure the codes match exactly.","sas.tooManyAttempts":"Too many incorrect attempts. Session reset for safety.","sas.verificationFailed":"Verification failed","sas.verified":"Verified \xB7 Perfect Forward Secrecy","sas.runVerification":"Run security verification","sec.panelTitle":"Network & crypto details","sec.security":"Security","sec.transport":"Transport","sec.keyExchange":"Key exchange","sec.allEnabled":"All security features enabled by default","sec.realTimeNote":"Real-time verification using actual cryptographic functions - no mock data.","sec.simulatedWarning":"Warning: connection may not be fully established - values may be simulated.","dl.title":"Download SecureBit","dl.free":"Free \xB7 open source","dl.soon":"Mobile (iOS, Android) and browser extensions (Chrome, Firefox, Opera) are coming soon.","chatHdr.chat":"Chat","chatHdr.chats":"Chats","chatHdr.newChat":"+ New","chatHdr.secure":"Secure","chatHdr.p2pSub":"P2P \xB7 end-to-end encrypted","chatHdr.save":"Save","chatHdr.close":"Close","chatHdr.expand":"Expand","chatHdr.you":"You","chatHdr.qrCode":"QR code","chat.disconnected":"Disconnected","call.mute":"Mute","call.endShort":"End","group.add":"Add","group.send":"Send","sec.pfsShort":"Perfect Forward Secrecy","sec.cipher":"Cipher","chat.close":"Close","file.needConnection":"File transfer needs an open connection","presence.available":"Available","presence.away":"Away","presence.busy":"Busy","presence.offline":"Offline","presence.invisible":"Invisible","presence.availableDesc":"Online and reachable","presence.awayDesc":"Idle \xB7 stepped away","presence.busyDesc":"Do not disturb","presence.invisibleDesc":"Appear offline to peers","presence.online":"Online","conn.p2p":"P2P \xB7 connected","conn.verifying":"Verifying\u2026","conn.connecting":"Connecting\u2026","conn.reconnecting":"Reconnecting\u2026","conn.peerDisconnected":"Peer disconnected","conn.disconnected":"Disconnected","chat.defaultLabel":"Chat","groupPhase.forming":"Forming\u2026","groupPhase.commitments":"Exchanging commitments\u2026","groupPhase.revealing":"Revealing\u2026","groupPhase.compare":"Compare the group code","groupPhase.ready":"Group ready","groupPhase.failed":"Group failed","call.qualityGood":"Good","call.qualityFair":"Fair","call.qualityWeak":"Weak","msg.code":"Code","msg.timer":"Timer","msg.voice":"Voice","msg.play":"Play","msg.sent":"Sent","msg.read":"Read","report.title":"Real-time security verification","report.active":"Active","report.testsPassed":"Tests passed","report.verifiedAt":"Verified at","report.source":"Source","secTest.verifyECDHKeyExchange":"ECDH key exchange","secTest.verifyECDSASignatures":"ECDSA digital signatures","secTest.verifyEncryption":"AES-GCM encryption","secTest.verifyMessageIntegrity":"Message integrity","secTest.verifyPerfectForwardSecrecy":"Perfect forward secrecy","secTest.verifyPFS":"Perfect forward secrecy","secTest.verifyReplayProtection":"Replay protection","secTest.verifyDTLSFingerprint":"DTLS fingerprint","secTest.verifySASVerification":"SAS verification","secTest.verifyMetadataProtection":"Metadata protection","secTest.verifyTrafficObfuscation":"Traffic obfuscation","secTest.verifyPacketPadding":"Packet padding","secTest.verifyNestedEncryption":"Nested encryption","secTest.verifyNonExtractableKeys":"Non-extractable keys","secTest.verifyRateLimiting":"Rate limiting","secTest.verifyMutualAuth":"Mutual authentication","secTest.verifyAuthProof":"Authentication proof","secTest.verifyEnhancedValidation":"Enhanced validation","secTest.verifyAdvancedFeatures":"Advanced features","secTest.verifySignature":"Signature check","secDetail.Security system initializing...":"Security system initializing...","secDetail.Nested encryption active":"Nested encryption active","secDetail.Nested encryption failed":"Nested encryption failed","secDetail.Packet padding active":"Packet padding active","secDetail.Packet padding failed":"Packet padding failed","secDetail.Advanced features active":"Advanced features active","secDetail.Advanced features failed":"Advanced features failed","secDetail.No encryption key available":"No encryption key available","secDetail.AES-GCM encryption/decryption working correctly":"AES-GCM encryption/decryption working correctly","secDetail.No ECDH key pair available":"No ECDH key pair available","secDetail.Key derivation failed":"Key derivation failed","secDetail.No ECDSA key pair available":"No ECDSA key pair available","secDetail.ECDSA digital signatures working correctly":"ECDSA digital signatures working correctly","secDetail.MAC key not available or invalid":"MAC key not available or invalid","secDetail.Rate limiter did not block a message over the limit":"Rate limiter did not block a message over the limit","secDetail.Rate limiter is not available":"Rate limiter is not available","secDetail.Replay protection is working correctly":"Replay protection is working correctly","secDetail.Replay protection not enabled":"Replay protection not enabled","secDetail.SAS code not available":"SAS code not available","secDetail.SAS verification code is valid and available":"SAS verification code is valid and available","secDetail.Traffic obfuscation is working correctly":"Traffic obfuscation is working correctly","secDetail.Traffic obfuscation not enabled":"Traffic obfuscation not enabled","secDetail.No non-extractable ephemeral ECDH key pair for this session":"No non-extractable ephemeral ECDH key pair for this session","secDetail.Session-level PFS only: keys are ephemeral per session, but the Double Ratchet is not active for this connection (peer on an older version), so a compromised session key exposes the whole conversation":"Session-level PFS only: keys are ephemeral per session, but the Double Ratchet is not active for this connection (peer on an older version), so a compromised session key exposes the whole conversation","msg.pause":"Pause","msg.failed":"Failed","groupErr.timeout":"A member stopped responding before the code was ready.","groupErr.keyMismatch":"A member's key did not match the identity claimed for it.","groupErr.revealMismatch":"A member's revealed value did not match what they committed to.","groupErr.commitChanged":"A member changed their commitment part-way through.","groupErr.missingKey":"A member was listed whose key never arrived.","groupErr.outsider":"A frame arrived from someone outside the group.","groupErr.limit":"A group is limited to eight members.","groupErr.tooLarge":"A message was too large to send to the group.","fileType.text":"Plain text","fileType.images":"Images","fileType.archives":"Archives","fileType.voice":"Voice messages","fileType.unsupported":"Unsupported","qrScan.title":"Scan QR Code","qrScan.auto":"Auto Mode","qrScan.reset":"Reset","qrScan.autoScroll":"Auto-scrolling enabled","qrScan.starting":"Starting camera...","qrScan.point":"Point camera at QR code","qrScan.tapFocus":"Tap screen to focus","qrScan.focusing":"Focusing...","iceErr.notArray":"Server list must be an array","iceErr.invalidJson":"Invalid JSON","iceErr.tooMany":"Too many servers (max {max})","iceErr.invalidEntry":"{label}: invalid entry","iceErr.urlCount":"{label}: between 1 and {max} URLs required","iceErr.turnCreds":"{label}: TURN servers usually require a username and credential","iceUrl.notString":"URL must be a string","iceUrl.empty":"URL is empty","iceUrl.tooLong":"URL is too long","iceUrl.badChars":"URL contains invalid characters","iceUrl.badScheme":"URL must start with stun:, stuns:, turn: or turns:","iceUrl.badQuery":"URL has an invalid query","iceUrl.noHost":"URL is missing a host","iceUrl.badHost":"URL has an invalid host or port","iceUrl.badTransport":"URL query must be transport=udp or transport=tcp","msg.off":"Off","file.consentUnavailable":"User consent unavailable","secLevel.MAXIMUM":"MAXIMUM","secLevel.INITIALIZING":"INITIALIZING","secLevel.ERROR":"ERROR","secLevel.UNKNOWN":"UNKNOWN","status.error":"Error","offline.disconnect":"Disconnect","offline.learnMore":"Learn more","pwa.installApp":"Install App","chat.onWeb":"You're on Web","groupCall.startVoice":"Start a group voice call","groupCall.startVideo":"Start a group video call","groupCall.join":"Join","groupCall.dismiss":"Not now","groupCall.leave":"Leave call","groupCall.you":"You","groupCall.connecting":"Connecting\u2026","groupCall.waitingLink":"Waiting for a direct link\u2026","groupCall.legFailed":"Could not connect","groupCall.startedVoice":"{name} started a voice call","groupCall.startedVideo":"{name} started a video call","groupCall.inCall":"{count} in the call","groupCall.err.permission_denied":"The call could not start - microphone and camera access is blocked. Allow it for this site, then try again.","groupCall.err.device_not_found":"The call could not start - no microphone was found on this device.","groupCall.err.device_busy":"The call could not start - your microphone is in use by another app. Close it and try again.","groupCall.err.media_failed":"The call could not start - the microphone could not be opened.","groupCall.err.call_in_progress":"A call is already running in this group. Join it instead of starting another.","groupCall.err.not_ready":"Confirm the group code before calling.","groupCall.speaking":"{name} is speaking","groupCall.pin":"Show {name} large","groupCall.unpin":"Back to everyone","groupCall.showEveryone":"Everyone","msg.after5s":"5s after reading","msg.after15s":"15s after reading","msg.after30s":"30s after reading","msg.after1m":"1m after reading","msg.sec30":"30 seconds","msg.min5":"5 minutes","msg.hour1":"1 hour","desktop.shareDesc":"Send the code to your peer. It is one-time and expires shortly.","desktop.invitationCreated":"Secure invitation created - send it to your peer.","desktop.joinDesc":"Paste your peer's invitation code to build your secure answer.","desktop.offerTag":"offer \xB7 copy text","desktop.answerTag":"answer \xB7 copy text","desktop.offerPlaceholder":"Invitation code will appear here\u2026","desktop.answerPlaceholder":"Response code will appear here\u2026","desktop.backToChats":"Back to chats","desktop.sendFeedback":"Send feedback","desktop.callsNeedVerified":"Calls require a verified secure channel.","desktop.noOpenChannel":"No open secure channel.","desktop.chatCarriesCall":"This chat is carrying a group call. Leave the group call before placing a 1:1 call.","desktop.err.permission_denied":"The call could not start - microphone and camera access is blocked. Allow it in system settings, then try again.","desktop.language":"Language","desktop.languageHint":"Applies at once. Messages already sent keep the words they were written in.","desktop.compareCode":"Compare the verification code with your peer and confirm if it matches.","desktop.verifyBeforeFiles":"Complete verification before sending files.","desktop.verifyBeforeSending":"Complete verification before sending messages.","desktop.disconnectedByBackend":"Connection securely disconnected.","desktop.restoreFailed":"Could not restore the connection. Closing this chat.","desktop.channelNotReady":"The data channel is not available yet. Wait for the connection to establish.","desktop.enterCode":"Enter the verification code to confirm.","desktop.noOffer":"No invitation found. Create one first.","desktop.notInitiator":"You did not create this connection, so there is no answer for you to apply.","desktop.decryptFailed":"A message could not be decrypted and was discarded.","desktop.badMessageFormat":"A malformed frame arrived and was discarded.","desktop.notSentNotReady":"Message not sent: the secure channel is not ready. Wait for verification to finish, or reconnect.","desktop.micDenied":"Microphone access was denied.","desktop.noChannelWait":"No open secure channel - wait for the connection to establish.","desktop.sasFailed":"Verification failed. A machine-in-the-middle may be present, so the connection was aborted.","desktop.sasOk":"Verification succeeded. This channel is authenticated end to end.","desktop.iceForgotten":"Saved servers forgotten. Using public ICE servers.","desktop.icePublic":"Using public ICE servers.","desktop.verificationInProgress":"Security verification is still running. Wait for it to finish.","desktop.fileGone":"This file is no longer available for download.","desktop.codeMismatch":"The verification codes do not match. Disconnecting for safety.","desktop.noLocalCode":"Verification failed: there is no locally derived code to compare against. Disconnecting for safety.","desktop.protocolViolation":"The peer claimed the code was confirmed before you confirmed it. Disconnecting for safety.","desktop.verificationRejected":"Verification rejected. The connection was aborted for safety.","secLevel.HIGH":"HIGH","secLevel.MEDIUM":"MEDIUM","secLevel.LOW":"LOW","desktop.rerun":"Re-run","desktop.ice.customDesc":"Up to {max} servers, one URL per line or JSON.","desktop.ice.persistDesc":"Stored locally on this device. Leave off to use only for this session.","desktop.group.leaveNote":"The other members are told you left. Nothing about this group is kept on this device afterwards - there is no server holding a copy to rejoin from, so you would need a fresh invitation.","desktop.sec.ecdsaOk":"Peer key package signature verified during the handshake (ECDSA P-384 / SHA-384)","desktop.sec.ecdsaNone":"No completed handshake","desktop.sec.ecdhOk":"Session keys derived from an ephemeral ECDH P-384 exchange via HKDF-SHA-256","desktop.sec.ecdhNone":"No session keys derived","desktop.sec.encryptionOk":"AES-GCM encryption and decryption verified inside the core","desktop.sec.encryptionNa":"The AES-GCM self-test could not be run","desktop.sec.integrityOk":"Message integrity verified (AES-GCM authentication)","desktop.sec.integrityNa":"The integrity self-test could not be run","desktop.sec.pfsOk":"Double Ratchet active - every message has a key of its own","desktop.sec.pfsNa":"Not measured","desktop.sec.replayOk":"Ratchet message keys are destroyed once used, so a captured frame cannot be replayed","desktop.sec.replayNa":"Not measured","desktop.sec.dtlsPinned":"Peer DTLS fingerprint pinned: {fp}","desktop.sec.dtlsNone":"No remote DTLS fingerprint available","desktop.sec.sasBoth":"Both peers confirmed the out-of-band safety code","desktop.sec.sasIncomplete":"The safety code has not been confirmed by both peers","desktop.sec.metadataOk":"A dedicated metadata key was derived (HKDF metadata-protection-v4)","desktop.sec.metadataNone":"No metadata key","desktop.sec.coverOn":"Cover traffic active: random fake frames (32-128 B every 15-30 s) on the ratcheted channel","desktop.sec.coverOff":"The cover traffic generator is not running","desktop.sec.coverUnsupported":"Cover traffic needs a Double Ratchet session (the peer is on an older release)","desktop.tagline":"End-to-end freedom","desktop.callsNotHere":"Calls are not available in this build yet. Messages, files and group chats work as usual."},Vn=globalThis.__SECUREBIT_I18N__||(globalThis.__SECUREBIT_I18N__=Object.create(null));Vn.en=zn;var Bn=globalThis.__SECUREBIT_I18N__||(globalThis.__SECUREBIT_I18N__=Object.create(null));function Lt(n){return Bn[n]||null}var Fi="securebit-locale";function Ki(n="/"){let e=String(n).split("/")[1];return Ke.includes(e)&&e!=="en"?e:null}function Hn(n=[]){for(let e of n){let t=String(e).toLowerCase(),r=Ke.find(a=>a.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<i;s++)r+=String.fromCharCode(t[s]);return btoa(r)}base64ToUint8Array(e){let t=atob(e),r=t.length,i=new Uint8Array(r);for(let s=0;s<r;s++)i[s]=t.charCodeAt(s);return i}getReceivedFileMeta(e){let t=this.receivedFileBuffers.get(e);return t?{fileId:e,fileName:t.name,fileSize:t.size,mimeType:t.type}:null}async getBlob(e){let t=this.receivedFileBuffers.get(e);return t?new Blob([t.buffer],{type:t.type}):null}async getObjectURL(e){let t=await this.getBlob(e);return t?URL.createObjectURL(t):null}revokeObjectURL(e){try{URL.revokeObjectURL(e)}catch{}}setupFileMessageHandlers(){if(!this.webrtcManager.dataChannel){let e=setInterval(()=>{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&&t<r;)await new Promise(i=>setTimeout(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<r;i++){let s=i*this.CHUNK_SIZE,a=Math.min(s+this.CHUNK_SIZE,t.size),o=await this.readFileChunk(t,s,a);await this.sendFileChunk(e,i,o),e.sentChunks++;let c=Math.round(e.sentChunks/r*95)+5;this._emitTransferProgress(e,"up"),await this.waitForBackpressure()}e.status="waiting_confirmation",this._armSenderIdleTimeout(e)}catch(t){let r=X.sanitizeError(t);throw console.error("\u274C Chunk transmission failed:",r),e.status="failed",new Error(r)}}_armSenderIdleTimeout(e){e._idleTimeout&&clearTimeout(e._idleTimeout),e._idleTimeout=setTimeout(()=>{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)&&s<i){s++,await this.waitForBackpressure(),await a(Math.min(50*s,500));continue}throw console.error("\u274C Failed to send secure message:",o),o}}async waitForBackpressure(){try{let e=this.webrtcManager?.dataChannel;if(!e)return;if(typeof e.bufferedAmountLowThreshold=="number"){e.bufferedAmount>e.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;u<e.totalChunks;u++)if(!e.receivedChunks.has(u))throw new Error(`Missing chunk ${u}`);let t=[];for(let u=0;u<e.totalChunks;u++){let h=e.receivedChunks.get(u);t.push(new Uint8Array(h))}let r=t.reduce((u,h)=>u+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;s<t.totalChunks&&i.length<r;s++)t.receivedChunks.has(s)||i.push(s);if(i.length!==0){t.status="receiving";try{await this.sendSecureMessage({type:"file_chunk_request",fileId:e,missing:i,timestamp:Date.now()})}catch{}}}async rejectIncomingFile(e,t="Rejected by user"){return this.pendingIncomingTransfers.has(e)?(this.pendingIncomingTransfers.delete(e),await this.sendSecureMessage({type:"file_transfer_response",fileId:e,accepted:!1,error:t,timestamp:Date.now()}),!0):!1}cancelTransfer(e){try{return this.activeTransfers.has(e)?(this.cleanupTransfer(e),!0):this.receivingTransfers.has(e)?(this.cleanupReceivingTransfer(e),!0):!1}catch(t){return console.error("\u274C Failed to cancel transfer:",t),!1}}cleanupTransfer(e){let t=this.activeTransfers.get(e);t&&(t._idleTimeout&&(clearTimeout(t._idleTimeout),t._idleTimeout=null),t.consentTimeout&&(clearTimeout(t.consentTimeout),t.consentTimeout=null),t.rejectConsent&&(t.rejectConsent(new Error("Transfer cancelled during cleanup or disconnect")),t.rejectConsent=null,t.resolveConsent=null)),this.activeTransfers.delete(e),this.sessionKeys.delete(e),this.transferNonces.delete(e),this.incomingTransferChunkLimiters.delete(e);for(let r of this.processedChunks)r.startsWith(e)&&this.processedChunks.delete(r)}_storeReceivedFileBuffer(e,t){for(this.receivedFileBuffers.set(e,t);this.receivedFileBuffers.size>this.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 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;a<n.lines.length;a++){let o=n.lines[a];(o.startsWith(`a=rtpmap:${t} `)||o.startsWith(`a=fmtp:${t} `)||o.startsWith(`a=rtcp-fb:${t} `))&&(s=a)}s===-1&&(s=n.lines.length-1),n.lines.splice(s+1,0,i)}}function ia(n,e){if(n.lines.some(i=>i.startsWith("a=extmap:")&&i.includes(e)))return;let t=0,r=-1;for(let i=0;i<n.lines.length;i++){let s=n.lines[i].match(/^a=extmap:(\d+)/);s&&(t=Math.max(t,Number(s[1])),r=i)}r===-1&&(r=n.lines.findIndex(i=>i.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.loss.recoverPct&&n.rttMs<t.rtt.recoverMs){if(a+=1,c="recovering",a>=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<t.length;r++)e+=String.fromCharCode(t[r]);return btoa(e)}function is(n){let e=atob(n),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}function H(n){try{n&&n.length&&(crypto.getRandomValues(n),n.fill(0))}catch{}}async function kr(n,e,t,r){let i=await crypto.subtle.importKey("raw",n,"HKDF",!1,["deriveBits"]),s=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:e,info:Nt.encode(t)},i,r*8);return new Uint8Array(s)}async function ss(n,e){let t=await crypto.subtle.importKey("raw",n,{name:"HMAC",hash:"SHA-256"},!1,["sign"]);return new Uint8Array(await crypto.subtle.sign("HMAC",t,e))}async function Tr(n){let e=await ss(n,da),t=await ss(n,ua);return{messageKey:e,nextChainKey:t}}async function Cr(n,e){let t=await kr(e,n,oa,64),r=t.slice(0,32),i=t.slice(32,64);return H(t),{nextRoot:r,chainKey:i}}var Ot=class{constructor(){this._rootKey=null,this._sendingChainKey=null,this._receivingChainKey=null,this._selfKeyPair=null,this._remotePublicKey=null,this._remotePublicKeyB64=null,this._sendCount=0,this._receiveCount=0,this._previousSendCount=0,this._skipped=new Map,this._namedCurve="P-384",this._initialised=!1}async init({sharedSecret:e,sessionSalt:t,selfPrivateKey:r,remotePublicKey:i,isInitiator:s}){if(!(e instanceof Uint8Array)||e.length===0)throw new Error("DoubleRatchet: a shared secret is required");if(!(r instanceof CryptoKey)||!(i instanceof CryptoKey))throw new Error("DoubleRatchet: handshake ECDH keys are required");if(this._namedCurve=r.algorithm?.namedCurve||"P-384",this._rootKey=await kr(e,t??new Uint8Array(0),la,32),s){this._selfKeyPair=await this._generateKeyPair(),this._remotePublicKey=i,this._remotePublicKeyB64=null;let a=await this._dh(this._selfKeyPair.privateKey,this._remotePublicKey),{nextRoot:o,chainKey:c}=await Cr(this._rootKey,a);H(a),H(this._rootKey),this._rootKey=o,this._sendingChainKey=c}else this._selfKeyPair={privateKey:r,publicKey:null},this._remotePublicKey=null,this._remotePublicKeyB64=null;this._initialised=!0}get isInitialised(){return this._initialised}get canEncrypt(){return this._initialised&&this._sendingChainKey!==null}getState(){return{initialised:this._initialised,sending:this._sendingChainKey!==null,receiving:this._receivingChainKey!==null,sendCount:this._sendCount,receiveCount:this._receiveCount,previousSendCount:this._previousSendCount,skippedKeys:this._skipped.size}}async _generateKeyPair(){return crypto.subtle.generateKey({name:"ECDH",namedCurve:this._namedCurve},!1,["deriveKey","deriveBits"])}async _dh(e,t){let r=await crypto.subtle.deriveBits({name:"ECDH",public:t},e,256);return new Uint8Array(r)}async _selfPublicKeyB64(){return this._selfKeyPair?.publicKey?rs(await crypto.subtle.exportKey("spki",this._selfKeyPair.publicKey)):null}async _importPublic(e){return crypto.subtle.importKey("spki",is(e),{name:"ECDH",namedCurve:this._namedCurve},!0,[])}async _messageCipher(e){let t=await kr(e,new Uint8Array(32),ca,44),r=await crypto.subtle.importKey("raw",t.slice(0,32),{name:"AES-GCM"},!1,["encrypt","decrypt"]),i=t.slice(32,44);return H(t),{key:r,iv:i}}async encrypt(e){if(!this._initialised)throw new Error("DoubleRatchet: not initialised");if(!this._sendingChainKey)throw new Error("DoubleRatchet: no sending chain \u2014 awaiting the peer's first message");let{messageKey:t,nextChainKey:r}=await Tr(this._sendingChainKey);H(this._sendingChainKey),this._sendingChainKey=r;let i=JSON.stringify({dh:await this._selfPublicKeyB64(),pn:this._previousSendCount,n:this._sendCount});this._sendCount+=1;let{key:s,iv:a}=await this._messageCipher(t);H(t);let o=await crypto.subtle.encrypt({name:"AES-GCM",iv:a,additionalData:Nt.encode(i)},s,Nt.encode(e));return{header:i,ciphertext:rs(o)}}async decrypt(e,t){if(!this._initialised)throw new Error("DoubleRatchet: not initialised");let r;try{r=JSON.parse(e)}catch{throw new Error("DoubleRatchet: malformed header")}let{dh:i,pn:s,n:a}=r;if(typeof i!="string"||!Number.isSafeInteger(a)||a<0||!Number.isSafeInteger(s)||s<0)throw new Error("DoubleRatchet: invalid header fields");this._pruneSkipped();let o=`${i}|${a}`,c=this._skipped.get(o);if(c){let h=await this._open(c.key,e,t);return this._skipped.delete(o),H(c.key),h}let d=await this._stageReceive(i,s,a),u;try{u=await this._open(d.messageKey,e,t)}catch(h){throw d.discard(),h}return d.commit(),u}async _stageReceive(e,t,r){let i=e!==this._remotePublicKeyB64,s=[],a=[],o=null,c,d,u;if(i){if(this._receivingChainKey){let S=await this._collectSkipped(this._receivingChainKey,this._receiveCount,t,this._remotePublicKeyB64);s.push(...S.keys),a.push(S.finalChainKey)}o=await this._stageDhRatchet(e),c=o.receivingChainKey,d=0,u=e}else c=this._receivingChainKey,d=this._receiveCount,u=this._remotePublicKeyB64;if(!c)throw new Error("DoubleRatchet: no receiving chain for this message");let h=await this._collectSkipped(c,d,r,u);s.push(...h.keys);let{messageKey:m,nextChainKey:p}=await Tr(h.finalChainKey);return h.finalChainKey!==c&&a.push(h.finalChainKey),{messageKey:m,commit:()=>{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(r<t)throw new Error("DoubleRatchet: message number is behind the current chain");if(r-t>Kt.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<r;o++){let{messageKey:c,nextChainKey:d}=await Tr(a);a!==e&&H(a),a=d,s.push({id:`${i}|${o}`,key:c})}return{keys:s,finalChainKey:a}}async _open(e,t,r){let{key:i,iv:s}=await this._messageCipher(e),a;try{a=await crypto.subtle.decrypt({name:"AES-GCM",iv:s,additionalData:Nt.encode(t)},i,is(r))}catch{throw new Error("DoubleRatchet: authentication failed")}return ha.decode(a)}_rememberSkipped(e,t){for(;this._skipped.size>=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<e&&(H(r.key),this._skipped.delete(t))}async _stageDhRatchet(e){let t=await this._importPublic(e),r=await this._dh(this._selfKeyPair.privateKey,t),i=await Cr(this._rootKey,r);H(r);let s=await this._generateKeyPair(),a=await this._dh(s.privateKey,t),o=await Cr(i.nextRoot,a);return H(a),{receivingChainKey:i.chainKey,apply:()=>{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;t<e.length;t++)this.b.push(e.charCodeAt(t)&255)}done(){return Uint8Array.from(this.b)}};function wa(n){(!Number.isInteger(n)||n<1024||n>2147483647)&&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;r<e;r++){let i=this.buf[this.i+r];(i<32||i>126)&&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<w;C++){let x=t.u8(),k=x>>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 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<n.length;t+=3){let r=n[t],i=n[t+1],s=n[t+2];if(e+=mt[r>>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<<s)-1&&F("payload has non-zero padding bits"),t.subarray(0,r)}var Ir="SB2:";function gs(n){return Ir+va(n)}function Nr(n){typeof n!="string"&&F("payload must be a string");let e=n.trim();return e.startsWith(Ir)||F("not an SB2 descriptor"),Ta(e.slice(Ir.length))}var ms=2,Ee=Object.freeze({OFFER:0,ANSWER:1}),We=Object.freeze({MAX_SPKI:256,MIN_SPKI:40,MAX_SIG:160,MIN_SIG:48,MAX_BLOB_BYTES:1024}),Or=class extends Error{constructor(e,t="key_exchange"){super(e),this.name="KeyExchangeError",this.code=t}},le=(n,e)=>{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.length<We.MIN_SPKI||o.length>We.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,(a<We.MIN_SPKI||a>We.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,(c<We.MIN_SPKI||c>We.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<i.length;a++)s|=i[a]^t[a];return s!==0&&le("the key material does not match the commitment in the invitation","commitment_mismatch"),!0}var Bt=class n{static TIMEOUTS={KEY_ROTATION_INTERVAL:3e5,CONNECTION_TIMEOUT:1e4,HEARTBEAT_INTERVAL:1e4,SECURITY_CALC_DELAY:1e3,SECURITY_CALC_RETRY_DELAY:3e3,CLEANUP_INTERVAL:3e5,CLEANUP_CHECK_INTERVAL:6e4,ICE_GATHERING_TIMEOUT:1e4,ICE_GATHERING_HARD_TIMEOUT:25e3,DISCONNECT_CLEANUP_DELAY:500,PEER_DISCONNECT_CLEANUP:2e3,STAGE2_ACTIVATION_DELAY:1e4,STAGE3_ACTIVATION_DELAY:15e3,STAGE4_ACTIVATION_DELAY:2e4,FILE_TRANSFER_INIT_DELAY:1e3,FAKE_TRAFFIC_MIN_INTERVAL:15e3,FAKE_TRAFFIC_MAX_INTERVAL:3e4,DECOY_INITIAL_DELAY:5e3,DECOY_TRAFFIC_MIN:1e4,DECOY_TRAFFIC_MAX:25e3,REORDER_TIMEOUT:3e3,RETRY_CONNECTION_DELAY:2e3,ICE_DISCONNECT_GRACE:8e3,ICE_RESTART_TIMEOUT:2e4,ICE_RESTART_GATHERING:4e3,RECONNECT_MAX_DURATION:12e4,RECOVERY_SILENCE_LIMIT:15e3,LIVENESS_PROBE_AFTER:12e3,LIVENESS_PROBE_TIMEOUT:5e3,LIVENESS_CHECK_INTERVAL:2e3};static RECONNECT_BACKOFF=Object.freeze([1e3,2e3,4e3,8e3,15e3,3e4]);static LIMITS={MAX_CONNECTION_ATTEMPTS:3,MAX_BARREN_ICE_FAILURES:2,MAX_OLD_KEYS:3,MAX_PROCESSED_MESSAGE_IDS:1e3,MAX_OUT_OF_ORDER_PACKETS:5,MAX_DECOY_CHANNELS:1,MESSAGE_RATE_LIMIT:60,MAX_KEY_AGE:9e5,OFFER_MAX_AGE:36e5,SALT_SIZE_V3:32,SALT_SIZE_V4:64};static SIZES={VERIFICATION_CODE_MIN_LENGTH:6,FAKE_TRAFFIC_MIN_SIZE:32,FAKE_TRAFFIC_MAX_SIZE:128,PACKET_PADDING_MIN:64,PACKET_PADDING_MAX:512,CHUNK_SIZE_MAX:2048,CHUNK_DELAY_MIN:100,CHUNK_DELAY_MAX:500,FINGERPRINT_DISPLAY_LENGTH:8,SESSION_ID_LENGTH:16,NESTED_ENCRYPTION_IV_SIZE:12};static MESSAGE_TYPES={MESSAGE:"message",ENHANCED_MESSAGE:"enhanced_message",RATCHET_MESSAGE:"ratchet_message",MESSAGE_DELETE:"message_delete",MESSAGE_RECEIPT:"message_receipt",HEARTBEAT:"heartbeat",VERIFICATION:"verification",VERIFICATION_RESPONSE:"verification_response",VERIFICATION_CONFIRMED:"verification_confirmed",VERIFICATION_BOTH_CONFIRMED:"verification_both_confirmed",PEER_DISCONNECT:"peer_disconnect",SECURITY_UPGRADE:"security_upgrade",KEY_ROTATION_SIGNAL:"key_rotation_signal",KEY_ROTATION_READY:"key_rotation_ready",FILE_TRANSFER_START:"file_transfer_start",FILE_TRANSFER_RESPONSE:"file_transfer_response",FILE_CHUNK:"file_chunk",CHUNK_CONFIRMATION:"chunk_confirmation",FILE_TRANSFER_COMPLETE:"file_transfer_complete",FILE_TRANSFER_ERROR:"file_transfer_error",CALL_OFFER:"call_offer",CALL_ANSWER:"call_answer",CALL_ICE:"call_ice",CALL_DECLINE:"call_decline",CALL_END:"call_end",ICE_RESTART_OFFER:"ice_restart_offer",ICE_RESTART_ANSWER:"ice_restart_answer",ICE_RESTART_REQUEST:"ice_restart_request",KEY_BLOB:"key_blob",KEY_PROOF:"key_proof",FAKE:"fake"};static FILTERED_RESULTS={FAKE_MESSAGE:"FAKE_MESSAGE_FILTERED",FILE_MESSAGE:"FILE_MESSAGE_FILTERED",SYSTEM_MESSAGE:"SYSTEM_MESSAGE_FILTERED"};static POST_VERIFICATION_CONTROL_TYPES=new Set([n.MESSAGE_TYPES.MESSAGE_DELETE,n.MESSAGE_TYPES.MESSAGE_RECEIPT,n.MESSAGE_TYPES.CALL_OFFER,n.MESSAGE_TYPES.CALL_ANSWER,n.MESSAGE_TYPES.CALL_ICE,n.MESSAGE_TYPES.CALL_DECLINE,n.MESSAGE_TYPES.CALL_END,n.MESSAGE_TYPES.ICE_RESTART_OFFER,n.MESSAGE_TYPES.ICE_RESTART_ANSWER,n.MESSAGE_TYPES.ICE_RESTART_REQUEST]);static SBQ2_SEND_ENABLED=!0;static SBQ2_KEY_EXCHANGE_TIMEOUT_MS=15e3;static PROTOCOL_VERSION="4.1";static RATCHET_VERSION=1;static MAX_SAS_ATTEMPTS=3;static DEFAULT_ICE_SERVERS=Object.freeze([Object.freeze({urls:"stun:stun.cloudflare.com:3478"}),Object.freeze({urls:"stun:stun.l.google.com:19302"}),Object.freeze({urls:"stun:stun1.l.google.com:19302"}),Object.freeze({urls:"stun:stun2.l.google.com:19302"}),Object.freeze({urls:"stun:stun3.l.google.com:19302"}),Object.freeze({urls:"stun:stun4.l.google.com:19302"})]);static DEBUG_MODE=!1;constructor(e,t,r,i,s=null,a=null,o={}){if(this._isProductionMode=this._detectProductionMode(),this._debugMode=!this._isProductionMode&&n.DEBUG_MODE,this._config={fakeTraffic:{enabled:o.fakeTraffic?.enabled??!0,minInterval:o.fakeTraffic?.minInterval??n.TIMEOUTS.FAKE_TRAFFIC_MIN_INTERVAL,maxInterval:o.fakeTraffic?.maxInterval??n.TIMEOUTS.FAKE_TRAFFIC_MAX_INTERVAL,minSize:o.fakeTraffic?.minSize??n.SIZES.FAKE_TRAFFIC_MIN_SIZE,maxSize:o.fakeTraffic?.maxSize??n.SIZES.FAKE_TRAFFIC_MAX_SIZE,patterns:o.fakeTraffic?.patterns??["heartbeat","status","sync"]},decoyChannels:{enabled:o.decoyChannels?.enabled??!0,maxDecoyChannels:o.decoyChannels?.maxDecoyChannels??n.LIMITS.MAX_DECOY_CHANNELS,decoyChannelNames:o.decoyChannels?.decoyChannelNames??["heartbeat"],sendDecoyData:o.decoyChannels?.sendDecoyData??!0,randomDecoyIntervals:o.decoyChannels?.randomDecoyIntervals??!0},packetPadding:{enabled:o.packetPadding?.enabled??!0,minPadding:o.packetPadding?.minPadding??n.SIZES.PACKET_PADDING_MIN,maxPadding:o.packetPadding?.maxPadding??n.SIZES.PACKET_PADDING_MAX,useRandomPadding:o.packetPadding?.useRandomPadding??!0,preserveMessageSize:o.packetPadding?.preserveMessageSize??!1},antiFingerprinting:{enabled:o.antiFingerprinting?.enabled??!1,randomizeTiming:o.antiFingerprinting?.randomizeTiming??!0,randomizeSizes:o.antiFingerprinting?.randomizeSizes??!1,addNoise:o.antiFingerprinting?.addNoise??!0,maskPatterns:o.antiFingerprinting?.maskPatterns??!1,useRandomHeaders:o.antiFingerprinting?.useRandomHeaders??!1},webrtc:{privacyMode:o.webrtc?.privacyMode??(o.webrtc?.relayOnly?"relay-only":"standard"),relayOnly:o.webrtc?.privacyMode?o.webrtc.privacyMode==="relay-only":o.webrtc?.relayOnly??!1,iceServers:o.webrtc?.iceServers??n.DEFAULT_ICE_SERVERS.map(c=>({...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<e.length;s+=t){let a=e.slice(s,s+t),o=await Promise.all(a);i.push(...o),s+t<e.length&&await this._asyncSleep(r)}return i}async _performNaturalCleanup(){await this._asyncSleep(0);for(let e=0;e<3;e++)await this._asyncSleep(10)}async _performHeavyCleanup(e){if(typeof Worker<"u")try{return await this._cleanupWithWorker(e)}catch(t){this._secureLog("warn","WebWorker cleanup failed, falling back to main thread",{errorType:t?.constructor?.name||"Unknown"})}return await this._cleanupInMainThread(e)}async _cleanupWithWorker(e){return new Promise((t,r)=>{let i=`
self.onmessage = function(e) {
const { type, data } = e.data;
try {
switch (type) {
case 'cleanup_arrays':
// Simulate heavy array cleanup
let processed = 0;
for (let i = 0; i < data.count; i++) {
// Simulate work
processed++;
if (processed % 1000 === 0) {
// Yield control periodically
setTimeout(() => {}, 0);
}
}
self.postMessage({ success: true, processed });
break;
case 'cleanup_objects':
// Simulate object cleanup
const cleaned = data.objects.map(() => null);
self.postMessage({ success: true, cleaned: cleaned.length });
break;
default:
self.postMessage({ success: true, message: 'Unknown cleanup type' });
}
} catch (error) {
self.postMessage({ success: false, error: error.message });
}
};
`,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(;i<r.count;){let d=Math.min(i+s,r.count);for(let u=i;u<d;u++);i=d,await this._asyncSleep(1)}return{success:!0,processed:i};case"cleanup_objects":let a=r.objects||[],o=[];for(let d=0;d<a.length;d+=50)o.push(a.slice(d,d+50));let c=0;for(let d of o)d.forEach(()=>c++),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(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&&e<t;)await new Promise(r=>setTimeout(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}(<REDACTED> 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&&t<n.LIMITS.OFFER_MAX_AGE;e||r?this._secureLog("debug","\u{1F9F9} Skipping crypto key wipe during periodic cleanup",{reason:e?"active ratchet connection":"offer awaiting answer"}):this._secureCleanupCryptographicMaterials(),this.messageQueue&&this.messageQueue.length>100&&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(e<this.expectedSequenceNumber-this.replayWindowSize)return this._secureLog("warn","Sequence number too old - possible replay attack",{received:e,expected:this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!1;if(e>this.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<<i)-1,o;do{let c=crypto.getRandomValues(new Uint8Array(s));o=0;for(let d=0;d<s;d++)o=o*256+c[d];o=o&a}while(o>=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.byteLength<n.SIZES.NESTED_ENCRYPTION_IV_SIZE+16)return this._debugMode&&this._secureLog("debug","\u{1F4DD} Data not encrypted or too short for nested decryption (need IV + minimum encrypted data)"),e;try{let t=new Uint8Array(e),r=t.slice(0,n.SIZES.NESTED_ENCRYPTION_IV_SIZE),i=t.slice(n.SIZES.NESTED_ENCRYPTION_IV_SIZE);return i.length===0?(this._debugMode&&this._secureLog("debug","\u{1F4DD} No encrypted data found"),e):await crypto.subtle.decrypt({name:"AES-GCM",iv:r},this.nestedEncryptionKey,i)}catch(t){return t.name==="OperationError"?this._debugMode&&this._secureLog("debug","\u{1F4DD} Data not encrypted with nested encryption, skipping..."):this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Nested decryption failed:",{details:t.message}),e}}applyPacketPadding(e){if(!this.securityFeatures.hasPacketPadding)return e;try{let t=e.byteLength,r;this.paddingConfig.useRandomPadding?r=Math.floor(Math.random()*(this.paddingConfig.maxPadding-this.paddingConfig.minPadding+1))+this.paddingConfig.minPadding:r=this.paddingConfig.minPadding;let i=crypto.getRandomValues(new Uint8Array(r)),s=new Uint8Array(t+r+4);return new DataView(s.buffer,0,4).setUint32(0,t,!1),s.set(new Uint8Array(e),4),s.set(i,4+t),s.buffer}catch(t){return this._secureLog("error","\u274C Packet padding failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}removePacketPadding(e){if(!this.securityFeatures.hasPacketPadding)return e;try{let t=new Uint8Array(e);if(t.length<5)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Data too short for packet padding removal, skipping"),e;let i=new DataView(t.buffer,0,4).getUint32(0,!1);return i<=0||i>t.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<e;t++){let r=this.decoyChannelConfig.decoyChannelNames[t],i=this.peerConnection.createDataChannel(r,{ordered:Math.random()>.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.length<r)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Data too short for reordering headers, processing directly"),this.processMessage(e);let i=new DataView(t.buffer,0,r),s=0,a=0,o=0;if(this.reorderingConfig.useSequenceNumbers&&(s=i.getUint32(0,!1)),this.reorderingConfig.useTimestamps&&(a=i.getUint32(4,!1)),o=i.getUint32(this.reorderingConfig.useTimestamps?8:4,!1),o>t.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.timestamp<e.timestamp)&&(e={sequence:t,...r});return e}cleanupOldPackets(e,t){for(let[r,i]of this.packetBuffer.entries())e-i.timestamp>t&&(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<t.length)return t.slice(0,i).buffer;return e}maskPatterns(e){let t=new Uint8Array(e),r=new Uint8Array(t.length);for(let i=0;i<t.length;i++){let s=this.fingerprintMask.noisePattern[i%this.fingerprintMask.noisePattern.length];r[i]=t[i]^s}return r.buffer}addRandomHeaders(e){let t=new Uint8Array(e),r=this.getUnbiasedRandomInRange(1,3),i=0;for(let o=0;o<r;o++)i+=4+this.getUnbiasedRandomInRange(0,15)+4;let s=new Uint8Array(i+t.length),a=0;for(let o=0;o<r;o++){let c;do c=crypto.getRandomValues(new Uint8Array(1))[0];while(c>=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;r<e.length;r++){let i=e.charCodeAt(r);t=(t<<5)-t+i,t=t&t}return Math.abs(t)}calculateChecksum(e){let t=0;for(let r=0;r<e.length;r++)t=t+e[r]&4294967295;return t}async removeSecurityLayers(e){try{let t=this.getSecurityStatus();if(this._debugMode&&this._secureLog("debug",`\u{1F50D} removeSecurityLayers (Stage ${t.stage})`,{dataType:typeof e,dataLength:e?.length||e?.byteLength||0,activeFeatures:t.activeFeaturesCount}),!e)return this._secureLog("warn","\u26A0\uFE0F Received empty data"),null;let r=e;if(typeof e=="string")try{let i=JSON.parse(e);if(i.type==="fake")return this._debugMode&&this._secureLog("debug",`\u{1F3AD} Fake message filtered out: ${i.pattern} (size: ${i.size})`),"FAKE_MESSAGE_FILTERED";if(i.type&&["heartbeat","verification","verification_response","peer_disconnect","key_rotation_signal","key_rotation_ready","security_upgrade","ice_restart_offer","ice_restart_answer","ice_restart_request"].includes(i.type))return"SYSTEM_MESSAGE_FILTERED";if(i.type&&["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"].includes(i.type))return this._debugMode&&this._secureLog("debug","\u{1F4C1} File transfer message detected, blocking from chat",{type:i.type}),"FILE_MESSAGE_FILTERED";if(i.type==="message")return this._debugMode&&this._secureLog("debug","\u{1F4DD} Regular message detected, extracting text",{data:i.data}),i.data;if(i.type==="enhanced_message"&&i.data){if(this._debugMode&&this._secureLog("debug","\u{1F510} Enhanced message detected, decrypting..."),!this.encryptionKey||!this.macKey||!this.metadataKey)return this._secureLog("error","\u274C Missing encryption keys"),null;let s=await window.EnhancedSecureCryptoUtils.decryptMessage(i.data,this.encryptionKey,this.macKey,this.metadataKey);this._debugMode&&(this._secureLog("debug","\u2705 Enhanced message decrypted, extracting..."),this._secureLog("debug","\u{1F50D} decryptedResult",{type:typeof s,hasMessage:!!s?.message,messageType:typeof s?.message,messageLength:s?.message?.length||0,messageSample:s?.message?.substring(0,50)||"no message"}));try{let a=JSON.parse(s.message);if(a.type==="fake"||a.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Encrypted fake message: ${a.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{this._debugMode&&this._secureLog("debug","\u{1F4DD} Decrypted content is not JSON, treating as plain text message")}return this._debugMode&&this._secureLog("debug","\u{1F4E4} Returning decrypted message",{message:s.message?.substring(0,50)}),s.message}if(i.type==="message"&&i.data)return this._debugMode&&this._secureLog("debug","\u{1F4DD} Regular message detected, extracting data"),i.data;if(i.type==="message")return this._debugMode&&this._secureLog("debug","\u{1F4DD} Regular message detected, returning for display"),e;if(!i.type||i.type!=="fake"&&!["heartbeat","verification","verification_response","peer_disconnect","key_rotation_signal","key_rotation_ready","enhanced_message","security_upgrade","ice_restart_offer","ice_restart_answer","ice_restart_request","file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"].includes(i.type))return this._debugMode&&this._secureLog("debug","\u{1F4DD} Regular message detected, returning for display"),e}catch{return this._debugMode&&this._secureLog("debug","\u{1F4C4} Not JSON, processing as raw data"),e}if(this.encryptionKey&&typeof r=="string"&&r.length>50)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&&o<c;)await new Promise(d=>setTimeout(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&&r<i;)await new Promise(s=>setTimeout(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(;r<i;){r++;let s=crypto.getRandomValues(new Uint8Array(e)),a=Array.from(s).map(o=>o.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;S<e.length;S++)t[e[S]]++;let r={shannon:0,min:0,collision:0,compression:0,quantum:0},i=0,s=e.length;for(let S=0;S<256;S++)if(t[S]>0){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(;r<e.length;){let i=0,s=0;for(let a=Math.max(0,r-255);a<r;a++){let o=0;for(;r+o<e.length&&e[r+o]===e[a+o]&&o<255;)o++;o>i&&(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<r.length;a++)if(e[i+a]!==r[a]){s=!1;break}if(s)return!0}return!1}_analyzeBitDistribution(e){let t=0,r=e.length*8;for(let c of e)t+=(c>>>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;a<e.length-r;a++)e[a]===e[a+r]&&i++,s++;if(s>0){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;c<s.length;c++)if(e[a+c]!==s[c]){o=!1;break}if(o)return!0}return this._calculateLocalEntropy(e).filter(s=>s<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<e.length;s++)if(e[s]===e[s-1]+1||e[s]===e[s-1]-1?i++:i=0,i>=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<n.SIZES.VERIFICATION_CODE_MIN_LENGTH)throw new Error("Failed to generate valid verification code");let m=window.EnhancedSecureCryptoUtils.generateMutualAuthChallenge();if(!m)throw new Error("Failed to generate mutual authentication challenge");if(this.sessionId=Array.from(crypto.getRandomValues(new Uint8Array(n.SIZES.SESSION_ID_LENGTH))).map(_=>_.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;d<a.length;d++)o|=a[d]^i.bindingTag[d];if(o!==0)throw new Error("This response belongs to a different invitation. Ask for a response to the code you are showing now.");t.remoteDescriptor=r,t.remoteCommitment=i.commitment,this._peerDTLSFingerprint=Array.from(i.fingerprint,d=>d.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<e.LIVENESS_PROBE_TIMEOUT)return;this._livenessProbeAt=0,this._secureLog("warn","\u26A0\uFE0F liveness probe unanswered and ICE is not connected \u2014 path presumed dead"),this._onPathLost("liveness_probe_timeout");return}if(t-this._lastInboundAt<e.LIVENESS_PROBE_AFTER)return;this._livenessProbeAt=t;let i=this._sendHeartbeat(!1);this._secureLog("info","\u{1F504} peer silent and ICE degraded, probing",{silentForMs:t-this._lastInboundAt,connectionState:this.peerConnection?.connectionState,probeSent:i})}isReconnecting(){return this._reconnect.phase!=="idle"&&this._reconnect.phase!=="exhausted"}_setupRecoveryLifecycleListeners(){typeof window>"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.barrenFailures<n.LIMITS.MAX_BARREN_ICE_FAILURES)&&(this._secureLog("warn","\u26A0\uFE0F ICE cannot gather any usable candidate \u2014 this connection is bound to a network that is gone",{consecutiveBarrenFailures:this._reconnect.barrenFailures}),this._giveUpAutoReconnect("ice_agent_unusable"))}}_onPathRecovered(){let e=this.isReconnecting();if(this._resetReconnectState(),this._lastInboundAt=Date.now(),this._livenessProbeAt=0,!e)return!1;this._secureLog("info","\u{1F504} connection recovered, session preserved"),this.onStatusChange("connected"),this.processMessageQueue();try{this._dispatchAppEvent?.(new CustomEvent("connection-recovered",{detail:{timestamp:Date.now()}}))}catch{}return!0}async _attemptIceRestart(){if(!this.isVerified||!this.peerConnection)return;if(this.peerConnection.connectionState==="connected"){this._onPathRecovered();return}let e=this._reconnect;if(typeof navigator<"u"&&navigator.onLine===!1){e.phase="waiting",e.startedAt=Date.now(),this._secureLog("debug","\u{1F504} Device offline \u2014 holding recovery open"),this._scheduleReconnectRetry();return}if(Date.now()-(e.startedAt||Date.now())>n.TIMEOUTS.RECONNECT_MAX_DURATION){this._giveUpAutoReconnect("timeout");return}if(e.inFlightAt&&Date.now()-e.inFlightAt<n.TIMEOUTS.ICE_RESTART_TIMEOUT){this._scheduleReconnectRetry();return}if(this.dataChannel?.readyState!=="open"){this._giveUpAutoReconnect("data_channel_closed");return}let r=Date.now()-Math.max(this._lastInboundAt||0,e.startedAt);if(e.attempts>=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:'<path d="M6 9l6 6 6-6"/>'}})]),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:'<rect x="2.5" y="4" width="19" height="13" rx="2"/><path d="M8 20.5h8M12 17.5v3"/>',light:'<circle cx="12" cy="12" r="4.2"/><path d="M12 2.6v2.4M12 19v2.4M2.6 12h2.4M19 12h2.4M5.3 5.3l1.7 1.7M17 17l1.7 1.7M18.7 5.3L17 7M7 17l-1.7 1.7"/>',dark:'<path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/>'},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:'<path d="M6 9l6 6 6-6"/>'}})]),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('<path d="M4.5 12.5l5 5 10-11"/>',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(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")}
`,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(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.`: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;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(var(--sb-scrim-rgb), 0.8);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
font-family: monospace;
`;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 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('<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/>',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('<path d="M5 12h14M13 6l6 6-6 6"/>',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:'<path d="M12 3l8 4v5c0 4.5-3.2 7.8-8 9-4.8-1.2-8-4.5-8-9V7l8-4z"/><path d="M9.2 12.2l2 2 3.6-3.8"/>'},{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:'<circle cx="5.5" cy="12" r="2.5"/><circle cx="18.5" cy="6" r="2.5"/><circle cx="18.5" cy="18" r="2.5"/><path d="M7.8 10.8l8.4-3.6M7.8 13.2l8.4 3.6"/>'},{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:'<path d="M21 8a8.5 8.5 0 0 0-15.6-2.5M3 4v4h4"/><path d="M3 16a8.5 8.5 0 0 0 15.6 2.5M21 20v-4h-4"/>'},{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:'<path d="M3 7h4l3 10h4M14 7h3l3 0"/><path d="M17 4l3 3-3 3"/><path d="M3 17h4l2-6"/>'},{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:'<path d="M9.9 5.1A9.6 9.6 0 0 1 12 5c5.5 0 9 5 9 7a11 11 0 0 1-2.2 3M6.3 7.3C3.6 8.9 2 11.2 2 12c0 1.4 3.5 7 10 7 1.6 0 3-.3 4.2-.8"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2M3 3l18 18"/>'}],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),'<path d="M15 6l-6 6 6 6"/>'),g("next",()=>S(1),'<path d="M9 6l6 6-6 6"/>')])]),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=D<h-1;return React.createElement("div",{key:D,style:{position:"relative",display:"grid",gridTemplateColumns:"54px 1fr",marginBottom:"16px"}},React.createElement("div",{style:{position:"relative"}},b&&React.createElement("div",{style:{position:"absolute",insetInlineStart:"26px",top:"30px",height:"calc(100% + 16px)",width:"2px",background:T.line}}),I(w.status)),React.createElement("div",{style:{borderRadius:"16px",background:"var(--sb-surface)",border:`1px solid ${w.status==="current"?"rgba(var(--sb-orange-rgb), 0.28)":"rgba(var(--sb-ink), 0.06)"}`,overflow:"hidden"}},React.createElement("div",{onClick:()=>d(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:'<path d="M12 2C6.48 2 2 6.58 2 12.26c0 4.5 2.87 8.32 6.84 9.67.5.09.68-.22.68-.49 0-.24-.01-.87-.01-1.71-2.78.62-3.37-1.36-3.37-1.36-.46-1.18-1.11-1.5-1.11-1.5-.91-.63.07-.62.07-.62 1 .07 1.53 1.05 1.53 1.05.89 1.56 2.34 1.11 2.91.85.09-.66.35-1.11.63-1.36-2.22-.26-4.55-1.14-4.55-5.07 0-1.12.39-2.03 1.03-2.75-.1-.26-.45-1.3.1-2.71 0 0 .84-.27 2.75 1.05a9.3 9.3 0 0 1 5 0c1.91-1.32 2.75-1.05 2.75-1.05.55 1.41.2 2.45.1 2.71.64.72 1.03 1.63 1.03 2.75 0 3.94-2.34 4.81-4.57 5.06.36.32.68.94.68 1.9 0 1.37-.01 2.47-.01 2.81 0 .27.18.59.69.49A10.02 10.02 0 0 0 22 12.26C22 6.58 17.52 2 12 2z"/>'}}),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:'<path d="M21 11.5a8 8 0 0 1-11.6 7.1L4 20l1.4-5.3A8 8 0 1 1 21 11.5z"/><path d="M8.5 11h7M8.5 14h4.5"/>'}}),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:re<M?C:"rgba(var(--sb-ink), 0.07)",border:"1px solid "+(re<M?"transparent":"rgba(var(--sb-ink), 0.05)"),boxShadow:re<M?`0 0 5px ${C}55`:"none",transition:"background .2s ease, box-shadow .2s ease"}}))),React.createElement("div",{key:"text",style:{display:"flex",alignItems:"center",justifyContent:"space-between",fontSize:"11.5px",color:"var(--sb-text-7)"}},[React.createElement("span",{key:"status",style:{display:"inline-flex",alignItems:"center",gap:"5px"}},[React.createElement("i",{key:"icon",className:_(b.status)}),I(b.status)]),React.createElement("span",{key:"count",style:{fontFamily:"'JetBrains Mono', ui-monospace, monospace",color:D(b)?C:"var(--sb-text-7)"}},x>0?`${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;e<n.length;e++){let t=n.charCodeAt(e);if(t<32||t===127)return!0}return!1}function Na(n){if(typeof n!="string")return f("iceUrl.notString");let e=n.trim();if(!e)return f("iceUrl.empty");if(e.length>ze.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:'<path d="M7 11V7a5 5 0 0 1 10 0v4"/><rect x="4.5" y="11" width="15" height="9" rx="2.2"/>',minimize:'<path d="M9 4v4a1 1 0 0 1-1 1H4M15 4v4a1 1 0 0 0 1 1h4M9 20v-4a1 1 0 0 0-1-1H4M15 20v-4a1 1 0 0 1 1-1h4"/>',expand:'<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/>',user:'<circle cx="12" cy="8" r="3.6"/><path d="M5 20c0-3.5 3-5.5 7-5.5s7 2 7 5.5"/>',micOn:'<rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0 0 14 0"/><path d="M12 18v3"/>',micOff:'<path d="M9 9v-1a3 3 0 0 1 5.1-2.1M15 11v3a3 3 0 0 1-4.6 2.5"/><path d="M5 11a7 7 0 0 0 10.3 6.2M19 11a7 7 0 0 1-.4 2.3"/><path d="M12 18v3"/><path d="M3 3l18 18"/>',camOn:'<path d="M23 7l-7 5 7 5V7z"/><rect x="1" y="5" width="15" height="14" rx="2.5"/>',camOff:'<path d="M16 16H3a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h2l2-2M11 6h2l7-3v14M2 2l20 20"/>',flip:'<path d="M3 7h3l2-2h8l2 2h3v12H3z"/><path d="M9.5 13a2.5 2.5 0 0 1 5 0M14.5 13l-1.3-1.3M14.5 13l1.3-1.3"/>',phone:'<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.8 19.8 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/>',phoneHangup:'<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.8 19.8 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z" transform="rotate(135 12 12)"/>'},s=(K,O,q)=>t("span",{style:{display:"grid",placeItems:"center",width:O+"px",height:O+"px"},dangerouslySetInnerHTML:{__html:`<svg width="${O}" height="${O}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${q}" stroke-linecap="round" stroke-linejoin="round">${K}</svg>`}}),[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:Y<O.bars?O.color:"rgba(var(--sb-ink), 0.18)"}})));return K?q:t("span",{key:"q",title:f("call.quality"),style:{display:"inline-flex",alignItems:"center",gap:"6px",fontSize:"11.5px",fontWeight:600,color:O.color}},[q,O.label])},fe=()=>n?.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<localStorage.length;e++){let t=localStorage.key(e);t&&t.startsWith("qr_offer_")&&n.push(t)}for(let e of n)try{localStorage.removeItem(e)}catch{}}catch{}},Fs=()=>(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
*
* @version 1.0.0
* @author SecureBit Team
* @license MIT
*/
/**
* Notification Integration Module for SecureBit WebRTC Chat
* Integrates secure notifications with existing WebRTC architecture
*
* @version 1.0.0
* @author SecureBit Team
* @license MIT
*/
/*! Bundled license information:
dompurify/dist/purify.es.mjs:
(*! @license DOMPurify 3.4.10 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.10/LICENSE *)
*/
//# sourceMappingURL=app-boot.js.map