From efb744d739aec309a6ac481b02d40f8e4b9114df Mon Sep 17 00:00:00 2001 From: Prince Kumar Date: Tue, 16 Jul 2024 14:53:54 +0530 Subject: [PATCH] NB-57 refresh the page when session key is activated --- netbox_secrets/project-static/src/secrets.ts | 1 + netbox_secrets/static/netbox_secrets/secrets.js | 8 ++++---- netbox_secrets/static/netbox_secrets/secrets.js.map | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/netbox_secrets/project-static/src/secrets.ts b/netbox_secrets/project-static/src/secrets.ts index c206ed2..bd4dc17 100644 --- a/netbox_secrets/project-static/src/secrets.ts +++ b/netbox_secrets/project-static/src/secrets.ts @@ -205,6 +205,7 @@ function requestSessionKey(privateKey: string) { } else { // If the response received was not an error, show the user a success message. const toast = createToast('success', 'Session Key Received', 'You may now unlock secrets.'); + window.location.reload(); toast.show(); } } else { diff --git a/netbox_secrets/static/netbox_secrets/secrets.js b/netbox_secrets/static/netbox_secrets/secrets.js index 1c5540c..25a156f 100644 --- a/netbox_secrets/static/netbox_secrets/secrets.js +++ b/netbox_secrets/static/netbox_secrets/secrets.js @@ -1,12 +1,12 @@ -"use strict";(()=>{var P=Object.create;var g=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var _=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports);var D=(e,n,i,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of M(n))!C.call(e,o)&&o!==i&&g(e,o,{get:()=>n[o],enumerable:!(t=R(n,o))||t.enumerable});return e};var H=(e,n,i)=>(i=e!=null?P(B(e)):{},D(n||!e||!e.__esModule?g(i,"default",{value:e,enumerable:!0}):i,e));var m=(e,n,i)=>new Promise((t,o)=>{var s=l=>{try{c(i.next(l))}catch(a){o(a)}},r=l=>{try{c(i.throw(l))}catch(a){o(a)}},c=l=>l.done?t(l.value):Promise.resolve(l.value).then(s,r);c((i=i.apply(e,n)).next())});var h=_(E=>{"use strict";E.parse=O;E.serialize=q;var I=Object.prototype.toString,f=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function O(e,n){if(typeof e!="string")throw new TypeError("argument str must be a string");for(var i={},t=n||{},o=t.decode||$,s=0;s{if(y(a))p("danger","Error",a.error).show();else{let{private_key:d,public_key:u}=a;o!==null&&s!==null&&(o.value=u,s.value=d)}})}function c(){let a=document.getElementById("id_public_key");o!==null&&(a.value=o.value,a.innerText=o.value)}function l(){let a=`Public Key +"use strict";(()=>{var P=Object.create;var g=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var _=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports);var D=(e,n,i,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of M(n))!C.call(e,o)&&o!==i&&g(e,o,{get:()=>n[o],enumerable:!(t=R(n,o))||t.enumerable});return e};var H=(e,n,i)=>(i=e!=null?P(B(e)):{},D(n||!e||!e.__esModule?g(i,"default",{value:e,enumerable:!0}):i,e));var m=(e,n,i)=>new Promise((t,o)=>{var s=l=>{try{c(i.next(l))}catch(a){o(a)}},r=l=>{try{c(i.throw(l))}catch(a){o(a)}},c=l=>l.done?t(l.value):Promise.resolve(l.value).then(s,r);c((i=i.apply(e,n)).next())});var h=_(w=>{"use strict";w.parse=O;w.serialize=q;var I=Object.prototype.toString,f=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function O(e,n){if(typeof e!="string")throw new TypeError("argument str must be a string");for(var i={},t=n||{},o=t.decode||$,s=0;s{if(y(a))p("danger","Error",a.error).show();else{let{private_key:d,public_key:u}=a;o!==null&&s!==null&&(o.value=u,s.value=d)}})}function c(){let a=document.getElementById("id_public_key");o!==null&&(a.value=o.value,a.innerText=o.value)}function l(){let a=`Public Key ${o==null?void 0:o.value} Private Key -${s==null?void 0:s.value}`,d=new Blob([a],{type:"text/plain"}),u=document.createElement("a");u.style.display="none",u.href=window.URL.createObjectURL(d),u.download="key.txt",document.body.appendChild(u),u.click(),window.URL.revokeObjectURL(u.href),document.body.removeChild(u)}e.addEventListener("shown.bs.modal",()=>r()),n.addEventListener("click",()=>c()),i.addEventListener("click",()=>navigator.clipboard.writeText((s==null?void 0:s.value)||"")),t.addEventListener("click",()=>l())}function S(e,n){let i=document.querySelector(`button.unlock-secret[secret-id='${e}']`),t=document.querySelector(`button.lock-secret[secret-id='${e}']`),o=document.querySelector(`span[secret-id='${e}']`);i!==null&&(n==="unlock"&&i.classList.add("d-none"),n==="lock"&&i.classList.remove("d-none")),t!==null&&(n==="unlock"&&t.classList.remove("d-none"),n==="lock"&&t.classList.add("d-none")),o!==null&&(n==="unlock"&&o.classList.remove("d-none"),n==="lock"&&o.classList.add("d-none"))}function G(){let e=new window.Modal("#privkey_modal");function n(t){let o=document.getElementById(`secret_${t}`);typeof t=="string"&&t!==""&&k(`/api/plugins/secrets/secrets/${t}/`).then(s=>{if(y(s))s.error.toLowerCase().includes("invalid session key")?e.show():p("danger","Error",s.error).show();else{let{plaintext:r}=s;o!==null&&r!==null?(v(o)?o.value=r:o.innerText=r,S(t,"unlock")):e.show()}})}function i(t){if(typeof t=="string"&&t!==""){let o=document.getElementById(`secret_${t}`);v(o)?o.value="********":o.innerText="********",S(t,"lock")}}for(let t of document.querySelectorAll("button.unlock-secret"))t.addEventListener("click",()=>n(t.getAttribute("secret-id")));for(let t of document.querySelectorAll("button.lock-secret"))t.addEventListener("click",()=>i(t.getAttribute("secret-id")))}function z(e){A("/api/plugins/secrets/session-keys/",{private_key:e,preserve_key:!0}).then(n=>{if(!y(n))window.location.pathname==="/plugins/secrets/user-key/"?window.location.reload():p("success","Session Key Received","You may now unlock secrets.").show();else{let i=n.error;L(n)&&(i+=` -${n.exception}`),p("danger","Failed to Retrieve Session Key",i).show()}})}function J(){for(let n of document.querySelectorAll("#request_session_key")){let i=function(){for(let t of document.querySelectorAll("#user_privkey"))z(t.value),t.value=""};var e=i;n.addEventListener("click",i)}}function X(){let e=new window.Modal("#privkey_modal");function n(i){document.cookie.indexOf("netbox_secrets_sessionid")===-1&&(i.preventDefault(),e.show())}for(let i of document.querySelectorAll(".requires-session-key")){let t=i.closest("form");t!==null&&t.addEventListener("submit",n)}}function w(){for(let e of[N,G,J,X])e()}document.readyState!=="loading"?w():document.addEventListener("DOMContentLoaded",w);})(); +${s==null?void 0:s.value}`,d=new Blob([a],{type:"text/plain"}),u=document.createElement("a");u.style.display="none",u.href=window.URL.createObjectURL(d),u.download="key.txt",document.body.appendChild(u),u.click(),window.URL.revokeObjectURL(u.href),document.body.removeChild(u)}e.addEventListener("shown.bs.modal",()=>r()),n.addEventListener("click",()=>c()),i.addEventListener("click",()=>navigator.clipboard.writeText((s==null?void 0:s.value)||"")),t.addEventListener("click",()=>l())}function S(e,n){let i=document.querySelector(`button.unlock-secret[secret-id='${e}']`),t=document.querySelector(`button.lock-secret[secret-id='${e}']`),o=document.querySelector(`span[secret-id='${e}']`);i!==null&&(n==="unlock"&&i.classList.add("d-none"),n==="lock"&&i.classList.remove("d-none")),t!==null&&(n==="unlock"&&t.classList.remove("d-none"),n==="lock"&&t.classList.add("d-none")),o!==null&&(n==="unlock"&&o.classList.remove("d-none"),n==="lock"&&o.classList.add("d-none"))}function G(){let e=new window.Modal("#privkey_modal");function n(t){let o=document.getElementById(`secret_${t}`);typeof t=="string"&&t!==""&&v(`/api/plugins/secrets/secrets/${t}/`).then(s=>{if(y(s))s.error.toLowerCase().includes("invalid session key")?e.show():p("danger","Error",s.error).show();else{let{plaintext:r}=s;o!==null&&r!==null?(E(o)?o.value=r:o.innerText=r,S(t,"unlock")):e.show()}})}function i(t){if(typeof t=="string"&&t!==""){let o=document.getElementById(`secret_${t}`);E(o)?o.value="********":o.innerText="********",S(t,"lock")}}for(let t of document.querySelectorAll("button.unlock-secret"))t.addEventListener("click",()=>n(t.getAttribute("secret-id")));for(let t of document.querySelectorAll("button.lock-secret"))t.addEventListener("click",()=>i(t.getAttribute("secret-id")))}function z(e){A("/api/plugins/secrets/session-keys/",{private_key:e,preserve_key:!0}).then(n=>{if(y(n)){let i=n.error;L(n)&&(i+=` +${n.exception}`),p("danger","Failed to Retrieve Session Key",i).show()}else if(window.location.pathname==="/plugins/secrets/user-key/")window.location.reload();else{let i=p("success","Session Key Received","You may now unlock secrets.");window.location.reload(),i.show()}})}function J(){for(let n of document.querySelectorAll("#request_session_key")){let i=function(){for(let t of document.querySelectorAll("#user_privkey"))z(t.value),t.value=""};var e=i;n.addEventListener("click",i)}}function X(){let e=new window.Modal("#privkey_modal");function n(i){document.cookie.indexOf("netbox_secrets_sessionid")===-1&&(i.preventDefault(),e.show())}for(let i of document.querySelectorAll(".requires-session-key")){let t=i.closest("form");t!==null&&t.addEventListener("submit",n)}}function k(){for(let e of[N,G,J,X])e()}document.readyState!=="loading"?k():document.addEventListener("DOMContentLoaded",k);})(); /*! Bundled license information: cookie/index.js: diff --git a/netbox_secrets/static/netbox_secrets/secrets.js.map b/netbox_secrets/static/netbox_secrets/secrets.js.map index 781a33d..51c16ff 100644 --- a/netbox_secrets/static/netbox_secrets/secrets.js.map +++ b/netbox_secrets/static/netbox_secrets/secrets.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/cookie/index.js", "../src/bs.ts", "../src/util.ts", "../src/secrets.ts", "../src/index.ts"], - "sourcesContent": ["/*!\n * cookie\n * Copyright(c) 2012-2014 Roman Shtylman\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module exports.\n * @public\n */\n\nexports.parse = parse;\nexports.serialize = serialize;\n\n/**\n * Module variables.\n * @private\n */\n\nvar __toString = Object.prototype.toString\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\n\nvar fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\n/**\n * Parse a cookie header.\n *\n * Parse the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n *\n * @param {string} str\n * @param {object} [options]\n * @return {object}\n * @public\n */\n\nfunction parse(str, options) {\n if (typeof str !== 'string') {\n throw new TypeError('argument str must be a string');\n }\n\n var obj = {}\n var opt = options || {};\n var dec = opt.decode || decode;\n\n var index = 0\n while (index < str.length) {\n var eqIdx = str.indexOf('=', index)\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break\n }\n\n var endIdx = str.indexOf(';', index)\n\n if (endIdx === -1) {\n endIdx = str.length\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(';', eqIdx - 1) + 1\n continue\n }\n\n var key = str.slice(index, eqIdx).trim()\n\n // only assign once\n if (undefined === obj[key]) {\n var val = str.slice(eqIdx + 1, endIdx).trim()\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1)\n }\n\n obj[key] = tryDecode(val, dec);\n }\n\n index = endIdx + 1\n }\n\n return obj;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * serialize('foo', 'bar', { httpOnly: true })\n * => \"foo=bar; httpOnly\"\n *\n * @param {string} name\n * @param {string} val\n * @param {object} [options]\n * @return {string}\n * @public\n */\n\nfunction serialize(name, val, options) {\n var opt = options || {};\n var enc = opt.encode || encode;\n\n if (typeof enc !== 'function') {\n throw new TypeError('option encode is invalid');\n }\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError('argument name is invalid');\n }\n\n var value = enc(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError('argument val is invalid');\n }\n\n var str = name + '=' + value;\n\n if (null != opt.maxAge) {\n var maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError('option maxAge is invalid')\n }\n\n str += '; Max-Age=' + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError('option domain is invalid');\n }\n\n str += '; Domain=' + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError('option path is invalid');\n }\n\n str += '; Path=' + opt.path;\n }\n\n if (opt.expires) {\n var expires = opt.expires\n\n if (!isDate(expires) || isNaN(expires.valueOf())) {\n throw new TypeError('option expires is invalid');\n }\n\n str += '; Expires=' + expires.toUTCString()\n }\n\n if (opt.httpOnly) {\n str += '; HttpOnly';\n }\n\n if (opt.secure) {\n str += '; Secure';\n }\n\n if (opt.priority) {\n var priority = typeof opt.priority === 'string'\n ? opt.priority.toLowerCase()\n : opt.priority\n\n switch (priority) {\n case 'low':\n str += '; Priority=Low'\n break\n case 'medium':\n str += '; Priority=Medium'\n break\n case 'high':\n str += '; Priority=High'\n break\n default:\n throw new TypeError('option priority is invalid')\n }\n }\n\n if (opt.sameSite) {\n var sameSite = typeof opt.sameSite === 'string'\n ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n str += '; SameSite=Strict';\n break;\n case 'lax':\n str += '; SameSite=Lax';\n break;\n case 'strict':\n str += '; SameSite=Strict';\n break;\n case 'none':\n str += '; SameSite=None';\n break;\n default:\n throw new TypeError('option sameSite is invalid');\n }\n }\n\n return str;\n}\n\n/**\n * URL-decode string value. Optimized to skip native call when no %.\n *\n * @param {string} str\n * @returns {string}\n */\n\nfunction decode (str) {\n return str.indexOf('%') !== -1\n ? decodeURIComponent(str)\n : str\n}\n\n/**\n * URL-encode value.\n *\n * @param {string} str\n * @returns {string}\n */\n\nfunction encode (val) {\n return encodeURIComponent(val)\n}\n\n/**\n * Determine if value is a Date.\n *\n * @param {*} val\n * @private\n */\n\nfunction isDate (val) {\n return __toString.call(val) === '[object Date]' ||\n val instanceof Date\n}\n\n/**\n * Try decoding a string using a decoding function.\n *\n * @param {string} str\n * @param {function} decode\n * @private\n */\n\nfunction tryDecode(str, decode) {\n try {\n return decode(str);\n } catch (e) {\n return str;\n }\n}\n", "type ToastLevel = 'danger' | 'warning' | 'success' | 'info';\n\nexport function createToast(\n level: ToastLevel,\n title: string,\n message: string,\n extra?: string,\n): InstanceType {\n let iconName = 'mdi-alert';\n switch (level) {\n case 'warning':\n iconName = 'mdi-alert';\n break;\n case 'success':\n iconName = 'mdi-check-circle';\n break;\n case 'info':\n iconName = 'mdi-information';\n break;\n case 'danger':\n iconName = 'mdi-alert';\n break;\n }\n\n const container = document.createElement('div');\n container.setAttribute('class', 'toast-container position-fixed bottom-0 end-0 m-3');\n\n const main = document.createElement('div');\n main.setAttribute('class', `toast bg-${level}`);\n main.setAttribute('role', 'alert');\n main.setAttribute('aria-live', 'assertive');\n main.setAttribute('aria-atomic', 'true');\n\n const header = document.createElement('div');\n header.setAttribute('class', `toast-header bg-${level} text-body`);\n\n const icon = document.createElement('i');\n icon.setAttribute('class', `mdi ${iconName}`);\n\n const titleElement = document.createElement('strong');\n titleElement.setAttribute('class', 'me-auto ms-1');\n titleElement.innerText = title;\n\n const button = document.createElement('button');\n button.setAttribute('type', 'button');\n button.setAttribute('class', 'btn-close');\n button.setAttribute('data-bs-dismiss', 'toast');\n button.setAttribute('aria-label', 'Close');\n\n const body = document.createElement('div');\n body.setAttribute('class', 'toast-body');\n\n header.appendChild(icon);\n header.appendChild(titleElement);\n\n if (typeof extra !== 'undefined') {\n const extraElement = document.createElement('small');\n extraElement.setAttribute('class', 'text-muted');\n header.appendChild(extraElement);\n }\n\n header.appendChild(button);\n\n body.innerText = message.trim();\n\n main.appendChild(header);\n main.appendChild(body);\n container.appendChild(main);\n document.body.appendChild(container);\n\n const toast = new window.Toast(main);\n return toast;\n}\n", "import Cookie from 'cookie';\n\ntype APIRes = T | ErrorBase | APIError;\ntype Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\ntype ReqData = URLSearchParams | Dict | undefined | unknown;\n\n/**\n * Type guard to determine if an API response is a detailed error.\n *\n * @param data API JSON Response\n * @returns Type guard for `data`.\n */\nexport function isApiError(data: Record): data is APIError {\n return 'error' in data && 'exception' in data;\n}\n\n/**\n * Type guard to determine if an API response is an error.\n *\n * @param data API JSON Response\n * @returns Type guard for `data`.\n */\nexport function hasError(data: Record): data is ErrorBase {\n return 'error' in data;\n}\n\n/**\n * Type guard to determine if an element is an `HTMLInputElement`.\n *\n * @param element HTML Element.\n */\nexport function isInputElement(element: HTMLElement): element is HTMLInputElement {\n return 'value' in element && 'required' in element;\n}\n\n/**\n * Retrieve the CSRF token from cookie storage.\n */\nexport function getCsrfToken(): string {\n const { csrftoken: csrfToken } = Cookie.parse(document.cookie);\n if (typeof csrfToken === 'undefined') {\n throw new Error('Invalid or missing CSRF token');\n }\n return csrfToken;\n}\n\n/**\n * Authenticate and interact with the NetBox API.\n *\n * @param url Request URL\n * @param method Request Method\n * @param data Data to `POST`, `PATCH`, or `PUT`, if applicable.\n * @returns JSON Response\n */\nexport async function apiRequest(\n url: string,\n method: Method,\n data?: D,\n): Promise> {\n const token = getCsrfToken();\n const headers = new Headers({ 'X-CSRFToken': token });\n\n let body;\n if (typeof data !== 'undefined') {\n body = JSON.stringify(data);\n headers.set('content-type', 'application/json');\n headers.set('Accept', 'application/json');\n }\n\n const res = await fetch(url, { method, body, headers, credentials: 'same-origin' });\n const contentType = res.headers.get('Content-Type');\n if (typeof contentType === 'string' && contentType.includes('text')) {\n const error = await res.text();\n return { error } as ErrorBase;\n }\n const json = (await res.json()) as R | APIError;\n if (!res.ok && Array.isArray(json)) {\n const error = json.join('\\n');\n return { error } as ErrorBase;\n } else if (!res.ok && 'detail' in json) {\n return { error: json.detail } as ErrorBase;\n }\n return json;\n}\n\n/**\n * `POST` an object as form data to the NetBox API.\n *\n * @param url Request URL\n * @param data Object to convert to form data\n * @returns JSON Response\n */\nexport async function apiPostForm(\n url: string,\n data: D,\n): Promise> {\n return await apiRequest(url, 'POST', data);\n}\n\n/**\n * `GET` data from the NetBox API.\n *\n * @param url Request URL\n * @returns JSON Response\n */\nexport async function apiGetBase(url: string): Promise> {\n return await apiRequest(url, 'GET');\n}\n", "import { createToast } from './bs';\nimport { apiGetBase, apiPostForm, isApiError, isInputElement, hasError } from './util';\n\nimport type { APISecret, APIKeyPair } from './types';\n\n/**\n * Initialize Generate Private Key Pair Elements.\n */\nfunction initGenerateKeyPair() {\n const element = document.getElementById('new_keypair_modal') as HTMLDivElement;\n const accept = document.getElementById('use_new_pubkey') as HTMLButtonElement;\n const copyBtn = document.getElementById('copy_prikey') as HTMLButtonElement;\n const exportBtn = document.getElementById('export_key') as HTMLButtonElement;\n // If the elements are not loaded, stop.\n if (element === null || accept === null || copyBtn === null || exportBtn === null) {\n return;\n }\n const publicElem = element.querySelector('textarea#new_pubkey');\n const privateElem = element.querySelector('textarea#new_privkey');\n\n /**\n * Handle Generate Private Key Pair Modal opening.\n */\n function handleOpen() {\n // When the modal opens, set the `readonly` attribute on the textarea elements.\n for (const elem of [publicElem, privateElem]) {\n if (elem !== null) {\n elem.setAttribute('readonly', '');\n }\n }\n // Fetch the key pair from the API.\n apiGetBase('/api/plugins/secrets/generate-rsa-key-pair/').then(data => {\n if (!hasError(data)) {\n // If key pair generation was successful, set the textarea elements' value to the generated\n // values.\n const { private_key: priv, public_key: pub } = data;\n if (publicElem !== null && privateElem !== null) {\n publicElem.value = pub;\n privateElem.value = priv;\n }\n } else {\n // Otherwise, show an error.\n const toast = createToast('danger', 'Error', data.error);\n toast.show();\n }\n });\n }\n\n /**\n * Set the public key form field's value to the generated public key.\n */\n function handleAccept() {\n const publicKeyField = document.getElementById('id_public_key') as HTMLTextAreaElement;\n if (publicElem !== null) {\n publicKeyField.value = publicElem.value;\n publicKeyField.innerText = publicElem.value;\n }\n }\n\n /**\n * Handles file download functionality.\n */\n function handleExport() {\n const content = `Public Key\\n\\n${publicElem?.value}\\n\\nPrivate Key\\n\\n${privateElem?.value}`;\n\n const blob = new Blob([content], { type: 'text/plain' });\n\n const a = document.createElement('a');\n a.style.display = 'none';\n a.href = window.URL.createObjectURL(blob);\n a.download = 'key.txt';\n document.body.appendChild(a);\n\n a.click();\n\n window.URL.revokeObjectURL(a.href);\n document.body.removeChild(a);\n }\n\n element.addEventListener('shown.bs.modal', () => handleOpen());\n accept.addEventListener('click', () => handleAccept());\n copyBtn.addEventListener('click', () => navigator.clipboard.writeText(privateElem?.value || ''));\n exportBtn.addEventListener('click', () => handleExport());\n}\n\n/**\n * Toggle copy/lock/unlock button visibility based on the action occurring.\n * @param id Secret ID.\n * @param action Lock or Unlock, so we know which buttons to display.\n */\nfunction toggleSecretButtons(id: string, action: 'lock' | 'unlock') {\n const unlockButton = document.querySelector(`button.unlock-secret[secret-id='${id}']`);\n const lockButton = document.querySelector(`button.lock-secret[secret-id='${id}']`);\n const copyButton = document.querySelector(`span[secret-id='${id}']`);\n // If we're unlocking, hide the unlock button. Otherwise, show it.\n if (unlockButton !== null) {\n if (action === 'unlock') unlockButton.classList.add('d-none');\n if (action === 'lock') unlockButton.classList.remove('d-none');\n }\n // If we're unlocking, show the lock button. Otherwise, hide it.\n if (lockButton !== null) {\n if (action === 'unlock') lockButton.classList.remove('d-none');\n if (action === 'lock') lockButton.classList.add('d-none');\n }\n // If we're unlocking, show the copy button. Otherwise, hide it.\n if (copyButton !== null) {\n if (action === 'unlock') copyButton.classList.remove('d-none');\n if (action === 'lock') copyButton.classList.add('d-none');\n }\n}\n\n/**\n * Initialize Lock & Unlock button event listeners & callbacks.\n */\nfunction initLockUnlock() {\n const privateKeyModal = new window.Modal('#privkey_modal');\n\n /**\n * Unlock a secret, or prompt the user for their private key, if a session key is not available.\n *\n * @param id Secret ID\n */\n function unlock(id: string | null) {\n const target = document.getElementById(`secret_${id}`) as HTMLDivElement | HTMLInputElement;\n if (typeof id === 'string' && id !== '') {\n apiGetBase(`/api/plugins/secrets/secrets/${id}/`).then(data => {\n if (!hasError(data)) {\n const { plaintext } = data;\n // `plaintext` is the plain text value of the secret. If it is null, it has not been\n // decrypted, likely due to a mission session key.\n\n if (target !== null && plaintext !== null) {\n // If `plaintext` is not null, we have the decrypted value. Set the target element's\n // inner text to the decrypted value and toggle copy/lock button visibility.\n if (isInputElement(target)) {\n target.value = plaintext;\n } else {\n target.innerText = plaintext;\n }\n\n toggleSecretButtons(id, 'unlock');\n } else {\n // Otherwise, we do _not_ have the decrypted value and need to prompt the user for\n // their private RSA key, in order to get a session key. The session key is then sent\n // as a cookie in future requests.\n privateKeyModal.show();\n }\n } else {\n if (data.error.toLowerCase().includes('invalid session key')) {\n // If, for some reason, a request was made but resulted in an API error that complains\n // of a missing session key, prompt the user for their session key.\n privateKeyModal.show();\n } else {\n // If we received an API error but it doesn't contain 'invalid session key', show the\n // user an error message.\n const toast = createToast('danger', 'Error', data.error);\n toast.show();\n }\n }\n });\n }\n }\n\n /**\n * Lock a secret and toggle visibility of the unlock button.\n * @param id Secret ID\n */\n function lock(id: string | null) {\n if (typeof id === 'string' && id !== '') {\n const target = document.getElementById(`secret_${id}`) as HTMLDivElement | HTMLInputElement;\n\n // Obscure the inner text of the secret element.\n if (isInputElement(target)) {\n target.value = '********';\n } else {\n target.innerText = '********';\n }\n\n // Toggle visibility of the copy/lock/unlock buttons.\n toggleSecretButtons(id, 'lock');\n }\n }\n\n for (const element of document.querySelectorAll('button.unlock-secret')) {\n element.addEventListener('click', () => unlock(element.getAttribute('secret-id')));\n }\n for (const element of document.querySelectorAll('button.lock-secret')) {\n element.addEventListener('click', () => lock(element.getAttribute('secret-id')));\n }\n}\n\n/**\n * Request a session key from the API.\n * @param privateKey RSA Private Key (valid JSON string)\n */\nfunction requestSessionKey(privateKey: string) {\n apiPostForm('/api/plugins/secrets/session-keys/', {\n private_key: privateKey,\n preserve_key: true,\n }).then(res => {\n if (!hasError(res)) {\n // If the session key has been added from the user key page, reload the page.\n if (window.location.pathname === '/plugins/secrets/user-key/') {\n window.location.reload();\n } else {\n // If the response received was not an error, show the user a success message.\n const toast = createToast('success', 'Session Key Received', 'You may now unlock secrets.');\n toast.show();\n }\n } else {\n // Otherwise, show the user an error message.\n let message = res.error;\n if (isApiError(res)) {\n // If the error received was a standard API error containing a Python exception message,\n // append it to the error.\n message += `\\n${res.exception}`;\n }\n const toast = createToast('danger', 'Failed to Retrieve Session Key', message);\n toast.show();\n }\n });\n}\n\n/**\n * Initialize Request Session Key Elements.\n */\nfunction initGetSessionKey() {\n for (const element of document.querySelectorAll('#request_session_key')) {\n /**\n * Send the user's input private key to the API to get a session key, which will be stored as\n * a cookie for future requests.\n */\n function handleClick() {\n for (const pk of document.querySelectorAll('#user_privkey')) {\n requestSessionKey(pk.value);\n // Clear the private key form field value.\n pk.value = '';\n }\n }\n element.addEventListener('click', handleClick);\n }\n}\n\n/**\n * Initialize Secret Edit Form Handler.\n */\nfunction initSecretsEdit() {\n const privateKeyModal = new window.Modal('#privkey_modal');\n\n /**\n * Check the cookie store for a `netbox_secrets_sessionid`. If not present, prompt the user to submit their\n * private key.\n */\n function handleSubmit(event: Event): void {\n if (document.cookie.indexOf('netbox_secrets_sessionid') === -1) {\n event.preventDefault();\n privateKeyModal.show();\n }\n }\n\n for (const element of document.querySelectorAll('.requires-session-key')) {\n const form = element.closest('form');\n if (form !== null) {\n form.addEventListener('submit', handleSubmit);\n }\n }\n}\n\nexport function initSecrets() {\n for (const func of [initGenerateKeyPair, initLockUnlock, initGetSessionKey, initSecretsEdit]) {\n func();\n }\n}\n", "import { initSecrets } from './secrets';\n\nif (document.readyState !== 'loading') {\n initSecrets();\n} else {\n document.addEventListener('DOMContentLoaded', initSecrets);\n}\n"], - "mappings": "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", - "names": ["require_cookie", "__commonJSMin", "exports", "parse", "serialize", "__toString", "fieldContentRegExp", "str", "options", "obj", "opt", "dec", "decode", "index", "eqIdx", "endIdx", "key", "val", "tryDecode", "name", "enc", "encode", "value", "maxAge", "expires", "isDate", "priority", "sameSite", "e", "createToast", "level", "title", "message", "extra", "iconName", "container", "main", "header", "icon", "titleElement", "button", "body", "extraElement", "import_cookie", "isApiError", "data", "hasError", "isInputElement", "element", "getCsrfToken", "csrfToken", "Cookie", "apiRequest", "url", "method", "__async", "token", "headers", "body", "res", "contentType", "json", "apiPostForm", "apiGetBase", "initGenerateKeyPair", "element", "accept", "copyBtn", "exportBtn", "publicElem", "privateElem", "handleOpen", "elem", "apiGetBase", "data", "hasError", "createToast", "priv", "pub", "handleAccept", "publicKeyField", "handleExport", "content", "blob", "a", "toggleSecretButtons", "id", "action", "unlockButton", "lockButton", "copyButton", "initLockUnlock", "privateKeyModal", "unlock", "target", "plaintext", "isInputElement", "lock", "requestSessionKey", "privateKey", "apiPostForm", "res", "message", "isApiError", "initGetSessionKey", "handleClick", "pk", "initSecretsEdit", "handleSubmit", "event", "form", "initSecrets", "func", "initSecrets"] + "sourcesContent": ["/*!\n * cookie\n * Copyright(c) 2012-2014 Roman Shtylman\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module exports.\n * @public\n */\n\nexports.parse = parse;\nexports.serialize = serialize;\n\n/**\n * Module variables.\n * @private\n */\n\nvar __toString = Object.prototype.toString\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\n\nvar fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\n/**\n * Parse a cookie header.\n *\n * Parse the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n *\n * @param {string} str\n * @param {object} [options]\n * @return {object}\n * @public\n */\n\nfunction parse(str, options) {\n if (typeof str !== 'string') {\n throw new TypeError('argument str must be a string');\n }\n\n var obj = {}\n var opt = options || {};\n var dec = opt.decode || decode;\n\n var index = 0\n while (index < str.length) {\n var eqIdx = str.indexOf('=', index)\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break\n }\n\n var endIdx = str.indexOf(';', index)\n\n if (endIdx === -1) {\n endIdx = str.length\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(';', eqIdx - 1) + 1\n continue\n }\n\n var key = str.slice(index, eqIdx).trim()\n\n // only assign once\n if (undefined === obj[key]) {\n var val = str.slice(eqIdx + 1, endIdx).trim()\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1)\n }\n\n obj[key] = tryDecode(val, dec);\n }\n\n index = endIdx + 1\n }\n\n return obj;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * serialize('foo', 'bar', { httpOnly: true })\n * => \"foo=bar; httpOnly\"\n *\n * @param {string} name\n * @param {string} val\n * @param {object} [options]\n * @return {string}\n * @public\n */\n\nfunction serialize(name, val, options) {\n var opt = options || {};\n var enc = opt.encode || encode;\n\n if (typeof enc !== 'function') {\n throw new TypeError('option encode is invalid');\n }\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError('argument name is invalid');\n }\n\n var value = enc(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError('argument val is invalid');\n }\n\n var str = name + '=' + value;\n\n if (null != opt.maxAge) {\n var maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError('option maxAge is invalid')\n }\n\n str += '; Max-Age=' + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError('option domain is invalid');\n }\n\n str += '; Domain=' + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError('option path is invalid');\n }\n\n str += '; Path=' + opt.path;\n }\n\n if (opt.expires) {\n var expires = opt.expires\n\n if (!isDate(expires) || isNaN(expires.valueOf())) {\n throw new TypeError('option expires is invalid');\n }\n\n str += '; Expires=' + expires.toUTCString()\n }\n\n if (opt.httpOnly) {\n str += '; HttpOnly';\n }\n\n if (opt.secure) {\n str += '; Secure';\n }\n\n if (opt.priority) {\n var priority = typeof opt.priority === 'string'\n ? opt.priority.toLowerCase()\n : opt.priority\n\n switch (priority) {\n case 'low':\n str += '; Priority=Low'\n break\n case 'medium':\n str += '; Priority=Medium'\n break\n case 'high':\n str += '; Priority=High'\n break\n default:\n throw new TypeError('option priority is invalid')\n }\n }\n\n if (opt.sameSite) {\n var sameSite = typeof opt.sameSite === 'string'\n ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n str += '; SameSite=Strict';\n break;\n case 'lax':\n str += '; SameSite=Lax';\n break;\n case 'strict':\n str += '; SameSite=Strict';\n break;\n case 'none':\n str += '; SameSite=None';\n break;\n default:\n throw new TypeError('option sameSite is invalid');\n }\n }\n\n return str;\n}\n\n/**\n * URL-decode string value. Optimized to skip native call when no %.\n *\n * @param {string} str\n * @returns {string}\n */\n\nfunction decode (str) {\n return str.indexOf('%') !== -1\n ? decodeURIComponent(str)\n : str\n}\n\n/**\n * URL-encode value.\n *\n * @param {string} str\n * @returns {string}\n */\n\nfunction encode (val) {\n return encodeURIComponent(val)\n}\n\n/**\n * Determine if value is a Date.\n *\n * @param {*} val\n * @private\n */\n\nfunction isDate (val) {\n return __toString.call(val) === '[object Date]' ||\n val instanceof Date\n}\n\n/**\n * Try decoding a string using a decoding function.\n *\n * @param {string} str\n * @param {function} decode\n * @private\n */\n\nfunction tryDecode(str, decode) {\n try {\n return decode(str);\n } catch (e) {\n return str;\n }\n}\n", "type ToastLevel = 'danger' | 'warning' | 'success' | 'info';\n\nexport function createToast(\n level: ToastLevel,\n title: string,\n message: string,\n extra?: string,\n): InstanceType {\n let iconName = 'mdi-alert';\n switch (level) {\n case 'warning':\n iconName = 'mdi-alert';\n break;\n case 'success':\n iconName = 'mdi-check-circle';\n break;\n case 'info':\n iconName = 'mdi-information';\n break;\n case 'danger':\n iconName = 'mdi-alert';\n break;\n }\n\n const container = document.createElement('div');\n container.setAttribute('class', 'toast-container position-fixed bottom-0 end-0 m-3');\n\n const main = document.createElement('div');\n main.setAttribute('class', `toast bg-${level}`);\n main.setAttribute('role', 'alert');\n main.setAttribute('aria-live', 'assertive');\n main.setAttribute('aria-atomic', 'true');\n\n const header = document.createElement('div');\n header.setAttribute('class', `toast-header bg-${level} text-body`);\n\n const icon = document.createElement('i');\n icon.setAttribute('class', `mdi ${iconName}`);\n\n const titleElement = document.createElement('strong');\n titleElement.setAttribute('class', 'me-auto ms-1');\n titleElement.innerText = title;\n\n const button = document.createElement('button');\n button.setAttribute('type', 'button');\n button.setAttribute('class', 'btn-close');\n button.setAttribute('data-bs-dismiss', 'toast');\n button.setAttribute('aria-label', 'Close');\n\n const body = document.createElement('div');\n body.setAttribute('class', 'toast-body');\n\n header.appendChild(icon);\n header.appendChild(titleElement);\n\n if (typeof extra !== 'undefined') {\n const extraElement = document.createElement('small');\n extraElement.setAttribute('class', 'text-muted');\n header.appendChild(extraElement);\n }\n\n header.appendChild(button);\n\n body.innerText = message.trim();\n\n main.appendChild(header);\n main.appendChild(body);\n container.appendChild(main);\n document.body.appendChild(container);\n\n const toast = new window.Toast(main);\n return toast;\n}\n", "import Cookie from 'cookie';\n\ntype APIRes = T | ErrorBase | APIError;\ntype Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\ntype ReqData = URLSearchParams | Dict | undefined | unknown;\n\n/**\n * Type guard to determine if an API response is a detailed error.\n *\n * @param data API JSON Response\n * @returns Type guard for `data`.\n */\nexport function isApiError(data: Record): data is APIError {\n return 'error' in data && 'exception' in data;\n}\n\n/**\n * Type guard to determine if an API response is an error.\n *\n * @param data API JSON Response\n * @returns Type guard for `data`.\n */\nexport function hasError(data: Record): data is ErrorBase {\n return 'error' in data;\n}\n\n/**\n * Type guard to determine if an element is an `HTMLInputElement`.\n *\n * @param element HTML Element.\n */\nexport function isInputElement(element: HTMLElement): element is HTMLInputElement {\n return 'value' in element && 'required' in element;\n}\n\n/**\n * Retrieve the CSRF token from cookie storage.\n */\nexport function getCsrfToken(): string {\n const { csrftoken: csrfToken } = Cookie.parse(document.cookie);\n if (typeof csrfToken === 'undefined') {\n throw new Error('Invalid or missing CSRF token');\n }\n return csrfToken;\n}\n\n/**\n * Authenticate and interact with the NetBox API.\n *\n * @param url Request URL\n * @param method Request Method\n * @param data Data to `POST`, `PATCH`, or `PUT`, if applicable.\n * @returns JSON Response\n */\nexport async function apiRequest(\n url: string,\n method: Method,\n data?: D,\n): Promise> {\n const token = getCsrfToken();\n const headers = new Headers({ 'X-CSRFToken': token });\n\n let body;\n if (typeof data !== 'undefined') {\n body = JSON.stringify(data);\n headers.set('content-type', 'application/json');\n headers.set('Accept', 'application/json');\n }\n\n const res = await fetch(url, { method, body, headers, credentials: 'same-origin' });\n const contentType = res.headers.get('Content-Type');\n if (typeof contentType === 'string' && contentType.includes('text')) {\n const error = await res.text();\n return { error } as ErrorBase;\n }\n const json = (await res.json()) as R | APIError;\n if (!res.ok && Array.isArray(json)) {\n const error = json.join('\\n');\n return { error } as ErrorBase;\n } else if (!res.ok && 'detail' in json) {\n return { error: json.detail } as ErrorBase;\n }\n return json;\n}\n\n/**\n * `POST` an object as form data to the NetBox API.\n *\n * @param url Request URL\n * @param data Object to convert to form data\n * @returns JSON Response\n */\nexport async function apiPostForm(\n url: string,\n data: D,\n): Promise> {\n return await apiRequest(url, 'POST', data);\n}\n\n/**\n * `GET` data from the NetBox API.\n *\n * @param url Request URL\n * @returns JSON Response\n */\nexport async function apiGetBase(url: string): Promise> {\n return await apiRequest(url, 'GET');\n}\n", "import { createToast } from './bs';\nimport { apiGetBase, apiPostForm, hasError, isApiError, isInputElement } from './util';\n\nimport type { APIKeyPair, APISecret } from './types';\n\n/**\n * Initialize Generate Private Key Pair Elements.\n */\nfunction initGenerateKeyPair() {\n const element = document.getElementById('new_keypair_modal') as HTMLDivElement;\n const accept = document.getElementById('use_new_pubkey') as HTMLButtonElement;\n const copyBtn = document.getElementById('copy_prikey') as HTMLButtonElement;\n const exportBtn = document.getElementById('export_key') as HTMLButtonElement;\n // If the elements are not loaded, stop.\n if (element === null || accept === null || copyBtn === null || exportBtn === null) {\n return;\n }\n const publicElem = element.querySelector('textarea#new_pubkey');\n const privateElem = element.querySelector('textarea#new_privkey');\n\n /**\n * Handle Generate Private Key Pair Modal opening.\n */\n function handleOpen() {\n // When the modal opens, set the `readonly` attribute on the textarea elements.\n for (const elem of [publicElem, privateElem]) {\n if (elem !== null) {\n elem.setAttribute('readonly', '');\n }\n }\n // Fetch the key pair from the API.\n apiGetBase('/api/plugins/secrets/generate-rsa-key-pair/').then(data => {\n if (!hasError(data)) {\n // If key pair generation was successful, set the textarea elements' value to the generated\n // values.\n const { private_key: priv, public_key: pub } = data;\n if (publicElem !== null && privateElem !== null) {\n publicElem.value = pub;\n privateElem.value = priv;\n }\n } else {\n // Otherwise, show an error.\n const toast = createToast('danger', 'Error', data.error);\n toast.show();\n }\n });\n }\n\n /**\n * Set the public key form field's value to the generated public key.\n */\n function handleAccept() {\n const publicKeyField = document.getElementById('id_public_key') as HTMLTextAreaElement;\n if (publicElem !== null) {\n publicKeyField.value = publicElem.value;\n publicKeyField.innerText = publicElem.value;\n }\n }\n\n /**\n * Handles file download functionality.\n */\n function handleExport() {\n const content = `Public Key\\n\\n${publicElem?.value}\\n\\nPrivate Key\\n\\n${privateElem?.value}`;\n\n const blob = new Blob([content], { type: 'text/plain' });\n\n const a = document.createElement('a');\n a.style.display = 'none';\n a.href = window.URL.createObjectURL(blob);\n a.download = 'key.txt';\n document.body.appendChild(a);\n\n a.click();\n\n window.URL.revokeObjectURL(a.href);\n document.body.removeChild(a);\n }\n\n element.addEventListener('shown.bs.modal', () => handleOpen());\n accept.addEventListener('click', () => handleAccept());\n copyBtn.addEventListener('click', () => navigator.clipboard.writeText(privateElem?.value || ''));\n exportBtn.addEventListener('click', () => handleExport());\n}\n\n/**\n * Toggle copy/lock/unlock button visibility based on the action occurring.\n * @param id Secret ID.\n * @param action Lock or Unlock, so we know which buttons to display.\n */\nfunction toggleSecretButtons(id: string, action: 'lock' | 'unlock') {\n const unlockButton = document.querySelector(`button.unlock-secret[secret-id='${id}']`);\n const lockButton = document.querySelector(`button.lock-secret[secret-id='${id}']`);\n const copyButton = document.querySelector(`span[secret-id='${id}']`);\n // If we're unlocking, hide the unlock button. Otherwise, show it.\n if (unlockButton !== null) {\n if (action === 'unlock') unlockButton.classList.add('d-none');\n if (action === 'lock') unlockButton.classList.remove('d-none');\n }\n // If we're unlocking, show the lock button. Otherwise, hide it.\n if (lockButton !== null) {\n if (action === 'unlock') lockButton.classList.remove('d-none');\n if (action === 'lock') lockButton.classList.add('d-none');\n }\n // If we're unlocking, show the copy button. Otherwise, hide it.\n if (copyButton !== null) {\n if (action === 'unlock') copyButton.classList.remove('d-none');\n if (action === 'lock') copyButton.classList.add('d-none');\n }\n}\n\n/**\n * Initialize Lock & Unlock button event listeners & callbacks.\n */\nfunction initLockUnlock() {\n const privateKeyModal = new window.Modal('#privkey_modal');\n\n /**\n * Unlock a secret, or prompt the user for their private key, if a session key is not available.\n *\n * @param id Secret ID\n */\n function unlock(id: string | null) {\n const target = document.getElementById(`secret_${id}`) as HTMLDivElement | HTMLInputElement;\n if (typeof id === 'string' && id !== '') {\n apiGetBase(`/api/plugins/secrets/secrets/${id}/`).then(data => {\n if (!hasError(data)) {\n const { plaintext } = data;\n // `plaintext` is the plain text value of the secret. If it is null, it has not been\n // decrypted, likely due to a mission session key.\n\n if (target !== null && plaintext !== null) {\n // If `plaintext` is not null, we have the decrypted value. Set the target element's\n // inner text to the decrypted value and toggle copy/lock button visibility.\n if (isInputElement(target)) {\n target.value = plaintext;\n } else {\n target.innerText = plaintext;\n }\n\n toggleSecretButtons(id, 'unlock');\n } else {\n // Otherwise, we do _not_ have the decrypted value and need to prompt the user for\n // their private RSA key, in order to get a session key. The session key is then sent\n // as a cookie in future requests.\n privateKeyModal.show();\n }\n } else {\n if (data.error.toLowerCase().includes('invalid session key')) {\n // If, for some reason, a request was made but resulted in an API error that complains\n // of a missing session key, prompt the user for their session key.\n privateKeyModal.show();\n } else {\n // If we received an API error but it doesn't contain 'invalid session key', show the\n // user an error message.\n const toast = createToast('danger', 'Error', data.error);\n toast.show();\n }\n }\n });\n }\n }\n\n /**\n * Lock a secret and toggle visibility of the unlock button.\n * @param id Secret ID\n */\n function lock(id: string | null) {\n if (typeof id === 'string' && id !== '') {\n const target = document.getElementById(`secret_${id}`) as HTMLDivElement | HTMLInputElement;\n\n // Obscure the inner text of the secret element.\n if (isInputElement(target)) {\n target.value = '********';\n } else {\n target.innerText = '********';\n }\n\n // Toggle visibility of the copy/lock/unlock buttons.\n toggleSecretButtons(id, 'lock');\n }\n }\n\n for (const element of document.querySelectorAll('button.unlock-secret')) {\n element.addEventListener('click', () => unlock(element.getAttribute('secret-id')));\n }\n for (const element of document.querySelectorAll('button.lock-secret')) {\n element.addEventListener('click', () => lock(element.getAttribute('secret-id')));\n }\n}\n\n/**\n * Request a session key from the API.\n * @param privateKey RSA Private Key (valid JSON string)\n */\nfunction requestSessionKey(privateKey: string) {\n apiPostForm('/api/plugins/secrets/session-keys/', {\n private_key: privateKey,\n preserve_key: true,\n }).then(res => {\n if (!hasError(res)) {\n // If the session key has been added from the user key page, reload the page.\n if (window.location.pathname === '/plugins/secrets/user-key/') {\n window.location.reload();\n } else {\n // If the response received was not an error, show the user a success message.\n const toast = createToast('success', 'Session Key Received', 'You may now unlock secrets.');\n window.location.reload();\n toast.show();\n }\n } else {\n // Otherwise, show the user an error message.\n let message = res.error;\n if (isApiError(res)) {\n // If the error received was a standard API error containing a Python exception message,\n // append it to the error.\n message += `\\n${res.exception}`;\n }\n const toast = createToast('danger', 'Failed to Retrieve Session Key', message);\n toast.show();\n }\n });\n}\n\n/**\n * Initialize Request Session Key Elements.\n */\nfunction initGetSessionKey() {\n for (const element of document.querySelectorAll('#request_session_key')) {\n /**\n * Send the user's input private key to the API to get a session key, which will be stored as\n * a cookie for future requests.\n */\n function handleClick() {\n for (const pk of document.querySelectorAll('#user_privkey')) {\n requestSessionKey(pk.value);\n // Clear the private key form field value.\n pk.value = '';\n }\n }\n element.addEventListener('click', handleClick);\n }\n}\n\n/**\n * Initialize Secret Edit Form Handler.\n */\nfunction initSecretsEdit() {\n const privateKeyModal = new window.Modal('#privkey_modal');\n\n /**\n * Check the cookie store for a `netbox_secrets_sessionid`. If not present, prompt the user to submit their\n * private key.\n */\n function handleSubmit(event: Event): void {\n if (document.cookie.indexOf('netbox_secrets_sessionid') === -1) {\n event.preventDefault();\n privateKeyModal.show();\n }\n }\n\n for (const element of document.querySelectorAll('.requires-session-key')) {\n const form = element.closest('form');\n if (form !== null) {\n form.addEventListener('submit', handleSubmit);\n }\n }\n}\n\nexport function initSecrets() {\n for (const func of [initGenerateKeyPair, initLockUnlock, initGetSessionKey, initSecretsEdit]) {\n func();\n }\n}\n", "import { initSecrets } from './secrets';\n\nif (document.readyState !== 'loading') {\n initSecrets();\n} else {\n document.addEventListener('DOMContentLoaded', initSecrets);\n}\n"], + "mappings": "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", + "names": ["require_cookie", "__commonJSMin", "exports", "parse", "serialize", "__toString", "fieldContentRegExp", "str", "options", "obj", "opt", "dec", "decode", "index", "eqIdx", "endIdx", "key", "val", "tryDecode", "name", "enc", "encode", "value", "maxAge", "expires", "isDate", "priority", "sameSite", "e", "createToast", "level", "title", "message", "extra", "iconName", "container", "main", "header", "icon", "titleElement", "button", "body", "extraElement", "import_cookie", "isApiError", "data", "hasError", "isInputElement", "element", "getCsrfToken", "csrfToken", "Cookie", "apiRequest", "url", "method", "__async", "token", "headers", "body", "res", "contentType", "json", "apiPostForm", "apiGetBase", "initGenerateKeyPair", "element", "accept", "copyBtn", "exportBtn", "publicElem", "privateElem", "handleOpen", "elem", "apiGetBase", "data", "hasError", "createToast", "priv", "pub", "handleAccept", "publicKeyField", "handleExport", "content", "blob", "a", "toggleSecretButtons", "id", "action", "unlockButton", "lockButton", "copyButton", "initLockUnlock", "privateKeyModal", "unlock", "target", "plaintext", "isInputElement", "lock", "requestSessionKey", "privateKey", "apiPostForm", "res", "message", "isApiError", "toast", "initGetSessionKey", "handleClick", "pk", "initSecretsEdit", "handleSubmit", "event", "form", "initSecrets", "func", "initSecrets"] }