"use strict";(()=>{var e=window.hydra=window.hydra||{};e.HydraAdmin=class{constructor(){}loadUser(t){t.preventDefault();var o=t.currentTarget.querySelector('input[id="username"]');e.client.resolveUser(o.value).then(e=>{if(!e)return window.alert("user not found");window.location=`/admin/user/${e._id}`}).catch(e=>{console.log("loadUser error",e),window.alert(e.message)})}askArchiveUser(t){var o=this;t.preventDefault();var r=JSON.parse(t.currentTarget.getAttribute("data-user"));e.client.showModal({title:"HYDRA Automated Perma-Ban™",prompt:`\n
Are you sure you want to archive user ${r.name} (@${r.username})'?
\nMessage editing will be added soon.
',buttons:[{label:"OK",class:"modal-btn-primary",onclick:()=>{hydra.client.closeModal()}}]})}deleteChatMessage(e){var t=e.target.getAttribute("data-message-id")||e.currentTarget.getAttribute("data-message-id");if(!t)return window.alert("The message cannot be deleted."),e.preventDefault(),!0;console.log("deleteChatMessage",e,t),hydra.client.showModal({title:"Delete chat message",prompt:'Are you sure you want to delete the message? It will be removed from everyone\'s view.
',buttons:[{label:"Cancel",class:"modal-btn-cancel",onclick:()=>{hydra.client.closeModal()}},{label:"Yes, Delete",class:"modal-btn-primary",onclick:()=>{fetch(`/chat/message/${t}`,{method:"DELETE"}).then(e=>e.ok?e.json():Promise.reject(new Error("failed to delete chat message"))).then(e=>{console.log("delete message response",e)}).finally(()=>{hydra.client.closeModal()})}}]})}sendInvitationStatusMessage(e){e.preventDefault(),e.stopPropagation();var t=e.currentTarget.getAttribute("data-room-type"),o=e.currentTarget.getAttribute("data-room-id"),r=this.getStatusMessageInputText();return this.postStatusMessage(r).then(e=>{if(!e.success)return Promise.reject(new Error(e.message));hydra.client.showModal({title:"Invitation sent",prompt:e.message,buttons:[{label:"Dismiss",class:"btn-primary",onclick:()=>{window.location=`/${t}/${o}`}}]})}).catch(e=>{console.error(e),hydra.client.closeModal(),window.alert(e.message)})}sendRequestChatInvitationStatusMessage(e){e.preventDefault(),e.stopPropagation();var t=this.getStatusMessageInputText();return this.postStatusMessage(t).then(e=>{if(!e.success)return Promise.reject(new Error(e.message));hydra.client.showModal({title:"Invitation request sent",prompt:e.message,buttons:[{label:"Dismiss",class:"btn-primary",onclick:()=>{window.location="/"}}]})}).catch(e=>{console.error(e),hydra.client.closeModal(),window.alert(e.message)})}sendStatusMessage(e){e.preventDefault(),e.stopPropagation();let t=this.getStatusMessageInputText();return this.postStatusMessage(t).then(e=>{if(!e.success)return Promise.reject(new Error(e.message));hydra.client.showModal({title:"Invitation sent",prompt:e.message,buttons:[{label:"Dismiss",class:"btn-primary",onclick:()=>{hydra.client.closeModal()}}]})}).catch(e=>{console.error(e),hydra.client.closeModal(),window.alert(e.message)})}getStatusMessageInputText(){let e=document.getElementById("status-message-text");if(!e)throw new Error("no status-message-text element found");let t=e.value;if("string"!=typeof t||!t.length)throw new Error("Status message text can't be empty.");return t}postStatusMessage(e){return fetch("/gab/status",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:e})}).then(e=>e.json())}addToSpotlight(e){let t=e.currentTarget.getAttribute("data-username"),o=e.currentTarget.getAttribute("data-user-id");console.log("addToSpotlight",e.currentTarget,o,t)}leaveChatRoom(e){var t=e.currentTarget.getAttribute("data-chat-room-id");fetch(`/chat/${t}/membership`,{method:"DELETE"}).then(e=>e.ok?e.json():Promise.reject(new Error("Failed to leave chat room."))).then(e=>{if(console.log("leave room",e),!e.success)return Promise.reject(e.message);window.location="/chat/global"}).catch(e=>{window.alert(`Error: ${e.message}`)})}mentionUser(e){let t=e.currentTarget.getAttribute("data-username");console.log("mentionUser",e.currentTarget,t),document.getElementById("chat-input").value+=`@${t} `}blockUser(e){var t=this,o=e.target.getAttribute("data-username")||e.currentTarget.getAttribute("data-username"),r=e.target.getAttribute("data-user-id")||e.currentTarget.getAttribute("data-user-id");e.preventDefault(),e.stopPropagation(),hydra.client.showModal({title:`Block ${o}`,prompt:`\n `,buttons:[{label:"Share to Gab",icon:"fa-hand-holding-heart",class:"btn-primary",onclick:()=>{let e=document.getElementById("share-status-message");fetch("/gab/status",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:e.value})}).then(e=>e.json()).then(e=>{if(!e.success)return new Error(e.message);window.alert(e.message)}).catch(e=>{console.error("shareToGab error",e),window.alert(e.message)}).finally(()=>{hydra.client.closeModal()})}}]}),!0}shareToTwitter(e){e.preventDefault();let t=`https://chat.gab.com/chat/${this.currentChatRoom._id}`,o=`https://twitter.com/intent/tweet?text=${encodeURIComponent(`I'm chatting in ${this.currentChatRoom.name} and thought you'd like to hop in here with us!`)}&url=${t}&via=getongab`;return window.open(o,"share-to-twitter",""),!0}shareToTelegram(e){e.preventDefault(),e.stopPropagation();let t=`https://telegram.me/share/url?url=${encodeURIComponent(`https://chat.gab.com/chat/${this.currentChatRoom._id}`)}&text=${encodeURIComponent(`I'm chatting in ${this.currentChatRoom.name} and thought you'd like to hop in here with us!`)}`;return window.open(t,"share-to-telegram",""),!0}shareToFacebook(e){e.preventDefault(),e.stopPropagation();let t=`https://chat.gab.com/chat/${this.currentChatRoom._id}`,o=["https://www.facebook.com/dialog/share","?app_id=507048810155691","&display=page",`&href=${encodeURIComponent(t)}`].join("");return window.open(o,"share-to-facebook",""),!0}shareToClipboard(e){e.preventDefault();let t=`https://chat.gab.com/chat/${this.currentChatRoom._id}`,o=`I'm chatting in ${this.currentChatRoom.name} and thought you'd like to hop in here with us!`;return console.log(t,o),this.copyTextToClipboard(`${o}\n${t}`).then(()=>{window.alert("Link copied to clipboard.")}).catch(e=>{console.error("Async: Could not copy text: ",e),window.alert("Failed to copy link to clipboard. You may need to grant Gab Trends permission to access the clipboard.")}),!0}fallbackCopyTextToClipboard(e){let t=!1,o=document.createElement("textarea");o.value=e,o.style.position="fixed",document.body.appendChild(o),o.focus(),o.select();try{t=document.execCommand("copy")}catch(e){console.error("unable to copy item to clipboard",e)}return document.body.removeChild(o),t}copyTextToClipboard(e){let t=this;return navigator.clipboard?navigator.clipboard.writeText(e):t.fallbackCopyTextToClipboard(e)?Promise.resolve():Promise.reject(new Error("Failed to copy Trends item to clipboard"))}}}();hydra=window.hydra=window.hydra||{};!function(){hydra.HydraClient=class{constructor(){var e=this;e.socket=io("/",{transports:["websocket"],forceNew:!0}),e.notifications=[],e.notificationIdx=0,e.isAuthenticated=!1,e.socket.on("connect",()=>{console.log("connected to Chat"),e.connect()}),e.socket.on("authenticated",e.onSocketAuthenticated.bind(e)),e.socket.on("autherror",e.onSocketAuthError.bind(e)),e.socket.on("notification",e.onNotification.bind(e)),e.notificationAlert=document.getElementById("notification-alert"),e.notificationTime=document.getElementById("notification-time"),e.notificationCategory=document.getElementById("notification-category"),e.notificationContent=document.getElementById("notification-content"),setInterval(e.update.bind(e),1e3)}getCurrentUser(){if(window.hydra&&window.hydra.data&&window.hydra.data.user)return window.hydra.data.user}connect(){var e=this;(new hydra.HydraResource).fetch("/user/connect-io").then(t=>{e.socket.emit("authenticate",t.response)}).catch(e=>{console.log("client error",e)})}onSocketAuthenticated(e){this.joinChannel(e.user._id,"user"),this.isAuthenticated=!0,document.dispatchEvent(new Event("hydra-socket-connected"))}onSocketAuthError(e){console.log("socket authentication error",e)}joinChannel(e,t){this.socket.emit("join",{channelType:t,channelId:e})}leaveChannel(e){this.socket.emit("leave",{channelId:e})}onNotification(e){this.notifications.push(e),this.notificationIdx=this.notifications.length-1,this.updateNotificationDisplay()}createNotification(e){this.notifications.push(e),this.notificationIdx=this.notifications.length-1,this.updateNotificationDisplay()}previousNotification(e){return e.preventDefault(),--this.notificationIdx<0&&(this.notificationIdx=this.notifications.length-1),this.updateNotificationDisplay(),!0}nextNotification(e){return e.preventDefault(),++this.notificationIdx>=this.notifications.length&&(this.notificationIdx=0),this.updateNotificationDisplay(),!0}closeNotification(e){return e.preventDefault(),this.notificationAlert.classList.add("closed"),!0}updateNotificationDisplay(){var e=this.notifications[this.notificationIdx];this.notificationTime.setAttribute("timestamp",e.created),this.notificationTime.innerText=moment(e.created).fromNow(),this.notificationCategory.innerText=e.category,this.notificationContent.innerHTML=e.content,this.notificationAlert.classList.remove("closed")}update(){}showModal(e){document.querySelector("#hydra-modal .modal-title").innerHTML=e.title,document.querySelector("#hydra-modal #modal-prompt").innerHTML=e.prompt;for(var t=document.querySelector("#hydra-modal .modal-footer");t.firstChild;)t.removeChild(t.firstChild);e.buttons&&e.buttons.length?(t.classList.remove("d-none"),e.buttons.forEach(e=>{var o=document.createElement("button");o.setAttribute("type","button"),e.onclick&&(o.onclick=e.onclick),e.label&&(o.innerHTML=e.label),o.classList.add("btn"),e.class&&o.classList.add(e.class),t.appendChild(o)})):t.classList.add("d-none"),$("#hydra-modal").modal({show:!0})}closeModal(){$("#hydra-modal").modal("hide")}showLightbox(e){var t=document.querySelector("#hydra-lightbox"),o=document.querySelector("#hydra-lightbox-image");t.classList.remove("d-none"),t.classList.add("d-flex"),o.src=e}hideLightbox(){var e=document.querySelector("#hydra-lightbox");e.classList.remove("d-flex"),e.classList.add("d-none")}loadHydraGraph(e,t){return fetch(e,{json:!0}).then(e=>e.ok?e.json():Promise.reject(new Error("failed to load HYDRA graph"))).then(e=>{var o=t.getContext("2d");return Promise.resolve(new Chart(o,e.graph))}).catch(e=>{console.error("HYDRA graph error",e)})}resolveUser(e){return fetch(`/user/resolve/${e}`).then(e=>e.json()).then(e=>e.success?Promise.resolve(e.user):Promise.reject(new Error(e.message)))}}}();hydra=window.hydra=window.hydra||{};const INIT_ERROR_MSG="HYDRA E2E is not properly configured. Please contact your system administrator for assistance.";(()=>{hydra.HydraSecurityKeyPassword=class{constructor(){let e=this;if(e.currentTask=null,e.modal=document.getElementById("hydra-skp-input"),!e.modal)throw new Error("Security Key Password input component not found.");try{e.attachModal(),e.attachStrengthFeedback()}catch(e){throw e}}attachModal(){if(this.passwordInputPrompt=this.modal.querySelector(".skp-input-prompt"),!this.passwordInputPrompt)throw new Error(INIT_ERROR_MSG);if(this.passwordInput=document.getElementById("skp-input"),!this.passwordInput)throw new Error(INIT_ERROR_MSG);if(this.savePasswordCheckbox=document.getElementById("skp-save-password"),!this.savePasswordCheckbox)throw new Error(INIT_ERROR_MSG);if(this.cancelButton=document.getElementById("skp-cancel-btn"),!this.cancelButton)throw new Error(INIT_ERROR_MSG);if(this.cancelButton.addEventListener("click",this.onModalCancel.bind(this)),this.acceptButton=document.getElementById("skp-accept-btn"),!this.acceptButton)throw new Error(INIT_ERROR_MSG);this.acceptButton.addEventListener("click",this.onModalAccept.bind(this))}attachStrengthFeedback(){let e,t=this;(e=document.getElementById("ecdh-key-password"))&&e.addEventListener("input",t.updatePasswordFeedback.bind(t)),(e=document.getElementById("ecdh-regen-password"))&&e.addEventListener("input",t.updatePasswordFeedback.bind(t)),t.skpInputFeedback=document.querySelectorAll(".skp-input-feedback")||[],t.skpInputWarning=document.querySelectorAll(".skp-input-feedback .skp-strength-warning")||[],t.skpInputStrength=document.querySelectorAll(".skp-input-feedback .skp-strength-indicator")||[],t.skpInputStrengthSuggestions=document.querySelectorAll(".skp-input-feedback .skp-strength-suggestions")||[]}updatePasswordFeedback(e){let t=zxcvbn(e.target.value);if(!t)return;let o="5%",r="bg-danger";switch(t.score){case 1:o="25%";break;case 2:o="50%",r="bg-warning";break;case 3:o="75%",r="bg-success";break;case 4:o="100%",r="bg-success"}this.skpInputStrength.forEach(e=>{e.style.width=o,e.classList.remove("bg-danger"),e.classList.remove("bg-warning"),e.classList.remove("bg-success"),e.classList.add(r)}),this.skpInputStrengthSuggestions.forEach(e=>{for(;e.firstChild;)e.removeChild(e.firstChild);t.feedback.suggestions.forEach(t=>{let o=document.createElement("small");o.classList.add("form-text"),o.classList.add("text-info"),o.textContent=`> ${t}`,e.appendChild(o)})}),this.skpInputWarning.forEach(e=>{t.feedback.warning&&t.feedback.warning.length?(e.textContent=t.feedback.warning,e.classList.remove("d-none")):(e.textContent="",e.classList.add("d-none"))})}getSecurityKeyPassword(){let e=this,t=window.sessionStorage.password||window.localStorage.password;return t?Promise.resolve({success:!0,isCancel:!1,skp:t}):e.currentTask?Promise.reject(new Error("Please resolve the current password request before starting another.")):new Promise((t,o)=>{e.currentTask={resolve:t,reject:o},$("#hydra-skp-input").modal({show:!0,keyboard:!1})})}validateSecurityKeyPassword(e){return zxcvbn(e)}onModalAccept(e){if(e&&e.preventDefault(),$("#hydra-skp-input").modal("hide"),!this.currentTask)return console.log("modal accept with no current task"),!0;let t=this.currentTask;this.currentTask=null;let o=this.passwordInput.value;return o&&"string"==typeof o&&o.length?(t.resolve({success:!0,isCancel:!1,skp:o}),!0):t.reject(new Error("No password entered."))}onModalCancel(e){if(e&&e.preventDefault(),$("#hydra-skp-input").modal("hide"),!this.currentTask)return console.log("modal cancel with no current task"),!0;let t=this.currentTask;return this.currentTask=null,t.reject(new Error("Security Key Password entry canceled.")),!0}}})();hydra=window.hydra=window.hydra||{};const BOOTSTRAP_ALERT_CLASSES=["alert-primary","alert-secondary","alert-success","alert-danger","alert-warning","alert-info","alert-light","alert-dark"];(()=>{hydra.HydraE2E=class{constructor(){this.b64=new hydra.HydraBase64}initialize(e){let t=this;return window.navigator.userAgent.match(/firefox/gi)?t.showIncompatibleMessage("firefox"):(e=Object.assign({requireKeyUnlock:!1},e),console.log("loading ECDH key pair..."),t.loadEcdhKeyPair(e).then(e=>e&&e.success?Promise.resolve(e.keyPair):e&&e.canceled?Promise.reject(new Error("Password entry canceled. You will be unable to proceed until you unlock these keys or generate new ones.")):t.fetchEcdhKeyPair()).then(e=>{e?(t.showKeyManager(),t.privateKey=e.privateKey,t.publicKey=e.publicKey):(console.log("user has no security keys"),document.dispatchEvent(new Event("hydra-chat-no-keys")),t.showKeyGenerator()),console.log("HydraE2E initialized",{privateKey:t.privateKey?"present":"absent",publicKey:t.publicKey?"present":"absent"})}).catch(e=>{console.error("failed to load ECDH key pair",e),window.alert(e.message)}))}showIncompatibleMessage(e){document.getElementById("key-generator").classList.add("d-none"),document.getElementById("key-management").classList.add("d-none"),document.getElementById("about-key-password").classList.add("d-none"),document.getElementById(`incompatible-${e}`).classList.remove("d-none")}showKeyGenerator(){let e=document.getElementById("key-generator"),t=document.getElementById("key-management"),o=document.getElementById("about-key-password");e&&e.classList.remove("d-none"),t&&t.classList.add("d-none"),o&&o.classList.add("d-none")}showKeyManager(){let e=document.getElementById("key-generator"),t=document.getElementById("key-management"),o=document.getElementById("about-key-password");e&&e.classList.add("d-none"),t&&t.classList.remove("d-none"),o&&o.classList.remove("d-none")}generateEcdhKeyPair(e){let t=this;e.preventDefault();let o=document.getElementById("key-generator"),r=document.getElementById("key-management"),a=document.getElementById("about-key-password"),s=document.getElementById("ecdh-key-password"),n=s.value;s.value="";let i=hydra.skp.validateSecurityKeyPassword(n);if(console.log(i),i.score<2)return window.alert("The password you entered is too insecure. Please try again."),s.focus(),!0;window.sessionStorage&&(window.sessionStorage.password=n);let l=document.getElementById("ecdh-savepw");return l&&l.checked?(console.log("persisting skp to localStorage"),window.localStorage&&(window.localStorage.password=n)):(console.log("removing skp from localStorage"),window.localStorage&&window.localStorage.removeItem("password")),o.classList.add("d-none"),t.createEcdhKeyPair(n).catch(e=>{console.error("generateEcdhKeyPair error",e),t.showAlert(e.message,"alert-danger")}).finally(()=>{r.classList.remove("d-none"),a.classList.remove("d-none"),s.value="",window.alert("Security Keys generated successfully."),window.location="/chat/global"}),!0}regenerateEcdhKeyPair(e){let t=this;e.preventDefault(),document.getElementById("key-generator").classList.add("d-none");let o=document.getElementById("key-management");o.classList.add("d-none");let r=document.getElementById("about-key-password");r.classList.add("d-none");let a=document.getElementById("ecdh-regen-password"),s=a.value,n=hydra.skp.validateSecurityKeyPassword(s);if(console.log(n),n.score<2)return window.alert("The password you entered is too insecure. Please try again."),a.focus(),!0;window.sessionStorage&&(window.sessionStorage.password=s);let i=document.getElementById("ecdh-regen-savepw");return i&&i.checked?window.localStorage&&(window.localStorage.password=s):window.localStorage&&window.localStorage.removeItem("password"),"string"!=typeof s||s.length<8?(window.alert("Password must be at least 8 characters long."),!0):(t.createEcdhKeyPair(s).then(e=>{if(!e.success)return Promise.reject(new Error(e.message))}).catch(e=>{console.error("regenerateEcdhKeyPair error",e),t.showAlert(e.message,"alert-danger")}).finally(()=>{o.classList.remove("d-none"),r.classList.remove("d-none"),a.value=""}),!0)}deleteEcdhKeyPair(e){return e&&e.preventDefault(),console.debug("removing ECDH key pair from Chat servers"),fetch("/user/ecdh-key-pair",{method:"DELETE"}).then(e=>{if(!e.ok)return Promise.reject(new Error("Failed to remove keys from Gab Chat servers. Please try again later."));window.localStorage&&(window.localStorage.removeItem("privateKey"),window.localStorage.removeItem("publicKey"),window.localStorage.removeItem("password"))}).catch(e=>{console.error("deleteEcdhKeyPair error",e),window.alert(e.message)})}createEcdhKeyPair(e){let t=this;return t.showAlert("Generating encryption keys..."),console.debug("generating new security key pair"),window.crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey","deriveBits"]).then(o=>(t.privateKey=o.privateKey,t.publicKey=o.publicKey,t.showAlert("Storing encryption keys..."),t.storeEcdhKeyPair(e))).then(e=>(t.closeAlert(),e))}storeEcdhKeyPair(e){let t=this,o={};return t.wrapKey(t.privateKey,e).then(e=>(o.privateKey=e,window.localStorage&&(window.localStorage.privateKey=JSON.stringify(e)),window.crypto.subtle.exportKey("jwk",t.publicKey))).then(e=>(o.publicKey=e,window.localStorage&&(window.localStorage.publicKey=JSON.stringify(e)),fetch("/user/ecdh-key-pair",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(o)}))).then(e=>e.json()).then(e=>(window.localStorage.keyVersion=e.keyPair.__v.toString(),console.log("storeEcdhKeyPair",e),Promise.resolve(e)))}loadEcdhKeyPair(e){if(!window.localStorage)return Promise.reject(new Error("Your browser does not support local storage. Browser local storage is required to use Gab Chat."));if(!window.localStorage.publicKey||!window.localStorage.privateKey)return Promise.resolve(null);let t=JSON.parse(window.localStorage.publicKey),o=JSON.parse(window.localStorage.privateKey);return o.data=this.b64.decode(o.data),o.salt=this.b64.decode(o.salt),o.iv=this.b64.decode(o.iv),this.unlockEcdhKeyPair(t,o,e)}unlockEcdhKeyPair(e,t,o){var r=this;return o=Object.assign({requireKeyUnlock:!1},o),hydra.skp.getSecurityKeyPassword().then(o=>r.importEcdhKeyPair(e,t,o.skp).then(e=>(window.sessionStorage&&(console.log("persisting SKP to browser session storage"),window.sessionStorage.password=o.skp),window.localStorage&&hydra.skp.savePasswordCheckbox.checked&&(console.log("persisting SKP to brower local storage"),window.localStorage.password=o.skp),Promise.resolve({success:!0,canceled:!1,keyPair:e}))).catch(o=>"OperationError"===o.name?(window.alert("The password entered failed to unlock your private key. Please try again."),r.unlockEcdhKeyPair(e,t)):Promise.resolve({success:!1,canceled:!1,error:o}))).catch(a=>o.requireKeyUnlock?(window.alert("You must unlock your private key before continuing."),r.unlockEcdhKeyPair(e,t,o)):Promise.resolve({success:!1,canceled:!0,error:a}))}fetchEcdhKeyPair(){let e=this;return console.log("fetching security keys from Chat servers"),fetch("/user/ecdh-key-pair",{json:!0}).then(e=>e.json()).then(t=>t.success?e.storeAndImportFetchedKeyPair(t):404===t.error.status?Promise.resolve():Promise.reject(new Error(t.message)))}storeAndImportFetchedKeyPair(e){var t=this;return console.log("persisting security keys to local storage",{response:e}),window.localStorage.keyVersion=e.keyPair.__v.toString(),window.localStorage.privateKey=JSON.stringify(e.keyPair.data.privateKey),window.localStorage.publicKey=JSON.stringify(e.keyPair.data.publicKey),e.keyPair.data.privateKey.data=t.b64.decode(e.keyPair.data.privateKey.data),e.keyPair.data.privateKey.salt=t.b64.decode(e.keyPair.data.privateKey.salt),e.keyPair.data.privateKey.iv=t.b64.decode(e.keyPair.data.privateKey.iv),hydra.skp.getSecurityKeyPassword().then(o=>t.importEcdhKeyPair(e.keyPair.data.publicKey,e.keyPair.data.privateKey,o.skp).then(e=>(window.sessionStorage&&(console.log("persisting SKP to browser session storage"),window.sessionStorage.password=o.skp),window.localStorage&&hydra.skp.savePasswordCheckbox.checked&&(console.log("persisting SKP to brower local storage"),window.localStorage.password=o.skp),Promise.resolve(e))))}importEcdhKeyPair(e,t,o){let r=this,a={};return e?t?o?window.crypto.subtle.importKey("jwk",e,{name:"ECDH",namedCurve:"P-256"},!0,e.key_ops).then(e=>(a.publicKey=e,r.unwrapKey(t,o))).then(e=>(a.privateKey=e,Promise.resolve(a))):Promise.reject(new Error("You must provide your Security Key Password to un-lock your security keys for use with Gab Chat.")):Promise.reject(new Error("Missing private key data. Please re-generate your security keys.")):Promise.reject(new Error("Missing public key data. Please re-generate your security keys."))}deleteLocalKeyStorage(){window.localStorage.removeItem("publicKey"),window.localStorage.removeItem("privateKey")}deriveKey(e){let t={};return window.crypto.subtle.deriveBits({name:"ECDH",public:e},this.privateKey,256).then(e=>(t.sharedDS=e.slice(0,16),window.crypto.subtle.importKey("raw",e.slice(16,32),"PBKDF2",!1,["deriveKey"]))).then(e=>(t.sharedDK=e,window.crypto.subtle.deriveKey({name:"PBKDF2",salt:t.sharedDS,iterations:1e5,hash:"SHA-256"},t.sharedDK,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"])))}getKeyMaterial(e){const t=new TextEncoder;return window.crypto.subtle.importKey("raw",t.encode(e),{name:"PBKDF2"},!1,["deriveBits","deriveKey"])}getKey(e,t){return window.crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:1e5,hash:"SHA-256"},e,{name:"AES-GCM",length:256},!0,["wrapKey","unwrapKey"])}wrapKey(e,t){let o=this,r={};return console.debug("wrapping security key for transmission or storage"),o.getKeyMaterial(t).then(e=>(r.salt=window.crypto.getRandomValues(new Uint8Array(16)),o.getKey(e,r.salt))).then(t=>(r.iv=window.crypto.getRandomValues(new Uint8Array(16)),window.crypto.subtle.wrapKey("jwk",e,t,{name:"AES-GCM",iv:r.iv}))).then(e=>(r.data=o.b64.encode(e),r.iv=o.b64.encode(r.iv),r.salt=o.b64.encode(r.salt),Promise.resolve(r))).catch(e=>(console.error("wrapKey error",e),Promise.reject(e)))}unwrapKey(e,t){let o=this,r={};return console.debug("unwrapping security key from storage or network"),o.getKeyMaterial(t).then(t=>(r.keyMaterial=t,o.getKey(t,e.salt))).then(t=>window.crypto.subtle.unwrapKey("jwk",e.data,t,{name:"AES-GCM",iv:e.iv},{name:"ECDH",namedCurve:"P-256",hash:{name:"SHA-256"}},!0,["deriveKey","deriveBits"])).catch(e=>(console.error("unwrapKey error",e),Promise.reject(e)))}showAlert(e,t="alert-secondary"){let o=document.getElementById("key-alert");BOOTSTRAP_ALERT_CLASSES.forEach(e=>{o.classList.remove(e)}),o.classList.add(t),o.classList.remove("d-none"),document.getElementById("key-alert-message").textContent=e}closeAlert(){let e=document.getElementById("key-alert");BOOTSTRAP_ALERT_CLASSES.forEach(t=>{e.classList.remove(t)}),e.classList.add("d-none")}importRoomMember(e){var t=this;return window.crypto.subtle.importKey("jwk",e.publicKey,{name:"ECDH",namedCurve:"P-256"},!0,e.publicKey.key_ops).then(o=>(e.publicKey=o,t.deriveKey(e.publicKey))).then(t=>(e.secretKey=t,window.crypto.subtle.exportKey("jwk",t))).then(t=>(e.secretKeyData=t,Promise.resolve(e)))}onJoinChatRoom(e){let t=this,o=[];return console.log("checking security key version",window.localStorage.keyVersion),fetch(`/user/ecdh-key-pair/version?v=${window.localStorage.keyVersion}`).then(e=>e.json()).then(e=>e.success?e.keyPair?t.storeAndImportFetchedKeyPair(e):Promise.resolve():Promise.reject(new Error(e.message))).then(()=>(e.members.forEach(e=>{e.publicKey?o.push(t.importRoomMember(e)):console.log(`Room member ${e.username} does not have a public key.`)}),Promise.all(o)))}encryptToChatRoom(e,t){let o=this,r=[],a=[];return e.members.forEach(e=>{e.publicKey?a.push(o.encryptContent(e,t).then(t=>{r.push({recipient:e._id,payload:t})}).catch(e=>{throw console.error("encryptToChatRoom error",e),e})):console.log(`room member ${e.username} does not have a public key.`)}),Promise.all(a).then(()=>Promise.resolve(r))}encryptContent(e,t){let o=this,r=[];return e&&e.publicKey?(e.secretKey||r.push(o.deriveKey(e.publicKey).then(t=>(e.secretKey=t,window.crypto.subtle.exportKey("jwk",t))).then(t=>{e.secretKeyData=t})),Promise.all(r).then(()=>{let r=window.crypto.getRandomValues(new Uint8Array(12)),a=(new TextEncoder).encode(t);return console.log("encrypt to user",{user:e.username,secretKey:e.secretKeyData}),window.crypto.subtle.encrypt({name:"AES-GCM",iv:r},e.secretKey,a).then(e=>{let t=o.b64.encode(e);return Promise.resolve({iv:o.b64.encode(r),encrypted:t})})})):Promise.reject(new Error(`Room member ${e.username} does not have a public key.`))}decryptMessage(e,t){let o=this,r=t.getAttribute("data-sender-id"),a=e.members.find(e=>e._id.toString()===r);if(!a)return Promise.reject(new Error("Room member does not exist"));if(!a.publicKey)return Promise.reject(new Error(`Room member ${a.username} does not have a public key.`));let s=[];return a.secretKey||s.push(o.deriveKey(a.publicKey).then(e=>(a.secretKey=e,window.crypto.subtle.exportKey("jwk",e))).then(e=>{a.secretKeyData=e})),Promise.all(s).then(()=>{let e=o.b64.decode(t.getAttribute("data-iv")),r=o.b64.decode(t.textContent);return window.crypto.subtle.decrypt({name:"AES-GCM",iv:e},a.secretKey,r)}).then(e=>{let o=(new TextDecoder).decode(e);t.textContent=o,t.setAttribute("data-is-decrypted",!0)}).catch(e=>(console.error("decryptMessage error",e),t.innerHTML=' ',Promise.reject(e)))}}})();hydra=window.hydra=window.hydra||{};!function(){hydra.HydraNotifications=class{constructor(){var e=this;e.favicon=document.querySelector('link[rel*="icon"]'),e.documentTitle=document.title,e.activityNotifications=0,"Notification"in window?(window.localStorage.notificationSettings||(window.localStorage.notificationSettings=JSON.stringify({enabled:!0,sound:!0,vibrate:!0})),e.settings=JSON.parse(window.localStorage.notificationSettings),hydra.audio.load("chat-notification.ribbit"),e.isWindowActive=!0,window.addEventListener("focus",()=>{console.log("window is active"),e.isWindowActive=!0,e.clearActivityNotification()}),window.addEventListener("blur",()=>{console.log("window is inactive"),e.isWindowActive=!1}),e.supported=!0,e.enabled="granted"===Notification.permission,console.log("HydraNotifications",{supported:e.supported,enabled:e.enabled}),e.enabled||e.requestPermission()):e.supported=!1}requestPermission(){var e=this;return"granted"===Notification.permission?Promise.resolve(!0):"denied"===Notification.permission?Promise.reject(new Error("Notification permissions have been denied.")):Notification.requestPermission().then(t=>{e.enabled="granted"===t})}showNotification(e,t){if(this.supported&&this.enabled&&this.settings.enabled&&!this.isWindowActive){var o=t||e.title||"Chat Notification",r=new Notification(o,{dir:e.dir,lang:e.lang,icon:e.icon,image:e.image,badge:e.badge,body:e.body,renotify:e.renotify,requireInteraction:e.requireInteraction,actions:e.actions,silent:e.silent,data:e.data,vibrate:this.settings.vibrate});r.addEventListener("click",()=>{console.log("notification clicked",r)}),r.addEventListener("error",e=>{console.log("notification error",r,e)})}}clearActivityNotification(){this.favicon&&this.favicon.setAttribute("href","/img/favicon/default.png"),this.activityNotifications=0,document.title=this.documentTitle}indicateActivity(){this.isWindowActive||(this.activityNotifications+=1,document.title=`(${this.activityNotifications}) ${this.documentTitle}`,this.favicon&&this.favicon.setAttribute("href","/img/favicon/active.png"))}}}(),function(){(window.hydra=window.hydra||{}).HydraResource=class{constructor(e,t){this.name=e||"Resource",t=t||{},this.options=Object.assign({async:!0,type:"json"},t)}fetch(e,t){var o=this,r={params:{method:"GET",url:e,params:t}};return new Promise(function(e,t){r.request=new XMLHttpRequest,r.resolve=e,r.reject=t,o.executeTransaction(r)})}post(e,t,o){var r,a={params:{method:"POST",url:e,body:t,bodyContentType:o||"application/json"}};try{r=new Promise(this.doPost.bind(this,a))}catch(e){throw console.error("hydra-resource.post error",e),e}return r}doPost(e,t,o){var r;if(this.options.type)switch(this.options.type){case"json":case"html":e.params.body=JSON.stringify(e.params.body);break;default:throw r=new Error("invalid resource type specified",{type:this.options.type}),console.error(r.message,{error:r}),r}e.request=new XMLHttpRequest,e.resolve=t,e.reject=o,this.executeTransaction(e)}put(e,t,o){var r,a={params:{method:"PUT",url:e,body:t,bodyContentType:o||"application/json"}};try{r=new Promise(this.doPut.bind(this,a))}catch(e){throw console.error("dmp-resource.put error",e),e}return r}doPut(e,t,o){var r;if(this.options.type)switch(this.options.type){case"json":e.params.body=JSON.stringify(e.params.body);break;default:throw r=new Error("invalid resource type specified",{type:this.options.type}),console.error(r.message,{error:r}),r}e.request=new XMLHttpRequest,e.resolve=t,e.reject=o,this.executeTransaction(e)}del(e){var t,o={params:{method:"DELETE",url:e}};try{t=new Promise(this.doDelete.bind(this,o))}catch(e){throw console.error("hydra-resource.post error",e),e}return t}doDelete(e,t,o){if(e.request=new XMLHttpRequest,e.resolve=t,e.reject=o,e.request.open(e.params.method,e.params.url,!0),this.options.type)switch(this.options.type){case"json":e.params.body=JSON.stringify(e.params.body);break;default:return console.error("invalid resource type specified:",this.options.type),e.request.abort(),void delete e.request}else e.params.body=JSON.stringify(e.params.body);this.executeTransaction(e)}buildTransactionUrl(e){var t=e.params.url,o="?";if(!e.params.params)return t;for(var r in e.params.params)e.params.params.hasOwnProperty(r)&&(t+=o,t+=r.toString(),t+="=",t+=e.params.params[r].toString(),o="&");return t}executeTransaction(e){var t=this.onReadyStateChange.bind(this,e);e.request.addEventListener("readystatechange",t),e.requestUrl=this.buildTransactionUrl(e),e.request.open(e.params.method,e.requestUrl,!0),e.params.bodyContentType&&e.request.setRequestHeader("Content-Type",e.params.bodyContentType),e.request.send(e.params.body)}onReadyStateChange(e){var t;if(e.request.readyState===XMLHttpRequest.DONE)if(200===e.request.status)t="json"===this.options.type?JSON.parse(e.request.response):e.request.response,e.resolve({url:e.params.url,status:e.request.status,statusText:e.request.statusText,response:t});else{var o;try{o=JSON.parse(e.request.response)}catch(t){console.log("response error",{error:e.request.response})}e.reject({status:e.request.status,statusText:e.request.statusText,response:o})}}}}(),function(){(window.hydra=window.hydra||{}).Spotlight=class{constructor(){let e=this;window.addEventListener("storage",t=>{console.log("Spotlight storage changed",t),e.load()}),e.load()}load(){let e=this;if(e.spotlight=localStorage.getItem("spotlight"),e.spotlight)return e.spotlight=JSON.parse(e.spotlight),void console.log("spotlight",e.spotlight);e.spotlight={},e.commit()}commit(){localStorage.setItem("spotlight",JSON.stringify(this.spotlight||{}))}addUser(e){this.spotlight.push(e),this.commit()}removeUser(e){let t=this.spotlight.indexOf(e);-1!==t&&(this.spotlight=this.spotlight.splice(t,1),this.commit())}clear(){this.spotlight={},this.commit()}}}();