4037b582757f86eed1c5559eca9ccc7af85c1496
braney
  Fri Aug 21 10:00:49 2026 -0700
lib: add htmlSanitize, an allowlist filter for HTML written elsewhere, refs #38126

htmlSanitize() takes a piece of HTML and returns a copy holding only the
elements, attributes and style properties on its lists.  An element on the
keep list survives with its allowed attributes.  A short list of elements
that carry nothing for a reader, script and style and form among them, is
dropped along with its contents.  Every other element loses its tag and
keeps its text, so a whole document that somebody saved and pasted in comes
out as the article it was meant to be.

The lists come from a survey of all 5390 description pages reachable from
the public hub list, so they are sized to what hubs actually write.  The
style attribute is filtered a property at a time, and href and src are
checked for a scheme we do not print, after decoding entities and padding.
An iframe is kept only when it plays a video from one of a few hosts, and
then with a sandbox attribute.

htmlSanitizeReport() returns the same copy plus a list of one-line messages
naming what came out, for hubCheck to show a hub author.

The tokenizer is hand written and forgiving.  It never aborts and always
returns something, because the HTML it will be handed is often broken.
lib/htmlPage.c cannot be reused for this: its parser aborts on bad input.

diff --git src/lib/makefile src/lib/makefile
index b17d260f20c..572178b2892 100644
--- src/lib/makefile
+++ src/lib/makefile
@@ -14,31 +14,32 @@
     dgRange.o diGraph.o dlist.o dnaLoad.o dnaMarkov.o dnaMotif.o dnaseq.o \
     dnautil.o dtdParse.o dyOut.o dystring.o elmTree.o \
     emblParse.o errCatch.o errAbort.o \
     fa.o ffAli.o ffScore.o fieldedTable.o filePath.o fixColor.o flydna.o fof.o \
     font/mgCourier10.o font/mgCourier12.o font/mgCourier14.o font/mgCourier18.o \
     font/mgCourier24.o font/mgCourier34.o font/mgCourier8.o font/mgHelvetica10.o \
     font/mgHelvetica12.o font/mgHelvetica14.o font/mgHelvetica18.o font/mgHelvetica24.o \
     font/mgHelvetica34.o font/mgHelvetica8.o font/mgHelveticaBold10.o font/mgHelveticaBold12.o \
     font/mgHelveticaBold14.o font/mgHelveticaBold18.o font/mgHelveticaBold24.o \
     font/mgHelveticaBold34.o font/mgHelveticaBold8.o font/mgSixhi6.o font/mgSail8.o \
     font/mgTimes10.o font/mgTimes12.o font/mgTimes14.o font/mgTimes18.o \
     font/mgTimes24.o font/mgTimes34.o font/mgTimes8.o font/mgMenlo12.o \
     fq.o freeType.o fuzzyShow.o \
     gapCalc.o gdf.o gemfont.o genomeRangeTree.o \
     gfNet.o gff.o gff3.o gfxPoly.o gifLabel.o \
-    hacTree.o hash.o hex.o hfileUdc.o histogram.o hmmPfamParse.o hmmstats.o htmlColor.o htmlPage.o htmshell.o \
+    hacTree.o hash.o hex.o hfileUdc.o histogram.o hmmPfamParse.o hmmstats.o htmlColor.o htmlPage.o \
+    htmlSanitize.o htmshell.o \
     hmac.o https.o intExp.o intValTree.o internet.o itsa.o iupac.o \
     jointalign.o jpegSize.o jsonParse.o jsonQuery.o jsonWrite.o \
     keys.o knetUdc.o kxTok.o linefile.o lineFileOnBigBed.o localmem.o log.o longTabix.o longToList.o \
     maf.o mafFromAxt.o mafScore.o mailViaPipe.o md5.o \
     matrixMarket.o memalloc.o memgfx.o meta.o metaWig.o mgCircle.o \
     mgPolygon.o mime.o mmHash.o net.o nib.o nibTwo.o nt4.o numObscure.o \
     obscure.o oldGff.o oligoTm.o options.o osunix.o pairHmm.o pairDistance.o \
     paraFetch.o peakCluster.o \
     phyloTree.o pipeline.o portimpl.o pngwrite.o psGfx.o psPoly.o pscmGfx.o \
     psl.o pslGenoShow.o pslShow.o pslTbl.o pslTransMap.o pthreadDoList.o pthreadWrap.o \
     qa.o quickHeap.o quotedP.o \
     ra.o rainbow.o raToStruct.o rbTree.o rangeTree.o regexHelper.o repMask.o \
     rle.o rnautil.o rqlEval.o rqlParse.o rqlToSql.o rudp.o \
     scoreWindow.o seg.o seqOut.o seqStats.o servBrcMcw.o servCrunx.o \
     servcis.o servcl.o servmsII.o servpws.o shaRes.o slog.o snof.o \