9ad04e0a0b06ec3c4f09ef1b6c3ce6be79b61c68 braney Sun Aug 16 11:56:56 2026 -0700 cart: validate file names read back out of the cart Several cart variables hold the name of a file the server created for a user. Route them through one shared check, isServerUserFilePath(), which accepts the trash directory, the session-data directories and myVariantsDataDir, and apply it both where values enter the cart and where the file names are used. A few of these variables may instead hold a remote URL. Those get their own list and isServerUserFileOrUrl(), because the code that reads them chooses between a fetch and a local open by looking for a protocol. Consolidates two hand-rolled copies of the same test in blatShare.c and customFactory.c, and drops the weaker private copy in sessionData.c. Adds hg/utils/cartFileVarCatalog, a registry that scans the tree for a cart value reaching a file call and reconciles what it finds against the lists in cart.c, so a new one of these cannot be added without somebody noticing. Its --reconcile is quiet enough for the nightly cron the other catalogs use, and it is what turned up seven of the names now on those lists. refs #37623 diff --git src/hg/hgIntegrator/hgIntegrator.c src/hg/hgIntegrator/hgIntegrator.c index 6eee46f4754..458c6ab044b 100644 --- src/hg/hgIntegrator/hgIntegrator.c +++ src/hg/hgIntegrator/hgIntegrator.c @@ -19,30 +19,31 @@ #include "cartTrackDb.h" #include "cheapcgi.h" #include "htmshell.h" #include "genbank.h" #include "hAnno.h" #include "hCommon.h" #include "hdb.h" #include "hgColors.h" #include "hui.h" #include "joiner.h" #include "jsHelper.h" #include "jsonParse.h" #include "knetUdc.h" #include "textOut.h" #include "trackHub.h" +#include "trashDir.h" #include "userRegions.h" #include "web.h" #include "annoFormatTab.h" #include "annoGratorQuery.h" #include "windowsToAscii.h" #include "chromAlias.h" #include "hgConfig.h" /* Global Variables */ struct cart *cart = NULL; /* CGI and other variables */ struct hash *oldVars = NULL; /* Old contents of cart before it was updated by CGI */ #define QUERY_SPEC "hgi_querySpec" #define UI_CHOICES "hgi_uiChoices" #define DO_QUERY "hgi_doQuery" @@ -410,31 +411,32 @@ // For now at least, use hgTables' CGI var names so regions are shared between hgI & hgTables //#*** TODO: get own CGI var names or libify these (dup'd from hgTables.h) #define hgtaEnteredUserRegions "hgta_enteredUserRegions" #define hgtaUserRegionsFile "hgta_userRegionsFile" #define hgtaUserRegionsDb "hgta_userRegionsDb" #define hgtaRegionTypeUserRegions "userRegions" #define hgtaRegionTypeGenome "genome" boolean userRegionsExist() /* Return true if the trash file for regions exists. It must be non-empty because * if the region list is set to empty we clear region state. */ { char *trashFileName = cartOptionalString(cart, hgtaUserRegionsFile); -return (isNotEmpty(trashFileName) && fileExists(trashFileName)); +return (isNotEmpty(trashFileName) && isServerUserFilePath(trashFileName) && + fileExists(trashFileName)); } struct bed4 *userRegionsGetBedList() /* Read parsed user-defined regions from local trash file and return as bed list. */ // Not libifying at this point because the cart variable names may differ between // apps -- in that case, libify this but with some kind of param to give cart // var name prefix. { if (! userRegionsExist()) return NULL; char *trashFileName = cartOptionalString(cart, hgtaUserRegionsFile); // Note: I wanted to use basicBed's bedLoadNAll but it chops by whitespace not tabs, // so it aborts if the name field is empty (that causes it to see 3 words not 4). char *words[4]; int wordCount; @@ -499,31 +501,31 @@ } } static void clearUserRegions(struct cartJson *cj, struct hash *paramHash) /* Remove all user-defined region info from cart, and send JSON update. */ // Not libifying at this point because the cart variable names may differ between // apps -- in that case, libify this but with some kind of param to give cart // var name prefix. { char *resultName = cartJsonOptionalParam(paramHash, "resultName"); if (isEmpty(resultName)) resultName = "userRegions"; struct jsonWrite *jw = cj->jw; cartRemove(cart, hgtaUserRegionsDb); char *trashFileName = cartOptionalString(cart, hgtaUserRegionsFile); -if (trashFileName && fileExists(trashFileName)) +if (trashFileName && isServerUserFilePath(trashFileName) && fileExists(trashFileName)) unlink(trashFileName); cartRemove(cart, hgtaUserRegionsFile); cartRemove(cart, hgtaEnteredUserRegions); char *regionType = cartUsualString(cart, hgiRegionType, hgiRegionTypeDefault); if (regionType && sameString(regionType, hgtaRegionTypeUserRegions)) { regionType = hgiRegionTypeDefault; cartSetString(cart, hgiRegionType, regionType); } jsonWriteString(jw, hgiRegionType, regionType); jsonWriteString(jw, resultName, NULL); jsonWriteString(jw, "userRegionsSummary", NULL); } static void setUserRegions(struct cartJson *cj, struct hash *paramHash)