e035146f3dc0ce0eaac009b1a37b416b31b068ea galt Wed Aug 1 13:37:07 2018 -0700 refs #21729. Added CSP and nonce and javascript-separation routines to the Python library hgLib in PyLib. Changed hgGeneGraph to use those functions and stop XSS attacks. Modified commit for demonstration. diff --git src/hg/hgGeneGraph/hgGeneGraph src/hg/hgGeneGraph/hgGeneGraph index 9ac9129..c6a271b 100755 --- src/hg/hgGeneGraph/hgGeneGraph +++ src/hg/hgGeneGraph/hgGeneGraph @@ -28,32 +28,32 @@ # ggLinkEvent (details about link), ggEventDb (details about links from databases), # ggEventText (details about links from text mining), ggDoc (details about documents for ggEventText) # ggGeneName (symbols), ggGeneClass (HPRD/Panther class) # these are default python modules on python 2.7, no errors expected here import sys, cgi, os, string, urllib, operator, hashlib from sys import exit from collections import defaultdict, namedtuple from os.path import * # import the UCSC-specific library sys.path.append(join(dirname(__file__), "pyLib")) try: from hgLib import cgiArgs, cgiSetup, cgiString, printContentType, printMenuBar, \ sqlConnect, sqlQuery, errAbort, cfgOption, runCmd, cgiGetAll, printHgcHeader, \ - printHgcSection, webStartGbNoBanner, htmlPageEnd, hConnectCentral, sqlTableExists, \ - readSmallFile + printHgcSection, getNonce, getCspMetaHeader, jsOnEventById, jsInlineFinish, webStartGbNoBanner, htmlPageEnd, hConnectCentral, sqlTableExists, \ + readSmallFil except: print("Content-type: text/html\n") print("Cannot find the directory cgi-bin/pyLib in Apache. This is an installation error.") print("All all parts of cgi-bin installed? Did you do 'make' in kent/src/hg/pyLib?") import MySQLdb # not using feedback button for now. Fan would have liked it, but not sure how we can write # to any form of database. # the list of allowed chars in cgi args: digits, letters and dashes legalChars = set(string.digits) legalChars.update(set(string.letters)) legalChars.update("_-./: ") @@ -133,31 +133,31 @@ #<script src="//code.jquery.com/jquery-1.10.2.js"></script> #<script src="//code.jquery.com/ui/1.11.0/jquery-ui.js"></script> #<script src="../js/readmore.min.js"></script> #<link rel="stylesheet" href="//code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css"> #<link rel="stylesheet" href="../style/HGStyle.css" type="text/css" /> #<link rel='stylesheet' href='../style/nice_menu.css' type='text/css' /> def printInlineAndStyles(): #print('<script src="//code.jquery.com/ui/1.11.0/jquery-ui.js"></script>') print('<script src="//cdn.rawgit.com/jedfoster/Readmore.js/master/readmore.min.js"></script>') print(""" -<script type="text/javascript"> +<script type="text/javascript" nonce='%s'> $(function() { //$( document ).uitooltip(); //$( document ).uitooltip(); $('[data-toggle="tooltip"]').bsTooltip(); // bootstrap does not really allow HTML in the title attribute // use jquery ui tooltips for the graph var opt = { items: "area", track : true, content: function() {return $(this).prop('title')} }; $("area").uitooltip(opt); // when user opens annotate genes menu, close the tooltip //$('#colorLink').click( function () { console.log($(this)); $(this).tooltip("close"); } ); @@ -203,35 +203,35 @@ } .ui-tooltip { font-size:10pt; font-family:Helvetica; padding: 3px; } ul { padding-left: 15px; margin: 0px; padding-top:3px;} .tooltip.right { margin-left: 20px; } .tooltip.left { margin-left: -20px; } </style> - """) + """ % getNonce()) def htmlHeader(): " print start of page " - webStartGbNoBanner("", "Genome Browser Gene Interaction Graph") + webStartGbNoBanner(getCspMetaHeader(), "Genome Browser Gene Interaction Graph") print('<body class="hgc cgi">') printMenuBar() db = getCgiVar("db") printHgcHeader(db, "Gene Interactions Track", "Gene interactions and pathways from curated databases and text-mining", addGoButton=False, infoUrl=MANUALURL, infoMouseOver="Open help page") def mustBeClean(str): """ make sure a string contains only letters and digits """ if str==None: return str str = urllib.unquote(str) @@ -886,99 +886,104 @@ q = 'SELECT text from ggGeneClass where gene="%s"' % gene rows = sqlQuery(conn, q) if len(rows)!=0: geneDescs[gene].append(rows[0].text) return geneDescs def printHttpHead(format): " print content type header " mimeType = mimeTypes[format] print "Content-Type: %s" % mimeType if format in ["pdf", "svg", "sif"]: fname = "graph."+format print "Content-Disposition: attachment; filename=%s" % fname print -def printCheckbox(name, isChecked, addAttr): +def printCheckbox(name, isChecked, event, codeStr): " print a html checkbox " addStr = "" if isChecked: addStr = 'checked="true" ' - print '<input type="checkbox" name="%s" value="on" %s%s />' % (name, addStr, addAttr) + print '<input type="checkbox" id="%s" name="%s" value="on" %s />' % (name, name, addStr) + if event != "": + jsOnEventById(event, name, codeStr) def getFilterStatus(): """ return a set of the support tags that should be shown, based on the CGI var 'supportLevel'. """ supportLevel = getCgiVar("supportLevel", "text") tagSet = set(["pwy"]) if supportLevel=="ppi" or supportLevel=="text": tagSet.add("ppi") if supportLevel=="text": tagSet.add("text") return tagSet -def printDropdown(cgiArgName, selectedName, options, addStr=""): +def printDropdown(cgiArgName, selectedName, options, event="", codeStr=""): " print a html dropdown <select> box. " - print("<select name='%s'%s>" % (cgiArgName, addStr)) + print("<select id='%s' name='%s'>" % (cgiArgName, cgiArgName)) for name, label in options: addStr = "" if name==selectedName: addStr = " selected" - print('<option value="%s"%s>%s</option>' % (name, addStr, label)) print("</select>") + if event != "": + jsOnEventById(event, cgiArgName, codeStr) + def printFilterMenu(targetGene, addNeighbors): # form to filter by type print "<small>" print '<form name="filterForm" action="%s" method="GET">' % makeSelfUrl({}, True) print """<b>Gene:</b>""" print '<input type="text" size="10" name="gene" value="%s" />' % targetGene print " " print '<input type="submit" name="1" value="OK">' print " " supportLevel = getCgiVar("supportLevel", "text") if supportLevel not in ["text", "pwy", "ppi"]: errAbort("Illegal value for the supportLevel argument. Can only be text,pwy or ppi.") - onChangeAttr = '''onchange="document.forms['filterForm'].submit();"''' + event = "change" + codeStr = "document.forms['filterForm'].submit();" - printDropdown("supportLevel", supportLevel, [("text", "Show all interactions, even only text-mining support"), ("ppi", "Show only interactions with some database support"), ("pwy", "Show only interactions with pathway database support")], addStr=onChangeAttr ) + printDropdown("supportLevel", supportLevel, [("text", "Show all interactions, even only text-mining support"), ("ppi", "Show only interactions with some database support"), ("pwy", "Show only interactions with pathway database support")], event, codeStr ) #filterTags = getFilterStatus() #printCheckbox("pwy", "pwy" in filterTags, onChangeAttr) #print '<span style="background:%s;color:white" title="Show interactions manually curated by a pathway database, like WikiPathways, KEGG or Reactome, in dark-blue" onclick="">Pathways</span>' % LTCOLOR #printCheckbox("ppi", "ppi" in filterTags, onChangeAttr) #print '<span style="background:%s;color:white" title="Show interactions manually curated by a protein interaction database, like IntAct or BioGrid, in light-blue">Protein Interaction</span>' % HTCOLOR #printCheckbox("text", "text" in filterTags, onChangeAttr) #print '<span style="background:%s;color:white" title="Show interactions automatically extracted from PubMed abstracts with text-mining software in grey." onclick="">Text-Mining</span>' % TEXTCOLOR print " " #if addNeighbors: #addNeighborLink = makeSelfLink("Show only %s links" % targetGene, {"onlyDirect":"1"}) #print("Only %s-interacting genes and only the most-mentioned interactions are shown. (%s)<br>" % (targetGene, noNeighborLink)) #else: #addNeighborLink = makeSelfLink("Show links between neighbors", {"onlyDirect":None}) #print("Only %s interactions are shown (%s)<br>" % (targetGene, addNeighborLink)) #print(addNeighborLink) hideIndirectStatus = (getCgiVar("hideIndirect")=="on") - printCheckbox("hideIndirect", hideIndirectStatus, onChangeAttr) + printCheckbox("hideIndirect", hideIndirectStatus, event, codeStr) print '<span style="font-weight:bold">Hide non-%s interactions</span>' % targetGene print " " geneCount = getCgiVar("geneCount", DEFGENECOUNT) print "<b>Show top" print '<input name="geneCount" type="text" size="3" value="%s">' % geneCount print "Genes on graph</b>" print " " printSelfHiddenVars({}, skipList=["supportLevel", "hideIndirect", "gene"]) print "</form>" print "</small>" def printDropDownMenu(label, entries, tooltip, selectedLabel=None): @@ -2007,18 +2012,19 @@ graphLinks, lowLinks = buildGraph(conn, gene, geneCount, MINSUPP, addNeighbors) weightedLinks, minAbsCount = flattenLink(graphLinks) printGraph(conn, weightedLinks, alg, addNeighbors, gene, format) sys.exit(0) printContentType() if cgiString("debug") is not None: global DEBUG DEBUG = True htmlHeader() printInlineAndStyles() htmlMiddle() + jsInlineFinish() htmlPageEnd() main()