a1d7c07c50f1d895337de121680ea672b261c058 max Mon Aug 17 02:26:36 2026 -0700 escape reflected/echoed user input across several CGIs (XSS), refs #38057 Route user-, DB- and hub-derived values through htmlEncode (HTML/attribute text), cgiEncode (values composed into URLs), jsonStringEscape (values placed in a JS string literal inside an inline script) or, for hgMirror, the existing mustBeClean sanitizer. Covers hgHubConnect, hgUserSuggestion, hgLiftOver, hgBlat, hgc pubs, hgVisiGene, hgSession, hgTrackUi, hgGenome, phyloPng, hgFileSearch, hgLinkIn, hgPal, hui, hgPhyloPlace, hgMirror, hgCustom and hgSearch. diff --git src/hg/hgGenome/mainPage.c src/hg/hgGenome/mainPage.c index c7145456375..c10dc02cca7 100644 --- src/hg/hgGenome/mainPage.c +++ src/hg/hgGenome/mainPage.c @@ -1,694 +1,694 @@ /* mainPage - draws the main hgGenome page, including some controls * on the top and the graphic. */ /* Copyright (C) 2013 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "psGfx.h" #include "pscmGfx.h" #include "linefile.h" #include "hash.h" #include "cheapcgi.h" #include "htmshell.h" #include "cart.h" #include "hui.h" #include "dbDb.h" #include "ra.h" #include "hdb.h" #include "web.h" #include "portable.h" #include "hgColors.h" #include "trackLayout.h" #include "chromInfo.h" #include "hvGfx.h" #include "genoLay.h" #include "cytoBand.h" #include "hCytoBand.h" #include "errCatch.h" #include "chromGraph.h" #include "customTrack.h" #include "hPrint.h" #include "jsHelper.h" #include "hgGenome.h" #include "trashDir.h" static char *allColors[] = { "black", "blue", "purple", "red", "orange", "yellow", "green", "gray", }; static char *defaultColors[maxLinesOfGraphs][maxGraphsPerLine] = { {"blue", "red", "black", "yellow", }, {"gray", "purple", "green", "orange",}, {"blue", "red", "black", "yellow", }, {"gray", "purple", "green", "orange",}, {"blue", "red", "black", "yellow", }, {"gray", "purple", "green", "orange",}, }; char *graphColorAt(int row, int col) /* Return graph color at given row/column, NULL if nonw. */ { char *varName = graphColorVarName(row, col); char *color = cartUsualString(cart, varName, defaultColors[row][col]); if (color == NULL) color = defaultColors[0][0]; return color; } Color colorFromAscii(struct hvGfx *hvg, char *asciiColor) /* Get color index for a named color. */ { if (sameWord("red", asciiColor)) return MG_RED; else if (sameWord("blue", asciiColor)) return MG_BLUE; else if (sameWord("yellow", asciiColor)) return hvGfxFindColorIx(hvg, 220, 220, 0); else if (sameWord("purple", asciiColor)) return hvGfxFindColorIx(hvg, 150, 0, 200); else if (sameWord("orange", asciiColor)) return hvGfxFindColorIx(hvg, 230, 120, 0); else if (sameWord("green", asciiColor)) return hvGfxFindColorIx(hvg, 0, 180, 0); else if (sameWord("gray", asciiColor)) return MG_GRAY; else return MG_BLACK; } /* Page drawing stuff. */ void drawChromGraph(struct hvGfx *hvg, struct sqlConnection *conn, struct genoLay *gl, char *chromGraph, int yOff, int height, Color color, boolean leftLabel, boolean rightLabel, boolean firstInRow) /* Draw chromosome graph on all chromosomes in layout at given * y offset and height. */ { boolean yellowMissing = getYellowMissing(); struct genoGraph *gg = hashFindVal(ggHash, chromGraph); if (gg != NULL) { /* Get binary data source and scaling info etc. */ struct chromGraphBin *cgb = gg->cgb; struct chromGraphSettings *cgs = gg->settings; int maxGapToFill = cgs->maxGapToFill; static struct rgbColor missingDataColor = { 180, 180, 120, 255}; Color missingColor = hvGfxFindRgb(hvg, &missingDataColor); double pixelsPerBase = 1.0/gl->basesPerPixel; double gMin = cgs->minVal, gMax = cgs->maxVal, gScale; gScale = height/(gMax-gMin); /* Draw significance threshold as a light blue line */ if (leftLabel) { static struct rgbColor guidelineColor = { 220, 220, 255, 255}; Color lightBlue = hvGfxFindRgb(hvg, &guidelineColor); struct slRef *ref; struct genoLayChrom *chrom; int rightX = gl->picWidth - gl->rightLabelWidth - gl->margin; int leftX = gl->leftLabelWidth + gl->margin; int width = rightX - leftX; double threshold = getThreshold(); if (threshold >= gMin && threshold <= gMax) { int y = height - ((threshold - gMin)*gScale) + yOff; for (ref = gl->leftList; ref != NULL; ref = ref->next) { chrom = ref->val; hvGfxBox(hvg, leftX, y + chrom->y, width, 1, lightBlue); } ref = gl->bottomList; if (ref != NULL) { chrom = ref->val; hvGfxBox(hvg, leftX, y + chrom->y, width, 1, lightBlue); } } } /* Draw graphs on each chromosome */ chromGraphBinRewind(cgb); while (chromGraphBinNextChrom(cgb)) { struct genoLayChrom *chrom = hashFindVal(gl->chromHash, cgb->chrom); if (chrom) { int chromX = chrom->x, chromY = chrom->y; int minY = chromY + yOff; int maxY = chromY + yOff + height - 1; if (chromGraphBinNextVal(cgb)) { /* Set clipping so can't scribble outside of box. */ hvGfxSetClip(hvg, chromX, chromY, chrom->width+1, chrom->height); /* Handle first point as special case here, so don't * have to test for first point in inner loop. */ double x,lastX; int y,start,lastStart,lastY; start = lastStart = cgb->chromStart; x = lastX = pixelsPerBase*start + chromX; y = lastY = (height - ((cgb->val - gMin)*gScale)) + chromY+yOff; if (y < minY) y = minY; else if (y > maxY) y = maxY; struct pscmGfx *pscm = NULL; if (hvg->pixelBased) { hvGfxDot(hvg, x, y, color); } else { pscm = (struct pscmGfx *)hvg->vg->data; pscmSetColor(pscm, color); psFillEllipse(pscm->ps, x, y, 0.01, 0.01); psSetLineWidth(pscm->ps, 0.01); } /* Draw rest of points, connecting with line to previous point * if not too far off. */ while (chromGraphBinNextVal(cgb)) { start = cgb->chromStart; x = pixelsPerBase*start + chromX; if (hvg->pixelBased) x = (int) x; y = (height - ((cgb->val - gMin)*gScale)) + chromY+yOff; if (y < minY) y = minY; else if (y > maxY) y = maxY; if (x != lastX || y != lastY) { if (start - lastStart <= maxGapToFill) { if (hvg->pixelBased) hvGfxLine(hvg, lastX, lastY, x, y, color); else { pscmSetColor(pscm, color); psDrawLine(pscm->ps, lastX, lastY, x, y); } } else { if (yellowMissing && leftLabel) { int width = x - lastX - 1; if (width > 0) hvGfxBox(hvg, lastX+1, minY, width, height, missingColor); } if (hvg->pixelBased) { hvGfxDot(hvg, x, y, color); } else { pscmSetColor(pscm, color); psFillEllipse(pscm->ps, x, y, 0.01, 0.01); } } } lastX = x; lastY = y; lastStart = start; } if (!hvg->pixelBased) { psSetLineWidth(pscm->ps, 1); } hvGfxUnclip(hvg); } } else { /* Just read and discard data. */ while (chromGraphBinNextVal(cgb)) ; } } /* Draw labels. */ if (withLabels && (leftLabel || rightLabel)) { int lineY = yOff; int i,j; int spaceWidth = tl.nWidth; int tickWidth = spaceWidth*2/3; int fontPixelHeight = mgFontPixelHeight(gl->font); for (i=0; ilineCount; ++i) { hvGfxSetClip(hvg, 0, lineY, gl->picWidth, gl->lineHeight); for (j=0; j< cgs->linesAtCount; ++j) { double lineAt = cgs->linesAt[j]; int y = (height - ((lineAt - gMin)*gScale)) + lineY; int textTop = y - fontPixelHeight/2+1; int textBottom = textTop + fontPixelHeight; char label[24]; safef(label, sizeof(label), "%g", lineAt); if (leftLabel) { hvGfxBox(hvg, gl->margin + gl->leftLabelWidth - tickWidth-1, y, tickWidth, 1, color); if (textTop >= lineY && textBottom < lineY + height) { hvGfxTextRight(hvg, gl->margin, textTop, gl->leftLabelWidth-spaceWidth, fontPixelHeight, color, gl->font, label); } } if (rightLabel) { hvGfxBox(hvg, gl->picWidth - gl->margin - gl->rightLabelWidth+1, y, tickWidth, 1, color); if (textTop >= lineY && textBottom < lineY + height) { hvGfxText(hvg, gl->picWidth - gl->margin - gl->rightLabelWidth + spaceWidth, textTop, color, gl->font, label); } } } lineY += gl->lineHeight; hvGfxUnclip(hvg); } } } } void genomeGif(struct sqlConnection *conn, struct genoLay *gl, int graphRows, int graphCols, int oneRowHeight, char *psOutput) /* Create genome GIF file and HTML that includes it. */ { struct hvGfx *hvg; struct tempName gifTn; Color shadesOfGray[10]; int maxShade = ArraySize(shadesOfGray)-1; int spacing = 1; int yOffset = 2*spacing; int innerHeight = oneRowHeight - 3*spacing; int i,j; if (psOutput) { hvg = hvGfxOpenPostScript(gl->picWidth, gl->picHeight, psOutput); } else { /* Create gif file and make reference to it in html. */ trashDirFile(&gifTn, "hgg", "ideo", ".png"); hvg = hvGfxOpenPng(gl->picWidth, gl->picHeight, gifTn.forCgi, FALSE); hPrintf("", gifTn.forHtml, gl->picWidth, gl->picHeight, hggClick); } /* Get our grayscale. */ hMakeGrayShades(hvg, shadesOfGray, maxShade); /* Draw the labels and then the chromosomes. */ genoLayDrawChromLabels(gl, hvg, MG_BLACK); genoLayDrawBandedChroms(gl, hvg, database, conn, shadesOfGray, maxShade, MG_BLACK); /* Draw chromosome graphs. */ for (i=0; i=0; --j) { char *graph = graphSourceAt(i,j); if (graph != NULL && graph[0] != 0) { Color color = colorFromAscii(hvg, graphColorAt(i,j)); drawChromGraph(hvg, conn, gl, graph, gl->betweenChromOffsetY + yOffset, innerHeight, color, j==0, j==1, firstInRow); firstInRow = FALSE; } } yOffset += oneRowHeight; } hvGfxBox(hvg, 0, 0, gl->picWidth, 1, MG_GRAY); hvGfxBox(hvg, 0, gl->picHeight-1, gl->picWidth, 1, MG_GRAY); hvGfxBox(hvg, 0, 0, 1, gl->picHeight, MG_GRAY); hvGfxBox(hvg, gl->picWidth-1, 0, 1, gl->picHeight, MG_GRAY); hvGfxClose(&hvg); } void graphDropdown(struct sqlConnection *conn, char *varName, char *curVal, char *event, char *js) /* Make a drop-down with available chrom graphs */ { int totalCount = 1; char **menu, **values; int i = 0; struct slRef *ref; for (ref = ggList; ref != NULL; ref = ref->next) { struct genoGraph *gg = ref->val; if (gg->isComposite == FALSE) totalCount++; } AllocArray(menu, totalCount); AllocArray(values, totalCount); menu[0] = "-- nothing --"; values[0] = ""; for (ref = ggList; ref != NULL; ref = ref->next) { struct genoGraph *gg = ref->val; if (gg->isComposite == FALSE) { ++i; - menu[i] = gg->shortLabel; + menu[i] = htmlEncode(gg->shortLabel); // user graph label in dropdown text, escape (XSS) values[i] = gg->name; } } cgiMakeDropListFull(varName, menu, values, totalCount, curVal, event, js); freez(&menu); freez(&values); } void colorDropdown(int row, int col, char *event, char *js) /* Put up color drop down menu. */ { char *varName = graphColorVarName(row, col); char *curVal = graphColorAt(row, col); cgiMakeDropListFull(varName, allColors, allColors, ArraySize(allColors), curVal, event, js); } static void addThresholdGraphCarries(struct dyString *dy, int graphRows, int graphCols, boolean cgaOnly) /* Add javascript that carries over threshold and graph vars * to new form. */ { if (cgaOnly) return; jsTextCarryOver(dy, getThresholdName()); int i,j; for (i=0; i