VYPR
Moderate severityNVD Advisory· Published Jun 2, 2025· Updated Jun 2, 2025

Gokapi vulnerable to stored XSS via uploading file with malicious file name

CVE-2025-48494

Description

Gokapi is a self-hosted file sharing server with automatic expiration and encryption support. When using end-to-end encryption, a stored cross-site scripting vulnerability can be exploited by uploading a file with JavaScript code embedded in the filename. After upload and every time someone opens the upload list, the script is then parsed. Prior to version 2.0.0, there was no user permission system implemented, therefore all authenticated users were already able to see and modify all resources, even if end-to-end encrypted, as the encryption key had to be the same for all users using a version prior to 2.0.0. If a user is the only authenticated user using Gokapi, they are not affected. This issue has been fixed in v2.0.0. A possible workaround would be to disable end-to-end encryption.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/forceu/gokapiGo
>= 1.0.1, <= 1.9.6
github.com/forceu/gokapiGo
< 0.0.0-20250530191232-343cc566cfd70.0.0-20250530191232-343cc566cfd7

Affected products

1

Patches

1
343cc566cfd7

Fix CVE-2025-48494 XSS vulnerability for file upload, refactoring and formatting

https://github.com/Forceu/GokapiMarc BullingMay 30, 2025via ghsa
4 files changed · +143 22
  • internal/webserver/web/static/js/admin_ui_upload.js+128 16 modified
    @@ -419,7 +419,7 @@ function showEditModal(filename, id, downloads, expiry, password, unlimitedown,
             $('body').append(myClone);
         });
     
    -    document.getElementById("m_filenamelabel").innerHTML = filename;
    +    document.getElementById("m_filenamelabel").innerText = filename;
         document.getElementById("mc_expiry").setAttribute("data-timestamp", expiry);
         document.getElementById("mb_save").setAttribute('data-fileid', id);
         createCalendar(expiry);
    @@ -562,14 +562,14 @@ function parseSseData(data) {
     function setNewDownloadCount(id, downloadCount, downloadsRemaining) {
         let downloadCell = document.getElementById("cell-downloads-" + id);
         if (downloadCell != null) {
    -        downloadCell.innerHTML = downloadCount;
    +        downloadCell.innerText = downloadCount;
             downloadCell.classList.add("updatedDownloadCount");
             setTimeout(() => downloadCell.classList.remove("updatedDownloadCount"), 500);
         }
         if (downloadsRemaining != -1) {
             let downloadsRemainingCell = document.getElementById("cell-downloadsRemaining-" + id);
             if (downloadsRemainingCell != null) {
    -            downloadsRemainingCell.innerHTML = downloadsRemaining;
    +            downloadsRemainingCell.innerText = downloadsRemaining;
                 downloadsRemainingCell.classList.add("updatedDownloadCount");
                 setTimeout(() => downloadsRemainingCell.classList.remove("updatedDownloadCount"), 500);
             }
    @@ -662,6 +662,7 @@ function removeFileStatus(chunkId) {
     function addRow(item) {
         let table = document.getElementById("downloadtable");
         let row = table.insertRow(0);
    +    item.Id = sanitizeId(item.Id);
         row.id = "row-" + item.Id;
         let cellFilename = row.insertCell(0);
         let cellFileSize = row.insertCell(1);
    @@ -670,11 +671,7 @@ function addRow(item) {
         let cellDownloadCount = row.insertCell(4);
         let cellUrl = row.insertCell(5);
         let cellButtons = row.insertCell(6);
    -    let lockIcon = "";
     
    -    if (item.IsPasswordProtected === true) {
    -        lockIcon = '  <i  title="Password protected" class="bi bi-key"></i>';
    -    }
         cellFilename.innerText = item.Name;
         cellFilename.id = "cell-name-" + item.Id;
         cellDownloadCount.id = "cell-downloads-" + item.Id;
    @@ -691,19 +688,130 @@ function addRow(item) {
             cellStoredUntil.innerText = item.ExpireAtString;
         }
         cellDownloadCount.innerText = item.DownloadCount;
    -    cellUrl.innerHTML = '<a  target="_blank" style="color: inherit" id="url-href-' + item.Id + '" href="' + item.UrlDownload + '">' + item.Id + '</a>' + lockIcon;
     
    -    let buttons = '<button type="button" onclick="showToast(1000)" id="url-button-' + item.Id + '"  data-clipboard-text="' + item.UrlDownload + '" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> URL</button> ';
    -    if (item.UrlHotlink === "") {
    -        buttons = buttons + '<button type="button"class="copyurl btn btn-outline-light btn-sm disabled"><i class="bi bi-copy"></i> Hotlink</button> ';
    +    // === URL Link ===
    +    const link = document.createElement('a');
    +    link.href = item.UrlDownload;
    +    link.target = '_blank';
    +    link.style.color = 'inherit';
    +    link.id = 'url-href-'+item.Id;
    +    link.textContent = item.Id;
    +
    +    cellUrl.appendChild(link);
    +
    +    if (item.IsPasswordProtected === true) {
    +        const icon = document.createElement('i');
    +        icon.className = 'bi bi-key';
    +        icon.title = 'Password protected';
    +        cellUrl.appendChild(document.createTextNode(' '));
    +        cellUrl.appendChild(icon);
    +    }
    +
    +    // === Button: Copy URL ===
    +    const copyUrlBtn = document.createElement('button');
    +    copyUrlBtn.type = 'button';
    +    copyUrlBtn.className = 'copyurl btn btn-outline-light btn-sm';
    +    copyUrlBtn.dataset.clipboardText = item.UrlDownload;
    +    copyUrlBtn.id = 'url-button-'+item.Id;
    +    copyUrlBtn.title = 'Copy URL';
    +
    +    const copyIcon = document.createElement('i');
    +    copyIcon.className = 'bi bi-copy';
    +    copyUrlBtn.appendChild(copyIcon);
    +    copyUrlBtn.appendChild(document.createTextNode(' URL'));
    +
    +    copyUrlBtn.addEventListener('click', () => {
    +        showToast(1000);
    +    });
    +
    +    cellButtons.appendChild(copyUrlBtn);
    +    cellButtons.appendChild(document.createTextNode(' '));
    +
    +    // === Button: Copy Hotlink ===
    +    const hotlinkBtn = document.createElement('button');
    +    hotlinkBtn.type = 'button';
    +    hotlinkBtn.className = 'copyurl btn btn-outline-light btn-sm';
    +    hotlinkBtn.title = 'Copy Hotlink';
    +
    +    const hotlinkIcon = document.createElement('i');
    +    hotlinkIcon.className = 'bi bi-copy';
    +    hotlinkBtn.appendChild(hotlinkIcon);
    +    hotlinkBtn.appendChild(document.createTextNode(' Hotlink'));
    +
    +    if (item.UrlHotlink) {
    +        hotlinkBtn.dataset.clipboardText = item.UrlHotlink;
    +        hotlinkBtn.addEventListener('click', () => {
    +            showToast(1000);
    +        });
         } else {
    -        buttons = buttons + '<button type="button" onclick="showToast(1000)" data-clipboard-text="' + item.UrlHotlink + '" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> Hotlink</button> ';
    +        hotlinkBtn.disabled = true;
         }
    -    buttons = buttons + '<button type="button" id="qrcode-' + item.Id + '" title="QR Code" class="btn btn-outline-light btn-sm" onclick="showQrCode(\'' + item.UrlDownload + '\');"><i class="bi bi-qr-code"></i></button> ';
    -    buttons = buttons + '<button type="button" title="Edit" class="btn btn-outline-light btn-sm" onclick="showEditModal(\'' + item.Name + '\',\'' + item.Id + '\', ' + item.DownloadsRemaining + ', ' + item.ExpireAt + ', ' + item.IsPasswordProtected + ', ' + item.UnlimitedDownloads + ', ' + item.UnlimitedTime + ', ' + item.IsEndToEndEncrypted + ', canReplaceOwnFiles);"><i class="bi bi-pencil"></i></button> ';
    -    buttons = buttons + '<button type="button" id="button-delete-' + item.Id + '" title="Delete" class="btn btn-outline-danger btn-sm" onclick="deleteFile(\'' + item.Id + '\')"><i class="bi bi-trash3"></i></button>';
     
    -    cellButtons.innerHTML = buttons;
    +    cellButtons.appendChild(hotlinkBtn);
    +    cellButtons.appendChild(document.createTextNode(' '));
    +
    +    // === Button: QR Code ===
    +    const qrBtn = document.createElement('button');
    +    qrBtn.type = 'button';
    +    qrBtn.className = 'btn btn-outline-light btn-sm';
    +    qrBtn.title = 'QR Code';
    +    qrBtn.id = 'qrcode-'+item.Id;
    +
    +    const qrIcon = document.createElement('i');
    +    qrIcon.className = 'bi bi-qr-code';
    +    qrBtn.appendChild(qrIcon);
    +
    +    qrBtn.addEventListener('click', () => {
    +        showQrCode(item.UrlDownload);
    +    });
    +
    +    cellButtons.appendChild(qrBtn);
    +    cellButtons.appendChild(document.createTextNode(' '));
    +
    +    // === Button: Edit ===
    +    const editBtn = document.createElement('button');
    +    editBtn.type = 'button';
    +    editBtn.className = 'btn btn-outline-light btn-sm';
    +    editBtn.title = 'Edit';
    +
    +    const editIcon = document.createElement('i');
    +    editIcon.className = 'bi bi-pencil';
    +    editBtn.appendChild(editIcon);
    +
    +    editBtn.addEventListener('click', () => {
    +        showEditModal(
    +            item.Name,
    +            item.Id,
    +            item.DownloadsRemaining,
    +            item.ExpireAt,
    +            item.IsPasswordProtected,
    +            item.UnlimitedDownloads,
    +            item.UnlimitedTime,
    +            item.IsEndToEndEncrypted,
    +            canReplaceOwnFiles
    +        );
    +    });
    +
    +    cellButtons.appendChild(editBtn);
    +    cellButtons.appendChild(document.createTextNode(' '));
    +
    +    // === Button: Delete ===
    +    const deleteBtn = document.createElement('button');
    +    deleteBtn.type = 'button';
    +    deleteBtn.className = 'btn btn-outline-danger btn-sm';
    +    deleteBtn.title = 'Delete';
    +    deleteBtn.id = 'button-delete-'+item.Id;
    +
    +    const deleteIcon = document.createElement('i');
    +    deleteIcon.className = 'bi bi-trash3';
    +    deleteBtn.appendChild(deleteIcon);
    +
    +    deleteBtn.addEventListener('click', () => {
    +        deleteFile(item.Id);
    +    });
    +
    +    cellButtons.appendChild(deleteBtn);
    +
     
         cellFilename.classList.add('newItem');
         cellFileSize.classList.add('newItem');
    @@ -718,6 +826,10 @@ function addRow(item) {
         return item.Id;
     }
     
    +function sanitizeId(str) {
    +    return str.replace(/[^a-zA-Z0-9]/g, '');
    +}
    +
     function changeRowCount(add, row) {
         let datatable = $('#maintable').DataTable();
         if (rowCount == -1) {
    
  • internal/webserver/web/static/js/end2end_admin.js+13 4 modified
    @@ -1,9 +1,17 @@
     function displayError(err) {
         document.getElementById("errordiv").style.display = "block";
    -    document.getElementById("errormessage").innerHTML = "<b>Error: </b> " + err.toString().replace(/^Error:/gi, "");
    -    console.error('Caught exception', err)
    -}
    +    const errorMessageEl = document.getElementById("errormessage");
    +
    +    errorMessageEl.innerText = "";
    +    const bold = document.createElement("b");
    +    bold.innerText = "Error: ";
    +    const message = document.createTextNode(err.toString().replace(/^Error:/gi, ""));
     
    +    errorMessageEl.appendChild(bold);
    +    errorMessageEl.appendChild(message);
    +
    +    console.error('Caught exception', err);
    +}
     
     function checkIfE2EKeyIsSet() {
         if (!isE2EKeySet()) {
    @@ -165,10 +173,11 @@ function decryptFileEntry(id, filename, cipher) {
         for (let i = 0; i < rows.length; i++) {
             const cell = datatable.cell(i, 0).node();
             if ("cell-name-" + id === $(cell).attr("id")) {
    -            datatable.cell(i, 0).data(filename);
    +            let cellNode = datatable.cell(i, 0).node();
                 let urlNode = datatable.cell(i, 5).node();
                 let urlLink = urlNode.querySelector("a");
                 let url = urlLink.getAttribute("href");
    +            cellNode.textContent = filename;
                 if (!url.includes(cipher)) {
                     if (IncludeFilename) {
                         url = url.replace("/Encrypted%20File", "/" + encodeURI(filename));
    
  • internal/webserver/web/static/js/min/admin.min.9.js+1 1 modified
    @@ -1,6 +1,6 @@
     async function apiAuthModify(e,t,n){const s="./api/auth/modify",o={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,targetKey:e,permission:t,permissionModifier:n}};try{const e=await fetch(s,o);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiAuthModify:",e),e}}async function apiAuthFriendlyName(e,t){const n="./api/auth/friendlyname",s={method:"PUT",headers:{"Content-Type":"application/json",apikey:systemKey,targetKey:e,friendlyName:t}};try{const e=await fetch(n,s);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiAuthModify:",e),e}}async function apiAuthDelete(e){const t="./api/auth/delete",n={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,targetKey:e}};try{const e=await fetch(t,n);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiAuthDelete:",e),e}}async function apiAuthCreate(){const e="./api/auth/create",t={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,basicPermissions:"true"}};try{const n=await fetch(e,t);if(!n.ok)throw new Error(`Request failed with status: ${n.status}`);const s=await n.json();return s}catch(e){throw console.error("Error in apiAuthCreate:",e),e}}async function apiChunkComplete(e,t,n,s,o,i,a,r,c,l){const d="./api/chunk/complete",u={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,uuid:e,filename:t,filesize:n,realsize:s,contenttype:o,allowedDownloads:i,expiryDays:a,password:r,isE2E:c,nonblocking:l}};try{const e=await fetch(d,u);if(!e.ok){let t;try{const n=await e.json();t=n.ErrorMessage||`Request failed with status: ${e.status}`}catch{const n=await e.text();t=n||`Request failed with status: ${e.status}`}throw new Error(t)}const t=await e.json();return t}catch(e){throw console.error("Error in apiChunkComplete:",e),e}}async function apiFilesReplace(e,t){const n="./api/files/replace",s={method:"PUT",headers:{"Content-Type":"application/json",id:e,apikey:systemKey,idNewContent:t,deleteNewFile:!1}};try{const e=await fetch(n,s);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`);const t=await e.json();return t}catch(e){throw console.error("Error in apiFilesReplace:",e),e}}async function apiFilesListById(e){const t="./api/files/list/"+e,n={method:"GET",headers:{"Content-Type":"application/json",apikey:systemKey}};try{const e=await fetch(t,n);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`);const s=await e.json();return s}catch(e){throw console.error("Error in apiFilesListById:",e),e}}async function apiFilesModify(e,t,n,s,o){const i="./api/files/modify",a={method:"PUT",headers:{"Content-Type":"application/json",id:e,apikey:systemKey,allowedDownloads:t,expiryTimestamp:n,password:s,originalPassword:o}};try{const e=await fetch(i,a);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`);const t=await e.json();return t}catch(e){throw console.error("Error in apiFilesModify:",e),e}}async function apiFilesDelete(e,t){const n="./api/files/delete",s={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,id:e,delay:t}};try{const e=await fetch(n,s);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiFilesDelete:",e),e}}async function apiFilesRestore(e){const t="./api/files/restore",n={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,id:e}};try{const e=await fetch(t,n);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`);const s=await e.json();return s}catch(e){throw console.error("Error in apiFilesRestore:",e),e}}async function apiUserCreate(e){const t="./api/user/create",n={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,username:e}};try{const e=await fetch(t,n);if(!e.ok)throw e.status==409?new Error("duplicate"):new Error(`Request failed with status: ${e.status}`);const s=await e.json();return s}catch(e){throw console.error("Error in apiUserModify:",e),e}}async function apiUserModify(e,t,n){const s="./api/user/modify",o={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,userid:e,userpermission:t,permissionModifier:n}};try{const e=await fetch(s,o);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiUserModify:",e),e}}async function apiUserChangeRank(e,t){const n="./api/user/changeRank",s={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,userid:e,newRank:t}};try{const e=await fetch(n,s);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiUserModify:",e),e}}async function apiUserDelete(e,t){const n="./api/user/delete",s={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,userid:e,deleteFiles:t}};try{const e=await fetch(n,s);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiUserDelete:",e),e}}async function apiUserResetPassword(e,t){const n="./api/user/resetPassword",s={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,userid:e,generateNewPassword:t}};try{const e=await fetch(n,s);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`);const t=await e.json();return t}catch(e){throw console.error("Error in apiUserResetPassword:",e),e}}async function apiLogsDelete(e){const t="./api/logs/delete",n={method:"POST",headers:{"Content-Type":"application/json",apikey:systemKey,timestamp:e}};try{const e=await fetch(t,n);if(!e.ok)throw new Error(`Request failed with status: ${e.status}`)}catch(e){throw console.error("Error in apiLogsDelete:",e),e}}var toastId,dropzoneObject,isE2EEnabled,isUploading,rowCount,calendarInstance,statusItemCount,clipboard=new ClipboardJS(".btn");function showToast(e,t){let n=document.getElementById("toastnotification");typeof t!="undefined"?n.innerText=t:n.innerText=n.dataset.default,n.classList.add("show"),clearTimeout(toastId),toastId=setTimeout(()=>{hideToast()},e)}function hideToast(){document.getElementById("toastnotification").classList.remove("show")}function changeApiPermission(e,t,n){var o,i,s=document.getElementById(n);if(s.classList.contains("perm-processing")||s.classList.contains("perm-nochange"))return;o=s.classList.contains("perm-granted"),s.classList.add("perm-processing"),s.classList.remove("perm-granted"),s.classList.remove("perm-notgranted"),i="GRANT",o&&(i="REVOKE"),apiAuthModify(e,t,i).then(e=>{o?s.classList.add("perm-notgranted"):s.classList.add("perm-granted"),s.classList.remove("perm-processing")}).catch(e=>{o?s.classList.add("perm-granted"):s.classList.add("perm-notgranted"),s.classList.remove("perm-processing"),alert("Unable to set permission: "+e),console.error("Error:",e)})}function deleteApiKey(e){document.getElementById("delete-"+e).disabled=!0,apiAuthDelete(e).then(t=>{document.getElementById("row-"+e).classList.add("rowDeleting"),setTimeout(()=>{document.getElementById("row-"+e).remove()},290)}).catch(e=>{alert("Unable to delete API key: "+e),console.error("Error:",e)})}function newApiKey(){document.getElementById("button-newapi").disabled=!0,apiAuthCreate().then(e=>{addRowApi(e.Id,e.PublicId),document.getElementById("button-newapi").disabled=!1}).catch(e=>{alert("Unable to create API key: "+e),console.error("Error:",e)})}function addFriendlyNameChange(e){let t=document.getElementById("friendlyname-"+e);if(t.classList.contains("isBeingEdited"))return;t.classList.add("isBeingEdited");let i=t.innerText,n=document.createElement("input");n.size=5,n.value=i;let s=!0,o=function(){if(!s)return;s=!1;let o=n.value;o==""&&(o="Unnamed key"),t.innerText=o,t.classList.remove("isBeingEdited"),apiAuthFriendlyName(e,o).catch(e=>{alert("Unable to save name: "+e),console.error("Error:",e)})};n.onblur=o,n.addEventListener("keyup",function(e){e.keyCode===13&&(e.preventDefault(),o())}),t.innerText="",t.appendChild(n),n.focus()}function addRowApi(e,t){let f=document.getElementById("apitable"),s=f.insertRow(0);s.id="row-"+t;let i=0,a=s.insertCell(i++),l=s.insertCell(i++),d=s.insertCell(i++),r=s.insertCell(i++),u;canViewOtherApiKeys&&(u=s.insertCell(i++));let c=s.insertCell(i++);canViewOtherApiKeys&&(u.classList.add("newApiKey"),u.innerText=userName),a.classList.add("newApiKey"),l.classList.add("newApiKey"),d.classList.add("newApiKey"),r.classList.add("newApiKey"),r.classList.add("prevent-select"),c.classList.add("newApiKey"),a.innerText="Unnamed key",a.id="friendlyname-"+t,a.onclick=function(){addFriendlyNameChange(t)},l.innerText=e,l.classList.add("font-monospace"),d.innerText="Never";const n=document.createElement("button");n.type="button",n.dataset.clipboardText=e,n.title="Copy API Key",n.className="copyurl btn btn-outline-light btn-sm",n.setAttribute("onclick","showToast(1000)");const h=document.createElement("i");h.className="bi bi-copy",n.appendChild(h);const o=document.createElement("button");o.type="button",o.id=`delete-${t}`,o.title="Delete",o.className="btn btn-outline-danger btn-sm",o.setAttribute("onclick",`deleteApiKey('${t}')`);const m=document.createElement("i");m.className="bi bi-trash3",o.appendChild(m),c.appendChild(n),c.appendChild(document.createTextNode(" ")),c.appendChild(o);const p=[{perm:"PERM_VIEW",icon:"bi-eye",granted:!0,title:"List Uploads"},{perm:"PERM_UPLOAD",icon:"bi-file-earmark-arrow-up",granted:!0,title:"Upload"},{perm:"PERM_EDIT",icon:"bi-pencil",granted:!0,title:"Edit Uploads"},{perm:"PERM_DELETE",icon:"bi-trash3",granted:!0,title:"Delete Uploads"},{perm:"PERM_REPLACE",icon:"bi-recycle",granted:!1,title:"Replace Uploads"},{perm:"PERM_MANAGE_USERS",icon:"bi-people",granted:!1,title:"Manage Users"},{perm:"PERM_MANAGE_LOGS",icon:"bi-card-list",granted:!1,title:"Manage System Logs"},{perm:"PERM_API_MOD",icon:"bi-sliders2",granted:!1,title:"Manage API Keys"}];if(p.forEach(({perm:e,icon:n,granted:s,title:o})=>{const i=document.createElement("i"),a=`perm_${e.toLowerCase().replace("perm_","")}_${t}`;i.id=a,i.className=`bi ${n} ${s?"perm-granted":"perm-notgranted"}`,i.title=o,i.setAttribute("onclick",`changeApiPermission("${t}","${e}", "${a}");`),r.appendChild(i),r.appendChild(document.createTextNode(" "))}),!canReplaceFiles){let e=document.getElementById("perm_replace_"+t);e.classList.add("perm-unavailable"),e.classList.add("perm-nochange")}if(!canManageUsers){let e=document.getElementById("perm_users_"+t);e.classList.add("perm-unavailable"),e.classList.add("perm-nochange")}setTimeout(()=>{a.classList.remove("newApiKey"),l.classList.remove("newApiKey"),d.classList.remove("newApiKey"),r.classList.remove("newApiKey"),c.classList.remove("newApiKey")},700)}function filterLogs(e){e=="all"?textarea.value=logContent:textarea.value=logContent.split(`
     `).filter(t=>t.includes("["+e+"]")).join(`
    -`),textarea.scrollTop=textarea.scrollHeight}function deleteLogs(e){if(e=="none")return;if(!confirm("Do you want to delete the selected logs?")){document.getElementById("deleteLogs").selectedIndex=0;return}let t=Math.floor(Date.now()/1e3);switch(e){case"all":t=0;break;case"2":t=t-2*24*60*60;break;case"7":t=t-7*24*60*60;break;case"14":t=t-14*24*60*60;break;case"30":t=t-30*24*60*60;break}apiLogsDelete(t).then(e=>{location.reload()}).catch(e=>{alert("Unable to delete logs: "+e),console.error("Error:",e)})}isE2EEnabled=!1,isUploading=!1,rowCount=-1;function initDropzone(){Dropzone.options.uploaddropzone={paramName:"file",dictDefaultMessage:"Drop files, paste or click here to upload",createImageThumbnails:!1,chunksUploaded:function(e,t){sendChunkComplete(e,t)},init:function(){dropzoneObject=this,this.on("addedfile",e=>{saveUploadDefaults(),addFileProgress(e)}),this.on("queuecomplete",function(){isUploading=!1}),this.on("sending",function(){isUploading=!0}),this.on("error",function(e,t,n){n&&n.status===413?showError(e,"File too large to upload. If you are using a reverse proxy, make sure that the allowed body size is at least 70MB."):showError(e,"Error: "+t)}),this.on("uploadprogress",function(e,t,n){updateProgressbar(e,t,n)}),isE2EEnabled&&(dropzoneObject.disable(),dropzoneObject.options.dictDefaultMessage="Loading end-to-end encryption...",document.getElementsByClassName("dz-button")[0].innerText="Loading end-to-end encryption...",setE2eUpload())}},document.onpaste=function(e){if(dropzoneObject.disabled)return;var t,n=(e.clipboardData||e.originalEvent.clipboardData).items;for(let e in n)t=n[e],t.kind==="file"&&dropzoneObject.addFile(t.getAsFile()),t.kind==="string"&&t.getAsString(function(e){const t=/<img *.+>/gi;if(t.test(e)===!1){let t=new Blob([e],{type:"text/plain"}),n=new File([t],"Pasted Text.txt",{type:"text/plain",lastModified:new Date(0)});dropzoneObject.addFile(n)}})},window.addEventListener("beforeunload",e=>{isUploading&&(e.returnValue="Upload is still in progress. Do you want to close this page?")})}function updateProgressbar(e,t,n){let o=e.upload.uuid,i=document.getElementById(`us-container-${o}`);if(i==null||i.getAttribute("data-complete")==="true")return;let s=Math.round(t);s<0&&(s=0),s>100&&(s=100);let r=Date.now()-i.getAttribute("data-starttime"),c=n/(r/1e3)/1024/1024;document.getElementById(`us-progressbar-${o}`).style.width=s+"%";let a=Math.round(c*10)/10;Number.isNaN(a)||(document.getElementById(`us-progress-info-${o}`).innerText=s+"% - "+a+"MB/s")}function addFileProgress(e){addFileStatus(e.upload.uuid,e.upload.filename)}function setUploadDefaults(){let s=getLocalStorageWithDefault("defaultDownloads",1),o=getLocalStorageWithDefault("defaultExpiry",14),e=getLocalStorageWithDefault("defaultPassword",""),t=getLocalStorageWithDefault("defaultUnlimitedDownloads",!1)==="true",n=getLocalStorageWithDefault("defaultUnlimitedTime",!1)==="true";document.getElementById("allowedDownloads").value=s,document.getElementById("expiryDays").value=o,document.getElementById("password").value=e,document.getElementById("enableDownloadLimit").checked=!t,document.getElementById("enableTimeLimit").checked=!n,e===""?(document.getElementById("enablePassword").checked=!1,document.getElementById("password").disabled=!0):(document.getElementById("enablePassword").checked=!0,document.getElementById("password").disabled=!1),t&&(document.getElementById("allowedDownloads").disabled=!0),n&&(document.getElementById("expiryDays").disabled=!0)}function saveUploadDefaults(){localStorage.setItem("defaultDownloads",document.getElementById("allowedDownloads").value),localStorage.setItem("defaultExpiry",document.getElementById("expiryDays").value),localStorage.setItem("defaultPassword",document.getElementById("password").value),localStorage.setItem("defaultUnlimitedDownloads",!document.getElementById("enableDownloadLimit").checked),localStorage.setItem("defaultUnlimitedTime",!document.getElementById("enableTimeLimit").checked)}function getLocalStorageWithDefault(e,t){var n=localStorage.getItem(e);return n===null?t:n}function urlencodeFormData(e){let t="";function s(e){return encodeURIComponent(e).replace(/%20/g,"+")}for(var n of e.entries())typeof n[1]=="string"&&(t+=(t?"&":"")+s(n[0])+"="+s(n[1]));return t}function sendChunkComplete(e,t){let c=e.upload.uuid,n=e.name,s=e.size,l=e.size,o=e.type,i=document.getElementById("allowedDownloads").value,a=document.getElementById("expiryDays").value,d=document.getElementById("password").value,r=e.isEndToEndEncrypted===!0,u=!0;document.getElementById("enableDownloadLimit").checked||(i=0),document.getElementById("enableTimeLimit").checked||(a=0),r&&(s=e.sizeEncrypted,n="Encrypted File",o=""),apiChunkComplete(c,n,s,l,o,i,a,d,r,u).then(n=>{t();let s=document.getElementById(`us-progress-info-${e.upload.uuid}`);s!=null&&(s.innerText="In Queue...")}).catch(t=>{console.error("Error:",t),dropzoneUploadError(e,t)})}function dropzoneUploadError(e,t){e.accepted=!1,dropzoneObject._errorProcessing([e],t),showError(e,t)}function dropzoneGetFile(e){for(let t=0;t<dropzoneObject.files.length;t++){const n=dropzoneObject.files[t];if(n.upload.uuid===e)return n}return null}function requestFileInfo(e,t){apiFilesListById(e).then(n=>{addRow(n);let s=dropzoneGetFile(t);if(s==null)return;if(s.isEndToEndEncrypted===!0){try{let o=GokapiE2EAddFile(t,e,s.name);if(o instanceof Error)throw o;let n=GokapiE2EInfoEncrypt();if(n instanceof Error)throw n;storeE2EInfo(n)}catch(e){s.accepted=!1,dropzoneObject._errorProcessing([s],e);return}GokapiE2EDecryptMenu()}removeFileStatus(t)}).catch(e=>{let n=dropzoneGetFile(t);n!=null&&dropzoneUploadError(n,e),console.error("Error:",e)})}function parseProgressStatus(e){let n=document.getElementById(`us-container-${e.chunk_id}`);if(n==null)return;n.setAttribute("data-complete","true");let t;switch(e.upload_status){case 0:t="Processing file...";break;case 1:t="Uploading file...";break;case 2:t="Finalising...",requestFileInfo(e.file_id,e.chunk_id);break;case 3:t="Error";let n=dropzoneGetFile(e.chunk_id);e.error_message==""&&(e.error_message="Server Error"),n!=null&&dropzoneUploadError(n,e.error_message);return;default:t="Unknown status";break}document.getElementById(`us-progress-info-${e.chunk_id}`).innerText=t}function showError(e,t){let n=e.upload.uuid;document.getElementById(`us-progressbar-${n}`).style.width="100%",document.getElementById(`us-progressbar-${n}`).style.backgroundColor="red",document.getElementById(`us-progress-info-${n}`).innerText=t,document.getElementById(`us-progress-info-${n}`).classList.add("uploaderror")}function editFile(){const e=document.getElementById("mb_save");e.disabled=!0;let s=e.getAttribute("data-fileid"),o=document.getElementById("mi_edit_down").value,i=document.getElementById("mi_edit_expiry").value,t=document.getElementById("mi_edit_pw").value,a=t==="(unchanged)";document.getElementById("mc_download").checked||(o=0),document.getElementById("mc_expiry").checked||(i=0),document.getElementById("mc_password").checked||(a=!1,t="");let r=!1,n="";document.getElementById("mc_replace").checked&&(n=document.getElementById("mi_edit_replace").value,r=n!=""),apiFilesModify(s,o,i,t,a).then(t=>{if(!r){location.reload();return}apiFilesReplace(s,n).then(e=>{location.reload()}).catch(t=>{alert("Unable to edit file: "+t),console.error("Error:",t),e.disabled=!1})}).catch(t=>{alert("Unable to edit file: "+t),console.error("Error:",t),e.disabled=!1})}calendarInstance=null;function createCalendar(e){const t=new Date(e*1e3);calendarInstance=flatpickr("#mi_edit_expiry",{enableTime:!0,dateFormat:"U",altInput:!0,altFormat:"Y-m-d H:i",allowInput:!0,time_24hr:!0,defaultDate:t,minDate:"today"})}function handleEditCheckboxChange(e){var t=document.getElementById(e.getAttribute("data-toggle-target")),n=e.getAttribute("data-timestamp");e.checked?(t.classList.remove("disabled"),t.removeAttribute("disabled"),n!=null&&(calendarInstance._input.disabled=!1)):(n!=null&&(calendarInstance._input.disabled=!0),t.classList.add("disabled"),t.setAttribute("disabled",!0))}function showEditModal(e,t,n,s,o,i,a,r,c){let d=$("#modaledit").clone();$("#modaledit").on("hide.bs.modal",function(){$("#modaledit").remove();let e=d.clone();$("body").append(e)}),document.getElementById("m_filenamelabel").innerHTML=e,document.getElementById("mc_expiry").setAttribute("data-timestamp",s),document.getElementById("mb_save").setAttribute("data-fileid",t),createCalendar(s),i?(document.getElementById("mi_edit_down").value="1",document.getElementById("mi_edit_down").disabled=!0,document.getElementById("mc_download").checked=!1):(document.getElementById("mi_edit_down").value=n,document.getElementById("mi_edit_down").disabled=!1,document.getElementById("mc_download").checked=!0),a?(document.getElementById("mi_edit_expiry").value=add14DaysIfBeforeCurrentTime(s),document.getElementById("mi_edit_expiry").disabled=!0,document.getElementById("mc_expiry").checked=!1,calendarInstance._input.disabled=!0):(document.getElementById("mi_edit_expiry").value=s,document.getElementById("mi_edit_expiry").disabled=!1,document.getElementById("mc_expiry").checked=!0,calendarInstance._input.disabled=!1),o?(document.getElementById("mi_edit_pw").value="(unchanged)",document.getElementById("mi_edit_pw").disabled=!1,document.getElementById("mc_password").checked=!0):(document.getElementById("mi_edit_pw").value="",document.getElementById("mi_edit_pw").disabled=!0,document.getElementById("mc_password").checked=!1);let l=document.getElementById("mi_edit_replace");if(c)if(document.getElementById("replaceGroup").style.display="flex",r)document.getElementById("mc_replace").disabled=!0,document.getElementById("mc_replace").title="Replacing content is not available for end-to-end encrypted files",l.add(new Option("Unavailable",0)),l.title="Replacing content is not available for end-to-end encrypted files",l.value="0";else{let e=getAllAvailableFiles();for(let n=0;n<e[0].length;n++){if(e[0][n]==t)continue;l.add(new Option(e[1][n]+" ("+e[0][n]+")",e[0][n]))}}else document.getElementById("replaceGroup").style.display="none";new bootstrap.Modal("#modaledit",{}).show()}function selectTextForPw(e){e.value==="(unchanged)"&&e.setSelectionRange(0,e.value.length)}function add14DaysIfBeforeCurrentTime(e){let t=Date.now(),n=e*1e3;if(n<t){let e=t+14*24*60*60*1e3;return Math.floor(e/1e3)}return e}function getAllAvailableFiles(){let e=[],t=[],n=document.querySelectorAll('[id^="cell-name-"]');for(let s of n)e.push(s.id.replace("cell-name-","")),t.push(s.innerHTML);return[e,t]}function deleteFile(e){document.getElementById("button-delete-"+e).disabled=!0,apiFilesDelete(e,10).then(t=>{changeRowCount(!1,document.getElementById("row-"+e)),showToastFileDeletion(e)}).catch(e=>{alert("Unable to delete file: "+e),console.error("Error:",e)})}function checkBoxChanged(e,t){let n=!e.checked;n?document.getElementById(t).setAttribute("disabled",""):document.getElementById(t).removeAttribute("disabled"),t==="password"&&n&&(document.getElementById("password").value="")}function parseSseData(e){let t;try{t=JSON.parse(e)}catch(e){console.error("Failed to parse event data:",e);return}switch(t.event){case"download":setNewDownloadCount(t.file_id,t.download_count,t.downloads_remaining);return;case"uploadStatus":parseProgressStatus(t);return;default:console.error("Unknown event",t)}}function setNewDownloadCount(e,t,n){let s=document.getElementById("cell-downloads-"+e);if(s!=null&&(s.innerHTML=t,s.classList.add("updatedDownloadCount"),setTimeout(()=>s.classList.remove("updatedDownloadCount"),500)),n!=-1){let t=document.getElementById("cell-downloadsRemaining-"+e);t!=null&&(t.innerHTML=n,t.classList.add("updatedDownloadCount"),setTimeout(()=>t.classList.remove("updatedDownloadCount"),500))}}function registerChangeHandler(){const e=new EventSource("./uploadStatus");e.onmessage=e=>{parseSseData(e.data)},e.onerror=t=>{t.target.readyState!==EventSource.CLOSED&&e.close(),console.log("Reconnecting to SSE..."),setTimeout(registerChangeHandler,5e3)}}statusItemCount=0;function addFileStatus(e,t){const n=document.createElement("div");n.setAttribute("id",`us-container-${e}`),n.classList.add("us-container");const a=document.createElement("div");a.classList.add("filename"),a.textContent=t,n.appendChild(a);const s=document.createElement("div");s.classList.add("upload-progress-container"),s.setAttribute("id",`us-progress-container-${e}`);const r=document.createElement("div");r.classList.add("upload-progress-bar");const o=document.createElement("div");o.setAttribute("id",`us-progressbar-${e}`),o.classList.add("upload-progress-bar-progress"),o.style.width="0%",r.appendChild(o);const i=document.createElement("div");i.setAttribute("id",`us-progress-info-${e}`),i.classList.add("upload-progress-info"),i.textContent="0%",s.appendChild(r),s.appendChild(i),n.appendChild(s),n.setAttribute("data-starttime",Date.now()),n.setAttribute("data-complete","false");const c=document.getElementById("uploadstatus");c.appendChild(n),c.style.visibility="visible",statusItemCount++}function removeFileStatus(e){const t=document.getElementById(`us-container-${e}`);if(t==null)return;t.remove(),statusItemCount--,statusItemCount<1&&(document.getElementById("uploadstatus").style.visibility="hidden")}function addRow(e){let u=document.getElementById("downloadtable"),n=u.insertRow(0);n.id="row-"+e.Id;let o=n.insertCell(0),i=n.insertCell(1),s=n.insertCell(2),a=n.insertCell(3),r=n.insertCell(4),c=n.insertCell(5),l=n.insertCell(6),d="";e.IsPasswordProtected===!0&&(d='  <i  title="Password protected" class="bi bi-key"></i>'),o.innerText=e.Name,o.id="cell-name-"+e.Id,r.id="cell-downloads-"+e.Id,i.innerText=e.Size,e.UnlimitedDownloads?s.innerText="Unlimited":(s.innerText=e.DownloadsRemaining,s.id="cell-downloadsRemaining-"+e.Id),e.UnlimitedTime?a.innerText="Unlimited":a.innerText=e.ExpireAtString,r.innerText=e.DownloadCount,c.innerHTML='<a  target="_blank" style="color: inherit" id="url-href-'+e.Id+'" href="'+e.UrlDownload+'">'+e.Id+"</a>"+d;let t='<button type="button" onclick="showToast(1000)" id="url-button-'+e.Id+'"  data-clipboard-text="'+e.UrlDownload+'" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> URL</button> ';return e.UrlHotlink===""?t=t+'<button type="button"class="copyurl btn btn-outline-light btn-sm disabled"><i class="bi bi-copy"></i> Hotlink</button> ':t=t+'<button type="button" onclick="showToast(1000)" data-clipboard-text="'+e.UrlHotlink+'" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> Hotlink</button> ',t=t+'<button type="button" id="qrcode-'+e.Id+`" title="QR Code" class="btn btn-outline-light btn-sm" onclick="showQrCode('`+e.UrlDownload+`');"><i class="bi bi-qr-code"></i></button> `,t=t+`<button type="button" title="Edit" class="btn btn-outline-light btn-sm" onclick="showEditModal('`+e.Name+"','"+e.Id+"', "+e.DownloadsRemaining+", "+e.ExpireAt+", "+e.IsPasswordProtected+", "+e.UnlimitedDownloads+", "+e.UnlimitedTime+", "+e.IsEndToEndEncrypted+', canReplaceOwnFiles);"><i class="bi bi-pencil"></i></button> ',t=t+'<button type="button" id="button-delete-'+e.Id+`" title="Delete" class="btn btn-outline-danger btn-sm" onclick="deleteFile('`+e.Id+`')"><i class="bi bi-trash3"></i></button>`,l.innerHTML=t,o.classList.add("newItem"),i.classList.add("newItem"),s.classList.add("newItem"),a.classList.add("newItem"),r.classList.add("newItem"),c.classList.add("newItem"),l.classList.add("newItem"),i.setAttribute("data-order",e.SizeBytes),changeRowCount(!0,n),e.Id}function changeRowCount(e,t){let n=$("#maintable").DataTable();rowCount==-1&&(rowCount=n.rows().count()),e?(rowCount=rowCount+1,n.row.add(t)):(rowCount=rowCount-1,t.classList.add("rowDeleting"),setTimeout(()=>{n.row(t).remove(),t.remove()},290));let s=document.getElementsByClassName("dataTables_empty")[0];typeof s!="undefined"?s.innerText="Files stored: "+rowCount:document.getElementsByClassName("dataTables_info")[0].innerText="Files stored: "+rowCount}function hideQrCode(){document.getElementById("qroverlay").style.display="none",document.getElementById("qrcode").innerHTML=""}function showQrCode(e){const t=document.getElementById("qroverlay");t.style.display="block",new QRCode(document.getElementById("qrcode"),{text:e,width:200,height:200,colorDark:"#000000",colorLight:"#ffffff",correctLevel:QRCode.CorrectLevel.H}),t.addEventListener("click",hideQrCode)}function showToastFileDeletion(e){let t=document.getElementById("toastnotificationUndo"),n=document.getElementById("cell-name-"+e).innerText,s=document.getElementById("toastFilename"),o=document.getElementById("toastUndoButton");s.innerText=n,o.dataset.fileid=e,hideToast(),t.classList.add("show"),clearTimeout(toastId),toastId=setTimeout(()=>{hideFileToast()},5e3)}function hideFileToast(){document.getElementById("toastnotificationUndo").classList.remove("show")}function handleUndo(e){hideFileToast(),apiFilesRestore(e.dataset.fileid).then(e=>{addRow(e.FileInfo)}).catch(e=>{alert("Unable to restore file: "+e),console.error("Error:",e)})}function changeUserPermission(e,t,n){let s=document.getElementById(n);if(s.classList.contains("perm-processing")||s.classList.contains("perm-nochange"))return;let o=s.classList.contains("perm-granted");s.classList.add("perm-processing"),s.classList.remove("perm-granted"),s.classList.remove("perm-notgranted");let i="GRANT";o&&(i="REVOKE"),t=="PERM_REPLACE_OTHER"&&!o&&(hasNotPermissionReplace=document.getElementById("perm_replace_"+e).classList.contains("perm-notgranted"),hasNotPermissionReplace&&(showToast(2e3,"Also granting permission to replace own files"),changeUserPermission(e,"PERM_REPLACE","perm_replace_"+e))),t=="PERM_REPLACE"&&o&&(hasPermissionReplaceOthers=document.getElementById("perm_replace_other_"+e).classList.contains("perm-granted"),hasPermissionReplaceOthers&&(showToast(2e3,"Also revoking permission to replace files of other users"),changeUserPermission(e,"PERM_REPLACE_OTHER","perm_replace_other_"+e))),apiUserModify(e,t,i).then(e=>{o?s.classList.add("perm-notgranted"):s.classList.add("perm-granted"),s.classList.remove("perm-processing")}).catch(e=>{o?s.classList.add("perm-granted"):s.classList.add("perm-notgranted"),s.classList.remove("perm-processing"),alert("Unable to set permission: "+e),console.error("Error:",e)})}function changeRank(e,t,n){let s=document.getElementById(n);if(s.disabled)return;s.disabled=!0,apiUserChangeRank(e,t).then(e=>{location.reload()}).catch(e=>{s.disabled=!1,alert("Unable to change rank: "+e),console.error("Error:",e)})}function showDeleteModal(e,t){let n=document.getElementById("checkboxDelete");n.checked=!1,document.getElementById("deleteModalBody").innerText=t,$("#deleteModal").modal("show"),document.getElementById("buttonDelete").onclick=function(){apiUserDelete(e,n.checked).then(t=>{$("#deleteModal").modal("hide"),document.getElementById("row-"+e).classList.add("rowDeleting"),setTimeout(()=>{document.getElementById("row-"+e).remove()},290)}).catch(e=>{alert("Unable to delete user: "+e),console.error("Error:",e)})}}function showAddUserModal(){let e=$("#newUserModal").clone();$("#newUserModal").on("hide.bs.modal",function(){$("#newUserModal").remove();let t=e.clone();$("body").append(t)}),$("#newUserModal").modal("show")}function showResetPwModal(e,t){let n=$("#resetPasswordModal").clone();$("#resetPasswordModal").on("hide.bs.modal",function(){$("#resetPasswordModal").remove();let e=n.clone();$("body").append(e)}),document.getElementById("l_userpwreset").innerText=t;let s=document.getElementById("resetPasswordButton");s.onclick=function(){resetPw(e,document.getElementById("generateRandomPassword").checked)},$("#resetPasswordModal").modal("show")}function resetPw(e,t){let n=document.getElementById("resetPasswordButton");document.getElementById("resetPasswordButton").disabled=!0,apiUserResetPassword(e,t).then(e=>{if(!t){$("#resetPasswordModal").modal("hide"),showToast(1e3,"Password change requirement set successfully");return}n.style.display="none",document.getElementById("cancelPasswordButton").style.display="none",document.getElementById("formentryReset").style.display="none",document.getElementById("randomPasswordContainer").style.display="block",document.getElementById("closeModalResetPw").style.display="block",document.getElementById("l_returnedPw").innerText=e.password,document.getElementById("copypwclip").onclick=function(){navigator.clipboard.writeText(e.password),showToast(1e3,"Password copied to clipboard")}}).catch(e=>{alert("Unable to reset user password: "+e),console.error("Error:",e),n.disabled=!1})}function addNewUser(){let e=document.getElementById("mb_addUser");e.disabled=!0;let t=document.getElementById("newUserForm");if(t.checkValidity()){let t=document.getElementById("e_userName");apiUserCreate(t.value.trim()).then(e=>{$("#newUserModal").modal("hide"),addRowUser(e.id,e.name)}).catch(t=>{t.message=="duplicate"?(alert("A user already exists with that name"),e.disabled=!1):(alert("Unable to create user: "+t),console.error("Error:",t),e.disabled=!1)})}else t.classList.add("was-validated"),e.disabled=!1}function addRowUser(e,t){let l=document.getElementById("usertable"),n=l.insertRow(1);n.id="row-"+e;let o=n.insertCell(0),i=n.insertCell(1),a=n.insertCell(2),r=n.insertCell(3),c=n.insertCell(4),s=n.insertCell(5);o.classList.add("newUser"),i.classList.add("newUser"),a.classList.add("newUser"),r.classList.add("newUser"),c.classList.add("newUser"),s.classList.add("newUser"),o.innerText=t,i.innerText="User",a.innerText="Never",r.innerText="0";let d='<button id="pwchange-'+e+`" type="button" class="btn btn-outline-light btn-sm" onclick="showResetPwModal('`+e+"', '"+t+`')" title="Reset Password"><i class="bi bi-key-fill"></i></button>&nbsp; `;s.innerHTML='<button id="changeRank_'+e+'" type="button" onclick="changeRank( '+e+" , 'ADMIN', 'changeRank_"+e+`')" title="Promote User" class="btn btn-outline-light btn-sm"><i class="bi bi-chevron-double-up"></i></button>&nbsp; <button id="delete-`+e+'" type="button" class="btn btn-outline-danger btn-sm"  onclick="showDeleteModal('+e+", '"+t+`')" title="Delete"><i class="bi bi-trash3"></i></button>`,isInternalAuth&&(s.innerHTML=d+s.innerHTML),c.innerHTML=`
    +`),textarea.scrollTop=textarea.scrollHeight}function deleteLogs(e){if(e=="none")return;if(!confirm("Do you want to delete the selected logs?")){document.getElementById("deleteLogs").selectedIndex=0;return}let t=Math.floor(Date.now()/1e3);switch(e){case"all":t=0;break;case"2":t=t-2*24*60*60;break;case"7":t=t-7*24*60*60;break;case"14":t=t-14*24*60*60;break;case"30":t=t-30*24*60*60;break}apiLogsDelete(t).then(e=>{location.reload()}).catch(e=>{alert("Unable to delete logs: "+e),console.error("Error:",e)})}isE2EEnabled=!1,isUploading=!1,rowCount=-1;function initDropzone(){Dropzone.options.uploaddropzone={paramName:"file",dictDefaultMessage:"Drop files, paste or click here to upload",createImageThumbnails:!1,chunksUploaded:function(e,t){sendChunkComplete(e,t)},init:function(){dropzoneObject=this,this.on("addedfile",e=>{saveUploadDefaults(),addFileProgress(e)}),this.on("queuecomplete",function(){isUploading=!1}),this.on("sending",function(){isUploading=!0}),this.on("error",function(e,t,n){n&&n.status===413?showError(e,"File too large to upload. If you are using a reverse proxy, make sure that the allowed body size is at least 70MB."):showError(e,"Error: "+t)}),this.on("uploadprogress",function(e,t,n){updateProgressbar(e,t,n)}),isE2EEnabled&&(dropzoneObject.disable(),dropzoneObject.options.dictDefaultMessage="Loading end-to-end encryption...",document.getElementsByClassName("dz-button")[0].innerText="Loading end-to-end encryption...",setE2eUpload())}},document.onpaste=function(e){if(dropzoneObject.disabled)return;var t,n=(e.clipboardData||e.originalEvent.clipboardData).items;for(let e in n)t=n[e],t.kind==="file"&&dropzoneObject.addFile(t.getAsFile()),t.kind==="string"&&t.getAsString(function(e){const t=/<img *.+>/gi;if(t.test(e)===!1){let t=new Blob([e],{type:"text/plain"}),n=new File([t],"Pasted Text.txt",{type:"text/plain",lastModified:new Date(0)});dropzoneObject.addFile(n)}})},window.addEventListener("beforeunload",e=>{isUploading&&(e.returnValue="Upload is still in progress. Do you want to close this page?")})}function updateProgressbar(e,t,n){let o=e.upload.uuid,i=document.getElementById(`us-container-${o}`);if(i==null||i.getAttribute("data-complete")==="true")return;let s=Math.round(t);s<0&&(s=0),s>100&&(s=100);let r=Date.now()-i.getAttribute("data-starttime"),c=n/(r/1e3)/1024/1024;document.getElementById(`us-progressbar-${o}`).style.width=s+"%";let a=Math.round(c*10)/10;Number.isNaN(a)||(document.getElementById(`us-progress-info-${o}`).innerText=s+"% - "+a+"MB/s")}function addFileProgress(e){addFileStatus(e.upload.uuid,e.upload.filename)}function setUploadDefaults(){let s=getLocalStorageWithDefault("defaultDownloads",1),o=getLocalStorageWithDefault("defaultExpiry",14),e=getLocalStorageWithDefault("defaultPassword",""),t=getLocalStorageWithDefault("defaultUnlimitedDownloads",!1)==="true",n=getLocalStorageWithDefault("defaultUnlimitedTime",!1)==="true";document.getElementById("allowedDownloads").value=s,document.getElementById("expiryDays").value=o,document.getElementById("password").value=e,document.getElementById("enableDownloadLimit").checked=!t,document.getElementById("enableTimeLimit").checked=!n,e===""?(document.getElementById("enablePassword").checked=!1,document.getElementById("password").disabled=!0):(document.getElementById("enablePassword").checked=!0,document.getElementById("password").disabled=!1),t&&(document.getElementById("allowedDownloads").disabled=!0),n&&(document.getElementById("expiryDays").disabled=!0)}function saveUploadDefaults(){localStorage.setItem("defaultDownloads",document.getElementById("allowedDownloads").value),localStorage.setItem("defaultExpiry",document.getElementById("expiryDays").value),localStorage.setItem("defaultPassword",document.getElementById("password").value),localStorage.setItem("defaultUnlimitedDownloads",!document.getElementById("enableDownloadLimit").checked),localStorage.setItem("defaultUnlimitedTime",!document.getElementById("enableTimeLimit").checked)}function getLocalStorageWithDefault(e,t){var n=localStorage.getItem(e);return n===null?t:n}function urlencodeFormData(e){let t="";function s(e){return encodeURIComponent(e).replace(/%20/g,"+")}for(var n of e.entries())typeof n[1]=="string"&&(t+=(t?"&":"")+s(n[0])+"="+s(n[1]));return t}function sendChunkComplete(e,t){let c=e.upload.uuid,n=e.name,s=e.size,l=e.size,o=e.type,i=document.getElementById("allowedDownloads").value,a=document.getElementById("expiryDays").value,d=document.getElementById("password").value,r=e.isEndToEndEncrypted===!0,u=!0;document.getElementById("enableDownloadLimit").checked||(i=0),document.getElementById("enableTimeLimit").checked||(a=0),r&&(s=e.sizeEncrypted,n="Encrypted File",o=""),apiChunkComplete(c,n,s,l,o,i,a,d,r,u).then(n=>{t();let s=document.getElementById(`us-progress-info-${e.upload.uuid}`);s!=null&&(s.innerText="In Queue...")}).catch(t=>{console.error("Error:",t),dropzoneUploadError(e,t)})}function dropzoneUploadError(e,t){e.accepted=!1,dropzoneObject._errorProcessing([e],t),showError(e,t)}function dropzoneGetFile(e){for(let t=0;t<dropzoneObject.files.length;t++){const n=dropzoneObject.files[t];if(n.upload.uuid===e)return n}return null}function requestFileInfo(e,t){apiFilesListById(e).then(n=>{addRow(n);let s=dropzoneGetFile(t);if(s==null)return;if(s.isEndToEndEncrypted===!0){try{let o=GokapiE2EAddFile(t,e,s.name);if(o instanceof Error)throw o;let n=GokapiE2EInfoEncrypt();if(n instanceof Error)throw n;storeE2EInfo(n)}catch(e){s.accepted=!1,dropzoneObject._errorProcessing([s],e);return}GokapiE2EDecryptMenu()}removeFileStatus(t)}).catch(e=>{let n=dropzoneGetFile(t);n!=null&&dropzoneUploadError(n,e),console.error("Error:",e)})}function parseProgressStatus(e){let n=document.getElementById(`us-container-${e.chunk_id}`);if(n==null)return;n.setAttribute("data-complete","true");let t;switch(e.upload_status){case 0:t="Processing file...";break;case 1:t="Uploading file...";break;case 2:t="Finalising...",requestFileInfo(e.file_id,e.chunk_id);break;case 3:t="Error";let n=dropzoneGetFile(e.chunk_id);e.error_message==""&&(e.error_message="Server Error"),n!=null&&dropzoneUploadError(n,e.error_message);return;default:t="Unknown status";break}document.getElementById(`us-progress-info-${e.chunk_id}`).innerText=t}function showError(e,t){let n=e.upload.uuid;document.getElementById(`us-progressbar-${n}`).style.width="100%",document.getElementById(`us-progressbar-${n}`).style.backgroundColor="red",document.getElementById(`us-progress-info-${n}`).innerText=t,document.getElementById(`us-progress-info-${n}`).classList.add("uploaderror")}function editFile(){const e=document.getElementById("mb_save");e.disabled=!0;let s=e.getAttribute("data-fileid"),o=document.getElementById("mi_edit_down").value,i=document.getElementById("mi_edit_expiry").value,t=document.getElementById("mi_edit_pw").value,a=t==="(unchanged)";document.getElementById("mc_download").checked||(o=0),document.getElementById("mc_expiry").checked||(i=0),document.getElementById("mc_password").checked||(a=!1,t="");let r=!1,n="";document.getElementById("mc_replace").checked&&(n=document.getElementById("mi_edit_replace").value,r=n!=""),apiFilesModify(s,o,i,t,a).then(t=>{if(!r){location.reload();return}apiFilesReplace(s,n).then(e=>{location.reload()}).catch(t=>{alert("Unable to edit file: "+t),console.error("Error:",t),e.disabled=!1})}).catch(t=>{alert("Unable to edit file: "+t),console.error("Error:",t),e.disabled=!1})}calendarInstance=null;function createCalendar(e){const t=new Date(e*1e3);calendarInstance=flatpickr("#mi_edit_expiry",{enableTime:!0,dateFormat:"U",altInput:!0,altFormat:"Y-m-d H:i",allowInput:!0,time_24hr:!0,defaultDate:t,minDate:"today"})}function handleEditCheckboxChange(e){var t=document.getElementById(e.getAttribute("data-toggle-target")),n=e.getAttribute("data-timestamp");e.checked?(t.classList.remove("disabled"),t.removeAttribute("disabled"),n!=null&&(calendarInstance._input.disabled=!1)):(n!=null&&(calendarInstance._input.disabled=!0),t.classList.add("disabled"),t.setAttribute("disabled",!0))}function showEditModal(e,t,n,s,o,i,a,r,c){let d=$("#modaledit").clone();$("#modaledit").on("hide.bs.modal",function(){$("#modaledit").remove();let e=d.clone();$("body").append(e)}),document.getElementById("m_filenamelabel").innerText=e,document.getElementById("mc_expiry").setAttribute("data-timestamp",s),document.getElementById("mb_save").setAttribute("data-fileid",t),createCalendar(s),i?(document.getElementById("mi_edit_down").value="1",document.getElementById("mi_edit_down").disabled=!0,document.getElementById("mc_download").checked=!1):(document.getElementById("mi_edit_down").value=n,document.getElementById("mi_edit_down").disabled=!1,document.getElementById("mc_download").checked=!0),a?(document.getElementById("mi_edit_expiry").value=add14DaysIfBeforeCurrentTime(s),document.getElementById("mi_edit_expiry").disabled=!0,document.getElementById("mc_expiry").checked=!1,calendarInstance._input.disabled=!0):(document.getElementById("mi_edit_expiry").value=s,document.getElementById("mi_edit_expiry").disabled=!1,document.getElementById("mc_expiry").checked=!0,calendarInstance._input.disabled=!1),o?(document.getElementById("mi_edit_pw").value="(unchanged)",document.getElementById("mi_edit_pw").disabled=!1,document.getElementById("mc_password").checked=!0):(document.getElementById("mi_edit_pw").value="",document.getElementById("mi_edit_pw").disabled=!0,document.getElementById("mc_password").checked=!1);let l=document.getElementById("mi_edit_replace");if(c)if(document.getElementById("replaceGroup").style.display="flex",r)document.getElementById("mc_replace").disabled=!0,document.getElementById("mc_replace").title="Replacing content is not available for end-to-end encrypted files",l.add(new Option("Unavailable",0)),l.title="Replacing content is not available for end-to-end encrypted files",l.value="0";else{let e=getAllAvailableFiles();for(let n=0;n<e[0].length;n++){if(e[0][n]==t)continue;l.add(new Option(e[1][n]+" ("+e[0][n]+")",e[0][n]))}}else document.getElementById("replaceGroup").style.display="none";new bootstrap.Modal("#modaledit",{}).show()}function selectTextForPw(e){e.value==="(unchanged)"&&e.setSelectionRange(0,e.value.length)}function add14DaysIfBeforeCurrentTime(e){let t=Date.now(),n=e*1e3;if(n<t){let e=t+14*24*60*60*1e3;return Math.floor(e/1e3)}return e}function getAllAvailableFiles(){let e=[],t=[],n=document.querySelectorAll('[id^="cell-name-"]');for(let s of n)e.push(s.id.replace("cell-name-","")),t.push(s.innerHTML);return[e,t]}function deleteFile(e){document.getElementById("button-delete-"+e).disabled=!0,apiFilesDelete(e,10).then(t=>{changeRowCount(!1,document.getElementById("row-"+e)),showToastFileDeletion(e)}).catch(e=>{alert("Unable to delete file: "+e),console.error("Error:",e)})}function checkBoxChanged(e,t){let n=!e.checked;n?document.getElementById(t).setAttribute("disabled",""):document.getElementById(t).removeAttribute("disabled"),t==="password"&&n&&(document.getElementById("password").value="")}function parseSseData(e){let t;try{t=JSON.parse(e)}catch(e){console.error("Failed to parse event data:",e);return}switch(t.event){case"download":setNewDownloadCount(t.file_id,t.download_count,t.downloads_remaining);return;case"uploadStatus":parseProgressStatus(t);return;default:console.error("Unknown event",t)}}function setNewDownloadCount(e,t,n){let s=document.getElementById("cell-downloads-"+e);if(s!=null&&(s.innerText=t,s.classList.add("updatedDownloadCount"),setTimeout(()=>s.classList.remove("updatedDownloadCount"),500)),n!=-1){let t=document.getElementById("cell-downloadsRemaining-"+e);t!=null&&(t.innerText=n,t.classList.add("updatedDownloadCount"),setTimeout(()=>t.classList.remove("updatedDownloadCount"),500))}}function registerChangeHandler(){const e=new EventSource("./uploadStatus");e.onmessage=e=>{parseSseData(e.data)},e.onerror=t=>{t.target.readyState!==EventSource.CLOSED&&e.close(),console.log("Reconnecting to SSE..."),setTimeout(registerChangeHandler,5e3)}}statusItemCount=0;function addFileStatus(e,t){const n=document.createElement("div");n.setAttribute("id",`us-container-${e}`),n.classList.add("us-container");const a=document.createElement("div");a.classList.add("filename"),a.textContent=t,n.appendChild(a);const s=document.createElement("div");s.classList.add("upload-progress-container"),s.setAttribute("id",`us-progress-container-${e}`);const r=document.createElement("div");r.classList.add("upload-progress-bar");const o=document.createElement("div");o.setAttribute("id",`us-progressbar-${e}`),o.classList.add("upload-progress-bar-progress"),o.style.width="0%",r.appendChild(o);const i=document.createElement("div");i.setAttribute("id",`us-progress-info-${e}`),i.classList.add("upload-progress-info"),i.textContent="0%",s.appendChild(r),s.appendChild(i),n.appendChild(s),n.setAttribute("data-starttime",Date.now()),n.setAttribute("data-complete","false");const c=document.getElementById("uploadstatus");c.appendChild(n),c.style.visibility="visible",statusItemCount++}function removeFileStatus(e){const t=document.getElementById(`us-container-${e}`);if(t==null)return;t.remove(),statusItemCount--,statusItemCount<1&&(document.getElementById("uploadstatus").style.visibility="hidden")}function addRow(e){let y=document.getElementById("downloadtable"),s=y.insertRow(0);e.Id=sanitizeId(e.Id),s.id="row-"+e.Id;let f=s.insertCell(0),m=s.insertCell(1),l=s.insertCell(2),u=s.insertCell(3),h=s.insertCell(4),d=s.insertCell(5),t=s.insertCell(6);f.innerText=e.Name,f.id="cell-name-"+e.Id,h.id="cell-downloads-"+e.Id,m.innerText=e.Size,e.UnlimitedDownloads?l.innerText="Unlimited":(l.innerText=e.DownloadsRemaining,l.id="cell-downloadsRemaining-"+e.Id),e.UnlimitedTime?u.innerText="Unlimited":u.innerText=e.ExpireAtString,h.innerText=e.DownloadCount;const c=document.createElement("a");if(c.href=e.UrlDownload,c.target="_blank",c.style.color="inherit",c.id="url-href-"+e.Id,c.textContent=e.Id,d.appendChild(c),e.IsPasswordProtected===!0){const e=document.createElement("i");e.className="bi bi-key",e.title="Password protected",d.appendChild(document.createTextNode(" ")),d.appendChild(e)}const n=document.createElement("button");n.type="button",n.className="copyurl btn btn-outline-light btn-sm",n.dataset.clipboardText=e.UrlDownload,n.id="url-button-"+e.Id,n.title="Copy URL";const p=document.createElement("i");p.className="bi bi-copy",n.appendChild(p),n.appendChild(document.createTextNode(" URL")),n.addEventListener("click",()=>{showToast(1e3)}),t.appendChild(n),t.appendChild(document.createTextNode(" "));const o=document.createElement("button");o.type="button",o.className="copyurl btn btn-outline-light btn-sm",o.title="Copy Hotlink";const g=document.createElement("i");g.className="bi bi-copy",o.appendChild(g),o.appendChild(document.createTextNode(" Hotlink")),e.UrlHotlink?(o.dataset.clipboardText=e.UrlHotlink,o.addEventListener("click",()=>{showToast(1e3)})):o.disabled=!0,t.appendChild(o),t.appendChild(document.createTextNode(" "));const a=document.createElement("button");a.type="button",a.className="btn btn-outline-light btn-sm",a.title="QR Code",a.id="qrcode-"+e.Id;const v=document.createElement("i");v.className="bi bi-qr-code",a.appendChild(v),a.addEventListener("click",()=>{showQrCode(e.UrlDownload)}),t.appendChild(a),t.appendChild(document.createTextNode(" "));const r=document.createElement("button");r.type="button",r.className="btn btn-outline-light btn-sm",r.title="Edit";const b=document.createElement("i");b.className="bi bi-pencil",r.appendChild(b),r.addEventListener("click",()=>{showEditModal(e.Name,e.Id,e.DownloadsRemaining,e.ExpireAt,e.IsPasswordProtected,e.UnlimitedDownloads,e.UnlimitedTime,e.IsEndToEndEncrypted,canReplaceOwnFiles)}),t.appendChild(r),t.appendChild(document.createTextNode(" "));const i=document.createElement("button");i.type="button",i.className="btn btn-outline-danger btn-sm",i.title="Delete",i.id="button-delete-"+e.Id;const j=document.createElement("i");return j.className="bi bi-trash3",i.appendChild(j),i.addEventListener("click",()=>{deleteFile(e.Id)}),t.appendChild(i),f.classList.add("newItem"),m.classList.add("newItem"),l.classList.add("newItem"),u.classList.add("newItem"),h.classList.add("newItem"),d.classList.add("newItem"),t.classList.add("newItem"),m.setAttribute("data-order",e.SizeBytes),changeRowCount(!0,s),e.Id}function sanitizeId(e){return e.replace(/[^a-zA-Z0-9]/g,"")}function changeRowCount(e,t){let n=$("#maintable").DataTable();rowCount==-1&&(rowCount=n.rows().count()),e?(rowCount=rowCount+1,n.row.add(t)):(rowCount=rowCount-1,t.classList.add("rowDeleting"),setTimeout(()=>{n.row(t).remove(),t.remove()},290));let s=document.getElementsByClassName("dataTables_empty")[0];typeof s!="undefined"?s.innerText="Files stored: "+rowCount:document.getElementsByClassName("dataTables_info")[0].innerText="Files stored: "+rowCount}function hideQrCode(){document.getElementById("qroverlay").style.display="none",document.getElementById("qrcode").innerHTML=""}function showQrCode(e){const t=document.getElementById("qroverlay");t.style.display="block",new QRCode(document.getElementById("qrcode"),{text:e,width:200,height:200,colorDark:"#000000",colorLight:"#ffffff",correctLevel:QRCode.CorrectLevel.H}),t.addEventListener("click",hideQrCode)}function showToastFileDeletion(e){let t=document.getElementById("toastnotificationUndo"),n=document.getElementById("cell-name-"+e).innerText,s=document.getElementById("toastFilename"),o=document.getElementById("toastUndoButton");s.innerText=n,o.dataset.fileid=e,hideToast(),t.classList.add("show"),clearTimeout(toastId),toastId=setTimeout(()=>{hideFileToast()},5e3)}function hideFileToast(){document.getElementById("toastnotificationUndo").classList.remove("show")}function handleUndo(e){hideFileToast(),apiFilesRestore(e.dataset.fileid).then(e=>{addRow(e.FileInfo)}).catch(e=>{alert("Unable to restore file: "+e),console.error("Error:",e)})}function changeUserPermission(e,t,n){let s=document.getElementById(n);if(s.classList.contains("perm-processing")||s.classList.contains("perm-nochange"))return;let o=s.classList.contains("perm-granted");s.classList.add("perm-processing"),s.classList.remove("perm-granted"),s.classList.remove("perm-notgranted");let i="GRANT";o&&(i="REVOKE"),t=="PERM_REPLACE_OTHER"&&!o&&(hasNotPermissionReplace=document.getElementById("perm_replace_"+e).classList.contains("perm-notgranted"),hasNotPermissionReplace&&(showToast(2e3,"Also granting permission to replace own files"),changeUserPermission(e,"PERM_REPLACE","perm_replace_"+e))),t=="PERM_REPLACE"&&o&&(hasPermissionReplaceOthers=document.getElementById("perm_replace_other_"+e).classList.contains("perm-granted"),hasPermissionReplaceOthers&&(showToast(2e3,"Also revoking permission to replace files of other users"),changeUserPermission(e,"PERM_REPLACE_OTHER","perm_replace_other_"+e))),apiUserModify(e,t,i).then(e=>{o?s.classList.add("perm-notgranted"):s.classList.add("perm-granted"),s.classList.remove("perm-processing")}).catch(e=>{o?s.classList.add("perm-granted"):s.classList.add("perm-notgranted"),s.classList.remove("perm-processing"),alert("Unable to set permission: "+e),console.error("Error:",e)})}function changeRank(e,t,n){let s=document.getElementById(n);if(s.disabled)return;s.disabled=!0,apiUserChangeRank(e,t).then(e=>{location.reload()}).catch(e=>{s.disabled=!1,alert("Unable to change rank: "+e),console.error("Error:",e)})}function showDeleteModal(e,t){let n=document.getElementById("checkboxDelete");n.checked=!1,document.getElementById("deleteModalBody").innerText=t,$("#deleteModal").modal("show"),document.getElementById("buttonDelete").onclick=function(){apiUserDelete(e,n.checked).then(t=>{$("#deleteModal").modal("hide"),document.getElementById("row-"+e).classList.add("rowDeleting"),setTimeout(()=>{document.getElementById("row-"+e).remove()},290)}).catch(e=>{alert("Unable to delete user: "+e),console.error("Error:",e)})}}function showAddUserModal(){let e=$("#newUserModal").clone();$("#newUserModal").on("hide.bs.modal",function(){$("#newUserModal").remove();let t=e.clone();$("body").append(t)}),$("#newUserModal").modal("show")}function showResetPwModal(e,t){let n=$("#resetPasswordModal").clone();$("#resetPasswordModal").on("hide.bs.modal",function(){$("#resetPasswordModal").remove();let e=n.clone();$("body").append(e)}),document.getElementById("l_userpwreset").innerText=t;let s=document.getElementById("resetPasswordButton");s.onclick=function(){resetPw(e,document.getElementById("generateRandomPassword").checked)},$("#resetPasswordModal").modal("show")}function resetPw(e,t){let n=document.getElementById("resetPasswordButton");document.getElementById("resetPasswordButton").disabled=!0,apiUserResetPassword(e,t).then(e=>{if(!t){$("#resetPasswordModal").modal("hide"),showToast(1e3,"Password change requirement set successfully");return}n.style.display="none",document.getElementById("cancelPasswordButton").style.display="none",document.getElementById("formentryReset").style.display="none",document.getElementById("randomPasswordContainer").style.display="block",document.getElementById("closeModalResetPw").style.display="block",document.getElementById("l_returnedPw").innerText=e.password,document.getElementById("copypwclip").onclick=function(){navigator.clipboard.writeText(e.password),showToast(1e3,"Password copied to clipboard")}}).catch(e=>{alert("Unable to reset user password: "+e),console.error("Error:",e),n.disabled=!1})}function addNewUser(){let e=document.getElementById("mb_addUser");e.disabled=!0;let t=document.getElementById("newUserForm");if(t.checkValidity()){let t=document.getElementById("e_userName");apiUserCreate(t.value.trim()).then(e=>{$("#newUserModal").modal("hide"),addRowUser(e.id,e.name)}).catch(t=>{t.message=="duplicate"?(alert("A user already exists with that name"),e.disabled=!1):(alert("Unable to create user: "+t),console.error("Error:",t),e.disabled=!1)})}else t.classList.add("was-validated"),e.disabled=!1}function addRowUser(e,t){let l=document.getElementById("usertable"),n=l.insertRow(1);n.id="row-"+e;let o=n.insertCell(0),i=n.insertCell(1),a=n.insertCell(2),r=n.insertCell(3),c=n.insertCell(4),s=n.insertCell(5);o.classList.add("newUser"),i.classList.add("newUser"),a.classList.add("newUser"),r.classList.add("newUser"),c.classList.add("newUser"),s.classList.add("newUser"),o.innerText=t,i.innerText="User",a.innerText="Never",r.innerText="0";let d='<button id="pwchange-'+e+`" type="button" class="btn btn-outline-light btn-sm" onclick="showResetPwModal('`+e+"', '"+t+`')" title="Reset Password"><i class="bi bi-key-fill"></i></button>&nbsp; `;s.innerHTML='<button id="changeRank_'+e+'" type="button" onclick="changeRank( '+e+" , 'ADMIN', 'changeRank_"+e+`')" title="Promote User" class="btn btn-outline-light btn-sm"><i class="bi bi-chevron-double-up"></i></button>&nbsp; <button id="delete-`+e+'" type="button" class="btn btn-outline-danger btn-sm"  onclick="showDeleteModal('+e+", '"+t+`')" title="Delete"><i class="bi bi-trash3"></i></button>`,isInternalAuth&&(s.innerHTML=d+s.innerHTML),c.innerHTML=`
         <i id="perm_replace_`+e+`" class="bi bi-recycle perm-notgranted " title="Replace own uploads" onclick='changeUserPermission(`+e+`,"PERM_REPLACE", "perm_replace_`+e+`");'></i>
     		
     		<i id="perm_list_`+e+`" class="bi bi-eye perm-notgranted " title="List other uploads" onclick='changeUserPermission(`+e+`,"PERM_LIST", "perm_list_`+e+`");'></i>
    
  • internal/webserver/web/static/js/min/end2end_admin.min.5.js+1 1 modified
    @@ -1 +1 @@
    -function displayError(e){document.getElementById("errordiv").style.display="block",document.getElementById("errormessage").innerHTML="<b>Error: </b> "+e.toString().replace(/^Error:/gi,""),console.error("Caught exception",e)}function checkIfE2EKeyIsSet(){isE2EKeySet()?loadWasm(function(){let t=localStorage.getItem("e2ekey"),e=GokapiE2ESetCipher(t);if(e!==null){displayError(e);return}getE2EInfo(),GokapiE2EDecryptMenu(),dropzoneObject.enable(),document.getElementsByClassName("dz-button")[0].innerText="Drop files, paste or click here to upload (end-to-end encrypted)"}):window.location="./e2eSetup"}function getE2EInfo(){var e=new XMLHttpRequest;e.open("GET","./e2eInfo?action=get",!1),e.onreadystatechange=function(){if(this.readyState==4)if(this.status==200){let t=GokapiE2EInfoParse(e.response);t!==null&&(displayError(t),t.message==="cipher: message authentication failed"&&invalidCipherRedirectConfim())}else displayError("Trying to get E2E info: "+e.statusText)},e.send()}function invalidCipherRedirectConfim(){confirm("It appears that an invalid end-to-end encryption key has been entered. Would you like to enter the correct one?")&&(window.location="./e2eSetup")}function storeE2EInfo(e){var t=new XMLHttpRequest;t.open("POST","./e2eInfo?action=store",!1),t.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),t.onreadystatechange=function(){this.readyState==4&&this.status!=200&&displayError("Trying to store E2E info: "+t.statusText)};let n=new FormData;n.append("info",e),t.send(urlencodeFormData(n))}function isE2EKeySet(){let e=localStorage.getItem("e2ekey");return e!==null&&e!==""}function loadWasm(e){const t=new Go,s="e2e.wasm?v=1";var n;try{"instantiateStreaming"in WebAssembly?WebAssembly.instantiateStreaming(fetch(s),t.importObject).then(function(s){n=s.instance,t.run(n),e()}):fetch(s).then(e=>e.arrayBuffer()).then(s=>WebAssembly.instantiate(s,t.importObject).then(function(s){n=s.instance,t.run(n),e()}))}catch(e){displayError(e)}}function urlencodeFormData(e){let t="";function s(e){return encodeURIComponent(e).replace(/%20/g,"+")}for(var n of e.entries())typeof n[1]=="string"&&(t+=(t?"&":"")+s(n[0])+"="+s(n[1]));return t}function setE2eUpload(){dropzoneObject.uploadFiles=function(e){this._transformFiles(e,t=>{let o=t[0];e[0].upload.chunked=!0,e[0].isEndToEndEncrypted=!0;let i=e[0].upload.filename,s=o.size,r=0,n=GokapiE2EEncryptNew(e[0].upload.uuid,s,i);if(n instanceof Error){displayError(n);return}e[0].upload.totalChunkCount=Math.ceil(n/this.options.chunkSize),e[0].sizeEncrypted=n;let a=e[0],c=0,l=0,d=!1,u=0;uploadChunk(a,0,n,s,dropzoneObject.options.chunkSize,0)})}}function decryptFileEntry(e,t,n){let s=$("#maintable").DataTable();const o=s.rows().nodes();for(let i=0;i<o.length;i++){const a=s.cell(i,0).node();if("cell-name-"+e===$(a).attr("id")){s.cell(i,0).data(t);let a=s.cell(i,5).node(),r=a.querySelector("a"),o=r.getAttribute("href");o.includes(n)||(IncludeFilename&&(o=o.replace("/Encrypted%20File","/"+encodeURI(t))),o=o+"#"+n,r.setAttribute("href",o)),s.cell(i,5).node(a);let c=s.cell(i,6).node(),l=c.querySelector("button");l.setAttribute("data-clipboard-text",o),document.getElementById("qrcode-"+e).onclick=function(){showQrCode(o)},s.cell(i,6).node(c);break}}}async function uploadChunk(e,t,n,s,o,i){let c=!1,l=t*o,d=l+o;t===e.upload.totalChunkCount-1&&(c=!0,d=s);let u=e.webkitSlice?e.webkitSlice(l,d):e.slice(l,d),a=await u.arrayBuffer(),r=await GokapiE2EUploadChunk(e.upload.uuid,a.byteLength,c,new Uint8Array(a));if(r instanceof Error){displayError(a);return}let h=await postChunk(e.upload.uuid,i,n,r,e);if(h!==null){e.accepted=!1,dropzoneObject._errorProcessing([e],h);return}i=i+r.byteLength,a=null,r=null,u=null,c?(e.status=Dropzone.SUCCESS,dropzoneObject.emit("success",e,"success",null),dropzoneObject.emit("complete",e),dropzoneObject.processQueue(),dropzoneObject.options.chunksUploaded(e,()=>{})):await uploadChunk(e,t+1,n,s,o,i)}async function postChunk(e,t,n,s,o){return new Promise(i=>{let r=new FormData;r.append("dztotalfilesize",n),r.append("dzchunkbyteoffset",t),r.append("dzuuid",e),r.append("file",new Blob([s]),"encrypted.file");let a=new XMLHttpRequest;a.open("POST","./uploadChunk");let c=a.upload!=null?a.upload:a;c.onprogress=e=>{try{dropzoneObject.emit("uploadprogress",o,100*(e.loaded+t)/n,e.loaded+t)}catch(e){console.log(e)}},a.onreadystatechange=function(){this.readyState==4&&(this.status==200?i(null):(console.log(a.responseText),i(a.responseText)))},a.send(r)})}
    \ No newline at end of file
    +function displayError(e){document.getElementById("errordiv").style.display="block";const t=document.getElementById("errormessage");t.innerText="";const n=document.createElement("b");n.innerText="Error: ";const s=document.createTextNode(e.toString().replace(/^Error:/gi,""));t.appendChild(n),t.appendChild(s),console.error("Caught exception",e)}function checkIfE2EKeyIsSet(){isE2EKeySet()?loadWasm(function(){let t=localStorage.getItem("e2ekey"),e=GokapiE2ESetCipher(t);if(e!==null){displayError(e);return}getE2EInfo(),GokapiE2EDecryptMenu(),dropzoneObject.enable(),document.getElementsByClassName("dz-button")[0].innerText="Drop files, paste or click here to upload (end-to-end encrypted)"}):window.location="./e2eSetup"}function getE2EInfo(){var e=new XMLHttpRequest;e.open("GET","./e2eInfo?action=get",!1),e.onreadystatechange=function(){if(this.readyState==4)if(this.status==200){let t=GokapiE2EInfoParse(e.response);t!==null&&(displayError(t),t.message==="cipher: message authentication failed"&&invalidCipherRedirectConfim())}else displayError("Trying to get E2E info: "+e.statusText)},e.send()}function invalidCipherRedirectConfim(){confirm("It appears that an invalid end-to-end encryption key has been entered. Would you like to enter the correct one?")&&(window.location="./e2eSetup")}function storeE2EInfo(e){var t=new XMLHttpRequest;t.open("POST","./e2eInfo?action=store",!1),t.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),t.onreadystatechange=function(){this.readyState==4&&this.status!=200&&displayError("Trying to store E2E info: "+t.statusText)};let n=new FormData;n.append("info",e),t.send(urlencodeFormData(n))}function isE2EKeySet(){let e=localStorage.getItem("e2ekey");return e!==null&&e!==""}function loadWasm(e){const t=new Go,s="e2e.wasm?v=1";var n;try{"instantiateStreaming"in WebAssembly?WebAssembly.instantiateStreaming(fetch(s),t.importObject).then(function(s){n=s.instance,t.run(n),e()}):fetch(s).then(e=>e.arrayBuffer()).then(s=>WebAssembly.instantiate(s,t.importObject).then(function(s){n=s.instance,t.run(n),e()}))}catch(e){displayError(e)}}function urlencodeFormData(e){let t="";function s(e){return encodeURIComponent(e).replace(/%20/g,"+")}for(var n of e.entries())typeof n[1]=="string"&&(t+=(t?"&":"")+s(n[0])+"="+s(n[1]));return t}function setE2eUpload(){dropzoneObject.uploadFiles=function(e){this._transformFiles(e,t=>{let o=t[0];e[0].upload.chunked=!0,e[0].isEndToEndEncrypted=!0;let i=e[0].upload.filename,s=o.size,r=0,n=GokapiE2EEncryptNew(e[0].upload.uuid,s,i);if(n instanceof Error){displayError(n);return}e[0].upload.totalChunkCount=Math.ceil(n/this.options.chunkSize),e[0].sizeEncrypted=n;let a=e[0],c=0,l=0,d=!1,u=0;uploadChunk(a,0,n,s,dropzoneObject.options.chunkSize,0)})}}function decryptFileEntry(e,t,n){let s=$("#maintable").DataTable();const o=s.rows().nodes();for(let i=0;i<o.length;i++){const a=s.cell(i,0).node();if("cell-name-"+e===$(a).attr("id")){let l=s.cell(i,0).node(),a=s.cell(i,5).node(),r=a.querySelector("a"),o=r.getAttribute("href");l.textContent=t,o.includes(n)||(IncludeFilename&&(o=o.replace("/Encrypted%20File","/"+encodeURI(t))),o=o+"#"+n,r.setAttribute("href",o)),s.cell(i,5).node(a);let c=s.cell(i,6).node(),d=c.querySelector("button");d.setAttribute("data-clipboard-text",o),document.getElementById("qrcode-"+e).onclick=function(){showQrCode(o)},s.cell(i,6).node(c);break}}}async function uploadChunk(e,t,n,s,o,i){let c=!1,l=t*o,d=l+o;t===e.upload.totalChunkCount-1&&(c=!0,d=s);let u=e.webkitSlice?e.webkitSlice(l,d):e.slice(l,d),a=await u.arrayBuffer(),r=await GokapiE2EUploadChunk(e.upload.uuid,a.byteLength,c,new Uint8Array(a));if(r instanceof Error){displayError(a);return}let h=await postChunk(e.upload.uuid,i,n,r,e);if(h!==null){e.accepted=!1,dropzoneObject._errorProcessing([e],h);return}i=i+r.byteLength,a=null,r=null,u=null,c?(e.status=Dropzone.SUCCESS,dropzoneObject.emit("success",e,"success",null),dropzoneObject.emit("complete",e),dropzoneObject.processQueue(),dropzoneObject.options.chunksUploaded(e,()=>{})):await uploadChunk(e,t+1,n,s,o,i)}async function postChunk(e,t,n,s,o){return new Promise(i=>{let r=new FormData;r.append("dztotalfilesize",n),r.append("dzchunkbyteoffset",t),r.append("dzuuid",e),r.append("file",new Blob([s]),"encrypted.file");let a=new XMLHttpRequest;a.open("POST","./uploadChunk");let c=a.upload!=null?a.upload:a;c.onprogress=e=>{try{dropzoneObject.emit("uploadprogress",o,100*(e.loaded+t)/n,e.loaded+t)}catch(e){console.log(e)}},a.onreadystatechange=function(){this.readyState==4&&(this.status==200?i(null):(console.log(a.responseText),i(a.responseText)))},a.send(r)})}
    \ No newline at end of file
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.