5a1d1a25ff3a7a7001e5dd98e1e4879b6f3ebe9d chmalee Tue Dec 16 16:15:02 2025 -0800 Fix up jsOnEventById calls to javascript literal encode the id's, so the ids can have parens, single quotes, double quotes, etc in them and still be selected. Fix up the matrix checkbox code to htmlEncode the subgroups so subgroups can have parens, single quotes, etc in them and still work as class names and selectors, refs #36841 diff --git src/hg/lib/hui.c src/hg/lib/hui.c index f7c4799f675..0f104a91ae9 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -5401,47 +5401,47 @@ buffer, priority); // keeing track of priority } // The checkbox has identifying classes including subCB and the tag for each dimension // (e.g. class='subCB GM12878 CTCF Peak') dyStringClear(dyHtml); dyStringAppend(dyHtml, "subCB"); // always first int di; if (membersForAll->dimensions && membership != NULL) { for (di=dimX;di<membersForAll->dimMax;di++) { if (membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count))) - dyStringPrintf(dyHtml," %s",membership->membership[ix]); + dyStringPrintf(dyHtml," %s",htmlEncode(membership->membership[ix])); } } else if (membersForAll->abcCount && membership != NULL) // "dimensions" don't exist but may be subgroups anyway { for (di=dimA;di<membersForAll->dimMax;di++) { if (membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count))) - dyStringPrintf(dyHtml," %s",membership->membership[ix]); + dyStringPrintf(dyHtml," %s",htmlEncode(membership->membership[ix])); } } if (membersForAll->members[dimV] && membership != NULL && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) - dyStringPrintf(dyHtml, " %s",membership->membership[ix]); // Saved view for last + dyStringPrintf(dyHtml, " %s",htmlEncode(membership->membership[ix])); // Saved view for last // And finally the checkBox is made! safef(buffer, sizeof(buffer), "%s_sel", subtrack->track); if (!enabledCB) { dyStringAppend(dyHtml, " disabled"); cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml), "style='cursor:pointer' title='view is hidden'"); jsOnEventById("click", id, "matSubCbClick(this);"); } else { cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml), "style='cursor:pointer'"); jsOnEventById("click", id, "matSubCbClick(this);"); @@ -5859,40 +5859,40 @@ } puts("</TBODY><TFOOT></TFOOT>"); puts("</TABLE>"); if (slCount(subtrackRefList) > 5) puts(" <span class='subCBcount'></span>"); puts("<P>"); if (!primarySubtrack) jsInline("matInitializeMatrix();\n"); } static void makeAddClearButtonPair(char *idPrefix, char *class,char *separator) // Print an [Add][Clear] button pair that uses javascript to check subtracks { char buf[256]; if (class) - safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true,'%s'); return false;", class); + safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true,CSS.escape('%s')); return false;", class); else safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true); return false;"); char id[256]; safef(id, sizeof id, "%s_add", idPrefix); cgiMakeOnClickButton(id, buf, ADD_BUTTON_LABEL); if (separator) printf("%s",separator); if (class) - safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false,'%s'); return false;", class); + safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false,CSS.escape('%s')); return false;", class); else safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false); return false;"); safef(id, sizeof id, "%s_clr", idPrefix); cgiMakeOnClickButton(id, buf, CLEAR_BUTTON_LABEL); } #define MANY_SUBTRACKS 8 #define WIGGLE_HELP_PAGE "../goldenPath/help/hgWiggleTrackHelp.html" boolean cfgBeginBoxAndTitle(struct trackDb *tdb, boolean boxed, char *title) // Handle start of box and title for individual track type settings { if (!boxed) { boxed = trackDbSettingOn(tdb,"boxedCfg"); @@ -8607,63 +8607,63 @@ { char *link = wgEncodeVocabLink( (sameWord(cvSetting,"antibody") ? "target" : "term"), (char *)cvTerm,(char *)cvTerm,rootLabel,suffix); return link; } } } } freeMem(words[0]); freeMem(rootLabel); return cloneString(label); } #define PM_BUTTON_UC "<IMG height=18 width=18 id='%s' src='../images/%s'>" -#define PM_BUTTON_UC_JS "return (matSetMatrixCheckBoxes(%s%s%s%s%s%s) == false);" +#define PM_BUTTON_UC_JS "return (matSetMatrixCheckBoxes(%s%sCSS.escape(\"%s\")%s%s%s) == false);" #define PM_MAKE_BUTTON_UC(s1,s2,s3,s4,s5,s6,name,img) \ safef(id, sizeof id, "btn_%s", (name)); \ - printf(PM_BUTTON_UC, id, (img)); \ + printf(PM_BUTTON_UC, htmlEncode(id), (img)); \ safef(javascript, sizeof javascript, PM_BUTTON_UC_JS, (s1),(s2),(s3),(s4),(s5),(s6)); \ jsOnEventById("click", id, javascript); #define MATRIX_RIGHT_BUTTONS_AFTER 8 #define MATRIX_BOTTOM_BUTTONS_AFTER 20 static void buttonsForAll(boolean left, boolean top) { char id[256]; char javascript[1024]; char fullname[256]; safef(fullname, sizeof fullname, "plus_all_%s_%s", left ? "left" : "right", top ? "top" : "bottom"); -PM_MAKE_BUTTON_UC("true", "", "", "", "", "", fullname, "add_sm.gif") +PM_MAKE_BUTTON_UC("true", ",", "", "", "", "", fullname, "add_sm.gif") safef(fullname, sizeof fullname, "minus_all_%s_%s", left ? "left" : "right", top ? "top" : "bottom"); -PM_MAKE_BUTTON_UC("false","", "", "", "", "", fullname, "remove_sm.gif") +PM_MAKE_BUTTON_UC("false",",", "", "", "", "", fullname, "remove_sm.gif") } static void buttonsForOne(char *class, boolean vertical, boolean left, boolean top) { char id[256]; char javascript[1024]; char fullname[256]; safef(fullname, sizeof fullname, "plus_%s_all_%s_%s" , class, left ? "left" : "right", top ? "top" : "bottom"); -PM_MAKE_BUTTON_UC("true", ",'", class, "'", "", "", fullname, "add_sm.gif") +PM_MAKE_BUTTON_UC("true", ",", class, "", "", "", fullname, "add_sm.gif") if (vertical) puts("<BR>"); safef(fullname, sizeof fullname, "minus_%s_all_%s_%s", class, left ? "left" : "right", top ? "top" : "bottom"); -PM_MAKE_BUTTON_UC("false", ",'", class, "'", "", "", fullname, "remove_sm.gif") +PM_MAKE_BUTTON_UC("false", ",", class, "", "", "", fullname, "remove_sm.gif") } #define MATRIX_SQUEEZE 10 static boolean matrixSqueeze(membersForAll_t* membersForAll) // Returns non-zero if the matrix will be squeezed. Non-zero is actually squeezedLabelHeight { char *browserVersion; if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '9') return 0; members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; if (dimensionX && dimensionY) { if (dimensionX->count>MATRIX_SQUEEZE) @@ -8825,48 +8825,48 @@ // prints the column of Y labels and buttons { members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; struct trackDb *childTdb = NULL; if (dimensionY && dimensionY->subtrackList && dimensionY->subtrackList[ixY] && dimensionY->subtrackList[ixY]->val) childTdb = dimensionY->subtrackList[ixY]->val; if (dimensionX && dimensionY && childTdb != NULL) // Both X and Y, then column of buttons { printf("<TH class='matCell all %s' ALIGN=%s nowrap colspan=2>", - dimensionY->tags[ixY],left?"RIGHT":"LEFT"); + htmlEncode(dimensionY->tags[ixY]),left?"RIGHT":"LEFT"); if (left) printf("%s ",compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag, dimensionY->titles[ixY])); buttonsForOne(dimensionY->tags[ixY], FALSE, left, FALSE); if (!left) printf(" %s",compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag, dimensionY->titles[ixY])); puts("</TH>"); } else if (dimensionX) { printf("<TH ALIGN=%s>",left?"RIGHT":"LEFT"); buttonsForAll(TRUE, TRUE); puts("</TH>"); } else if (left && dimensionY && childTdb != NULL) - printf("<TH class='matCell all %s' ALIGN=RIGHT nowrap>%s</TH>\n",dimensionY->tags[ixY], + printf("<TH class='matCell all %s' ALIGN=RIGHT nowrap>%s</TH>\n",htmlEncode(dimensionY->tags[ixY]), compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag, dimensionY->titles[ixY])); } static int displayABCdimensions(char *db,struct cart *cart, struct trackDb *parentTdb, struct slRef *subtrackRefList, membersForAll_t* membersForAll) // This will walk through all declared nonX&Y dimensions (X and Y is the 2D matrix of CBs. // NOTE: ABC dims are only supported if there are X & Y both. // Also expected number should be passed in { int count=0,ix; for (ix=dimA;ix<membersForAll->dimMax;ix++) { if (membersForAll->members[ix]==NULL) continue; @@ -9228,31 +9228,31 @@ (void)matrixXheadings(db,parentTdb,membersForAll,TRUE); // Now the Y by X matrix int cntX=0,cntY=0; for (ixY = 0; ixY < sizeOfY; ixY++) { if (dimensionY == NULL || (dimensionY->tags[ixY])) { cntY++; assert(!dimensionY || ixY < dimensionY->count); printf("<TR ALIGN=CENTER>"); matrixYheadings(db,parentTdb, membersForAll,ixY,TRUE); #define MAT_CB_SETUP "<INPUT TYPE=CHECKBOX NAME='%s' ID='%s' VALUE=on %s>" -#define MAT_CB(name,js) printf(MAT_CB_SETUP,(name),(name),(js)); +#define MAT_CB(name,js) printf(MAT_CB_SETUP,(htmlEncode(name)),(htmlEncode(name)),(js)); for (ixX = 0; ixX < sizeOfX; ixX++) { if (dimensionX == NULL || (dimensionX->tags[ixX])) { assert(!dimensionX || ixX < dimensionX->count); if (cntY==1) // Only do this on the first good Y cntX++; if (dimensionX && ixX == dimensionX->count) break; char *ttlX = NULL; char *ttlY = NULL; if (dimensionX) { @@ -9272,34 +9272,34 @@ && chked[ixX][ixY] < enabd[ixX][ixY]); struct dyString *dySettings = dyStringNew(256); if (dimensionX && dimensionY) { safef(objName, sizeof(objName), "mat_%s_%s_cb", dimensionX->tags[ixX],dimensionY->tags[ixY]); } else { safef(objName, sizeof(objName), "mat_%s_cb", (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY])); } if (ttlX && ttlY) printf("<TD class='matCell %s %s'>\n", - dimensionX->tags[ixX],dimensionY->tags[ixY]); + htmlEncode(dimensionX->tags[ixX]),htmlEncode(dimensionY->tags[ixY])); else printf("<TD class='matCell %s'>\n", - (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY])); + htmlEncode(dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY])); dyStringPrintf(dySettings, " class=\"matCB"); if (halfChecked) dyStringPrintf(dySettings, " disabled"); // appears disabled but still clickable! if (dimensionX) dyStringPrintf(dySettings, " %s",dimensionX->tags[ixX]); if (dimensionY) dyStringPrintf(dySettings, " %s",dimensionY->tags[ixY]); dyStringAppendC(dySettings,'"'); if (chked[ixX][ixY] > 0) dyStringAppend(dySettings," CHECKED"); if (halfChecked) dyStringAppend(dySettings," title='Not all associated subtracks have been selected'"); MAT_CB(objName,dyStringCannibalize(&dySettings)); jsOnEventById("click", objName, "matCbClick(this);"); // X&Y are set by javascript