72a39a73f65feecd86b7e6cf20bdd346fcad4868
chmalee
  Thu Jan 23 13:09:33 2025 -0800
Fix bug in handling non alphanum characters in filenames in hubspace. I was mistakenly double encoding the filenames when creating trackDb stanzas. Also on client side, prevent users from even submitting files with weird characters to start with, refs #35064

diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js
index cba6cb72786..1c3e4130e38 100644
--- src/hg/js/hgMyData.js
+++ src/hg/js/hgMyData.js
@@ -57,44 +57,51 @@
     let handleSuccess = function(req) {
         apiKeyInstr.style.display = "none";
         document.getElementById("spinner").remove();
         let generateDiv = document.getElementById("generateDiv");
         generateDiv.style.display = "block";
         let revokeDiv = document.getElementById("revokeDiv");
         revokeDiv.style.display = "none";
     };
 
     let cartData = {revokeApiKey: {}};
     cart.setCgi("hgHubConnect");
     cart.send(cartData, handleSuccess);
     cart.flush();
 }
 
+const fileNameRegex = /[0-9a-zA-Z._\-+]+/g; // allowed characters in file names
 // make our Uppy instance:
 const uppy = new Uppy.Uppy({
     debug: true,
     allowMultipleUploadBatches: false,
     onBeforeUpload: (files) => {
         // set all the fileTypes and genomes from their selects
         let doUpload = true;
         for (let [key, file] of Object.entries(files)) {
+            let fileNameMatch = file.meta.name.match(fileNameRegex);
+            if (!fileNameMatch || fileNameMatch[0] !== file.meta.name) {
+                uppy.info(`Error: File name has special characters, please rename file: ${file.meta.name} to only include alpha-numeric characters, period, dash, underscore or plus.`, 'error', 2000);
+                doUpload = false;
+                continue;
+            }
             if (!file.meta.genome) {
-                uppy.info(`Error: No genome selected for file ${file.name}!`, 'error', 2000);
+                uppy.info(`Error: No genome selected for file ${file.meta.name}!`, 'error', 2000);
                 doUpload = false;
                 continue;
             } else if  (!file.meta.fileType) {
-                uppy.info(`Error: File type not supported, please rename file: ${file.name}!`, 'error', 2000);
+                uppy.info(`Error: File type not supported, file: ${file.meta.name}!`, 'error', 2000);
                 doUpload = false;
                 continue;
             }
             uppy.setFileMeta(file.id, {
                 fileName: file.meta.name,
                 fileSize: file.size,
                 lastModified: file.data.lastModified,
             });
         }
         return doUpload;
     },
 });
 
 var hubCreate = (function() {
     let uiState = { // our object for keeping track of the current UI and what to do
@@ -188,34 +195,34 @@
 
     function viewInGenomeBrowser(fname, ftype, genome, hubName) {
         // redirect to hgTracks with this track open in the hub
         if (typeof uiState.userUrl !== "undefined" && uiState.userUrl.length > 0) {
             if (ftype in extensionMap) {
                 // TODO: tusd should return this location in it's response after
                 // uploading a file and then we can look it up somehow, the cgi can
                 // write the links directly into the html directly for prev uploaded files maybe?
                 let url = "../cgi-bin/hgTracks?hgsid=" + getHgsid() + "&db=" + genome + "&hubUrl=" + uiState.userUrl + hubName + "/hub.txt&" + trackHubFixName(fname) + "=pack";
                 window.location.assign(url);
                 return false;
             }
         }
     }
 
-    const regex = /[^A-Za-z0-9_-]+/g;
+    const regex = /[^A-Za-z0-9_-]/g;
     function trackHubFixName(trackName) {
         // replace everything but alphanumeric, underscore and dash with underscore
-        return trackName.replaceAll(regex, "_");
+        return encodeURIComponent(trackName).replaceAll(regex, "_");
     }
 
     // helper object so we don't need to use an AbortController to update
     // the data this function is using
     let selectedData = {};
     function viewAllInGenomeBrowser(ev) {
         // redirect to hgTracks with these tracks/hubs open
         let data = selectedData;
         if (typeof uiState.userUrl !== "undefined" && uiState.userUrl.length > 0) {
             let url = "../cgi-bin/hgTracks?hgsid=" + getHgsid();
             let genome; // may be multiple genomes in list, just redirect to the first one
                         // TODO: this should probably raise an alert to click through
             let hubsAdded = {};
             _.forEach(data, (d) => {
                 if (!genome) {