spamscanner 7.0.10 → 7.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/arf.cjs.map +1 -1
- package/dist/cjs/index.cjs +1456 -191
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/esm/arf.js.map +1 -1
- package/dist/esm/cli.js +1392 -142
- package/dist/esm/cli.js.map +4 -4
- package/dist/esm/index.js +1423 -174
- package/dist/esm/index.js.map +4 -4
- package/dist/types/attachments.d.ts +1 -0
- package/dist/types/entities.d.ts +2 -0
- package/dist/types/html.d.ts +2 -2
- package/dist/types/index.d.ts +26 -6
- package/dist/types/links.d.ts +26 -0
- package/dist/types/parse.d.ts +1 -1
- package/dist/types/tokenizer.d.ts +9 -0
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -1624,6 +1624,286 @@ var init_homograph = __esm({
|
|
|
1624
1624
|
}
|
|
1625
1625
|
});
|
|
1626
1626
|
|
|
1627
|
+
// src/entities.js
|
|
1628
|
+
var NAMED, NAMED_REFERENCES;
|
|
1629
|
+
var init_entities = __esm({
|
|
1630
|
+
"src/entities.js"() {
|
|
1631
|
+
NAMED = [
|
|
1632
|
+
"AElig=c6,AMP=26,Aacute=c1,Abreve=102,Acirc=c2,Acy=410,Afr=1d504,Agrave=c0,Alpha=391,Amacr=100,And=2a",
|
|
1633
|
+
"53,Aogon=104,Aopf=1d538,ApplyFunction=2061,Aring=c5,Ascr=1d49c,Assign=2254,Atilde=c3,Auml=c4,Backsla",
|
|
1634
|
+
"sh=2216,Barv=2ae7,Barwed=2306,Bcy=411,Because=2235,Bernoullis=212c,Beta=392,Bfr=1d505,Bopf=1d539,Bre",
|
|
1635
|
+
"ve=2d8,Bscr=212c,Bumpeq=224e,CHcy=427,COPY=a9,Cacute=106,Cap=22d2,CapitalDifferentialD=2145,Cayleys=",
|
|
1636
|
+
"212d,Ccaron=10c,Ccedil=c7,Ccirc=108,Cconint=2230,Cdot=10a,Cedilla=b8,CenterDot=b7,Cfr=212d,Chi=3a7,C",
|
|
1637
|
+
"ircleDot=2299,CircleMinus=2296,CirclePlus=2295,CircleTimes=2297,ClockwiseContourIntegral=2232,CloseC",
|
|
1638
|
+
"urlyDoubleQuote=201d,CloseCurlyQuote=2019,Colon=2237,Colone=2a74,Congruent=2261,Conint=222f,ContourI",
|
|
1639
|
+
"ntegral=222e,Copf=2102,Coproduct=2210,CounterClockwiseContourIntegral=2233,Cross=2a2f,Cscr=1d49e,Cup",
|
|
1640
|
+
"=22d3,CupCap=224d,DD=2145,DDotrahd=2911,DJcy=402,DScy=405,DZcy=40f,Dagger=2021,Darr=21a1,Dashv=2ae4,",
|
|
1641
|
+
"Dcaron=10e,Dcy=414,Del=2207,Delta=394,Dfr=1d507,DiacriticalAcute=b4,DiacriticalDot=2d9,DiacriticalDo",
|
|
1642
|
+
"ubleAcute=2dd,DiacriticalGrave=60,DiacriticalTilde=2dc,Diamond=22c4,DifferentialD=2146,Dopf=1d53b,Do",
|
|
1643
|
+
"t=a8,DotDot=20dc,DotEqual=2250,DoubleContourIntegral=222f,DoubleDot=a8,DoubleDownArrow=21d3,DoubleLe",
|
|
1644
|
+
"ftArrow=21d0,DoubleLeftRightArrow=21d4,DoubleLeftTee=2ae4,DoubleLongLeftArrow=27f8,DoubleLongLeftRig",
|
|
1645
|
+
"htArrow=27fa,DoubleLongRightArrow=27f9,DoubleRightArrow=21d2,DoubleRightTee=22a8,DoubleUpArrow=21d1,",
|
|
1646
|
+
"DoubleUpDownArrow=21d5,DoubleVerticalBar=2225,DownArrow=2193,DownArrowBar=2913,DownArrowUpArrow=21f5",
|
|
1647
|
+
",DownBreve=311,DownLeftRightVector=2950,DownLeftTeeVector=295e,DownLeftVector=21bd,DownLeftVectorBar",
|
|
1648
|
+
"=2956,DownRightTeeVector=295f,DownRightVector=21c1,DownRightVectorBar=2957,DownTee=22a4,DownTeeArrow",
|
|
1649
|
+
"=21a7,Downarrow=21d3,Dscr=1d49f,Dstrok=110,ENG=14a,ETH=d0,Eacute=c9,Ecaron=11a,Ecirc=ca,Ecy=42d,Edot",
|
|
1650
|
+
"=116,Efr=1d508,Egrave=c8,Element=2208,Emacr=112,EmptySmallSquare=25fb,EmptyVerySmallSquare=25ab,Eogo",
|
|
1651
|
+
"n=118,Eopf=1d53c,Epsilon=395,Equal=2a75,EqualTilde=2242,Equilibrium=21cc,Escr=2130,Esim=2a73,Eta=397",
|
|
1652
|
+
",Euml=cb,Exists=2203,ExponentialE=2147,Fcy=424,Ffr=1d509,FilledSmallSquare=25fc,FilledVerySmallSquar",
|
|
1653
|
+
"e=25aa,Fopf=1d53d,ForAll=2200,Fouriertrf=2131,Fscr=2131,GJcy=403,GT=3e,Gamma=393,Gammad=3dc,Gbreve=1",
|
|
1654
|
+
"1e,Gcedil=122,Gcirc=11c,Gcy=413,Gdot=120,Gfr=1d50a,Gg=22d9,Gopf=1d53e,GreaterEqual=2265,GreaterEqual",
|
|
1655
|
+
"Less=22db,GreaterFullEqual=2267,GreaterGreater=2aa2,GreaterLess=2277,GreaterSlantEqual=2a7e,GreaterT",
|
|
1656
|
+
"ilde=2273,Gscr=1d4a2,Gt=226b,HARDcy=42a,Hacek=2c7,Hat=5e,Hcirc=124,Hfr=210c,HilbertSpace=210b,Hopf=2",
|
|
1657
|
+
"10d,HorizontalLine=2500,Hscr=210b,Hstrok=126,HumpDownHump=224e,HumpEqual=224f,IEcy=415,IJlig=132,IOc",
|
|
1658
|
+
"y=401,Iacute=cd,Icirc=ce,Icy=418,Idot=130,Ifr=2111,Igrave=cc,Im=2111,Imacr=12a,ImaginaryI=2148,Impli",
|
|
1659
|
+
"es=21d2,Int=222c,Integral=222b,Intersection=22c2,InvisibleComma=2063,InvisibleTimes=2062,Iogon=12e,I",
|
|
1660
|
+
"opf=1d540,Iota=399,Iscr=2110,Itilde=128,Iukcy=406,Iuml=cf,Jcirc=134,Jcy=419,Jfr=1d50d,Jopf=1d541,Jsc",
|
|
1661
|
+
"r=1d4a5,Jsercy=408,Jukcy=404,KHcy=425,KJcy=40c,Kappa=39a,Kcedil=136,Kcy=41a,Kfr=1d50e,Kopf=1d542,Ksc",
|
|
1662
|
+
"r=1d4a6,LJcy=409,LT=3c,Lacute=139,Lambda=39b,Lang=27ea,Laplacetrf=2112,Larr=219e,Lcaron=13d,Lcedil=1",
|
|
1663
|
+
"3b,Lcy=41b,LeftAngleBracket=27e8,LeftArrow=2190,LeftArrowBar=21e4,LeftArrowRightArrow=21c6,LeftCeili",
|
|
1664
|
+
"ng=2308,LeftDoubleBracket=27e6,LeftDownTeeVector=2961,LeftDownVector=21c3,LeftDownVectorBar=2959,Lef",
|
|
1665
|
+
"tFloor=230a,LeftRightArrow=2194,LeftRightVector=294e,LeftTee=22a3,LeftTeeArrow=21a4,LeftTeeVector=29",
|
|
1666
|
+
"5a,LeftTriangle=22b2,LeftTriangleBar=29cf,LeftTriangleEqual=22b4,LeftUpDownVector=2951,LeftUpTeeVect",
|
|
1667
|
+
"or=2960,LeftUpVector=21bf,LeftUpVectorBar=2958,LeftVector=21bc,LeftVectorBar=2952,Leftarrow=21d0,Lef",
|
|
1668
|
+
"trightarrow=21d4,LessEqualGreater=22da,LessFullEqual=2266,LessGreater=2276,LessLess=2aa1,LessSlantEq",
|
|
1669
|
+
"ual=2a7d,LessTilde=2272,Lfr=1d50f,Ll=22d8,Lleftarrow=21da,Lmidot=13f,LongLeftArrow=27f5,LongLeftRigh",
|
|
1670
|
+
"tArrow=27f7,LongRightArrow=27f6,Longleftarrow=27f8,Longleftrightarrow=27fa,Longrightarrow=27f9,Lopf=",
|
|
1671
|
+
"1d543,LowerLeftArrow=2199,LowerRightArrow=2198,Lscr=2112,Lsh=21b0,Lstrok=141,Lt=226a,Map=2905,Mcy=41",
|
|
1672
|
+
"c,MediumSpace=205f,Mellintrf=2133,Mfr=1d510,MinusPlus=2213,Mopf=1d544,Mscr=2133,Mu=39c,NJcy=40a,Nacu",
|
|
1673
|
+
"te=143,Ncaron=147,Ncedil=145,Ncy=41d,NegativeMediumSpace=200b,NegativeThickSpace=200b,NegativeThinSp",
|
|
1674
|
+
"ace=200b,NegativeVeryThinSpace=200b,NestedGreaterGreater=226b,NestedLessLess=226a,NewLine=a,Nfr=1d51",
|
|
1675
|
+
"1,NoBreak=2060,NonBreakingSpace=a0,Nopf=2115,Not=2aec,NotCongruent=2262,NotCupCap=226d,NotDoubleVert",
|
|
1676
|
+
"icalBar=2226,NotElement=2209,NotEqual=2260,NotEqualTilde=2242.338,NotExists=2204,NotGreater=226f,Not",
|
|
1677
|
+
"GreaterEqual=2271,NotGreaterFullEqual=2267.338,NotGreaterGreater=226b.338,NotGreaterLess=2279,NotGre",
|
|
1678
|
+
"aterSlantEqual=2a7e.338,NotGreaterTilde=2275,NotHumpDownHump=224e.338,NotHumpEqual=224f.338,NotLeftT",
|
|
1679
|
+
"riangle=22ea,NotLeftTriangleBar=29cf.338,NotLeftTriangleEqual=22ec,NotLess=226e,NotLessEqual=2270,No",
|
|
1680
|
+
"tLessGreater=2278,NotLessLess=226a.338,NotLessSlantEqual=2a7d.338,NotLessTilde=2274,NotNestedGreater",
|
|
1681
|
+
"Greater=2aa2.338,NotNestedLessLess=2aa1.338,NotPrecedes=2280,NotPrecedesEqual=2aaf.338,NotPrecedesSl",
|
|
1682
|
+
"antEqual=22e0,NotReverseElement=220c,NotRightTriangle=22eb,NotRightTriangleBar=29d0.338,NotRightTria",
|
|
1683
|
+
"ngleEqual=22ed,NotSquareSubset=228f.338,NotSquareSubsetEqual=22e2,NotSquareSuperset=2290.338,NotSqua",
|
|
1684
|
+
"reSupersetEqual=22e3,NotSubset=2282.20d2,NotSubsetEqual=2288,NotSucceeds=2281,NotSucceedsEqual=2ab0.",
|
|
1685
|
+
"338,NotSucceedsSlantEqual=22e1,NotSucceedsTilde=227f.338,NotSuperset=2283.20d2,NotSupersetEqual=2289",
|
|
1686
|
+
",NotTilde=2241,NotTildeEqual=2244,NotTildeFullEqual=2247,NotTildeTilde=2249,NotVerticalBar=2224,Nscr",
|
|
1687
|
+
"=1d4a9,Ntilde=d1,Nu=39d,OElig=152,Oacute=d3,Ocirc=d4,Ocy=41e,Odblac=150,Ofr=1d512,Ograve=d2,Omacr=14",
|
|
1688
|
+
"c,Omega=3a9,Omicron=39f,Oopf=1d546,OpenCurlyDoubleQuote=201c,OpenCurlyQuote=2018,Or=2a54,Oscr=1d4aa,",
|
|
1689
|
+
"Oslash=d8,Otilde=d5,Otimes=2a37,Ouml=d6,OverBar=203e,OverBrace=23de,OverBracket=23b4,OverParenthesis",
|
|
1690
|
+
"=23dc,PartialD=2202,Pcy=41f,Pfr=1d513,Phi=3a6,Pi=3a0,PlusMinus=b1,Poincareplane=210c,Popf=2119,Pr=2a",
|
|
1691
|
+
"bb,Precedes=227a,PrecedesEqual=2aaf,PrecedesSlantEqual=227c,PrecedesTilde=227e,Prime=2033,Product=22",
|
|
1692
|
+
"0f,Proportion=2237,Proportional=221d,Pscr=1d4ab,Psi=3a8,QUOT=22,Qfr=1d514,Qopf=211a,Qscr=1d4ac,RBarr",
|
|
1693
|
+
"=2910,REG=ae,Racute=154,Rang=27eb,Rarr=21a0,Rarrtl=2916,Rcaron=158,Rcedil=156,Rcy=420,Re=211c,Revers",
|
|
1694
|
+
"eElement=220b,ReverseEquilibrium=21cb,ReverseUpEquilibrium=296f,Rfr=211c,Rho=3a1,RightAngleBracket=2",
|
|
1695
|
+
"7e9,RightArrow=2192,RightArrowBar=21e5,RightArrowLeftArrow=21c4,RightCeiling=2309,RightDoubleBracket",
|
|
1696
|
+
"=27e7,RightDownTeeVector=295d,RightDownVector=21c2,RightDownVectorBar=2955,RightFloor=230b,RightTee=",
|
|
1697
|
+
"22a2,RightTeeArrow=21a6,RightTeeVector=295b,RightTriangle=22b3,RightTriangleBar=29d0,RightTriangleEq",
|
|
1698
|
+
"ual=22b5,RightUpDownVector=294f,RightUpTeeVector=295c,RightUpVector=21be,RightUpVectorBar=2954,Right",
|
|
1699
|
+
"Vector=21c0,RightVectorBar=2953,Rightarrow=21d2,Ropf=211d,RoundImplies=2970,Rrightarrow=21db,Rscr=21",
|
|
1700
|
+
"1b,Rsh=21b1,RuleDelayed=29f4,SHCHcy=429,SHcy=428,SOFTcy=42c,Sacute=15a,Sc=2abc,Scaron=160,Scedil=15e",
|
|
1701
|
+
",Scirc=15c,Scy=421,Sfr=1d516,ShortDownArrow=2193,ShortLeftArrow=2190,ShortRightArrow=2192,ShortUpArr",
|
|
1702
|
+
"ow=2191,Sigma=3a3,SmallCircle=2218,Sopf=1d54a,Sqrt=221a,Square=25a1,SquareIntersection=2293,SquareSu",
|
|
1703
|
+
"bset=228f,SquareSubsetEqual=2291,SquareSuperset=2290,SquareSupersetEqual=2292,SquareUnion=2294,Sscr=",
|
|
1704
|
+
"1d4ae,Star=22c6,Sub=22d0,Subset=22d0,SubsetEqual=2286,Succeeds=227b,SucceedsEqual=2ab0,SucceedsSlant",
|
|
1705
|
+
"Equal=227d,SucceedsTilde=227f,SuchThat=220b,Sum=2211,Sup=22d1,Superset=2283,SupersetEqual=2287,Supse",
|
|
1706
|
+
"t=22d1,THORN=de,TRADE=2122,TSHcy=40b,TScy=426,Tab=9,Tau=3a4,Tcaron=164,Tcedil=162,Tcy=422,Tfr=1d517,",
|
|
1707
|
+
"Therefore=2234,Theta=398,ThickSpace=205f.200a,ThinSpace=2009,Tilde=223c,TildeEqual=2243,TildeFullEqu",
|
|
1708
|
+
"al=2245,TildeTilde=2248,Topf=1d54b,TripleDot=20db,Tscr=1d4af,Tstrok=166,Uacute=da,Uarr=219f,Uarrocir",
|
|
1709
|
+
"=2949,Ubrcy=40e,Ubreve=16c,Ucirc=db,Ucy=423,Udblac=170,Ufr=1d518,Ugrave=d9,Umacr=16a,UnderBar=5f,Und",
|
|
1710
|
+
"erBrace=23df,UnderBracket=23b5,UnderParenthesis=23dd,Union=22c3,UnionPlus=228e,Uogon=172,Uopf=1d54c,",
|
|
1711
|
+
"UpArrow=2191,UpArrowBar=2912,UpArrowDownArrow=21c5,UpDownArrow=2195,UpEquilibrium=296e,UpTee=22a5,Up",
|
|
1712
|
+
"TeeArrow=21a5,Uparrow=21d1,Updownarrow=21d5,UpperLeftArrow=2196,UpperRightArrow=2197,Upsi=3d2,Upsilo",
|
|
1713
|
+
"n=3a5,Uring=16e,Uscr=1d4b0,Utilde=168,Uuml=dc,VDash=22ab,Vbar=2aeb,Vcy=412,Vdash=22a9,Vdashl=2ae6,Ve",
|
|
1714
|
+
"e=22c1,Verbar=2016,Vert=2016,VerticalBar=2223,VerticalLine=7c,VerticalSeparator=2758,VerticalTilde=2",
|
|
1715
|
+
"240,VeryThinSpace=200a,Vfr=1d519,Vopf=1d54d,Vscr=1d4b1,Vvdash=22aa,Wcirc=174,Wedge=22c0,Wfr=1d51a,Wo",
|
|
1716
|
+
"pf=1d54e,Wscr=1d4b2,Xfr=1d51b,Xi=39e,Xopf=1d54f,Xscr=1d4b3,YAcy=42f,YIcy=407,YUcy=42e,Yacute=dd,Ycir",
|
|
1717
|
+
"c=176,Ycy=42b,Yfr=1d51c,Yopf=1d550,Yscr=1d4b4,Yuml=178,ZHcy=416,Zacute=179,Zcaron=17d,Zcy=417,Zdot=1",
|
|
1718
|
+
"7b,ZeroWidthSpace=200b,Zeta=396,Zfr=2128,Zopf=2124,Zscr=1d4b5,aacute=e1,abreve=103,ac=223e,acE=223e.",
|
|
1719
|
+
"333,acd=223f,acirc=e2,acute=b4,acy=430,aelig=e6,af=2061,afr=1d51e,agrave=e0,alefsym=2135,aleph=2135,",
|
|
1720
|
+
"alpha=3b1,amacr=101,amalg=2a3f,amp=26,and=2227,andand=2a55,andd=2a5c,andslope=2a58,andv=2a5a,ang=222",
|
|
1721
|
+
"0,ange=29a4,angle=2220,angmsd=2221,angmsdaa=29a8,angmsdab=29a9,angmsdac=29aa,angmsdad=29ab,angmsdae=",
|
|
1722
|
+
"29ac,angmsdaf=29ad,angmsdag=29ae,angmsdah=29af,angrt=221f,angrtvb=22be,angrtvbd=299d,angsph=2222,ang",
|
|
1723
|
+
"st=c5,angzarr=237c,aogon=105,aopf=1d552,ap=2248,apE=2a70,apacir=2a6f,ape=224a,apid=224b,apos=27,appr",
|
|
1724
|
+
"ox=2248,approxeq=224a,aring=e5,ascr=1d4b6,ast=2a,asymp=2248,asympeq=224d,atilde=e3,auml=e4,awconint=",
|
|
1725
|
+
"2233,awint=2a11,bNot=2aed,backcong=224c,backepsilon=3f6,backprime=2035,backsim=223d,backsimeq=22cd,b",
|
|
1726
|
+
"arvee=22bd,barwed=2305,barwedge=2305,bbrk=23b5,bbrktbrk=23b6,bcong=224c,bcy=431,bdquo=201e,becaus=22",
|
|
1727
|
+
"35,because=2235,bemptyv=29b0,bepsi=3f6,bernou=212c,beta=3b2,beth=2136,between=226c,bfr=1d51f,bigcap=",
|
|
1728
|
+
"22c2,bigcirc=25ef,bigcup=22c3,bigodot=2a00,bigoplus=2a01,bigotimes=2a02,bigsqcup=2a06,bigstar=2605,b",
|
|
1729
|
+
"igtriangledown=25bd,bigtriangleup=25b3,biguplus=2a04,bigvee=22c1,bigwedge=22c0,bkarow=290d,blackloze",
|
|
1730
|
+
"nge=29eb,blacksquare=25aa,blacktriangle=25b4,blacktriangledown=25be,blacktriangleleft=25c2,blacktria",
|
|
1731
|
+
"ngleright=25b8,blank=2423,blk12=2592,blk14=2591,blk34=2593,block=2588,bne=3d.20e5,bnequiv=2261.20e5,",
|
|
1732
|
+
"bnot=2310,bopf=1d553,bot=22a5,bottom=22a5,bowtie=22c8,boxDL=2557,boxDR=2554,boxDl=2556,boxDr=2553,bo",
|
|
1733
|
+
"xH=2550,boxHD=2566,boxHU=2569,boxHd=2564,boxHu=2567,boxUL=255d,boxUR=255a,boxUl=255c,boxUr=2559,boxV",
|
|
1734
|
+
"=2551,boxVH=256c,boxVL=2563,boxVR=2560,boxVh=256b,boxVl=2562,boxVr=255f,boxbox=29c9,boxdL=2555,boxdR",
|
|
1735
|
+
"=2552,boxdl=2510,boxdr=250c,boxh=2500,boxhD=2565,boxhU=2568,boxhd=252c,boxhu=2534,boxminus=229f,boxp",
|
|
1736
|
+
"lus=229e,boxtimes=22a0,boxuL=255b,boxuR=2558,boxul=2518,boxur=2514,boxv=2502,boxvH=256a,boxvL=2561,b",
|
|
1737
|
+
"oxvR=255e,boxvh=253c,boxvl=2524,boxvr=251c,bprime=2035,breve=2d8,brvbar=a6,bscr=1d4b7,bsemi=204f,bsi",
|
|
1738
|
+
"m=223d,bsime=22cd,bsol=5c,bsolb=29c5,bsolhsub=27c8,bull=2022,bullet=2022,bump=224e,bumpE=2aae,bumpe=",
|
|
1739
|
+
"224f,bumpeq=224f,cacute=107,cap=2229,capand=2a44,capbrcup=2a49,capcap=2a4b,capcup=2a47,capdot=2a40,c",
|
|
1740
|
+
"aps=2229.fe00,caret=2041,caron=2c7,ccaps=2a4d,ccaron=10d,ccedil=e7,ccirc=109,ccups=2a4c,ccupssm=2a50",
|
|
1741
|
+
",cdot=10b,cedil=b8,cemptyv=29b2,cent=a2,centerdot=b7,cfr=1d520,chcy=447,check=2713,checkmark=2713,ch",
|
|
1742
|
+
"i=3c7,cir=25cb,cirE=29c3,circ=2c6,circeq=2257,circlearrowleft=21ba,circlearrowright=21bb,circledR=ae",
|
|
1743
|
+
",circledS=24c8,circledast=229b,circledcirc=229a,circleddash=229d,cire=2257,cirfnint=2a10,cirmid=2aef",
|
|
1744
|
+
",cirscir=29c2,clubs=2663,clubsuit=2663,colon=3a,colone=2254,coloneq=2254,comma=2c,commat=40,comp=220",
|
|
1745
|
+
"1,compfn=2218,complement=2201,complexes=2102,cong=2245,congdot=2a6d,conint=222e,copf=1d554,coprod=22",
|
|
1746
|
+
"10,copy=a9,copysr=2117,crarr=21b5,cross=2717,cscr=1d4b8,csub=2acf,csube=2ad1,csup=2ad0,csupe=2ad2,ct",
|
|
1747
|
+
"dot=22ef,cudarrl=2938,cudarrr=2935,cuepr=22de,cuesc=22df,cularr=21b6,cularrp=293d,cup=222a,cupbrcap=",
|
|
1748
|
+
"2a48,cupcap=2a46,cupcup=2a4a,cupdot=228d,cupor=2a45,cups=222a.fe00,curarr=21b7,curarrm=293c,curlyeqp",
|
|
1749
|
+
"rec=22de,curlyeqsucc=22df,curlyvee=22ce,curlywedge=22cf,curren=a4,curvearrowleft=21b6,curvearrowrigh",
|
|
1750
|
+
"t=21b7,cuvee=22ce,cuwed=22cf,cwconint=2232,cwint=2231,cylcty=232d,dArr=21d3,dHar=2965,dagger=2020,da",
|
|
1751
|
+
"leth=2138,darr=2193,dash=2010,dashv=22a3,dbkarow=290f,dblac=2dd,dcaron=10f,dcy=434,dd=2146,ddagger=2",
|
|
1752
|
+
"021,ddarr=21ca,ddotseq=2a77,deg=b0,delta=3b4,demptyv=29b1,dfisht=297f,dfr=1d521,dharl=21c3,dharr=21c",
|
|
1753
|
+
"2,diam=22c4,diamond=22c4,diamondsuit=2666,diams=2666,die=a8,digamma=3dd,disin=22f2,div=f7,divide=f7,",
|
|
1754
|
+
"divideontimes=22c7,divonx=22c7,djcy=452,dlcorn=231e,dlcrop=230d,dollar=24,dopf=1d555,dot=2d9,doteq=2",
|
|
1755
|
+
"250,doteqdot=2251,dotminus=2238,dotplus=2214,dotsquare=22a1,doublebarwedge=2306,downarrow=2193,downd",
|
|
1756
|
+
"ownarrows=21ca,downharpoonleft=21c3,downharpoonright=21c2,drbkarow=2910,drcorn=231f,drcrop=230c,dscr",
|
|
1757
|
+
"=1d4b9,dscy=455,dsol=29f6,dstrok=111,dtdot=22f1,dtri=25bf,dtrif=25be,duarr=21f5,duhar=296f,dwangle=2",
|
|
1758
|
+
"9a6,dzcy=45f,dzigrarr=27ff,eDDot=2a77,eDot=2251,eacute=e9,easter=2a6e,ecaron=11b,ecir=2256,ecirc=ea,",
|
|
1759
|
+
"ecolon=2255,ecy=44d,edot=117,ee=2147,efDot=2252,efr=1d522,eg=2a9a,egrave=e8,egs=2a96,egsdot=2a98,el=",
|
|
1760
|
+
"2a99,elinters=23e7,ell=2113,els=2a95,elsdot=2a97,emacr=113,empty=2205,emptyset=2205,emptyv=2205,emsp",
|
|
1761
|
+
"=2003,emsp13=2004,emsp14=2005,eng=14b,ensp=2002,eogon=119,eopf=1d556,epar=22d5,eparsl=29e3,eplus=2a7",
|
|
1762
|
+
"1,epsi=3b5,epsilon=3b5,epsiv=3f5,eqcirc=2256,eqcolon=2255,eqsim=2242,eqslantgtr=2a96,eqslantless=2a9",
|
|
1763
|
+
"5,equals=3d,equest=225f,equiv=2261,equivDD=2a78,eqvparsl=29e5,erDot=2253,erarr=2971,escr=212f,esdot=",
|
|
1764
|
+
"2250,esim=2242,eta=3b7,eth=f0,euml=eb,euro=20ac,excl=21,exist=2203,expectation=2130,exponentiale=214",
|
|
1765
|
+
"7,fallingdotseq=2252,fcy=444,female=2640,ffilig=fb03,fflig=fb00,ffllig=fb04,ffr=1d523,filig=fb01,fjl",
|
|
1766
|
+
"ig=66.6a,flat=266d,fllig=fb02,fltns=25b1,fnof=192,fopf=1d557,forall=2200,fork=22d4,forkv=2ad9,fparti",
|
|
1767
|
+
"nt=2a0d,frac12=bd,frac13=2153,frac14=bc,frac15=2155,frac16=2159,frac18=215b,frac23=2154,frac25=2156,",
|
|
1768
|
+
"frac34=be,frac35=2157,frac38=215c,frac45=2158,frac56=215a,frac58=215d,frac78=215e,frasl=2044,frown=2",
|
|
1769
|
+
"322,fscr=1d4bb,gE=2267,gEl=2a8c,gacute=1f5,gamma=3b3,gammad=3dd,gap=2a86,gbreve=11f,gcirc=11d,gcy=43",
|
|
1770
|
+
"3,gdot=121,ge=2265,gel=22db,geq=2265,geqq=2267,geqslant=2a7e,ges=2a7e,gescc=2aa9,gesdot=2a80,gesdoto",
|
|
1771
|
+
"=2a82,gesdotol=2a84,gesl=22db.fe00,gesles=2a94,gfr=1d524,gg=226b,ggg=22d9,gimel=2137,gjcy=453,gl=227",
|
|
1772
|
+
"7,glE=2a92,gla=2aa5,glj=2aa4,gnE=2269,gnap=2a8a,gnapprox=2a8a,gne=2a88,gneq=2a88,gneqq=2269,gnsim=22",
|
|
1773
|
+
"e7,gopf=1d558,grave=60,gscr=210a,gsim=2273,gsime=2a8e,gsiml=2a90,gt=3e,gtcc=2aa7,gtcir=2a7a,gtdot=22",
|
|
1774
|
+
"d7,gtlPar=2995,gtquest=2a7c,gtrapprox=2a86,gtrarr=2978,gtrdot=22d7,gtreqless=22db,gtreqqless=2a8c,gt",
|
|
1775
|
+
"rless=2277,gtrsim=2273,gvertneqq=2269.fe00,gvnE=2269.fe00,hArr=21d4,hairsp=200a,half=bd,hamilt=210b,",
|
|
1776
|
+
"hardcy=44a,harr=2194,harrcir=2948,harrw=21ad,hbar=210f,hcirc=125,hearts=2665,heartsuit=2665,hellip=2",
|
|
1777
|
+
"026,hercon=22b9,hfr=1d525,hksearow=2925,hkswarow=2926,hoarr=21ff,homtht=223b,hookleftarrow=21a9,hook",
|
|
1778
|
+
"rightarrow=21aa,hopf=1d559,horbar=2015,hscr=1d4bd,hslash=210f,hstrok=127,hybull=2043,hyphen=2010,iac",
|
|
1779
|
+
"ute=ed,ic=2063,icirc=ee,icy=438,iecy=435,iexcl=a1,iff=21d4,ifr=1d526,igrave=ec,ii=2148,iiiint=2a0c,i",
|
|
1780
|
+
"iint=222d,iinfin=29dc,iiota=2129,ijlig=133,imacr=12b,image=2111,imagline=2110,imagpart=2111,imath=13",
|
|
1781
|
+
"1,imof=22b7,imped=1b5,in=2208,incare=2105,infin=221e,infintie=29dd,inodot=131,int=222b,intcal=22ba,i",
|
|
1782
|
+
"ntegers=2124,intercal=22ba,intlarhk=2a17,intprod=2a3c,iocy=451,iogon=12f,iopf=1d55a,iota=3b9,iprod=2",
|
|
1783
|
+
"a3c,iquest=bf,iscr=1d4be,isin=2208,isinE=22f9,isindot=22f5,isins=22f4,isinsv=22f3,isinv=2208,it=2062",
|
|
1784
|
+
",itilde=129,iukcy=456,iuml=ef,jcirc=135,jcy=439,jfr=1d527,jmath=237,jopf=1d55b,jscr=1d4bf,jsercy=458",
|
|
1785
|
+
",jukcy=454,kappa=3ba,kappav=3f0,kcedil=137,kcy=43a,kfr=1d528,kgreen=138,khcy=445,kjcy=45c,kopf=1d55c",
|
|
1786
|
+
",kscr=1d4c0,lAarr=21da,lArr=21d0,lAtail=291b,lBarr=290e,lE=2266,lEg=2a8b,lHar=2962,lacute=13a,laempt",
|
|
1787
|
+
"yv=29b4,lagran=2112,lambda=3bb,lang=27e8,langd=2991,langle=27e8,lap=2a85,laquo=ab,larr=2190,larrb=21",
|
|
1788
|
+
"e4,larrbfs=291f,larrfs=291d,larrhk=21a9,larrlp=21ab,larrpl=2939,larrsim=2973,larrtl=21a2,lat=2aab,la",
|
|
1789
|
+
"tail=2919,late=2aad,lates=2aad.fe00,lbarr=290c,lbbrk=2772,lbrace=7b,lbrack=5b,lbrke=298b,lbrksld=298",
|
|
1790
|
+
"f,lbrkslu=298d,lcaron=13e,lcedil=13c,lceil=2308,lcub=7b,lcy=43b,ldca=2936,ldquo=201c,ldquor=201e,ldr",
|
|
1791
|
+
"dhar=2967,ldrushar=294b,ldsh=21b2,le=2264,leftarrow=2190,leftarrowtail=21a2,leftharpoondown=21bd,lef",
|
|
1792
|
+
"tharpoonup=21bc,leftleftarrows=21c7,leftrightarrow=2194,leftrightarrows=21c6,leftrightharpoons=21cb,",
|
|
1793
|
+
"leftrightsquigarrow=21ad,leftthreetimes=22cb,leg=22da,leq=2264,leqq=2266,leqslant=2a7d,les=2a7d,lesc",
|
|
1794
|
+
"c=2aa8,lesdot=2a7f,lesdoto=2a81,lesdotor=2a83,lesg=22da.fe00,lesges=2a93,lessapprox=2a85,lessdot=22d",
|
|
1795
|
+
"6,lesseqgtr=22da,lesseqqgtr=2a8b,lessgtr=2276,lesssim=2272,lfisht=297c,lfloor=230a,lfr=1d529,lg=2276",
|
|
1796
|
+
",lgE=2a91,lhard=21bd,lharu=21bc,lharul=296a,lhblk=2584,ljcy=459,ll=226a,llarr=21c7,llcorner=231e,llh",
|
|
1797
|
+
"ard=296b,lltri=25fa,lmidot=140,lmoust=23b0,lmoustache=23b0,lnE=2268,lnap=2a89,lnapprox=2a89,lne=2a87",
|
|
1798
|
+
",lneq=2a87,lneqq=2268,lnsim=22e6,loang=27ec,loarr=21fd,lobrk=27e6,longleftarrow=27f5,longleftrightar",
|
|
1799
|
+
"row=27f7,longmapsto=27fc,longrightarrow=27f6,looparrowleft=21ab,looparrowright=21ac,lopar=2985,lopf=",
|
|
1800
|
+
"1d55d,loplus=2a2d,lotimes=2a34,lowast=2217,lowbar=5f,loz=25ca,lozenge=25ca,lozf=29eb,lpar=28,lparlt=",
|
|
1801
|
+
"2993,lrarr=21c6,lrcorner=231f,lrhar=21cb,lrhard=296d,lrm=200e,lrtri=22bf,lsaquo=2039,lscr=1d4c1,lsh=",
|
|
1802
|
+
"21b0,lsim=2272,lsime=2a8d,lsimg=2a8f,lsqb=5b,lsquo=2018,lsquor=201a,lstrok=142,lt=3c,ltcc=2aa6,ltcir",
|
|
1803
|
+
"=2a79,ltdot=22d6,lthree=22cb,ltimes=22c9,ltlarr=2976,ltquest=2a7b,ltrPar=2996,ltri=25c3,ltrie=22b4,l",
|
|
1804
|
+
"trif=25c2,lurdshar=294a,luruhar=2966,lvertneqq=2268.fe00,lvnE=2268.fe00,mDDot=223a,macr=af,male=2642",
|
|
1805
|
+
",malt=2720,maltese=2720,map=21a6,mapsto=21a6,mapstodown=21a7,mapstoleft=21a4,mapstoup=21a5,marker=25",
|
|
1806
|
+
"ae,mcomma=2a29,mcy=43c,mdash=2014,measuredangle=2221,mfr=1d52a,mho=2127,micro=b5,mid=2223,midast=2a,",
|
|
1807
|
+
"midcir=2af0,middot=b7,minus=2212,minusb=229f,minusd=2238,minusdu=2a2a,mlcp=2adb,mldr=2026,mnplus=221",
|
|
1808
|
+
"3,models=22a7,mopf=1d55e,mp=2213,mscr=1d4c2,mstpos=223e,mu=3bc,multimap=22b8,mumap=22b8,nGg=22d9.338",
|
|
1809
|
+
",nGt=226b.20d2,nGtv=226b.338,nLeftarrow=21cd,nLeftrightarrow=21ce,nLl=22d8.338,nLt=226a.20d2,nLtv=22",
|
|
1810
|
+
"6a.338,nRightarrow=21cf,nVDash=22af,nVdash=22ae,nabla=2207,nacute=144,nang=2220.20d2,nap=2249,napE=2",
|
|
1811
|
+
"a70.338,napid=224b.338,napos=149,napprox=2249,natur=266e,natural=266e,naturals=2115,nbsp=a0,nbump=22",
|
|
1812
|
+
"4e.338,nbumpe=224f.338,ncap=2a43,ncaron=148,ncedil=146,ncong=2247,ncongdot=2a6d.338,ncup=2a42,ncy=43",
|
|
1813
|
+
"d,ndash=2013,ne=2260,neArr=21d7,nearhk=2924,nearr=2197,nearrow=2197,nedot=2250.338,nequiv=2262,nesea",
|
|
1814
|
+
"r=2928,nesim=2242.338,nexist=2204,nexists=2204,nfr=1d52b,ngE=2267.338,nge=2271,ngeq=2271,ngeqq=2267.",
|
|
1815
|
+
"338,ngeqslant=2a7e.338,nges=2a7e.338,ngsim=2275,ngt=226f,ngtr=226f,nhArr=21ce,nharr=21ae,nhpar=2af2,",
|
|
1816
|
+
"ni=220b,nis=22fc,nisd=22fa,niv=220b,njcy=45a,nlArr=21cd,nlE=2266.338,nlarr=219a,nldr=2025,nle=2270,n",
|
|
1817
|
+
"leftarrow=219a,nleftrightarrow=21ae,nleq=2270,nleqq=2266.338,nleqslant=2a7d.338,nles=2a7d.338,nless=",
|
|
1818
|
+
"226e,nlsim=2274,nlt=226e,nltri=22ea,nltrie=22ec,nmid=2224,nopf=1d55f,not=ac,notin=2209,notinE=22f9.3",
|
|
1819
|
+
"38,notindot=22f5.338,notinva=2209,notinvb=22f7,notinvc=22f6,notni=220c,notniva=220c,notnivb=22fe,not",
|
|
1820
|
+
"nivc=22fd,npar=2226,nparallel=2226,nparsl=2afd.20e5,npart=2202.338,npolint=2a14,npr=2280,nprcue=22e0",
|
|
1821
|
+
",npre=2aaf.338,nprec=2280,npreceq=2aaf.338,nrArr=21cf,nrarr=219b,nrarrc=2933.338,nrarrw=219d.338,nri",
|
|
1822
|
+
"ghtarrow=219b,nrtri=22eb,nrtrie=22ed,nsc=2281,nsccue=22e1,nsce=2ab0.338,nscr=1d4c3,nshortmid=2224,ns",
|
|
1823
|
+
"hortparallel=2226,nsim=2241,nsime=2244,nsimeq=2244,nsmid=2224,nspar=2226,nsqsube=22e2,nsqsupe=22e3,n",
|
|
1824
|
+
"sub=2284,nsubE=2ac5.338,nsube=2288,nsubset=2282.20d2,nsubseteq=2288,nsubseteqq=2ac5.338,nsucc=2281,n",
|
|
1825
|
+
"succeq=2ab0.338,nsup=2285,nsupE=2ac6.338,nsupe=2289,nsupset=2283.20d2,nsupseteq=2289,nsupseteqq=2ac6",
|
|
1826
|
+
".338,ntgl=2279,ntilde=f1,ntlg=2278,ntriangleleft=22ea,ntrianglelefteq=22ec,ntriangleright=22eb,ntria",
|
|
1827
|
+
"nglerighteq=22ed,nu=3bd,num=23,numero=2116,numsp=2007,nvDash=22ad,nvHarr=2904,nvap=224d.20d2,nvdash=",
|
|
1828
|
+
"22ac,nvge=2265.20d2,nvgt=3e.20d2,nvinfin=29de,nvlArr=2902,nvle=2264.20d2,nvlt=3c.20d2,nvltrie=22b4.2",
|
|
1829
|
+
"0d2,nvrArr=2903,nvrtrie=22b5.20d2,nvsim=223c.20d2,nwArr=21d6,nwarhk=2923,nwarr=2196,nwarrow=2196,nwn",
|
|
1830
|
+
"ear=2927,oS=24c8,oacute=f3,oast=229b,ocir=229a,ocirc=f4,ocy=43e,odash=229d,odblac=151,odiv=2a38,odot",
|
|
1831
|
+
"=2299,odsold=29bc,oelig=153,ofcir=29bf,ofr=1d52c,ogon=2db,ograve=f2,ogt=29c1,ohbar=29b5,ohm=3a9,oint",
|
|
1832
|
+
"=222e,olarr=21ba,olcir=29be,olcross=29bb,oline=203e,olt=29c0,omacr=14d,omega=3c9,omicron=3bf,omid=29",
|
|
1833
|
+
"b6,ominus=2296,oopf=1d560,opar=29b7,operp=29b9,oplus=2295,or=2228,orarr=21bb,ord=2a5d,order=2134,ord",
|
|
1834
|
+
"erof=2134,ordf=aa,ordm=ba,origof=22b6,oror=2a56,orslope=2a57,orv=2a5b,oscr=2134,oslash=f8,osol=2298,",
|
|
1835
|
+
"otilde=f5,otimes=2297,otimesas=2a36,ouml=f6,ovbar=233d,par=2225,para=b6,parallel=2225,parsim=2af3,pa",
|
|
1836
|
+
"rsl=2afd,part=2202,pcy=43f,percnt=25,period=2e,permil=2030,perp=22a5,pertenk=2031,pfr=1d52d,phi=3c6,",
|
|
1837
|
+
"phiv=3d5,phmmat=2133,phone=260e,pi=3c0,pitchfork=22d4,piv=3d6,planck=210f,planckh=210e,plankv=210f,p",
|
|
1838
|
+
"lus=2b,plusacir=2a23,plusb=229e,pluscir=2a22,plusdo=2214,plusdu=2a25,pluse=2a72,plusmn=b1,plussim=2a",
|
|
1839
|
+
"26,plustwo=2a27,pm=b1,pointint=2a15,popf=1d561,pound=a3,pr=227a,prE=2ab3,prap=2ab7,prcue=227c,pre=2a",
|
|
1840
|
+
"af,prec=227a,precapprox=2ab7,preccurlyeq=227c,preceq=2aaf,precnapprox=2ab9,precneqq=2ab5,precnsim=22",
|
|
1841
|
+
"e8,precsim=227e,prime=2032,primes=2119,prnE=2ab5,prnap=2ab9,prnsim=22e8,prod=220f,profalar=232e,prof",
|
|
1842
|
+
"line=2312,profsurf=2313,prop=221d,propto=221d,prsim=227e,prurel=22b0,pscr=1d4c5,psi=3c8,puncsp=2008,",
|
|
1843
|
+
"qfr=1d52e,qint=2a0c,qopf=1d562,qprime=2057,qscr=1d4c6,quaternions=210d,quatint=2a16,quest=3f,questeq",
|
|
1844
|
+
"=225f,quot=22,rAarr=21db,rArr=21d2,rAtail=291c,rBarr=290f,rHar=2964,race=223d.331,racute=155,radic=2",
|
|
1845
|
+
"21a,raemptyv=29b3,rang=27e9,rangd=2992,range=29a5,rangle=27e9,raquo=bb,rarr=2192,rarrap=2975,rarrb=2",
|
|
1846
|
+
"1e5,rarrbfs=2920,rarrc=2933,rarrfs=291e,rarrhk=21aa,rarrlp=21ac,rarrpl=2945,rarrsim=2974,rarrtl=21a3",
|
|
1847
|
+
",rarrw=219d,ratail=291a,ratio=2236,rationals=211a,rbarr=290d,rbbrk=2773,rbrace=7d,rbrack=5d,rbrke=29",
|
|
1848
|
+
"8c,rbrksld=298e,rbrkslu=2990,rcaron=159,rcedil=157,rceil=2309,rcub=7d,rcy=440,rdca=2937,rdldhar=2969",
|
|
1849
|
+
",rdquo=201d,rdquor=201d,rdsh=21b3,real=211c,realine=211b,realpart=211c,reals=211d,rect=25ad,reg=ae,r",
|
|
1850
|
+
"fisht=297d,rfloor=230b,rfr=1d52f,rhard=21c1,rharu=21c0,rharul=296c,rho=3c1,rhov=3f1,rightarrow=2192,",
|
|
1851
|
+
"rightarrowtail=21a3,rightharpoondown=21c1,rightharpoonup=21c0,rightleftarrows=21c4,rightleftharpoons",
|
|
1852
|
+
"=21cc,rightrightarrows=21c9,rightsquigarrow=219d,rightthreetimes=22cc,ring=2da,risingdotseq=2253,rla",
|
|
1853
|
+
"rr=21c4,rlhar=21cc,rlm=200f,rmoust=23b1,rmoustache=23b1,rnmid=2aee,roang=27ed,roarr=21fe,robrk=27e7,",
|
|
1854
|
+
"ropar=2986,ropf=1d563,roplus=2a2e,rotimes=2a35,rpar=29,rpargt=2994,rppolint=2a12,rrarr=21c9,rsaquo=2",
|
|
1855
|
+
"03a,rscr=1d4c7,rsh=21b1,rsqb=5d,rsquo=2019,rsquor=2019,rthree=22cc,rtimes=22ca,rtri=25b9,rtrie=22b5,",
|
|
1856
|
+
"rtrif=25b8,rtriltri=29ce,ruluhar=2968,rx=211e,sacute=15b,sbquo=201a,sc=227b,scE=2ab4,scap=2ab8,scaro",
|
|
1857
|
+
"n=161,sccue=227d,sce=2ab0,scedil=15f,scirc=15d,scnE=2ab6,scnap=2aba,scnsim=22e9,scpolint=2a13,scsim=",
|
|
1858
|
+
"227f,scy=441,sdot=22c5,sdotb=22a1,sdote=2a66,seArr=21d8,searhk=2925,searr=2198,searrow=2198,sect=a7,",
|
|
1859
|
+
"semi=3b,seswar=2929,setminus=2216,setmn=2216,sext=2736,sfr=1d530,sfrown=2322,sharp=266f,shchcy=449,s",
|
|
1860
|
+
"hcy=448,shortmid=2223,shortparallel=2225,shy=ad,sigma=3c3,sigmaf=3c2,sigmav=3c2,sim=223c,simdot=2a6a",
|
|
1861
|
+
",sime=2243,simeq=2243,simg=2a9e,simgE=2aa0,siml=2a9d,simlE=2a9f,simne=2246,simplus=2a24,simrarr=2972",
|
|
1862
|
+
",slarr=2190,smallsetminus=2216,smashp=2a33,smeparsl=29e4,smid=2223,smile=2323,smt=2aaa,smte=2aac,smt",
|
|
1863
|
+
"es=2aac.fe00,softcy=44c,sol=2f,solb=29c4,solbar=233f,sopf=1d564,spades=2660,spadesuit=2660,spar=2225",
|
|
1864
|
+
",sqcap=2293,sqcaps=2293.fe00,sqcup=2294,sqcups=2294.fe00,sqsub=228f,sqsube=2291,sqsubset=228f,sqsubs",
|
|
1865
|
+
"eteq=2291,sqsup=2290,sqsupe=2292,sqsupset=2290,sqsupseteq=2292,squ=25a1,square=25a1,squarf=25aa,squf",
|
|
1866
|
+
"=25aa,srarr=2192,sscr=1d4c8,ssetmn=2216,ssmile=2323,sstarf=22c6,star=2606,starf=2605,straightepsilon",
|
|
1867
|
+
"=3f5,straightphi=3d5,strns=af,sub=2282,subE=2ac5,subdot=2abd,sube=2286,subedot=2ac3,submult=2ac1,sub",
|
|
1868
|
+
"nE=2acb,subne=228a,subplus=2abf,subrarr=2979,subset=2282,subseteq=2286,subseteqq=2ac5,subsetneq=228a",
|
|
1869
|
+
",subsetneqq=2acb,subsim=2ac7,subsub=2ad5,subsup=2ad3,succ=227b,succapprox=2ab8,succcurlyeq=227d,succ",
|
|
1870
|
+
"eq=2ab0,succnapprox=2aba,succneqq=2ab6,succnsim=22e9,succsim=227f,sum=2211,sung=266a,sup=2283,sup1=b",
|
|
1871
|
+
"9,sup2=b2,sup3=b3,supE=2ac6,supdot=2abe,supdsub=2ad8,supe=2287,supedot=2ac4,suphsol=27c9,suphsub=2ad",
|
|
1872
|
+
"7,suplarr=297b,supmult=2ac2,supnE=2acc,supne=228b,supplus=2ac0,supset=2283,supseteq=2287,supseteqq=2",
|
|
1873
|
+
"ac6,supsetneq=228b,supsetneqq=2acc,supsim=2ac8,supsub=2ad4,supsup=2ad6,swArr=21d9,swarhk=2926,swarr=",
|
|
1874
|
+
"2199,swarrow=2199,swnwar=292a,szlig=df,target=2316,tau=3c4,tbrk=23b4,tcaron=165,tcedil=163,tcy=442,t",
|
|
1875
|
+
"dot=20db,telrec=2315,tfr=1d531,there4=2234,therefore=2234,theta=3b8,thetasym=3d1,thetav=3d1,thickapp",
|
|
1876
|
+
"rox=2248,thicksim=223c,thinsp=2009,thkap=2248,thksim=223c,thorn=fe,tilde=2dc,times=d7,timesb=22a0,ti",
|
|
1877
|
+
"mesbar=2a31,timesd=2a30,tint=222d,toea=2928,top=22a4,topbot=2336,topcir=2af1,topf=1d565,topfork=2ada",
|
|
1878
|
+
",tosa=2929,tprime=2034,trade=2122,triangle=25b5,triangledown=25bf,triangleleft=25c3,trianglelefteq=2",
|
|
1879
|
+
"2b4,triangleq=225c,triangleright=25b9,trianglerighteq=22b5,tridot=25ec,trie=225c,triminus=2a3a,tripl",
|
|
1880
|
+
"us=2a39,trisb=29cd,tritime=2a3b,trpezium=23e2,tscr=1d4c9,tscy=446,tshcy=45b,tstrok=167,twixt=226c,tw",
|
|
1881
|
+
"oheadleftarrow=219e,twoheadrightarrow=21a0,uArr=21d1,uHar=2963,uacute=fa,uarr=2191,ubrcy=45e,ubreve=",
|
|
1882
|
+
"16d,ucirc=fb,ucy=443,udarr=21c5,udblac=171,udhar=296e,ufisht=297e,ufr=1d532,ugrave=f9,uharl=21bf,uha",
|
|
1883
|
+
"rr=21be,uhblk=2580,ulcorn=231c,ulcorner=231c,ulcrop=230f,ultri=25f8,umacr=16b,uml=a8,uogon=173,uopf=",
|
|
1884
|
+
"1d566,uparrow=2191,updownarrow=2195,upharpoonleft=21bf,upharpoonright=21be,uplus=228e,upsi=3c5,upsih",
|
|
1885
|
+
"=3d2,upsilon=3c5,upuparrows=21c8,urcorn=231d,urcorner=231d,urcrop=230e,uring=16f,urtri=25f9,uscr=1d4",
|
|
1886
|
+
"ca,utdot=22f0,utilde=169,utri=25b5,utrif=25b4,uuarr=21c8,uuml=fc,uwangle=29a7,vArr=21d5,vBar=2ae8,vB",
|
|
1887
|
+
"arv=2ae9,vDash=22a8,vangrt=299c,varepsilon=3f5,varkappa=3f0,varnothing=2205,varphi=3d5,varpi=3d6,var",
|
|
1888
|
+
"propto=221d,varr=2195,varrho=3f1,varsigma=3c2,varsubsetneq=228a.fe00,varsubsetneqq=2acb.fe00,varsups",
|
|
1889
|
+
"etneq=228b.fe00,varsupsetneqq=2acc.fe00,vartheta=3d1,vartriangleleft=22b2,vartriangleright=22b3,vcy=",
|
|
1890
|
+
"432,vdash=22a2,vee=2228,veebar=22bb,veeeq=225a,vellip=22ee,verbar=7c,vert=7c,vfr=1d533,vltri=22b2,vn",
|
|
1891
|
+
"sub=2282.20d2,vnsup=2283.20d2,vopf=1d567,vprop=221d,vrtri=22b3,vscr=1d4cb,vsubnE=2acb.fe00,vsubne=22",
|
|
1892
|
+
"8a.fe00,vsupnE=2acc.fe00,vsupne=228b.fe00,vzigzag=299a,wcirc=175,wedbar=2a5f,wedge=2227,wedgeq=2259,",
|
|
1893
|
+
"weierp=2118,wfr=1d534,wopf=1d568,wp=2118,wr=2240,wreath=2240,wscr=1d4cc,xcap=22c2,xcirc=25ef,xcup=22",
|
|
1894
|
+
"c3,xdtri=25bd,xfr=1d535,xhArr=27fa,xharr=27f7,xi=3be,xlArr=27f8,xlarr=27f5,xmap=27fc,xnis=22fb,xodot",
|
|
1895
|
+
"=2a00,xopf=1d569,xoplus=2a01,xotime=2a02,xrArr=27f9,xrarr=27f6,xscr=1d4cd,xsqcup=2a06,xuplus=2a04,xu",
|
|
1896
|
+
"tri=25b3,xvee=22c1,xwedge=22c0,yacute=fd,yacy=44f,ycirc=177,ycy=44b,yen=a5,yfr=1d536,yicy=457,yopf=1",
|
|
1897
|
+
"d56a,yscr=1d4ce,yucy=44e,yuml=ff,zacute=17a,zcaron=17e,zcy=437,zdot=17c,zeetrf=2128,zeta=3b6,zfr=1d5",
|
|
1898
|
+
"37,zhcy=436,zigrarr=21dd,zopf=1d56b,zscr=1d4cf,zwj=200d,zwnj=200c"
|
|
1899
|
+
].join("");
|
|
1900
|
+
NAMED_REFERENCES = new Map(NAMED.split(",").map((entry) => {
|
|
1901
|
+
const [name, codes] = entry.split("=");
|
|
1902
|
+
return [name, String.fromCodePoint(...codes.split(".").map((code) => Number.parseInt(code, 16)))];
|
|
1903
|
+
}));
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1906
|
+
|
|
1627
1907
|
// src/html.js
|
|
1628
1908
|
function fromCode(code) {
|
|
1629
1909
|
if (code === 0 || code > 1114111 || code >= 55296 && code <= 57343) {
|
|
@@ -1640,8 +1920,8 @@ function decodeEntities(value, { attribute = false } = {}) {
|
|
|
1640
1920
|
if (hex !== void 0 || decimal !== void 0) {
|
|
1641
1921
|
return fromCode(hex === void 0 ? Number.parseInt(decimal, 10) : Number.parseInt(hex, 16));
|
|
1642
1922
|
}
|
|
1643
|
-
if (semicolon &&
|
|
1644
|
-
return
|
|
1923
|
+
if (semicolon && NAMED_REFERENCES.has(name)) {
|
|
1924
|
+
return NAMED_REFERENCES.get(name);
|
|
1645
1925
|
}
|
|
1646
1926
|
let legacy;
|
|
1647
1927
|
for (let length = Math.min(name.length, LEGACY_LONGEST); length >= 2 && legacy === void 0; length--) {
|
|
@@ -1655,7 +1935,7 @@ function decodeEntities(value, { attribute = false } = {}) {
|
|
|
1655
1935
|
if (attribute && /[\da-zA-Z=]/.test(next)) {
|
|
1656
1936
|
return match;
|
|
1657
1937
|
}
|
|
1658
|
-
return
|
|
1938
|
+
return NAMED_REFERENCES.get(legacy) + rest;
|
|
1659
1939
|
});
|
|
1660
1940
|
}
|
|
1661
1941
|
function readTag(html2, start) {
|
|
@@ -2296,106 +2576,14 @@ function visibleText(html2) {
|
|
|
2296
2576
|
}
|
|
2297
2577
|
return { text: parts.join(""), hidden };
|
|
2298
2578
|
}
|
|
2299
|
-
var LATIN1,
|
|
2579
|
+
var LATIN1, LEGACY, LEGACY_LONGEST, WINDOWS_1252, REFERENCE, UNSHOWN, RAW_SHOWN, RAW_END, BREAKS, SPECIAL, SCOPE, FORMATTING, LINE, OWN_PLACE, VOID, CLOSES_PARAGRAPH, PARAGRAPH, IMPLIED, TABLE_PARTS, TABLE_BOXES, HEADINGS, IMPLIED_END, PARTS_OF_TABLE, TABLE_STRUCTURE, IN_TABLE, MAX_FORMATTING, MARKERS, FOSTERED_MARKERS, NOT_REOPENING, LEAVES_FOREIGN, HOLDS_HTML, SVG_UNSHOWN, MAX_OPEN, MAX_ATTRIBUTES, MAX_STYLE, COMMENT_END, WHITESPACE2, NO_WORD_ATTRIBUTES, FIELDS, FIELD_HELP, HINTS, MAX_HELP, LABEL_END, isHelp, MAX_VALUE, LENGTH, UNITS, SIZE_KEYWORDS, ZERO_NUMBER, DISPLAY_INLINE, DISPLAY_BLOCK, isZero, declarationCache, ROOT, DOCTYPE, QUIRKS_PUBLIC, QUIRKS_IF_NO_SYSTEM;
|
|
2300
2580
|
var init_html = __esm({
|
|
2301
2581
|
"src/html.js"() {
|
|
2582
|
+
init_entities();
|
|
2302
2583
|
init_linear();
|
|
2303
2584
|
LATIN1 = "nbsp iexcl cent pound curren yen brvbar sect uml copy ordf laquo not shy reg macr deg plusmn sup2 sup3 acute micro para middot cedil sup1 ordm raquo frac14 frac12 frac34 iquest Agrave Aacute Acirc Atilde Auml Aring AElig Ccedil Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml ETH Ntilde Ograve Oacute Ocirc Otilde Ouml times Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig agrave aacute acirc atilde auml aring aelig ccedil egrave eacute ecirc euml igrave iacute icirc iuml eth ntilde ograve oacute ocirc otilde ouml divide oslash ugrave uacute ucirc uuml yacute thorn yuml".split(" ");
|
|
2304
|
-
ENTITIES = new Map([
|
|
2305
|
-
...LATIN1.map((name, index) => [name, String.fromCodePoint(160 + index)]),
|
|
2306
|
-
["amp", "&"],
|
|
2307
|
-
["lt", "<"],
|
|
2308
|
-
["gt", ">"],
|
|
2309
|
-
["quot", '"'],
|
|
2310
|
-
["apos", "'"],
|
|
2311
|
-
["AMP", "&"],
|
|
2312
|
-
["LT", "<"],
|
|
2313
|
-
["GT", ">"],
|
|
2314
|
-
["QUOT", '"'],
|
|
2315
|
-
["COPY", "\xA9"],
|
|
2316
|
-
["REG", "\xAE"],
|
|
2317
|
-
["OElig", "\u0152"],
|
|
2318
|
-
["oelig", "\u0153"],
|
|
2319
|
-
["Scaron", "\u0160"],
|
|
2320
|
-
["scaron", "\u0161"],
|
|
2321
|
-
["Yuml", "\u0178"],
|
|
2322
|
-
["fnof", "\u0192"],
|
|
2323
|
-
["circ", "\u02C6"],
|
|
2324
|
-
["tilde", "\u02DC"],
|
|
2325
|
-
["ensp", "\u2002"],
|
|
2326
|
-
["emsp", "\u2003"],
|
|
2327
|
-
["thinsp", "\u2009"],
|
|
2328
|
-
["zwnj", "\u200C"],
|
|
2329
|
-
["zwj", "\u200D"],
|
|
2330
|
-
["lrm", "\u200E"],
|
|
2331
|
-
["rlm", "\u200F"],
|
|
2332
|
-
["ndash", "\u2013"],
|
|
2333
|
-
["mdash", "\u2014"],
|
|
2334
|
-
["lsquo", "\u2018"],
|
|
2335
|
-
["rsquo", "\u2019"],
|
|
2336
|
-
["sbquo", "\u201A"],
|
|
2337
|
-
["ldquo", "\u201C"],
|
|
2338
|
-
["rdquo", "\u201D"],
|
|
2339
|
-
["bdquo", "\u201E"],
|
|
2340
|
-
["dagger", "\u2020"],
|
|
2341
|
-
["Dagger", "\u2021"],
|
|
2342
|
-
["bull", "\u2022"],
|
|
2343
|
-
["hellip", "\u2026"],
|
|
2344
|
-
["permil", "\u2030"],
|
|
2345
|
-
["prime", "\u2032"],
|
|
2346
|
-
["Prime", "\u2033"],
|
|
2347
|
-
["lsaquo", "\u2039"],
|
|
2348
|
-
["rsaquo", "\u203A"],
|
|
2349
|
-
["euro", "\u20AC"],
|
|
2350
|
-
["trade", "\u2122"],
|
|
2351
|
-
["larr", "\u2190"],
|
|
2352
|
-
["uarr", "\u2191"],
|
|
2353
|
-
["rarr", "\u2192"],
|
|
2354
|
-
["darr", "\u2193"],
|
|
2355
|
-
["hearts", "\u2665"],
|
|
2356
|
-
["check", "\u2713"],
|
|
2357
|
-
// The punctuation of a web address, as browsers read these names
|
|
2358
|
-
// ("https://bank.example@evil.example/" goes to evil.example)
|
|
2359
|
-
["Tab", " "],
|
|
2360
|
-
["NewLine", "\n"],
|
|
2361
|
-
["excl", "!"],
|
|
2362
|
-
["num", "#"],
|
|
2363
|
-
["dollar", "$"],
|
|
2364
|
-
["percnt", "%"],
|
|
2365
|
-
["lpar", "("],
|
|
2366
|
-
["rpar", ")"],
|
|
2367
|
-
["ast", "*"],
|
|
2368
|
-
["midast", "*"],
|
|
2369
|
-
["plus", "+"],
|
|
2370
|
-
["comma", ","],
|
|
2371
|
-
["period", "."],
|
|
2372
|
-
["sol", "/"],
|
|
2373
|
-
["colon", ":"],
|
|
2374
|
-
["semi", ";"],
|
|
2375
|
-
["equals", "="],
|
|
2376
|
-
["quest", "?"],
|
|
2377
|
-
["commat", "@"],
|
|
2378
|
-
["lsqb", "["],
|
|
2379
|
-
["lbrack", "["],
|
|
2380
|
-
["bsol", "\\"],
|
|
2381
|
-
["rsqb", "]"],
|
|
2382
|
-
["rbrack", "]"],
|
|
2383
|
-
["Hat", "^"],
|
|
2384
|
-
["lowbar", "_"],
|
|
2385
|
-
["UnderBar", "_"],
|
|
2386
|
-
["grave", "`"],
|
|
2387
|
-
["DiacriticalGrave", "`"],
|
|
2388
|
-
["lcub", "{"],
|
|
2389
|
-
["lbrace", "{"],
|
|
2390
|
-
["verbar", "|"],
|
|
2391
|
-
["vert", "|"],
|
|
2392
|
-
["VerticalLine", "|"],
|
|
2393
|
-
["rcub", "}"],
|
|
2394
|
-
["rbrace", "}"]
|
|
2395
|
-
]);
|
|
2396
2585
|
LEGACY = /* @__PURE__ */ new Set([...LATIN1, "amp", "lt", "gt", "quot", "AMP", "LT", "GT", "QUOT", "COPY", "REG"]);
|
|
2397
2586
|
LEGACY_LONGEST = Math.max(...[...LEGACY].map((name) => name.length));
|
|
2398
|
-
LONGER_NAMES = new Set("centerdot copysr divideontimes gtcc gtcir gtdot gtlPar gtquest gtrapprox gtrarr gtrdot gtreqless gtreqqless gtrless gtrsim ltcc ltcir ltdot lthree ltimes ltlarr ltquest ltrPar ltri ltrie ltrif notin notinE notindot notinva notinvb notinvc notni notniva notnivb notnivc parallel timesb timesbar timesd".split(" "));
|
|
2399
2587
|
WINDOWS_1252 = [8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141, 381, 143, 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250, 339, 157, 382, 376];
|
|
2400
2588
|
REFERENCE = /&(?:#([xX])([\da-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z\d]{0,31}))(;?)/g;
|
|
2401
2589
|
UNSHOWN = /* @__PURE__ */ new Set(["script", "style", "title", "noembed", "noframes", "iframe"]);
|
|
@@ -2509,6 +2697,31 @@ function continuesName(text, index) {
|
|
|
2509
2697
|
}
|
|
2510
2698
|
return (text[index - 1] === "." || text[index - 1] === "-") && NAME_END.test(text.slice(Math.max(0, index - 3), index - 1));
|
|
2511
2699
|
}
|
|
2700
|
+
function boundedUrl(address2) {
|
|
2701
|
+
const text = String(address2).replaceAll(/[\t\n\r]/g, "");
|
|
2702
|
+
const colon = text.indexOf(":");
|
|
2703
|
+
let start = colon === -1 ? 0 : colon + 1;
|
|
2704
|
+
while (start < text.length && (text[start] === "/" || text[start] === "\\")) {
|
|
2705
|
+
start++;
|
|
2706
|
+
}
|
|
2707
|
+
AUTHORITY_END.lastIndex = start;
|
|
2708
|
+
const end = AUTHORITY_END.exec(text)?.index ?? text.length;
|
|
2709
|
+
const file = /^[\0- ]*file:/i.test(text);
|
|
2710
|
+
const at = file ? start : Math.max(start, text.lastIndexOf("@", end - 1) + 1);
|
|
2711
|
+
const bracket = text.lastIndexOf("]", end - 1);
|
|
2712
|
+
const port = text.lastIndexOf(":", end - 1);
|
|
2713
|
+
let host = text.slice(at, !file && port > Math.max(at - 1, bracket) ? port : end);
|
|
2714
|
+
if (host.length > MAX_URL_HOST && host.includes("%")) {
|
|
2715
|
+
try {
|
|
2716
|
+
host = decodeURIComponent(host);
|
|
2717
|
+
} catch {
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
if (host.length > MAX_URL_HOST && host.replaceAll(IGNORED_IN_HOST, "").length > MAX_URL_HOST) {
|
|
2721
|
+
throw new TypeError("Invalid URL: host too long");
|
|
2722
|
+
}
|
|
2723
|
+
return new URL(text);
|
|
2724
|
+
}
|
|
2512
2725
|
function isClickTracker(url) {
|
|
2513
2726
|
const host = url.hostname.toLowerCase();
|
|
2514
2727
|
return CLICK_TRACKERS.some((domain) => isUnder(host, domain)) || host === "substack.com" && url.pathname.startsWith("/redirect/");
|
|
@@ -2535,7 +2748,7 @@ function gatewayTarget(url) {
|
|
|
2535
2748
|
function unwrapLink(address2) {
|
|
2536
2749
|
let url;
|
|
2537
2750
|
try {
|
|
2538
|
-
url =
|
|
2751
|
+
url = boundedUrl(address2);
|
|
2539
2752
|
} catch {
|
|
2540
2753
|
return null;
|
|
2541
2754
|
}
|
|
@@ -2546,7 +2759,7 @@ function unwrapLink(address2) {
|
|
|
2546
2759
|
}
|
|
2547
2760
|
let next;
|
|
2548
2761
|
try {
|
|
2549
|
-
next =
|
|
2762
|
+
next = boundedUrl(target);
|
|
2550
2763
|
} catch {
|
|
2551
2764
|
break;
|
|
2552
2765
|
}
|
|
@@ -2790,7 +3003,7 @@ function endsInsideTag(html2, end, link) {
|
|
|
2790
3003
|
const joined = trimEndOf(link.replace(/^https?:\/\//i, "") + after, ".-");
|
|
2791
3004
|
return joined !== host && (!isHost(host) || isHost(joined) && registrableDomain(joined) !== registrableDomain(host));
|
|
2792
3005
|
}
|
|
2793
|
-
function extractLinks(text, html2, { maxLength = 5e5, bareHosts = false } = {}) {
|
|
3006
|
+
function extractLinks(text, html2, { maxLength = 5e5, bareHosts: bareHosts2 = false } = {}) {
|
|
2794
3007
|
text = typeof text === "string" ? foldToAscii(text) : text;
|
|
2795
3008
|
html2 = typeof html2 === "string" ? foldToAscii(html2) : html2;
|
|
2796
3009
|
const links = [];
|
|
@@ -2808,7 +3021,7 @@ function extractLinks(text, html2, { maxLength = 5e5, bareHosts = false } = {})
|
|
|
2808
3021
|
}
|
|
2809
3022
|
let url;
|
|
2810
3023
|
try {
|
|
2811
|
-
url =
|
|
3024
|
+
url = boundedUrl(href);
|
|
2812
3025
|
} catch {
|
|
2813
3026
|
return;
|
|
2814
3027
|
}
|
|
@@ -2857,7 +3070,7 @@ ${shown || ""}`;
|
|
|
2857
3070
|
}
|
|
2858
3071
|
add(link);
|
|
2859
3072
|
}
|
|
2860
|
-
if (
|
|
3073
|
+
if (bareHosts2 && index < 2) {
|
|
2861
3074
|
bareLinkHosts(read, (host) => {
|
|
2862
3075
|
bareFound.push(host);
|
|
2863
3076
|
});
|
|
@@ -3121,7 +3334,7 @@ function isDeceptiveLink(link, { from } = {}) {
|
|
|
3121
3334
|
}
|
|
3122
3335
|
let shownUrl;
|
|
3123
3336
|
try {
|
|
3124
|
-
shownUrl =
|
|
3337
|
+
shownUrl = boundedUrl(/^https?:\/\//i.test(link.text) ? link.text : `http://${link.text}`);
|
|
3125
3338
|
} catch {
|
|
3126
3339
|
return false;
|
|
3127
3340
|
}
|
|
@@ -3479,7 +3692,7 @@ ${body}`);
|
|
|
3479
3692
|
hidden: visible.hidden
|
|
3480
3693
|
};
|
|
3481
3694
|
}
|
|
3482
|
-
var import_tldts2, INVISIBLE, OBFUSCATING, JOINERS, INVISIBLE_OR_JOINER, ZERO_WIDTH_SPACE, ZERO_WIDTH_JOINERS, LATIN_END, LATIN_START, ZWSP_SCRIPTS, ZWSP_SCRIPT_END, ZWSP_SCRIPT_START, SOFT_HYPHEN, BIDI, RIGHT_TO_LEFT, LETTER_END, LETTER_START, DIGIT_END, DIGIT_START, STYLED_LETTERS, WIDE_LETTERS, CJK, LOOKALIKES, UNIT_LETTERS, UNIT_WORD, LEET, LEET_DIGITS, UNSPACED, URL_PATTERN, EMAIL_SOURCE, EMAIL_PATTERN, PHONE_PATTERN, IP_PATTERN, MONEY_PATTERN, BITCOIN_PATTERN, CARD_PATTERN, ANCHOR_START, MAX_LINK_TEXT, MAX_URL, SHOWN_URL, IMG_PIXEL, IMG, BARE_HOST, MAX_BARE_HOSTS, NAME_END, FILE_TLDS, LINK_FILE_TLDS, CLICK_TRACKERS, isUnder, MAX_GATEWAYS, BRAND_NAMES, SHORTENERS, FREEMAIL, segmenters, LATIN_LOOKALIKES, LATIN, CYRILLIC_OR_GREEK, INLINE_TAG, HOST_CHAR, MAX_SHOWN_HTML, IN_WORD, MAX_BARE_NAME, LINKED_BRANDS, SIGN_IN_PART, signInPath, SENDING_DOMAINS, ADDRESS_SOURCE, NAMED_ADDRESS, MIN_SHOWN_WORDS, PART_WORD;
|
|
3695
|
+
var import_tldts2, INVISIBLE, OBFUSCATING, JOINERS, INVISIBLE_OR_JOINER, ZERO_WIDTH_SPACE, ZERO_WIDTH_JOINERS, LATIN_END, LATIN_START, ZWSP_SCRIPTS, ZWSP_SCRIPT_END, ZWSP_SCRIPT_START, SOFT_HYPHEN, BIDI, RIGHT_TO_LEFT, LETTER_END, LETTER_START, DIGIT_END, DIGIT_START, STYLED_LETTERS, WIDE_LETTERS, CJK, LOOKALIKES, UNIT_LETTERS, UNIT_WORD, LEET, LEET_DIGITS, UNSPACED, URL_PATTERN, EMAIL_SOURCE, EMAIL_PATTERN, PHONE_PATTERN, IP_PATTERN, MONEY_PATTERN, BITCOIN_PATTERN, CARD_PATTERN, ANCHOR_START, MAX_LINK_TEXT, MAX_URL, SHOWN_URL, IMG_PIXEL, IMG, BARE_HOST, MAX_BARE_HOSTS, NAME_END, FILE_TLDS, LINK_FILE_TLDS, CLICK_TRACKERS, MAX_URL_HOST, AUTHORITY_END, IGNORED_IN_HOST, isUnder, MAX_GATEWAYS, BRAND_NAMES, SHORTENERS, FREEMAIL, segmenters, LATIN_LOOKALIKES, LATIN, CYRILLIC_OR_GREEK, INLINE_TAG, HOST_CHAR, MAX_SHOWN_HTML, IN_WORD, MAX_BARE_NAME, LINKED_BRANDS, SIGN_IN_PART, signInPath, SENDING_DOMAINS, ADDRESS_SOURCE, NAMED_ADDRESS, MIN_SHOWN_WORDS, PART_WORD;
|
|
3483
3696
|
var init_tokenizer = __esm({
|
|
3484
3697
|
"src/tokenizer.js"() {
|
|
3485
3698
|
import_tldts2 = require("tldts");
|
|
@@ -3585,6 +3798,9 @@ var init_tokenizer = __esm({
|
|
|
3585
3798
|
FILE_TLDS = /* @__PURE__ */ new Set(["ai", "app", "md", "mov", "pm", "ps", "py", "rs", "sh", "so", "zip"]);
|
|
3586
3799
|
LINK_FILE_TLDS = /* @__PURE__ */ new Set(["md", "mov", "pm", "ps", "py", "rs", "sh", "so", "zip"]);
|
|
3587
3800
|
CLICK_TRACKERS = ["sendgrid.net", "list-manage.com", "mandrillapp.com", "awstrack.me", "pstmrk.it", "hubspotlinks.com", "rs6.net", "klclick.com", "mjt.lu", "exacttarget.com", "convertkit-mail.com", "convertkit-mail2.com", "kit-mail3.com", "sendibt2.com", "sendibt3.com", "createsend1.com", "cmail20.com", "clicks.mlsend.com", "acemlnb.com", "link.mail.beehiiv.com", "bhclick.com", "safelinks.protection.outlook.com", "urldefense.com", "urldefense.proofpoint.com", "mimecast.com", "mimecastprotect.com", "cudasvc.com", "secure-web.cisco.com"];
|
|
3801
|
+
MAX_URL_HOST = 4096;
|
|
3802
|
+
AUTHORITY_END = /[/\\?#]/g;
|
|
3803
|
+
IGNORED_IN_HOST = /[\u00AD\u034F\u180B-\u180D\u180F\u200B\u2060\u2064\uFE00-\uFE0F\uFEFF]|\uD82F[\uDCA0-\uDCA3]|\uDB40[\uDD00-\uDDEF]/g;
|
|
3588
3804
|
isUnder = (host, domain) => host === domain || host.endsWith(`.${domain}`);
|
|
3589
3805
|
MAX_GATEWAYS = 16;
|
|
3590
3806
|
BRAND_NAMES = new Set(BRANDS);
|
|
@@ -4423,7 +4639,8 @@ async function parseWithin(raw, parse = parseMessage, deadline = Date.now() + PA
|
|
|
4423
4639
|
}
|
|
4424
4640
|
}
|
|
4425
4641
|
}
|
|
4426
|
-
async function expandAttachments(attachments = [], errors = [], parse = parseMessage,
|
|
4642
|
+
async function expandAttachments(attachments = [], errors = [], parse = parseMessage, gets = {}) {
|
|
4643
|
+
const { unopened = [], mails = [] } = Array.isArray(gets) ? { unopened: gets } : gets ?? {};
|
|
4427
4644
|
const all = [];
|
|
4428
4645
|
const deadline = Date.now() + PARSE_TIMEOUT;
|
|
4429
4646
|
let budget = MAX_NESTED_BYTES;
|
|
@@ -4472,6 +4689,7 @@ async function expandAttachments(attachments = [], errors = [], parse = parseMes
|
|
|
4472
4689
|
if (inner.error) {
|
|
4473
4690
|
errors.push(inner.error);
|
|
4474
4691
|
}
|
|
4692
|
+
mails.push(inner.mail);
|
|
4475
4693
|
await visit(inner.mail.attachments, prefix ? `${prefix}/${name}` : name || "attached message", depth + 1);
|
|
4476
4694
|
}
|
|
4477
4695
|
}
|
|
@@ -4571,6 +4789,10 @@ var init_parse = __esm({
|
|
|
4571
4789
|
});
|
|
4572
4790
|
|
|
4573
4791
|
// src/dnsbl.js
|
|
4792
|
+
function lastLabels(name) {
|
|
4793
|
+
const separators = [...name.matchAll(LABEL_SEPARATOR)];
|
|
4794
|
+
return separators.length < 128 ? 0 : separators.at(-128).index + 1;
|
|
4795
|
+
}
|
|
4574
4796
|
function lookupName(host) {
|
|
4575
4797
|
if (typeof host !== "string") {
|
|
4576
4798
|
return null;
|
|
@@ -4581,6 +4803,7 @@ function lookupName(host) {
|
|
|
4581
4803
|
}
|
|
4582
4804
|
let name = host.slice(0, end).toLowerCase();
|
|
4583
4805
|
if (/[\u0080-\u{10FFFF}]/u.test(name)) {
|
|
4806
|
+
name = name.slice(lastLabels(name));
|
|
4584
4807
|
name = (0, import_node_url2.domainToASCII)(name) || name;
|
|
4585
4808
|
}
|
|
4586
4809
|
if ((0, import_node_net.isIP)(name.replaceAll(/^\[|]$/g, "")) !== 0) {
|
|
@@ -4680,7 +4903,7 @@ function isListedAnswer(address2, zone) {
|
|
|
4680
4903
|
}
|
|
4681
4904
|
return true;
|
|
4682
4905
|
}
|
|
4683
|
-
var import_node_dns, import_node_net, import_node_url2, import_tldts3, LOOKUP_LABEL, CLOUDFLARE_MALWARE, CLOUDFLARE_FAMILY, DnsChecker;
|
|
4906
|
+
var import_node_dns, import_node_net, import_node_url2, import_tldts3, LOOKUP_LABEL, LABEL_SEPARATOR, CLOUDFLARE_MALWARE, CLOUDFLARE_FAMILY, DnsChecker;
|
|
4684
4907
|
var init_dnsbl = __esm({
|
|
4685
4908
|
"src/dnsbl.js"() {
|
|
4686
4909
|
import_node_dns = __toESM(require("node:dns"), 1);
|
|
@@ -4688,6 +4911,7 @@ var init_dnsbl = __esm({
|
|
|
4688
4911
|
import_node_url2 = require("node:url");
|
|
4689
4912
|
import_tldts3 = require("tldts");
|
|
4690
4913
|
LOOKUP_LABEL = /^[a-z\d_-]{1,63}$/;
|
|
4914
|
+
LABEL_SEPARATOR = /[.\u3002\uFF0E\uFF61]/g;
|
|
4691
4915
|
CLOUDFLARE_MALWARE = ["1.1.1.2", "1.0.0.2"];
|
|
4692
4916
|
CLOUDFLARE_FAMILY = ["1.1.1.3", "1.0.0.3"];
|
|
4693
4917
|
DnsChecker = class {
|
|
@@ -4927,7 +5151,7 @@ function asciiHostname(value) {
|
|
|
4927
5151
|
return null;
|
|
4928
5152
|
}
|
|
4929
5153
|
const lower = value.normalize("NFKC").toLowerCase().replace(/\.$/, "");
|
|
4930
|
-
if (lower === "" || /[\0-,/:-^`{-\u007F]/.test(lower)) {
|
|
5154
|
+
if (lower === "" || lower.length > 1024 || /[\0-,/:-^`{-\u007F]/.test(lower)) {
|
|
4931
5155
|
return null;
|
|
4932
5156
|
}
|
|
4933
5157
|
const ascii = (0, import_node_url3.domainToASCII)(lower);
|
|
@@ -5000,8 +5224,8 @@ function trustReputation(result, trusted = []) {
|
|
|
5000
5224
|
for (const value of result.checkedValues.filter((item) => allowed.has(item))) {
|
|
5001
5225
|
const signers = allowed.get(value);
|
|
5002
5226
|
const counts = (entry) => Boolean(entry) && (signers === null || signers.some((signer) => vouches(normalizeEntry(entry), signer)));
|
|
5003
|
-
const detail = result.details[value];
|
|
5004
|
-
const listed = result.allowlisted[value] || (detail?.isAllowlisted ? detail.allowlistValue : null);
|
|
5227
|
+
const detail = Object.hasOwn(result.details, value) ? result.details[value] : void 0;
|
|
5228
|
+
const listed = Object.hasOwn(result.allowlisted, value) && result.allowlisted[value] || (detail?.isAllowlisted ? detail.allowlistValue : null);
|
|
5005
5229
|
if (counts(listed) && !out.isAllowlisted) {
|
|
5006
5230
|
out.isAllowlisted = true;
|
|
5007
5231
|
out.allowlistValue = listed;
|
|
@@ -6015,6 +6239,997 @@ var init_classifier = __esm({
|
|
|
6015
6239
|
}
|
|
6016
6240
|
});
|
|
6017
6241
|
|
|
6242
|
+
// src/links.js
|
|
6243
|
+
function isHostCode2(code) {
|
|
6244
|
+
return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 45 || code === 46;
|
|
6245
|
+
}
|
|
6246
|
+
function isSpace(code) {
|
|
6247
|
+
return code === 32 || code >= 9 && code <= 13;
|
|
6248
|
+
}
|
|
6249
|
+
function urlOf(value) {
|
|
6250
|
+
let href = value.replaceAll(/[\t\n\r]/g, "");
|
|
6251
|
+
let start = 0;
|
|
6252
|
+
let end = href.length;
|
|
6253
|
+
while (start < end && href.codePointAt(start) <= 32) {
|
|
6254
|
+
start++;
|
|
6255
|
+
}
|
|
6256
|
+
while (end > start && href.codePointAt(end - 1) <= 32) {
|
|
6257
|
+
end--;
|
|
6258
|
+
}
|
|
6259
|
+
while (end > start && TRAILING.has(href[end - 1])) {
|
|
6260
|
+
end--;
|
|
6261
|
+
}
|
|
6262
|
+
href = href.slice(start, end);
|
|
6263
|
+
if (/^[\\/]{2}/.test(href)) {
|
|
6264
|
+
href = `https://${href.slice(2)}`;
|
|
6265
|
+
} else if (/^www\./i.test(href)) {
|
|
6266
|
+
href = `http://${href}`;
|
|
6267
|
+
} else if (!/^https?:/i.test(href)) {
|
|
6268
|
+
return null;
|
|
6269
|
+
}
|
|
6270
|
+
try {
|
|
6271
|
+
return boundedUrl(href);
|
|
6272
|
+
} catch {
|
|
6273
|
+
return null;
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
function hostOfUrl(url) {
|
|
6277
|
+
let host = url.hostname.toLowerCase();
|
|
6278
|
+
let dots = host.length;
|
|
6279
|
+
while (dots > 0 && host[dots - 1] === ".") {
|
|
6280
|
+
dots--;
|
|
6281
|
+
}
|
|
6282
|
+
host = host.slice(0, dots);
|
|
6283
|
+
if (host.startsWith("[") && host.endsWith("]")) {
|
|
6284
|
+
host = host.slice(1, -1);
|
|
6285
|
+
}
|
|
6286
|
+
if (!host || NAMESPACES.has(host)) {
|
|
6287
|
+
return null;
|
|
6288
|
+
}
|
|
6289
|
+
return (0, import_node_net4.isIP)(host) ? host : lookupName(host);
|
|
6290
|
+
}
|
|
6291
|
+
function hostsOf(value) {
|
|
6292
|
+
const url = urlOf(value);
|
|
6293
|
+
if (!url) {
|
|
6294
|
+
return [];
|
|
6295
|
+
}
|
|
6296
|
+
const host = hostOfUrl(url);
|
|
6297
|
+
const hosts = host ? [host] : [];
|
|
6298
|
+
const target = unwrapLink(url.href);
|
|
6299
|
+
if (target && target.href !== url.href) {
|
|
6300
|
+
const targetHost = hostOfUrl(target);
|
|
6301
|
+
if (targetHost && targetHost !== host) {
|
|
6302
|
+
hosts.push(targetHost);
|
|
6303
|
+
}
|
|
6304
|
+
const further = unwrapLink(target.href);
|
|
6305
|
+
if (further && further.href !== target.href) {
|
|
6306
|
+
hosts.unresolved = true;
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6309
|
+
return hosts;
|
|
6310
|
+
}
|
|
6311
|
+
function* attributesOf(html2) {
|
|
6312
|
+
TAG_START.lastIndex = 0;
|
|
6313
|
+
let match;
|
|
6314
|
+
while ((match = TAG_START.exec(html2)) !== null) {
|
|
6315
|
+
let i = match.index + match[0].length;
|
|
6316
|
+
while (i < html2.length && html2[i] !== ">") {
|
|
6317
|
+
if (isSpace(html2.codePointAt(i)) || html2[i] === "/") {
|
|
6318
|
+
i++;
|
|
6319
|
+
continue;
|
|
6320
|
+
}
|
|
6321
|
+
let j = i;
|
|
6322
|
+
while (j < html2.length && html2[j] !== "=" && html2[j] !== ">" && html2[j] !== "/" && !isSpace(html2.codePointAt(j))) {
|
|
6323
|
+
j++;
|
|
6324
|
+
}
|
|
6325
|
+
const name = html2.slice(i, j).toLowerCase();
|
|
6326
|
+
if (j === i) {
|
|
6327
|
+
j++;
|
|
6328
|
+
}
|
|
6329
|
+
while (j < html2.length && isSpace(html2.codePointAt(j))) {
|
|
6330
|
+
j++;
|
|
6331
|
+
}
|
|
6332
|
+
if (html2[j] !== "=") {
|
|
6333
|
+
i = j;
|
|
6334
|
+
continue;
|
|
6335
|
+
}
|
|
6336
|
+
j++;
|
|
6337
|
+
while (j < html2.length && isSpace(html2.codePointAt(j))) {
|
|
6338
|
+
j++;
|
|
6339
|
+
}
|
|
6340
|
+
let value;
|
|
6341
|
+
if (html2[j] === '"' || html2[j] === "'") {
|
|
6342
|
+
const close = html2.indexOf(html2[j], j + 1);
|
|
6343
|
+
const stop = close === -1 ? html2.length : close;
|
|
6344
|
+
value = html2.slice(j + 1, stop);
|
|
6345
|
+
j = stop + 1;
|
|
6346
|
+
} else {
|
|
6347
|
+
const start = j;
|
|
6348
|
+
while (j < html2.length && html2[j] !== ">" && !isSpace(html2.codePointAt(j))) {
|
|
6349
|
+
j++;
|
|
6350
|
+
}
|
|
6351
|
+
value = html2.slice(start, j);
|
|
6352
|
+
}
|
|
6353
|
+
if (name) {
|
|
6354
|
+
yield [name, value];
|
|
6355
|
+
}
|
|
6356
|
+
i = j;
|
|
6357
|
+
}
|
|
6358
|
+
TAG_START.lastIndex = Math.max(i, match.index + 1);
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
function linksOf(name, value, { add, embed, cut }) {
|
|
6362
|
+
if (value.length > MAX_VALUE2) {
|
|
6363
|
+
cut();
|
|
6364
|
+
value = value.slice(0, MAX_VALUE2);
|
|
6365
|
+
}
|
|
6366
|
+
const decoded = decodeEntities(value, { attribute: true });
|
|
6367
|
+
switch (name) {
|
|
6368
|
+
case "srcdoc": {
|
|
6369
|
+
embed(decoded);
|
|
6370
|
+
break;
|
|
6371
|
+
}
|
|
6372
|
+
case "style": {
|
|
6373
|
+
for (const [, link] of decoded.matchAll(CSS_URL)) {
|
|
6374
|
+
add(link);
|
|
6375
|
+
}
|
|
6376
|
+
break;
|
|
6377
|
+
}
|
|
6378
|
+
case "srcset": {
|
|
6379
|
+
for (const candidate of decoded.split(",")) {
|
|
6380
|
+
add(candidate.trim().split(/\s/, 1)[0]);
|
|
6381
|
+
}
|
|
6382
|
+
break;
|
|
6383
|
+
}
|
|
6384
|
+
// (several, separated by spaces)
|
|
6385
|
+
case "ping": {
|
|
6386
|
+
for (const link of decoded.split(/\s+/)) {
|
|
6387
|
+
add(link);
|
|
6388
|
+
}
|
|
6389
|
+
break;
|
|
6390
|
+
}
|
|
6391
|
+
// (only the address of a refresh)
|
|
6392
|
+
case "content": {
|
|
6393
|
+
const match = /(?:^|[\s;,])url\s*=\s*["']?([^\s"';]+)/i.exec(decoded.slice(0, 4096));
|
|
6394
|
+
if (match) {
|
|
6395
|
+
add(match[1]);
|
|
6396
|
+
}
|
|
6397
|
+
break;
|
|
6398
|
+
}
|
|
6399
|
+
default: {
|
|
6400
|
+
add(decoded);
|
|
6401
|
+
}
|
|
6402
|
+
}
|
|
6403
|
+
}
|
|
6404
|
+
function lenientLinks(html2, done, reader) {
|
|
6405
|
+
LENIENT.lastIndex = 0;
|
|
6406
|
+
let match;
|
|
6407
|
+
while (!done() && (match = LENIENT.exec(html2)) !== null) {
|
|
6408
|
+
const name = match[1].toLowerCase();
|
|
6409
|
+
let i = LENIENT.lastIndex;
|
|
6410
|
+
let end = i;
|
|
6411
|
+
if (html2[i] === '"' || html2[i] === "'") {
|
|
6412
|
+
const quote = html2[i];
|
|
6413
|
+
i++;
|
|
6414
|
+
end = i;
|
|
6415
|
+
while (end < html2.length && html2[end] !== quote && html2[end] !== "<" && html2[end] !== ">") {
|
|
6416
|
+
end++;
|
|
6417
|
+
}
|
|
6418
|
+
if (end < html2.length && html2[end] !== quote) {
|
|
6419
|
+
const close = html2.indexOf(quote, end);
|
|
6420
|
+
if (close !== -1 && close - i <= MAX_LENIENT_VALUE && !reader.spend(close - i)) {
|
|
6421
|
+
linksOf(name, html2.slice(i, close), reader);
|
|
6422
|
+
}
|
|
6423
|
+
}
|
|
6424
|
+
} else {
|
|
6425
|
+
while (end < html2.length && !isSpace(html2.codePointAt(end)) && !UNQUOTED_END.has(html2[end])) {
|
|
6426
|
+
end++;
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6429
|
+
if (reader.spend(end - i)) {
|
|
6430
|
+
break;
|
|
6431
|
+
}
|
|
6432
|
+
linksOf(name, html2.slice(i, end), reader);
|
|
6433
|
+
}
|
|
6434
|
+
}
|
|
6435
|
+
function endsLink2(text, i) {
|
|
6436
|
+
const code = text.codePointAt(i);
|
|
6437
|
+
if (code < 128) {
|
|
6438
|
+
return isSpace(code) || code === 34 || code === 39 || code === 60 || code === 62 || code === 96;
|
|
6439
|
+
}
|
|
6440
|
+
return /\s/u.test(text[i]);
|
|
6441
|
+
}
|
|
6442
|
+
function linkReader(text) {
|
|
6443
|
+
let read = 0;
|
|
6444
|
+
let space = -1;
|
|
6445
|
+
let scheme = -1;
|
|
6446
|
+
return (start) => {
|
|
6447
|
+
for (; read < start; read++) {
|
|
6448
|
+
if (endsLink2(text, read)) {
|
|
6449
|
+
space = read;
|
|
6450
|
+
} else if (text[read] === "/" && text[read - 1] === "/" && text[read - 2] === ":") {
|
|
6451
|
+
scheme = read;
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6454
|
+
return scheme > space;
|
|
6455
|
+
};
|
|
6456
|
+
}
|
|
6457
|
+
function isSchemeless(text, start) {
|
|
6458
|
+
if (start < 2 || text[start - 2] !== "/") {
|
|
6459
|
+
return false;
|
|
6460
|
+
}
|
|
6461
|
+
if (start === 2) {
|
|
6462
|
+
return true;
|
|
6463
|
+
}
|
|
6464
|
+
const before = text[start - 3];
|
|
6465
|
+
return !(before === ":" || before === "/" || isHostCode2(text.codePointAt(start - 3)));
|
|
6466
|
+
}
|
|
6467
|
+
function bareName(name) {
|
|
6468
|
+
const labels = name.split(".");
|
|
6469
|
+
const tld = labels.pop();
|
|
6470
|
+
if (!/^(?:[a-z]{2,24}|xn--[a-z\d-]{1,59})$/i.test(tld)) {
|
|
6471
|
+
return null;
|
|
6472
|
+
}
|
|
6473
|
+
const names = [];
|
|
6474
|
+
while (labels.length > 0 && names.length < 11) {
|
|
6475
|
+
const label = labels.pop();
|
|
6476
|
+
if (!/^[a-z\d-]{1,63}$/i.test(label)) {
|
|
6477
|
+
break;
|
|
6478
|
+
}
|
|
6479
|
+
names.unshift(label);
|
|
6480
|
+
}
|
|
6481
|
+
if (names.length === 0) {
|
|
6482
|
+
return null;
|
|
6483
|
+
}
|
|
6484
|
+
names[0] = names[0].replace(/^-+/, "");
|
|
6485
|
+
if (!names[0]) {
|
|
6486
|
+
return null;
|
|
6487
|
+
}
|
|
6488
|
+
return `${names.join(".")}.${tld}`.toLowerCase();
|
|
6489
|
+
}
|
|
6490
|
+
function isRealName(host) {
|
|
6491
|
+
const parsed = (0, import_tldts4.parse)(host);
|
|
6492
|
+
return Boolean(parsed.isIcann && parsed.domain);
|
|
6493
|
+
}
|
|
6494
|
+
function bareHosts(text, add, { done, seen, from = 0, cutEnd = false }) {
|
|
6495
|
+
let previous = -1;
|
|
6496
|
+
const inLink = linkReader(text);
|
|
6497
|
+
for (let slash = text.indexOf("/"); slash !== -1; slash = text.indexOf("/", slash + 1)) {
|
|
6498
|
+
if (done()) {
|
|
6499
|
+
return;
|
|
6500
|
+
}
|
|
6501
|
+
const floor = Math.max(previous + 1, slash - MAX_HOST);
|
|
6502
|
+
previous = slash;
|
|
6503
|
+
let end = slash;
|
|
6504
|
+
while (end > floor && text.codePointAt(end - 1) >= 48 && text.codePointAt(end - 1) <= 57) {
|
|
6505
|
+
end--;
|
|
6506
|
+
}
|
|
6507
|
+
end = end > floor && text[end - 1] === ":" ? end - 1 : slash;
|
|
6508
|
+
let start = end;
|
|
6509
|
+
while (start > floor && isHostCode2(text.codePointAt(start - 1))) {
|
|
6510
|
+
start--;
|
|
6511
|
+
}
|
|
6512
|
+
if (start === end || start < from || cutEnd && slash === text.length - 1) {
|
|
6513
|
+
continue;
|
|
6514
|
+
}
|
|
6515
|
+
if (start > 0 && (IN_WORD2.test(text[start - 1]) || text[start - 1] === "/" && !isSchemeless(text, start)) || inLink(start)) {
|
|
6516
|
+
continue;
|
|
6517
|
+
}
|
|
6518
|
+
while (end > start && text[end - 1] === ".") {
|
|
6519
|
+
end--;
|
|
6520
|
+
}
|
|
6521
|
+
const host = bareName(text.slice(start, end));
|
|
6522
|
+
if (!host || seen.has(host)) {
|
|
6523
|
+
continue;
|
|
6524
|
+
}
|
|
6525
|
+
if (seen.size < MAX_SEEN) {
|
|
6526
|
+
seen.add(host);
|
|
6527
|
+
}
|
|
6528
|
+
if (isRealName(host)) {
|
|
6529
|
+
add(`http://${host}/`);
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
function looseHosts(text, add, { from = 0, cutEnd = false, seen, done }) {
|
|
6534
|
+
const inLink = linkReader(text);
|
|
6535
|
+
const { length } = text;
|
|
6536
|
+
let i = 0;
|
|
6537
|
+
while (i < length) {
|
|
6538
|
+
if (!isHostCode2(text.codePointAt(i))) {
|
|
6539
|
+
i++;
|
|
6540
|
+
continue;
|
|
6541
|
+
}
|
|
6542
|
+
const start = i;
|
|
6543
|
+
while (i < length && isHostCode2(text.codePointAt(i))) {
|
|
6544
|
+
i++;
|
|
6545
|
+
}
|
|
6546
|
+
let end = i;
|
|
6547
|
+
if (end - start > MAX_HOST || start < from || cutEnd && end === length) {
|
|
6548
|
+
continue;
|
|
6549
|
+
}
|
|
6550
|
+
while (end > start && text[end - 1] === ".") {
|
|
6551
|
+
end--;
|
|
6552
|
+
}
|
|
6553
|
+
const before = start > 0 ? text[start - 1] : "";
|
|
6554
|
+
const after = end < length ? text[end] : "";
|
|
6555
|
+
if (after === "/" || after === "@" || before === "@") {
|
|
6556
|
+
continue;
|
|
6557
|
+
}
|
|
6558
|
+
if (before && (IN_WORD2.test(before) || before === "/" || before === "\\" || before === "&" || before === "#")) {
|
|
6559
|
+
continue;
|
|
6560
|
+
}
|
|
6561
|
+
if (after && after !== "." && IN_WORD2.test(after)) {
|
|
6562
|
+
continue;
|
|
6563
|
+
}
|
|
6564
|
+
const name = text.slice(start, end);
|
|
6565
|
+
if (!name.includes(".") || inLink(start)) {
|
|
6566
|
+
continue;
|
|
6567
|
+
}
|
|
6568
|
+
const lower = name.toLowerCase();
|
|
6569
|
+
if (seen.has(lower)) {
|
|
6570
|
+
continue;
|
|
6571
|
+
}
|
|
6572
|
+
if (seen.size < MAX_SEEN) {
|
|
6573
|
+
seen.add(lower);
|
|
6574
|
+
}
|
|
6575
|
+
if (done()) {
|
|
6576
|
+
return;
|
|
6577
|
+
}
|
|
6578
|
+
const host = bareName(name);
|
|
6579
|
+
if (host && isRealName(host)) {
|
|
6580
|
+
add(host);
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
function* chunksOf(html2) {
|
|
6585
|
+
let start = 0;
|
|
6586
|
+
let cutStart = false;
|
|
6587
|
+
while (start < html2.length) {
|
|
6588
|
+
const end = Math.min(html2.length, start + DECODE_CHUNK);
|
|
6589
|
+
if (end < html2.length) {
|
|
6590
|
+
let cut = end;
|
|
6591
|
+
while (cut > end - 65536 && cut > start) {
|
|
6592
|
+
if (html2[cut] === "<" || isSpace(html2.codePointAt(cut))) {
|
|
6593
|
+
break;
|
|
6594
|
+
}
|
|
6595
|
+
cut--;
|
|
6596
|
+
}
|
|
6597
|
+
if (cut > start && cut > end - 65536) {
|
|
6598
|
+
yield { text: html2.slice(start, cut), cutStart, cutEnd: false };
|
|
6599
|
+
start = cut;
|
|
6600
|
+
cutStart = false;
|
|
6601
|
+
continue;
|
|
6602
|
+
}
|
|
6603
|
+
let hard = end;
|
|
6604
|
+
while (hard > start + CHUNK_OVERLAP + 1 && /[\dA-Za-z#]/.test(html2[hard - 1])) {
|
|
6605
|
+
hard--;
|
|
6606
|
+
}
|
|
6607
|
+
if (hard < end && html2[hard - 1] === "&" && hard - 1 > start + CHUNK_OVERLAP) {
|
|
6608
|
+
hard--;
|
|
6609
|
+
} else {
|
|
6610
|
+
hard = end;
|
|
6611
|
+
}
|
|
6612
|
+
yield { text: html2.slice(start, hard), cutStart, cutEnd: true };
|
|
6613
|
+
start = hard - CHUNK_OVERLAP;
|
|
6614
|
+
cutStart = true;
|
|
6615
|
+
continue;
|
|
6616
|
+
}
|
|
6617
|
+
yield { text: html2.slice(start, end), cutStart, cutEnd: false };
|
|
6618
|
+
start = end;
|
|
6619
|
+
}
|
|
6620
|
+
}
|
|
6621
|
+
function withoutNul(text) {
|
|
6622
|
+
return text.includes("\0") ? `${text}
|
|
6623
|
+
${text.replaceAll("\0", "")}` : text;
|
|
6624
|
+
}
|
|
6625
|
+
function hexValue(code) {
|
|
6626
|
+
if (code >= 48 && code <= 57) {
|
|
6627
|
+
return code - 48;
|
|
6628
|
+
}
|
|
6629
|
+
if (code >= 65 && code <= 70) {
|
|
6630
|
+
return code - 55;
|
|
6631
|
+
}
|
|
6632
|
+
if (code >= 97 && code <= 102) {
|
|
6633
|
+
return code - 87;
|
|
6634
|
+
}
|
|
6635
|
+
return -1;
|
|
6636
|
+
}
|
|
6637
|
+
function percentDecoded(text) {
|
|
6638
|
+
const input = import_node_buffer7.Buffer.from(text);
|
|
6639
|
+
const output = import_node_buffer7.Buffer.allocUnsafe(input.length);
|
|
6640
|
+
let length = 0;
|
|
6641
|
+
for (let i = 0; i < input.length; i++) {
|
|
6642
|
+
const high = input[i] === 37 ? hexValue(input[i + 1]) : -1;
|
|
6643
|
+
const low = high === -1 ? -1 : hexValue(input[i + 2]);
|
|
6644
|
+
if (low === -1) {
|
|
6645
|
+
output[length++] = input[i];
|
|
6646
|
+
continue;
|
|
6647
|
+
}
|
|
6648
|
+
output[length++] = high * 16 + low;
|
|
6649
|
+
i += 2;
|
|
6650
|
+
}
|
|
6651
|
+
return output.subarray(0, length);
|
|
6652
|
+
}
|
|
6653
|
+
function swapped(bytes) {
|
|
6654
|
+
return import_node_buffer7.Buffer.from(bytes.subarray(0, bytes.length - bytes.length % 2)).swap16().toString("utf16le");
|
|
6655
|
+
}
|
|
6656
|
+
function decodeText(content, charset = "") {
|
|
6657
|
+
if (content[0] === 255 && content[1] === 254) {
|
|
6658
|
+
return content.subarray(2).toString("utf16le");
|
|
6659
|
+
}
|
|
6660
|
+
if (content[0] === 254 && content[1] === 255) {
|
|
6661
|
+
return swapped(content.subarray(2));
|
|
6662
|
+
}
|
|
6663
|
+
if (UTF16LE.has(charset)) {
|
|
6664
|
+
return content.toString("utf16le");
|
|
6665
|
+
}
|
|
6666
|
+
return UTF16BE.has(charset) ? swapped(content) : content.toString("utf8");
|
|
6667
|
+
}
|
|
6668
|
+
function dataDocument(value) {
|
|
6669
|
+
const match = DATA_DOCUMENT.exec(value.slice(0, 1024));
|
|
6670
|
+
if (!match) {
|
|
6671
|
+
return null;
|
|
6672
|
+
}
|
|
6673
|
+
const bytes = percentDecoded(value.slice(match[0].length));
|
|
6674
|
+
const content = /;\s*base64\s*$/i.test(match[1]) ? import_node_buffer7.Buffer.from(bytes.toString("latin1"), "base64") : bytes;
|
|
6675
|
+
const charset = /;\s*charset\s*=\s*"?([^;"\s]+)/i.exec(match[1]);
|
|
6676
|
+
return decodeText(content, charset ? charset[1].toLowerCase() : "");
|
|
6677
|
+
}
|
|
6678
|
+
function readEscapes(text, lenient = false) {
|
|
6679
|
+
let index = text.indexOf("\\");
|
|
6680
|
+
if (index === -1) {
|
|
6681
|
+
return text;
|
|
6682
|
+
}
|
|
6683
|
+
let out = "";
|
|
6684
|
+
let parts = [];
|
|
6685
|
+
let start = 0;
|
|
6686
|
+
while (index !== -1 && index + 1 < text.length) {
|
|
6687
|
+
const next = text[index + 1];
|
|
6688
|
+
if (lenient || "nN,;\\".includes(next)) {
|
|
6689
|
+
parts.push(text.slice(start, index), next === "n" || next === "N" ? "\n" : next);
|
|
6690
|
+
start = index + 2;
|
|
6691
|
+
index = text.indexOf("\\", start);
|
|
6692
|
+
if (parts.length >= 65536) {
|
|
6693
|
+
out += parts.join("");
|
|
6694
|
+
parts = [];
|
|
6695
|
+
}
|
|
6696
|
+
} else {
|
|
6697
|
+
index = text.indexOf("\\", index + 1);
|
|
6698
|
+
}
|
|
6699
|
+
}
|
|
6700
|
+
parts.push(text.slice(start));
|
|
6701
|
+
return out + parts.join("");
|
|
6702
|
+
}
|
|
6703
|
+
function valueColon(line) {
|
|
6704
|
+
let colon = line.indexOf(":");
|
|
6705
|
+
let from = 0;
|
|
6706
|
+
for (; ; ) {
|
|
6707
|
+
const quote = line.indexOf('"', from);
|
|
6708
|
+
if (quote === -1 || colon === -1 || colon < quote) {
|
|
6709
|
+
return colon;
|
|
6710
|
+
}
|
|
6711
|
+
const end = line.indexOf('"', quote + 1);
|
|
6712
|
+
if (end === -1) {
|
|
6713
|
+
return -1;
|
|
6714
|
+
}
|
|
6715
|
+
from = end + 1;
|
|
6716
|
+
if (colon < from) {
|
|
6717
|
+
colon = line.indexOf(":", from);
|
|
6718
|
+
}
|
|
6719
|
+
}
|
|
6720
|
+
}
|
|
6721
|
+
function trimSpaceEnd(text) {
|
|
6722
|
+
let end = text.length;
|
|
6723
|
+
while (end > 0 && (text[end - 1] === " " || text[end - 1] === " ")) {
|
|
6724
|
+
end--;
|
|
6725
|
+
}
|
|
6726
|
+
return end === text.length ? text : text.slice(0, end);
|
|
6727
|
+
}
|
|
6728
|
+
function decodeQuotedPrintable(value, charset) {
|
|
6729
|
+
let decoder;
|
|
6730
|
+
try {
|
|
6731
|
+
decoder = new TextDecoder(charset || "utf8");
|
|
6732
|
+
} catch {
|
|
6733
|
+
decoder = new TextDecoder("utf8");
|
|
6734
|
+
}
|
|
6735
|
+
if (!/[\u0080-\u{10FFFF}]/u.test(value)) {
|
|
6736
|
+
const bytes = import_node_buffer7.Buffer.from(value, "latin1");
|
|
6737
|
+
let length = 0;
|
|
6738
|
+
for (let index = 0; index < bytes.length; index++) {
|
|
6739
|
+
const hex = bytes[index] === 61 ? value.slice(index + 1, index + 3) : "";
|
|
6740
|
+
if (/^[\da-f]{2}$/i.test(hex)) {
|
|
6741
|
+
bytes[length++] = Number.parseInt(hex, 16);
|
|
6742
|
+
index += 2;
|
|
6743
|
+
} else {
|
|
6744
|
+
bytes[length++] = bytes[index];
|
|
6745
|
+
}
|
|
6746
|
+
}
|
|
6747
|
+
return decoder.decode(bytes.subarray(0, length));
|
|
6748
|
+
}
|
|
6749
|
+
return value.replaceAll(/(?:=[\da-f]{2})+/gi, (run) => decoder.decode(import_node_buffer7.Buffer.from(run.replaceAll("=", ""), "hex")));
|
|
6750
|
+
}
|
|
6751
|
+
function quotedPrintableValues(text) {
|
|
6752
|
+
if (!/quoted-printable/i.test(text)) {
|
|
6753
|
+
return text;
|
|
6754
|
+
}
|
|
6755
|
+
const lines2 = text.split(LINE_BREAK);
|
|
6756
|
+
const out = [];
|
|
6757
|
+
for (let i = 0; i < lines2.length; i++) {
|
|
6758
|
+
const line = lines2[i];
|
|
6759
|
+
const colon = valueColon(line);
|
|
6760
|
+
const parameters = colon === -1 ? "" : line.slice(0, colon);
|
|
6761
|
+
if (colon === -1 || !QUOTED_PRINTABLE.test(parameters)) {
|
|
6762
|
+
out.push(line);
|
|
6763
|
+
continue;
|
|
6764
|
+
}
|
|
6765
|
+
const charset = /;\s*charset\s*=\s*"?([\w.:-]+)/i.exec(parameters)?.[1];
|
|
6766
|
+
const parts = [trimSpaceEnd(line.slice(colon + 1))];
|
|
6767
|
+
while (parts.at(-1).endsWith("=") && i + 1 < lines2.length) {
|
|
6768
|
+
parts[parts.length - 1] = parts.at(-1).slice(0, -1);
|
|
6769
|
+
parts.push(trimSpaceEnd(lines2[++i]));
|
|
6770
|
+
}
|
|
6771
|
+
out.push(line.slice(0, colon + 1) + decodeQuotedPrintable(parts.join(""), charset));
|
|
6772
|
+
}
|
|
6773
|
+
return out.join("\n");
|
|
6774
|
+
}
|
|
6775
|
+
function shownText(text) {
|
|
6776
|
+
const unfolded = text.replaceAll(FOLD, "");
|
|
6777
|
+
const shown = /* @__PURE__ */ new Set([text, readEscapes(unfolded)]);
|
|
6778
|
+
const decoded = quotedPrintableValues(unfolded);
|
|
6779
|
+
if (decoded !== unfolded) {
|
|
6780
|
+
shown.add(readEscapes(decoded));
|
|
6781
|
+
if (unfolded !== text) {
|
|
6782
|
+
shown.add(quotedPrintableValues(text));
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
if (/\\[^nN,;\\]/.test(decoded)) {
|
|
6786
|
+
shown.add(readEscapes(decoded, true));
|
|
6787
|
+
}
|
|
6788
|
+
return [...shown].reverse().join("\n");
|
|
6789
|
+
}
|
|
6790
|
+
function htmlDescriptions(text) {
|
|
6791
|
+
if (!/[<&]|altrep/i.test(text)) {
|
|
6792
|
+
return "";
|
|
6793
|
+
}
|
|
6794
|
+
const html2 = [];
|
|
6795
|
+
for (const line of text.replaceAll(FOLD, "").split(LINE_BREAK)) {
|
|
6796
|
+
const colon = valueColon(line);
|
|
6797
|
+
if (colon === -1) {
|
|
6798
|
+
continue;
|
|
6799
|
+
}
|
|
6800
|
+
const altrep = /;\s*altrep\s*=\s*"([^"]*)"/i.exec(line.slice(0, colon))?.[1];
|
|
6801
|
+
if (altrep) {
|
|
6802
|
+
html2.push(`<iframe src="${altrep.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<")}"></iframe>`);
|
|
6803
|
+
}
|
|
6804
|
+
if (!HTML_PROPERTIES.test(line)) {
|
|
6805
|
+
continue;
|
|
6806
|
+
}
|
|
6807
|
+
const value = readEscapes(line.slice(colon + 1));
|
|
6808
|
+
if (/[<&]/.test(value)) {
|
|
6809
|
+
html2.push(value);
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6812
|
+
return html2.join("\n");
|
|
6813
|
+
}
|
|
6814
|
+
function withoutBinaryValues(text) {
|
|
6815
|
+
if (!/base64|binary|encoding\s*=\s*"?b|;\s*b\s*[;:]/i.test(text)) {
|
|
6816
|
+
return text;
|
|
6817
|
+
}
|
|
6818
|
+
const lines2 = text.split(LINE_BREAK);
|
|
6819
|
+
const out = [];
|
|
6820
|
+
for (let i = 0; i < lines2.length; i++) {
|
|
6821
|
+
const line = lines2[i];
|
|
6822
|
+
const colon = valueColon(line);
|
|
6823
|
+
if (colon === -1 || !BINARY.test(line.slice(0, colon))) {
|
|
6824
|
+
out.push(line);
|
|
6825
|
+
continue;
|
|
6826
|
+
}
|
|
6827
|
+
const value = [line.slice(colon + 1)];
|
|
6828
|
+
let next = i + 1;
|
|
6829
|
+
while (next < lines2.length && (lines2[next].startsWith(" ") || lines2[next].startsWith(" "))) {
|
|
6830
|
+
value.push(lines2[next++]);
|
|
6831
|
+
}
|
|
6832
|
+
if (!value.every((part) => /^[\w+/=\s]*$/.test(part))) {
|
|
6833
|
+
for (let index = i; index < next; index++) {
|
|
6834
|
+
out.push(lines2[index]);
|
|
6835
|
+
}
|
|
6836
|
+
i = next - 1;
|
|
6837
|
+
continue;
|
|
6838
|
+
}
|
|
6839
|
+
while (next < lines2.length && lines2[next] !== "" && /^[\w+/=]+$/.test(lines2[next])) {
|
|
6840
|
+
value.push(lines2[next++]);
|
|
6841
|
+
}
|
|
6842
|
+
if (next < lines2.length && lines2[next] === "") {
|
|
6843
|
+
next++;
|
|
6844
|
+
}
|
|
6845
|
+
i = next - 1;
|
|
6846
|
+
const name = line.slice(0, colon).split(";")[0].split(".").pop().trim().toLowerCase();
|
|
6847
|
+
out.push(MEDIA_PROPERTIES.has(name) ? line.slice(0, colon + 1) : line.slice(0, colon + 1) + import_node_buffer7.Buffer.from(value.join("").replaceAll(/\s/g, ""), "base64").toString("utf8"));
|
|
6848
|
+
}
|
|
6849
|
+
return out.join("\n");
|
|
6850
|
+
}
|
|
6851
|
+
function extensionOf2(filename) {
|
|
6852
|
+
let end = filename.length;
|
|
6853
|
+
while (end > 0 && (filename[end - 1] === "." || filename[end - 1] === " ")) {
|
|
6854
|
+
end--;
|
|
6855
|
+
}
|
|
6856
|
+
const name = filename.slice(0, end).trim().toLowerCase();
|
|
6857
|
+
const index = name.lastIndexOf(".");
|
|
6858
|
+
return index !== -1 && index < name.length - 1 ? name.slice(index + 1) : null;
|
|
6859
|
+
}
|
|
6860
|
+
function extensionsOf(attachment) {
|
|
6861
|
+
const names = [];
|
|
6862
|
+
if (typeof attachment.filename === "string") {
|
|
6863
|
+
names.push(attachment.filename);
|
|
6864
|
+
}
|
|
6865
|
+
const { headers } = attachment;
|
|
6866
|
+
if (headers && typeof headers.get === "function") {
|
|
6867
|
+
for (const [field, parameter] of [["content-type", "name"], ["content-disposition", "filename"]]) {
|
|
6868
|
+
const value = headers.get(field)?.params?.[parameter];
|
|
6869
|
+
if (typeof value === "string" && value !== "") {
|
|
6870
|
+
names.push(value);
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6873
|
+
}
|
|
6874
|
+
return new Set(names.flatMap((name) => [extensionOf2(name), extensionOf(name)]).filter(Boolean));
|
|
6875
|
+
}
|
|
6876
|
+
function charsetOf(attachment) {
|
|
6877
|
+
const { headers } = attachment;
|
|
6878
|
+
const charset = headers && typeof headers.get === "function" ? headers.get("content-type")?.params?.charset : null;
|
|
6879
|
+
return typeof charset === "string" ? charset.toLowerCase() : "";
|
|
6880
|
+
}
|
|
6881
|
+
function kindOf(attachment) {
|
|
6882
|
+
const { content } = attachment ?? {};
|
|
6883
|
+
if (!import_node_buffer7.Buffer.isBuffer(content) || content.length === 0) {
|
|
6884
|
+
return null;
|
|
6885
|
+
}
|
|
6886
|
+
const type = typeof attachment.contentType === "string" ? attachment.contentType.toLowerCase() : "";
|
|
6887
|
+
const extensions = extensionsOf(attachment);
|
|
6888
|
+
const has = (set) => [...extensions].some((name) => set.has(name));
|
|
6889
|
+
if (MESSAGE_TYPES.has(type) || extensions.has("eml") || extensions.has("u8msg")) {
|
|
6890
|
+
return null;
|
|
6891
|
+
}
|
|
6892
|
+
const isHtml = HTML_TYPES.has(type) || has(HTML_EXTENSIONS);
|
|
6893
|
+
const isCard = !isHtml && (CARD_TYPES.has(type) || has(CARD_EXTENSIONS));
|
|
6894
|
+
const isText = isCard || !isHtml && type === "text/plain";
|
|
6895
|
+
return isHtml || isText ? { isHtml, isText, isCard } : null;
|
|
6896
|
+
}
|
|
6897
|
+
function* documentsOf(attachments, state, late) {
|
|
6898
|
+
const read = [];
|
|
6899
|
+
let bytes = 0;
|
|
6900
|
+
let opened = 0;
|
|
6901
|
+
for (const attachment of attachments) {
|
|
6902
|
+
const kind = kindOf(attachment);
|
|
6903
|
+
if (!kind) {
|
|
6904
|
+
continue;
|
|
6905
|
+
}
|
|
6906
|
+
if (!kind.isText && ++opened > MAX_ATTACHED || bytes + attachment.content.length > MAX_ATTACHED_BYTES) {
|
|
6907
|
+
state.tooComplex = true;
|
|
6908
|
+
break;
|
|
6909
|
+
}
|
|
6910
|
+
bytes += attachment.content.length;
|
|
6911
|
+
read.push({ attachment, kind });
|
|
6912
|
+
}
|
|
6913
|
+
for (const { attachment, kind: { isHtml, isCard } } of read) {
|
|
6914
|
+
if (late()) {
|
|
6915
|
+
state.incomplete = true;
|
|
6916
|
+
return;
|
|
6917
|
+
}
|
|
6918
|
+
const text = decodeText(attachment.content, charsetOf(attachment));
|
|
6919
|
+
if (isHtml) {
|
|
6920
|
+
yield { html: text };
|
|
6921
|
+
continue;
|
|
6922
|
+
}
|
|
6923
|
+
if (!isCard) {
|
|
6924
|
+
yield { text };
|
|
6925
|
+
continue;
|
|
6926
|
+
}
|
|
6927
|
+
let readable = withoutBinaryValues(text.length > MAX_CARD_BYTES ? text.slice(0, MAX_CARD_BYTES) : text);
|
|
6928
|
+
if (text.length > MAX_CARD_BYTES || readable.length > MAX_SHOWN_BYTES) {
|
|
6929
|
+
state.tooComplex = true;
|
|
6930
|
+
readable = readable.slice(0, MAX_SHOWN_BYTES);
|
|
6931
|
+
}
|
|
6932
|
+
if (late()) {
|
|
6933
|
+
state.incomplete = true;
|
|
6934
|
+
return;
|
|
6935
|
+
}
|
|
6936
|
+
yield { text: shownText(readable) };
|
|
6937
|
+
if (late()) {
|
|
6938
|
+
state.incomplete = true;
|
|
6939
|
+
return;
|
|
6940
|
+
}
|
|
6941
|
+
const html2 = htmlDescriptions(readable);
|
|
6942
|
+
if (html2 !== "") {
|
|
6943
|
+
yield { html: html2 };
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
}
|
|
6947
|
+
function carriedLinkHosts(mail, {
|
|
6948
|
+
mails = [],
|
|
6949
|
+
attachments = [],
|
|
6950
|
+
maxHosts = 250,
|
|
6951
|
+
hostsInText = false
|
|
6952
|
+
} = {}) {
|
|
6953
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
6954
|
+
const loose = /* @__PURE__ */ new Set();
|
|
6955
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6956
|
+
const seenBare = /* @__PURE__ */ new Set();
|
|
6957
|
+
const seenLoose = /* @__PURE__ */ new Set();
|
|
6958
|
+
let more = false;
|
|
6959
|
+
let full = false;
|
|
6960
|
+
const domains = /* @__PURE__ */ new Set();
|
|
6961
|
+
const state = { tooComplex: false, incomplete: false };
|
|
6962
|
+
const until = Date.now() + MAX_READ_TIME;
|
|
6963
|
+
const late = () => {
|
|
6964
|
+
if (!state.incomplete && Date.now() > until) {
|
|
6965
|
+
state.incomplete = true;
|
|
6966
|
+
}
|
|
6967
|
+
return state.incomplete;
|
|
6968
|
+
};
|
|
6969
|
+
let calls = 0;
|
|
6970
|
+
const done = () => full || state.incomplete || ++calls % LATE_EVERY === 0 && late();
|
|
6971
|
+
const looseDone = () => done() || loose.size > maxHosts;
|
|
6972
|
+
const addLoose = (host) => {
|
|
6973
|
+
if (!looseDone()) {
|
|
6974
|
+
loose.add(host);
|
|
6975
|
+
}
|
|
6976
|
+
};
|
|
6977
|
+
const queue = [mail, ...mails].map((document) => ({ document, depth: 0 }));
|
|
6978
|
+
const carried = documentsOf(attachments, state, late);
|
|
6979
|
+
let depth = 0;
|
|
6980
|
+
let embedded = 0;
|
|
6981
|
+
let embeddedLength = 0;
|
|
6982
|
+
const embeddedSeen = /* @__PURE__ */ new Set();
|
|
6983
|
+
const embed = (html2) => {
|
|
6984
|
+
if (html2 === "" || embeddedSeen.has(html2)) {
|
|
6985
|
+
return;
|
|
6986
|
+
}
|
|
6987
|
+
if (depth >= MAX_EMBED_DEPTH || embedded >= MAX_EMBEDDED || embeddedLength + html2.length > MAX_EMBEDDED_LENGTH) {
|
|
6988
|
+
state.tooComplex = true;
|
|
6989
|
+
return;
|
|
6990
|
+
}
|
|
6991
|
+
embeddedSeen.add(html2);
|
|
6992
|
+
embedded++;
|
|
6993
|
+
embeddedLength += html2.length;
|
|
6994
|
+
queue.push({ document: { html: html2 }, depth: depth + 1 });
|
|
6995
|
+
};
|
|
6996
|
+
const add = (value) => {
|
|
6997
|
+
if (full || typeof value !== "string" || value === "" || seen.has(value)) {
|
|
6998
|
+
return;
|
|
6999
|
+
}
|
|
7000
|
+
if (seen.size < MAX_SEEN) {
|
|
7001
|
+
seen.add(value);
|
|
7002
|
+
}
|
|
7003
|
+
if (/^\s*data:/i.test(value)) {
|
|
7004
|
+
const html2 = dataDocument(value);
|
|
7005
|
+
if (html2 !== null) {
|
|
7006
|
+
embed(html2);
|
|
7007
|
+
}
|
|
7008
|
+
return;
|
|
7009
|
+
}
|
|
7010
|
+
const found = hostsOf(value);
|
|
7011
|
+
if (found.unresolved) {
|
|
7012
|
+
state.tooComplex = true;
|
|
7013
|
+
}
|
|
7014
|
+
for (const host of found) {
|
|
7015
|
+
if (hosts.has(host)) {
|
|
7016
|
+
continue;
|
|
7017
|
+
}
|
|
7018
|
+
const domain = registrableDomain(host);
|
|
7019
|
+
if (hosts.size < maxHosts || !domains.has(domain) && domains.size < maxHosts) {
|
|
7020
|
+
hosts.add(host);
|
|
7021
|
+
domains.add(domain);
|
|
7022
|
+
continue;
|
|
7023
|
+
}
|
|
7024
|
+
more = true;
|
|
7025
|
+
if (domains.size >= maxHosts) {
|
|
7026
|
+
full = true;
|
|
7027
|
+
return;
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
};
|
|
7031
|
+
let spent = 0;
|
|
7032
|
+
const spend = (length) => {
|
|
7033
|
+
spent += length;
|
|
7034
|
+
if (spent < LONG_VALUE) {
|
|
7035
|
+
return false;
|
|
7036
|
+
}
|
|
7037
|
+
spent = 0;
|
|
7038
|
+
return late();
|
|
7039
|
+
};
|
|
7040
|
+
const reader = {
|
|
7041
|
+
add,
|
|
7042
|
+
embed,
|
|
7043
|
+
spend,
|
|
7044
|
+
cut() {
|
|
7045
|
+
state.tooComplex = true;
|
|
7046
|
+
}
|
|
7047
|
+
};
|
|
7048
|
+
const readText = (source, { cutStart = false, cutEnd = false, exact = false } = {}) => {
|
|
7049
|
+
for (const match of source.matchAll(URL_START)) {
|
|
7050
|
+
if (done()) {
|
|
7051
|
+
break;
|
|
7052
|
+
}
|
|
7053
|
+
if (cutStart && match.index === 0) {
|
|
7054
|
+
continue;
|
|
7055
|
+
}
|
|
7056
|
+
if (cutEnd && match.index + match[0].length === source.length) {
|
|
7057
|
+
if (exact && source.length - match.index < CHUNK_OVERLAP) {
|
|
7058
|
+
continue;
|
|
7059
|
+
}
|
|
7060
|
+
const value = match[0];
|
|
7061
|
+
const at = /^www\./i.test(value) ? 0 : value.indexOf("//") + 2;
|
|
7062
|
+
if (!/[/?#\\]/.test(value.slice(at))) {
|
|
7063
|
+
state.tooComplex = true;
|
|
7064
|
+
continue;
|
|
7065
|
+
}
|
|
7066
|
+
add(value);
|
|
7067
|
+
const url = urlOf(value);
|
|
7068
|
+
if (url && isClickTracker(url)) {
|
|
7069
|
+
state.tooComplex = true;
|
|
7070
|
+
}
|
|
7071
|
+
continue;
|
|
7072
|
+
}
|
|
7073
|
+
add(match[0]);
|
|
7074
|
+
}
|
|
7075
|
+
const from = cutStart ? 1 : 0;
|
|
7076
|
+
bareHosts(source, add, {
|
|
7077
|
+
done,
|
|
7078
|
+
seen: seenBare,
|
|
7079
|
+
from,
|
|
7080
|
+
cutEnd
|
|
7081
|
+
});
|
|
7082
|
+
if (hostsInText && !looseDone()) {
|
|
7083
|
+
looseHosts(source, addLoose, {
|
|
7084
|
+
from,
|
|
7085
|
+
cutEnd,
|
|
7086
|
+
seen: seenLoose,
|
|
7087
|
+
done: looseDone
|
|
7088
|
+
});
|
|
7089
|
+
}
|
|
7090
|
+
};
|
|
7091
|
+
for (let index = 0; ; index++) {
|
|
7092
|
+
if (full || late()) {
|
|
7093
|
+
break;
|
|
7094
|
+
}
|
|
7095
|
+
if (index >= queue.length) {
|
|
7096
|
+
const next = carried.next();
|
|
7097
|
+
if (next.done) {
|
|
7098
|
+
break;
|
|
7099
|
+
}
|
|
7100
|
+
queue.push({ document: next.value, depth: 0 });
|
|
7101
|
+
}
|
|
7102
|
+
({ depth } = queue[index]);
|
|
7103
|
+
const { document } = queue[index];
|
|
7104
|
+
const html2 = withoutNul(typeof document?.html === "string" ? document.html : "");
|
|
7105
|
+
const text = withoutNul(typeof document?.text === "string" ? document.text : "");
|
|
7106
|
+
for (const [name, value] of attributesOf(html2)) {
|
|
7107
|
+
if (done()) {
|
|
7108
|
+
break;
|
|
7109
|
+
}
|
|
7110
|
+
if (!LINK_ATTRIBUTES.has(name)) {
|
|
7111
|
+
continue;
|
|
7112
|
+
}
|
|
7113
|
+
if (spend(value.length)) {
|
|
7114
|
+
break;
|
|
7115
|
+
}
|
|
7116
|
+
linksOf(name, value, reader);
|
|
7117
|
+
}
|
|
7118
|
+
lenientLinks(html2, done, reader);
|
|
7119
|
+
for (const pattern of [CSS_URL, CSS_IMPORT]) {
|
|
7120
|
+
for (const [, link] of html2.matchAll(pattern)) {
|
|
7121
|
+
if (done() || spend(link.length)) {
|
|
7122
|
+
break;
|
|
7123
|
+
}
|
|
7124
|
+
if (link.length > MAX_VALUE2) {
|
|
7125
|
+
state.tooComplex = true;
|
|
7126
|
+
}
|
|
7127
|
+
add(decodeEntities(link.slice(0, MAX_VALUE2), { attribute: true }));
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
for (const chunk2 of chunksOf(text)) {
|
|
7131
|
+
if (full || late()) {
|
|
7132
|
+
break;
|
|
7133
|
+
}
|
|
7134
|
+
readText(chunk2.text, { ...chunk2, exact: true });
|
|
7135
|
+
}
|
|
7136
|
+
for (const chunk2 of chunksOf(html2)) {
|
|
7137
|
+
if (full || late()) {
|
|
7138
|
+
break;
|
|
7139
|
+
}
|
|
7140
|
+
const decoded = decodeEntities(chunk2.text);
|
|
7141
|
+
readText(decoded, { ...chunk2, exact: decoded.endsWith(chunk2.text.slice(-CHUNK_OVERLAP)) });
|
|
7142
|
+
}
|
|
7143
|
+
}
|
|
7144
|
+
if (!more && !state.incomplete) {
|
|
7145
|
+
for (const name of loose) {
|
|
7146
|
+
if (hosts.size >= maxHosts) {
|
|
7147
|
+
break;
|
|
7148
|
+
}
|
|
7149
|
+
const [host] = hostsOf(`http://${name}/`);
|
|
7150
|
+
if (host) {
|
|
7151
|
+
hosts.add(host);
|
|
7152
|
+
}
|
|
7153
|
+
}
|
|
7154
|
+
}
|
|
7155
|
+
return {
|
|
7156
|
+
hosts: [...hosts],
|
|
7157
|
+
more,
|
|
7158
|
+
tooComplex: state.tooComplex,
|
|
7159
|
+
incomplete: state.incomplete
|
|
7160
|
+
};
|
|
7161
|
+
}
|
|
7162
|
+
var import_node_buffer7, import_node_net4, import_tldts4, LINK_ATTRIBUTES, TAG_START, URL_START, CSS_URL, CSS_IMPORT, LENIENT, IN_WORD2, NAMESPACES, MAX_HOST, MAX_SEEN, TRAILING, DECODE_CHUNK, CHUNK_OVERLAP, MAX_EMBED_DEPTH, MAX_EMBEDDED, MAX_EMBEDDED_LENGTH, MAX_ATTACHED, MAX_ATTACHED_BYTES, MAX_READ_TIME, MAX_CARD_BYTES, MAX_SHOWN_BYTES, MAX_VALUE2, LONG_VALUE, MAX_LENIENT_VALUE, UNQUOTED_END, UTF16LE, UTF16BE, DATA_DOCUMENT, LINE_BREAK, FOLD, QUOTED_PRINTABLE, MEDIA_PROPERTIES, HTML_PROPERTIES, BINARY, HTML_TYPES, HTML_EXTENSIONS, CARD_TYPES, CARD_EXTENSIONS, MESSAGE_TYPES, LATE_EVERY;
|
|
7163
|
+
var init_links = __esm({
|
|
7164
|
+
"src/links.js"() {
|
|
7165
|
+
import_node_buffer7 = require("node:buffer");
|
|
7166
|
+
import_node_net4 = require("node:net");
|
|
7167
|
+
import_tldts4 = require("tldts");
|
|
7168
|
+
init_attachments();
|
|
7169
|
+
init_dnsbl();
|
|
7170
|
+
init_html();
|
|
7171
|
+
init_tokenizer();
|
|
7172
|
+
LINK_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
7173
|
+
"href",
|
|
7174
|
+
"src",
|
|
7175
|
+
"srcset",
|
|
7176
|
+
"background",
|
|
7177
|
+
"action",
|
|
7178
|
+
"formaction",
|
|
7179
|
+
"poster",
|
|
7180
|
+
"cite",
|
|
7181
|
+
"longdesc",
|
|
7182
|
+
"xlink:href",
|
|
7183
|
+
"style",
|
|
7184
|
+
"data",
|
|
7185
|
+
"ping",
|
|
7186
|
+
// (of a <meta> refresh: "0;url=https://example.com/")
|
|
7187
|
+
"content",
|
|
7188
|
+
// (a document of its own, see linksOf)
|
|
7189
|
+
"srcdoc"
|
|
7190
|
+
]);
|
|
7191
|
+
TAG_START = /<[a-z][^\s/>]*/gi;
|
|
7192
|
+
URL_START = /\b(?:https?:\/\/|www\.)[^\s<>"'`]+/gi;
|
|
7193
|
+
CSS_URL = /url\(\s*["']?([^()"']*)/gi;
|
|
7194
|
+
CSS_IMPORT = /@import\s+["']([^"'<>]*)/gi;
|
|
7195
|
+
LENIENT = /[\s"'/<](href|src|srcset|background|action|formaction|poster|cite|longdesc|xlink:href|style|data|ping|content|srcdoc)\s*=\s*/gi;
|
|
7196
|
+
IN_WORD2 = /[\p{L}\p{N}\p{M}_%]/u;
|
|
7197
|
+
NAMESPACES = /* @__PURE__ */ new Set(["www.w3.org", "w3.org"]);
|
|
7198
|
+
MAX_HOST = 760;
|
|
7199
|
+
MAX_SEEN = 1e5;
|
|
7200
|
+
TRAILING = /* @__PURE__ */ new Set([")", ".", ",", ";", ":", "!", "?", "'", '"', "]"]);
|
|
7201
|
+
DECODE_CHUNK = 1024 * 1024;
|
|
7202
|
+
CHUNK_OVERLAP = 4096;
|
|
7203
|
+
MAX_EMBED_DEPTH = 3;
|
|
7204
|
+
MAX_EMBEDDED = 1e3;
|
|
7205
|
+
MAX_EMBEDDED_LENGTH = 10 * 1024 * 1024;
|
|
7206
|
+
MAX_ATTACHED = 100;
|
|
7207
|
+
MAX_ATTACHED_BYTES = 50 * 1024 * 1024;
|
|
7208
|
+
MAX_READ_TIME = 5e3;
|
|
7209
|
+
MAX_CARD_BYTES = 4 * 1024 * 1024;
|
|
7210
|
+
MAX_SHOWN_BYTES = 1024 * 1024;
|
|
7211
|
+
MAX_VALUE2 = 1024 * 1024;
|
|
7212
|
+
LONG_VALUE = 64 * 1024;
|
|
7213
|
+
MAX_LENIENT_VALUE = 4096;
|
|
7214
|
+
UNQUOTED_END = /* @__PURE__ */ new Set(["<", ">", '"', "'", "`", "="]);
|
|
7215
|
+
UTF16LE = /* @__PURE__ */ new Set(["csunicode", "iso-10646-ucs-2", "ucs-2", "unicode", "unicodefeff", "utf-16", "utf-16le"]);
|
|
7216
|
+
UTF16BE = /* @__PURE__ */ new Set(["unicodefffe", "utf-16be"]);
|
|
7217
|
+
DATA_DOCUMENT = /^\s*data:\s*(?:text\/html|application\/xhtml\+xml|image\/svg\+xml|text\/xml|application\/xml)\b([^,]*),/i;
|
|
7218
|
+
LINE_BREAK = /\r\n?|\n/;
|
|
7219
|
+
FOLD = /(?:\r\n?|\n)[ \t]/g;
|
|
7220
|
+
QUOTED_PRINTABLE = /;\s*(?:encoding\s*=\s*)?"?quoted-printable"?\s*(?:;|$)/i;
|
|
7221
|
+
MEDIA_PROPERTIES = /* @__PURE__ */ new Set(["photo", "logo", "sound", "key", "attach"]);
|
|
7222
|
+
HTML_PROPERTIES = /^(?:x-alt-desc|styled-description|description|comment)[;:]/i;
|
|
7223
|
+
BINARY = /;\s*(?:(?:encoding\s*=\s*)?"?(?:b|base64)"?|value\s*=\s*"?binary"?)\s*(?:;|$)/i;
|
|
7224
|
+
HTML_TYPES = /* @__PURE__ */ new Set(["text/html", "application/xhtml+xml", "image/svg+xml", "text/xml", "application/xml"]);
|
|
7225
|
+
HTML_EXTENSIONS = /* @__PURE__ */ new Set(["html", "htm", "shtml", "xhtml", "xht", "svg", "xml"]);
|
|
7226
|
+
CARD_TYPES = /* @__PURE__ */ new Set(["text/calendar", "text/x-vcalendar", "application/ics", "text/vcard", "text/x-vcard", "text/directory"]);
|
|
7227
|
+
CARD_EXTENSIONS = /* @__PURE__ */ new Set(["ics", "ical", "ifb", "vcs", "vcf", "vcard"]);
|
|
7228
|
+
MESSAGE_TYPES = /* @__PURE__ */ new Set(["message/rfc822", "message/global"]);
|
|
7229
|
+
LATE_EVERY = 1024;
|
|
7230
|
+
}
|
|
7231
|
+
});
|
|
7232
|
+
|
|
6018
7233
|
// src/is-arbitrary.js
|
|
6019
7234
|
function unquoted(text) {
|
|
6020
7235
|
let start = 0;
|
|
@@ -6079,13 +7294,13 @@ function joinsDisplay(brand, display, name) {
|
|
|
6079
7294
|
return false;
|
|
6080
7295
|
}
|
|
6081
7296
|
function isOfficial({ brand, official }, domain, display, shared = true) {
|
|
6082
|
-
const parsed = (0,
|
|
7297
|
+
const parsed = (0, import_tldts5.parse)(domain);
|
|
6083
7298
|
const name = parsed.domainWithoutSuffix ?? "";
|
|
6084
7299
|
const compact = brand.replaceAll(" ", "");
|
|
6085
7300
|
if (parsed.publicSuffix === compact || compact.length >= 5 && joinsDisplay(brand, display, name) && !JOINED_WORDS.some((word) => name.slice(compact.length).includes(word))) {
|
|
6086
7301
|
return true;
|
|
6087
7302
|
}
|
|
6088
|
-
return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || (0,
|
|
7303
|
+
return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || (0, import_tldts5.parse)(entry).domain !== null) && (domain === entry || domain.endsWith(`.${entry}`)) : name === entry);
|
|
6089
7304
|
}
|
|
6090
7305
|
function headerString(mail, name) {
|
|
6091
7306
|
const value = mail.headers?.get?.(name);
|
|
@@ -6187,7 +7402,7 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
|
|
|
6187
7402
|
}
|
|
6188
7403
|
} else if (claimed && isWholeName(name, claimed)) {
|
|
6189
7404
|
const domain = claimed[1];
|
|
6190
|
-
const brand = MAILBOXES.has((0,
|
|
7405
|
+
const brand = MAILBOXES.has((0, import_tldts5.parse)(domain).domainWithoutSuffix) ? null : DISPLAY_BRANDS.find((entry) => isOfficial(entry, domain, "", false) && !isOfficial(entry, session.originalFromAddressDomain, ""));
|
|
6191
7406
|
if (brand) {
|
|
6192
7407
|
hit("FROM_NAME_BRAND", 2, `Display name is an address of "${brand.brand}" but the message is from ${fromRoot}`, "PHISHING");
|
|
6193
7408
|
}
|
|
@@ -6220,10 +7435,10 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
|
|
|
6220
7435
|
category
|
|
6221
7436
|
};
|
|
6222
7437
|
}
|
|
6223
|
-
var
|
|
7438
|
+
var import_tldts5, GTUBE, BLOCKED_SUBJECT, HACKED_SUBJECT, COIN, CODE, CURRENCY, MONEY, CRYPTOCURRENCY, AMOUNT_DEMAND, AMOUNT_GIVEN, HARM_VERB, HARMED, RECORDING, THREAT, HOURS, COUNT, DEADLINE, isPaymentDemand, BITCOIN_ADDRESS, IGNORE_INSTRUCTIONS, AI_ACTION, AI_OBJECT, AI_ACTION_OBJECT, AI_NEAR, VERDICT, VERDICT_WORD, VERDICT_ORDER, VERDICT_CLAIM, CLASSIFY, SYSTEM_PROMPT, YOU_ARE, QUOTE, CONDITION, DISCUSSED, DISCUSSED_SHOWN, DISCUSSED_NEAR, isDiscussed, isInjection, QUOTE_OR_SPACE, SHOWN_NEAR, isOrder, PAYPAL_DOMAIN, PAYPAL_SPAM_TYPE_IDS, PAYPAL_OWN_REQUEST, PAYPAL_INVOICE_SUBJECT, MS_SPAM_VERDICT, MS_SPAM_CATEGORY, APPLE_NEXT, APPLE_FILLER, APPLE_STRONG, APPLE_BUSINESS, APPLE_ALONE, APPLE_BESIDE, APPLE_PART, NEXT_WORD, MAX_AFTER, APPLE, DISPLAY_BRANDS, ADDRESSES, LIST_HOSTS, VIA_LIST, MAILBOXES, BEFORE_ADDRESS, AFTER_ADDRESS, isWholeName, JOINED_WORDS, MAX_DISPLAY;
|
|
6224
7439
|
var init_is_arbitrary = __esm({
|
|
6225
7440
|
"src/is-arbitrary.js"() {
|
|
6226
|
-
|
|
7441
|
+
import_tldts5 = require("tldts");
|
|
6227
7442
|
init_homograph();
|
|
6228
7443
|
init_html();
|
|
6229
7444
|
init_linear();
|
|
@@ -6474,7 +7689,7 @@ function authHeaders(config) {
|
|
|
6474
7689
|
case "basic": {
|
|
6475
7690
|
const user = config.username ?? "";
|
|
6476
7691
|
const pass = config.password ?? config.apiKey ?? "";
|
|
6477
|
-
headers.authorization = `Basic ${
|
|
7692
|
+
headers.authorization = `Basic ${import_node_buffer8.Buffer.from(`${user}:${pass}`).toString("base64")}`;
|
|
6478
7693
|
break;
|
|
6479
7694
|
}
|
|
6480
7695
|
case "x-api-key": {
|
|
@@ -6921,10 +8136,10 @@ function replyText(api, reply2) {
|
|
|
6921
8136
|
}
|
|
6922
8137
|
return reply2?.choices?.[0]?.message?.content || null;
|
|
6923
8138
|
}
|
|
6924
|
-
var
|
|
8139
|
+
var import_node_buffer8, import_node_crypto2, import_node_os, import_node_process, PROVIDERS, DECISION_APIS, TOP_LOGPROBS, VERDICTS, VERDICT_CRITERIA, SIGNS, GUIDE, DEFAULT_SYSTEM_PROMPT, DECISION_SYSTEM_PROMPT, DECISION_INSTRUCTIONS, LOCALHOST, PRIVATE_HOST, REDACTIONS, THINK_OPEN, THINK_CLOSE, ANSWER_FIRST, LOCAL_CHARACTER, BREAKS2, VERDICT_WORD2, NOT, DENIED, JOINED, SPAM_LABEL, HAM_WORDS, HAM_LABEL, NOT_HAM_LABEL, UNWANTED, MIN_VERDICT_MASS, percent, MODES, LLMClassifier;
|
|
6925
8140
|
var init_llm = __esm({
|
|
6926
8141
|
"src/llm.js"() {
|
|
6927
|
-
|
|
8142
|
+
import_node_buffer8 = require("node:buffer");
|
|
6928
8143
|
import_node_crypto2 = require("node:crypto");
|
|
6929
8144
|
import_node_os = __toESM(require("node:os"), 1);
|
|
6930
8145
|
import_node_process = __toESM(require("node:process"), 1);
|
|
@@ -7676,7 +8891,7 @@ var init_package = __esm({
|
|
|
7676
8891
|
package_default = {
|
|
7677
8892
|
name: "spamscanner",
|
|
7678
8893
|
description: "Spam, phishing and malware filter for email in any language: a trainable classifier, link and attachment checks, SPF/DKIM/DMARC, and an optional AI second opinion from any LLM, including local Ollama models. Works as a library, CLI, Postfix milter or HTTP API.",
|
|
7679
|
-
version: "7.0.
|
|
8894
|
+
version: "7.0.12",
|
|
7680
8895
|
author: "Forward Email (https://forwardemail.net)",
|
|
7681
8896
|
bin: {
|
|
7682
8897
|
spamscanner: "./dist/esm/cli.js"
|
|
@@ -7865,10 +9080,10 @@ function splitMessage(raw) {
|
|
|
7865
9080
|
const match = /^\r?\n|\r?\n\r?\n/.exec(text);
|
|
7866
9081
|
if (!match) {
|
|
7867
9082
|
const newline2 = text.includes("\n") && !text.includes("\r\n") ? "\n" : "\r\n";
|
|
7868
|
-
return { header: text.replace(/\r?\n$/, ""), body:
|
|
9083
|
+
return { header: text.replace(/\r?\n$/, ""), body: import_node_buffer9.Buffer.alloc(0), newline: newline2 };
|
|
7869
9084
|
}
|
|
7870
9085
|
const newline = match[0].startsWith("\r") ? "\r\n" : "\n";
|
|
7871
|
-
return { header: text.slice(0, match.index), body: raw.subarray(
|
|
9086
|
+
return { header: text.slice(0, match.index), body: raw.subarray(import_node_buffer9.Buffer.byteLength(text.slice(0, match.index + match[0].length), "latin1")), newline };
|
|
7872
9087
|
}
|
|
7873
9088
|
function subjectTagText(tag, spaceAfter = false) {
|
|
7874
9089
|
const line = String(tag).replaceAll(new RegExp("\\p{Cc}+", "gu"), " ").trim();
|
|
@@ -7878,14 +9093,14 @@ function subjectTagText(tag, spaceAfter = false) {
|
|
|
7878
9093
|
const words2 = [];
|
|
7879
9094
|
let chunk2 = "";
|
|
7880
9095
|
for (const character of spaceAfter ? `${line} ` : line) {
|
|
7881
|
-
if (
|
|
9096
|
+
if (import_node_buffer9.Buffer.byteLength(chunk2 + character, "utf8") > ENCODED_BYTES) {
|
|
7882
9097
|
words2.push(chunk2);
|
|
7883
9098
|
chunk2 = "";
|
|
7884
9099
|
}
|
|
7885
9100
|
chunk2 += character;
|
|
7886
9101
|
}
|
|
7887
9102
|
words2.push(chunk2);
|
|
7888
|
-
return words2.map((word) => `=?UTF-8?B?${
|
|
9103
|
+
return words2.map((word) => `=?UTF-8?B?${import_node_buffer9.Buffer.from(word, "utf8").toString("base64")}?=`).join(" ");
|
|
7889
9104
|
}
|
|
7890
9105
|
function taggedSubject(tag, current, newline = "\r\n") {
|
|
7891
9106
|
const unfolded = current.replaceAll(/\r?\n/g, "");
|
|
@@ -7916,7 +9131,7 @@ function taggedSubject(tag, current, newline = "\r\n") {
|
|
|
7916
9131
|
return lines2.join(newline).slice("Subject: ".length);
|
|
7917
9132
|
}
|
|
7918
9133
|
function rewriteMessage(source, headers = [], options = {}) {
|
|
7919
|
-
const raw =
|
|
9134
|
+
const raw = import_node_buffer9.Buffer.isBuffer(source) ? source : import_node_buffer9.Buffer.from(String(source), "utf8");
|
|
7920
9135
|
const { header, body, newline } = splitMessage(raw);
|
|
7921
9136
|
const remove = options.remove ?? /^x-spam-/i;
|
|
7922
9137
|
const lines2 = header === "" ? [] : header.split(/\r?\n/);
|
|
@@ -7941,15 +9156,18 @@ function rewriteMessage(source, headers = [], options = {}) {
|
|
|
7941
9156
|
}
|
|
7942
9157
|
}
|
|
7943
9158
|
}
|
|
7944
|
-
const added = headers.map(([name, value]) => foldHeader(name,
|
|
7945
|
-
const mbox = kept.length > 0 && kept[0][0].startsWith("From ") ? kept.shift() : [];
|
|
9159
|
+
const added = headers.map(([name, value]) => foldHeader(name, import_node_buffer9.Buffer.from(String(value), "utf8").toString("latin1"), newline));
|
|
9160
|
+
const mbox = kept.length > 0 && kept[0][0].startsWith("From ") ? kept.shift().slice(0, 1) : [];
|
|
9161
|
+
if (kept.length > 0 && /^[ \t]/.test(kept[0][0])) {
|
|
9162
|
+
kept.shift();
|
|
9163
|
+
}
|
|
7946
9164
|
const head = [...mbox, ...added, ...kept.map((field) => field.join(newline))].join(newline);
|
|
7947
|
-
return
|
|
9165
|
+
return import_node_buffer9.Buffer.concat([import_node_buffer9.Buffer.from(head === "" ? newline : `${head}${newline}${newline}`, "latin1"), body]);
|
|
7948
9166
|
}
|
|
7949
|
-
var
|
|
9167
|
+
var import_node_buffer9, ENCODED_BYTES, PLAIN_WORD, ENCODED_LINE, MAX_LINE2, ENCODED_WORD, ENCODED_START;
|
|
7950
9168
|
var init_headers = __esm({
|
|
7951
9169
|
"src/headers.js"() {
|
|
7952
|
-
|
|
9170
|
+
import_node_buffer9 = require("node:buffer");
|
|
7953
9171
|
ENCODED_BYTES = 39;
|
|
7954
9172
|
PLAIN_WORD = 64;
|
|
7955
9173
|
ENCODED_LINE = 76;
|
|
@@ -8125,7 +9343,7 @@ async function* readJsonl(file, options = {}) {
|
|
|
8125
9343
|
}
|
|
8126
9344
|
async function* walk(directory) {
|
|
8127
9345
|
const entries = await import_promises.default.readdir(directory, { withFileTypes: true });
|
|
8128
|
-
entries.sort((a, b) =>
|
|
9346
|
+
entries.sort((a, b) => import_node_buffer10.Buffer.compare(import_node_buffer10.Buffer.from(a.name), import_node_buffer10.Buffer.from(b.name)));
|
|
8129
9347
|
for (const entry of entries) {
|
|
8130
9348
|
if (SKIP.has(entry.name) || entry.name.startsWith(".")) {
|
|
8131
9349
|
continue;
|
|
@@ -8150,7 +9368,7 @@ async function* readMessages(source) {
|
|
|
8150
9368
|
const handle = await import_promises.default.open(file);
|
|
8151
9369
|
let head;
|
|
8152
9370
|
try {
|
|
8153
|
-
const { buffer, bytesRead } = await handle.read(
|
|
9371
|
+
const { buffer, bytesRead } = await handle.read(import_node_buffer10.Buffer.alloc(64), 0, 64, 0);
|
|
8154
9372
|
head = buffer.subarray(0, bytesRead).toString("latin1");
|
|
8155
9373
|
} finally {
|
|
8156
9374
|
await handle.close();
|
|
@@ -8162,10 +9380,10 @@ async function* readMessages(source) {
|
|
|
8162
9380
|
}
|
|
8163
9381
|
}
|
|
8164
9382
|
}
|
|
8165
|
-
var
|
|
9383
|
+
var import_node_buffer10, import_node_fs3, import_promises, import_node_path2, import_node_readline, import_node_zlib, SKIP, SPAM_LABELS, HAM_LABELS, MAX_RECORD_LINES, MAX_RECORD_LENGTH, TEXT_NAMES, LABEL_NAMES, JSONL_LABEL_NAMES, JSONL_TEXT_NAMES;
|
|
8166
9384
|
var init_sources = __esm({
|
|
8167
9385
|
"src/sources.js"() {
|
|
8168
|
-
|
|
9386
|
+
import_node_buffer10 = require("node:buffer");
|
|
8169
9387
|
import_node_fs3 = require("node:fs");
|
|
8170
9388
|
import_promises = __toESM(require("node:fs/promises"), 1);
|
|
8171
9389
|
import_node_path2 = __toESM(require("node:path"), 1);
|
|
@@ -8306,7 +9524,12 @@ var init_train = __esm({
|
|
|
8306
9524
|
|
|
8307
9525
|
// src/server.js
|
|
8308
9526
|
function serializeResult(result, options = {}) {
|
|
8309
|
-
const {
|
|
9527
|
+
const {
|
|
9528
|
+
mail,
|
|
9529
|
+
tokens,
|
|
9530
|
+
attached,
|
|
9531
|
+
...rest
|
|
9532
|
+
} = result;
|
|
8310
9533
|
const output = {
|
|
8311
9534
|
...rest,
|
|
8312
9535
|
results: { ...result.results }
|
|
@@ -8339,8 +9562,8 @@ function sessionFromQuery(query) {
|
|
|
8339
9562
|
return session;
|
|
8340
9563
|
}
|
|
8341
9564
|
function sameToken(given, expected) {
|
|
8342
|
-
const a =
|
|
8343
|
-
const b =
|
|
9565
|
+
const a = import_node_buffer11.Buffer.from(String(given));
|
|
9566
|
+
const b = import_node_buffer11.Buffer.from(String(expected));
|
|
8344
9567
|
return a.length === b.length && (0, import_node_crypto5.timingSafeEqual)(a, b);
|
|
8345
9568
|
}
|
|
8346
9569
|
function readBody(request, limit) {
|
|
@@ -8360,7 +9583,7 @@ function readBody(request, limit) {
|
|
|
8360
9583
|
reject(error);
|
|
8361
9584
|
return;
|
|
8362
9585
|
}
|
|
8363
|
-
resolve(
|
|
9586
|
+
resolve(import_node_buffer11.Buffer.concat(chunks));
|
|
8364
9587
|
});
|
|
8365
9588
|
request.on("error", reject);
|
|
8366
9589
|
});
|
|
@@ -8375,7 +9598,7 @@ function createHttpServer(scanner, options = {}) {
|
|
|
8375
9598
|
let active = 0;
|
|
8376
9599
|
const server = import_node_http2.default.createServer(async (request, response) => {
|
|
8377
9600
|
const send = (status, body, headers = {}) => {
|
|
8378
|
-
const isBuffer =
|
|
9601
|
+
const isBuffer = import_node_buffer11.Buffer.isBuffer(body);
|
|
8379
9602
|
response.writeHead(status, { "content-type": isBuffer ? "message/rfc822" : "application/json; charset=utf-8", "cache-control": "no-store", ...headers });
|
|
8380
9603
|
response.end(isBuffer ? body : `${JSON.stringify(body)}
|
|
8381
9604
|
`);
|
|
@@ -8448,14 +9671,14 @@ function createTcpServer(scanner, options = {}) {
|
|
|
8448
9671
|
timeout = 6e4,
|
|
8449
9672
|
maxConnections = MAX_CONNECTIONS
|
|
8450
9673
|
} = options;
|
|
8451
|
-
const server =
|
|
9674
|
+
const server = import_node_net5.default.createServer({ allowHalfOpen: true }, (socket) => {
|
|
8452
9675
|
const chunks = [];
|
|
8453
9676
|
let size = 0;
|
|
8454
9677
|
socket.setTimeout(timeout, () => socket.destroy());
|
|
8455
9678
|
const onEnd = async () => {
|
|
8456
9679
|
socket.setTimeout(0);
|
|
8457
9680
|
try {
|
|
8458
|
-
const result = await scanner.scan(
|
|
9681
|
+
const result = await scanner.scan(import_node_buffer11.Buffer.concat(chunks));
|
|
8459
9682
|
socket.end(json ? `${JSON.stringify(serializeResult(result))}
|
|
8460
9683
|
` : `${result.isSpam ? "SPAM" : "HAM"} ${result.score.toFixed(1)}/${result.threshold.toFixed(1)} ${result.tests.map((test) => test.name).join(",")}
|
|
8461
9684
|
`);
|
|
@@ -8484,13 +9707,13 @@ function createTcpServer(scanner, options = {}) {
|
|
|
8484
9707
|
server.maxConnections = maxConnections;
|
|
8485
9708
|
return server;
|
|
8486
9709
|
}
|
|
8487
|
-
var
|
|
9710
|
+
var import_node_buffer11, import_node_crypto5, import_node_http2, import_node_net5, MAX_MESSAGE_SIZE, MAX_CONNECTIONS;
|
|
8488
9711
|
var init_server = __esm({
|
|
8489
9712
|
"src/server.js"() {
|
|
8490
|
-
|
|
9713
|
+
import_node_buffer11 = require("node:buffer");
|
|
8491
9714
|
import_node_crypto5 = require("node:crypto");
|
|
8492
9715
|
import_node_http2 = __toESM(require("node:http"), 1);
|
|
8493
|
-
|
|
9716
|
+
import_node_net5 = __toESM(require("node:net"), 1);
|
|
8494
9717
|
init_headers();
|
|
8495
9718
|
init_version();
|
|
8496
9719
|
MAX_MESSAGE_SIZE = 25 * 1024 * 1024;
|
|
@@ -8499,12 +9722,12 @@ var init_server = __esm({
|
|
|
8499
9722
|
});
|
|
8500
9723
|
|
|
8501
9724
|
// src/milter.js
|
|
8502
|
-
function packet(command, data2 =
|
|
8503
|
-
const payload =
|
|
8504
|
-
const header =
|
|
9725
|
+
function packet(command, data2 = import_node_buffer12.Buffer.alloc(0)) {
|
|
9726
|
+
const payload = import_node_buffer12.Buffer.isBuffer(data2) ? data2 : import_node_buffer12.Buffer.from(data2, "latin1");
|
|
9727
|
+
const header = import_node_buffer12.Buffer.alloc(5);
|
|
8505
9728
|
header.writeUInt32BE(payload.length + 1);
|
|
8506
9729
|
header.write(command, 4, "latin1");
|
|
8507
|
-
return
|
|
9730
|
+
return import_node_buffer12.Buffer.concat([header, payload]);
|
|
8508
9731
|
}
|
|
8509
9732
|
function cstrings(data2) {
|
|
8510
9733
|
const parts = data2.toString("latin1").split("\0");
|
|
@@ -8514,19 +9737,19 @@ function cstrings(data2) {
|
|
|
8514
9737
|
return parts;
|
|
8515
9738
|
}
|
|
8516
9739
|
function cstring(value) {
|
|
8517
|
-
return
|
|
9740
|
+
return import_node_buffer12.Buffer.from(`${value}\0`, "latin1");
|
|
8518
9741
|
}
|
|
8519
9742
|
function address(value) {
|
|
8520
9743
|
const text = String(value ?? "").trim();
|
|
8521
9744
|
const match = /^<?([^<>]*)>?$/.exec(text);
|
|
8522
9745
|
return match ? match[1] : text;
|
|
8523
9746
|
}
|
|
8524
|
-
var
|
|
9747
|
+
var import_node_buffer12, import_node_events, import_node_net6, COMMANDS, RESPONSES, ACTIONS, PROTOCOL, MAX_PACKET, MilterSession, MilterServer;
|
|
8525
9748
|
var init_milter = __esm({
|
|
8526
9749
|
"src/milter.js"() {
|
|
8527
|
-
|
|
9750
|
+
import_node_buffer12 = require("node:buffer");
|
|
8528
9751
|
import_node_events = require("node:events");
|
|
8529
|
-
|
|
9752
|
+
import_node_net6 = __toESM(require("node:net"), 1);
|
|
8530
9753
|
init_headers();
|
|
8531
9754
|
init_auth();
|
|
8532
9755
|
init_server();
|
|
@@ -8644,7 +9867,7 @@ var init_milter = __esm({
|
|
|
8644
9867
|
if (this.buffered < this.needed) {
|
|
8645
9868
|
return;
|
|
8646
9869
|
}
|
|
8647
|
-
let buffer = this.chunks.length === 1 ? this.chunks[0] :
|
|
9870
|
+
let buffer = this.chunks.length === 1 ? this.chunks[0] : import_node_buffer12.Buffer.concat(this.chunks);
|
|
8648
9871
|
this.needed = 4;
|
|
8649
9872
|
while (buffer.length >= 4) {
|
|
8650
9873
|
const length = buffer.readUInt32BE(0);
|
|
@@ -8689,7 +9912,7 @@ var init_milter = __esm({
|
|
|
8689
9912
|
const protocol = data2.readUInt32BE(8);
|
|
8690
9913
|
const wanted = ACTIONS.ADDHDRS | ACTIONS.CHGHDRS | ACTIONS.QUARANTINE;
|
|
8691
9914
|
this.leadingSpace = Boolean(protocol & PROTOCOL.HDR_LEADSPC);
|
|
8692
|
-
const reply2 =
|
|
9915
|
+
const reply2 = import_node_buffer12.Buffer.alloc(12);
|
|
8693
9916
|
reply2.writeUInt32BE(Math.min(version, 6), 0);
|
|
8694
9917
|
reply2.writeUInt32BE(actions & wanted, 4);
|
|
8695
9918
|
reply2.writeUInt32BE(protocol & (PROTOCOL.HDR_LEADSPC | PROTOCOL.NOUNKNOWN), 8);
|
|
@@ -8754,7 +9977,7 @@ var init_milter = __esm({
|
|
|
8754
9977
|
if (this.truncated || this.size + data2.length > options.maxSize) {
|
|
8755
9978
|
this.truncated = true;
|
|
8756
9979
|
} else {
|
|
8757
|
-
this.body.push(
|
|
9980
|
+
this.body.push(import_node_buffer12.Buffer.from(data2));
|
|
8758
9981
|
this.size += data2.length;
|
|
8759
9982
|
}
|
|
8760
9983
|
this.send(RESPONSES.CONTINUE);
|
|
@@ -8789,7 +10012,7 @@ var init_milter = __esm({
|
|
|
8789
10012
|
/** @returns {Buffer} */
|
|
8790
10013
|
rawMessage() {
|
|
8791
10014
|
const head = this.headers.map(([name, value]) => `${name}:${this.leadingSpace || value.startsWith(" ") || value.startsWith(" ") ? "" : " "}${value}`).join("\r\n");
|
|
8792
|
-
return
|
|
10015
|
+
return import_node_buffer12.Buffer.concat([import_node_buffer12.Buffer.from(this.headers.length > 0 ? `${head}\r
|
|
8793
10016
|
\r
|
|
8794
10017
|
` : "\r\n", "latin1"), ...this.body]);
|
|
8795
10018
|
}
|
|
@@ -8800,9 +10023,9 @@ var init_milter = __esm({
|
|
|
8800
10023
|
const key = name.toLowerCase();
|
|
8801
10024
|
counts.set(key, (counts.get(key) || 0) + 1);
|
|
8802
10025
|
if (key.startsWith("x-spam-")) {
|
|
8803
|
-
const index =
|
|
10026
|
+
const index = import_node_buffer12.Buffer.alloc(4);
|
|
8804
10027
|
index.writeUInt32BE(counts.get(key));
|
|
8805
|
-
this.send(RESPONSES.CHGHEADER,
|
|
10028
|
+
this.send(RESPONSES.CHGHEADER, import_node_buffer12.Buffer.concat([index, cstring(name), cstring("")]));
|
|
8806
10029
|
}
|
|
8807
10030
|
}
|
|
8808
10031
|
}
|
|
@@ -8825,7 +10048,7 @@ var init_milter = __esm({
|
|
|
8825
10048
|
}
|
|
8826
10049
|
this.server.report(error);
|
|
8827
10050
|
this.removeForgedHeaders();
|
|
8828
|
-
this.send(RESPONSES.ADDHEADER,
|
|
10051
|
+
this.send(RESPONSES.ADDHEADER, import_node_buffer12.Buffer.concat([cstring("X-Spam-Virus-Scan"), cstring(`${this.leadingSpace ? " " : ""}failed`)]));
|
|
8829
10052
|
this.send(RESPONSES.CONTINUE);
|
|
8830
10053
|
this.resetMessage();
|
|
8831
10054
|
return;
|
|
@@ -8846,15 +10069,15 @@ var init_milter = __esm({
|
|
|
8846
10069
|
headers.unshift(["Authentication-Results", formatAuthResultsHeader(result.results.authentication, options.hostname)]);
|
|
8847
10070
|
}
|
|
8848
10071
|
for (const [name, value] of headers) {
|
|
8849
|
-
this.send(RESPONSES.ADDHEADER,
|
|
10072
|
+
this.send(RESPONSES.ADDHEADER, import_node_buffer12.Buffer.concat([cstring(name), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
|
|
8850
10073
|
}
|
|
8851
10074
|
if (result.isSpam && options.subjectTag) {
|
|
8852
10075
|
const subject = this.headers.find(([name]) => name.toLowerCase() === "subject");
|
|
8853
10076
|
const value = taggedSubject(options.subjectTag, subject ? subject[1].trim() : "", "\n");
|
|
8854
10077
|
if (value !== null) {
|
|
8855
|
-
const index =
|
|
10078
|
+
const index = import_node_buffer12.Buffer.alloc(4);
|
|
8856
10079
|
index.writeUInt32BE(1);
|
|
8857
|
-
this.send(RESPONSES.CHGHEADER,
|
|
10080
|
+
this.send(RESPONSES.CHGHEADER, import_node_buffer12.Buffer.concat([index, cstring("Subject"), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
|
|
8858
10081
|
}
|
|
8859
10082
|
}
|
|
8860
10083
|
if (result.action === "reject" && options.reject) {
|
|
@@ -8905,7 +10128,7 @@ var init_milter = __esm({
|
|
|
8905
10128
|
throw new RangeError(`rejectCode must be a 4xx or 5xx SMTP code, not ${this.options.rejectCode}`);
|
|
8906
10129
|
}
|
|
8907
10130
|
this.sockets = /* @__PURE__ */ new Set();
|
|
8908
|
-
this.server =
|
|
10131
|
+
this.server = import_node_net6.default.createServer((socket) => {
|
|
8909
10132
|
this.sockets.add(socket);
|
|
8910
10133
|
socket.on("close", () => this.sockets.delete(socket));
|
|
8911
10134
|
return new MilterSession(socket, this);
|
|
@@ -8981,7 +10204,7 @@ function reply(code, text, headers = [], body = null) {
|
|
|
8981
10204
|
lines2.push(`Content-length: ${body.length}`);
|
|
8982
10205
|
}
|
|
8983
10206
|
lines2.push(...headers.map(([name, value]) => `${name}: ${value}`), "", "");
|
|
8984
|
-
return body === null ?
|
|
10207
|
+
return body === null ? import_node_buffer13.Buffer.from(lines2.join("\r\n")) : import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from(lines2.join("\r\n")), body]);
|
|
8985
10208
|
}
|
|
8986
10209
|
function report(result) {
|
|
8987
10210
|
const lines2 = [
|
|
@@ -8991,7 +10214,7 @@ function report(result) {
|
|
|
8991
10214
|
"",
|
|
8992
10215
|
" pts rule name description",
|
|
8993
10216
|
"---- ---------------------- --------------------------------------------------",
|
|
8994
|
-
...result.tests.map((test) => `${test.score.toFixed(1).padStart(4)} ${test.name.padEnd(22)} ${test.description}`)
|
|
10217
|
+
...result.tests.map((test) => `${test.score.toFixed(1).padStart(4)} ${oneLine2(test.name).padEnd(22)} ${oneLine2(test.description)}`)
|
|
8995
10218
|
];
|
|
8996
10219
|
return `${lines2.join("\r\n")}\r
|
|
8997
10220
|
`;
|
|
@@ -9026,11 +10249,11 @@ async function answer(scanner, request, message, options) {
|
|
|
9026
10249
|
return reply(EX_OK, "EX_OK", [verdict]);
|
|
9027
10250
|
}
|
|
9028
10251
|
case "SYMBOLS": {
|
|
9029
|
-
return reply(EX_OK, "EX_OK", [verdict],
|
|
10252
|
+
return reply(EX_OK, "EX_OK", [verdict], import_node_buffer13.Buffer.from(result.tests.map((test) => test.name).join(",")));
|
|
9030
10253
|
}
|
|
9031
10254
|
case "REPORT":
|
|
9032
10255
|
case "REPORT_IFSPAM": {
|
|
9033
|
-
return reply(EX_OK, "EX_OK", [verdict], command === "REPORT" || result.isSpam ?
|
|
10256
|
+
return reply(EX_OK, "EX_OK", [verdict], command === "REPORT" || result.isSpam ? import_node_buffer13.Buffer.from(report(result)) : import_node_buffer13.Buffer.alloc(0));
|
|
9034
10257
|
}
|
|
9035
10258
|
default: {
|
|
9036
10259
|
const rewritten = rewriteMessage(message, spamHeaders(result, { version: VERSION }), { subjectTag: result.isSpam ? options.subjectTag : null });
|
|
@@ -9038,7 +10261,7 @@ async function answer(scanner, request, message, options) {
|
|
|
9038
10261
|
return reply(EX_OK, "EX_OK", [verdict], rewritten);
|
|
9039
10262
|
}
|
|
9040
10263
|
const { header, newline } = splitMessage(rewritten);
|
|
9041
|
-
return reply(EX_OK, "EX_OK", [verdict],
|
|
10264
|
+
return reply(EX_OK, "EX_OK", [verdict], import_node_buffer13.Buffer.from(`${header}${newline}${newline}`, "latin1"));
|
|
9042
10265
|
}
|
|
9043
10266
|
}
|
|
9044
10267
|
}
|
|
@@ -9052,8 +10275,8 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
9052
10275
|
maxConnections: MAX_CONNECTIONS,
|
|
9053
10276
|
...options
|
|
9054
10277
|
};
|
|
9055
|
-
const server =
|
|
9056
|
-
let head =
|
|
10278
|
+
const server = import_node_net7.default.createServer({ allowHalfOpen: true }, (socket) => {
|
|
10279
|
+
let head = import_node_buffer13.Buffer.alloc(0);
|
|
9057
10280
|
const chunks = [];
|
|
9058
10281
|
let size = 0;
|
|
9059
10282
|
let request = null;
|
|
@@ -9079,7 +10302,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
9079
10302
|
return;
|
|
9080
10303
|
}
|
|
9081
10304
|
if (!request) {
|
|
9082
|
-
head =
|
|
10305
|
+
head = import_node_buffer13.Buffer.concat([head, chunk2]);
|
|
9083
10306
|
const end = head.indexOf("\r\n\r\n");
|
|
9084
10307
|
if (end === -1) {
|
|
9085
10308
|
if (head.length > 64 * 1024) {
|
|
@@ -9114,7 +10337,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
9114
10337
|
chunks.push(chunk2);
|
|
9115
10338
|
size += chunk2.length;
|
|
9116
10339
|
if (request.length === null ? ["PING", "SKIP"].includes(request.command) : size >= request.length) {
|
|
9117
|
-
finish(
|
|
10340
|
+
finish(import_node_buffer13.Buffer.concat(chunks).subarray(0, request.length ?? 0));
|
|
9118
10341
|
} else if (size > settings.maxSize) {
|
|
9119
10342
|
fail(EX_DATAERR, `Message larger than ${settings.maxSize} bytes`);
|
|
9120
10343
|
}
|
|
@@ -9126,7 +10349,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
9126
10349
|
if (!request) {
|
|
9127
10350
|
fail(EX_PROTOCOL, "Incomplete request");
|
|
9128
10351
|
} else if (request.length === null) {
|
|
9129
|
-
finish(
|
|
10352
|
+
finish(import_node_buffer13.Buffer.concat(chunks));
|
|
9130
10353
|
} else {
|
|
9131
10354
|
fail(EX_PROTOCOL, `Message shorter than its Content-length of ${request.length} bytes`);
|
|
9132
10355
|
}
|
|
@@ -9137,11 +10360,11 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
9137
10360
|
server.maxConnections = settings.maxConnections;
|
|
9138
10361
|
return server;
|
|
9139
10362
|
}
|
|
9140
|
-
var
|
|
10363
|
+
var import_node_buffer13, import_node_net7, EX_OK, EX_USAGE, EX_DATAERR, EX_SOFTWARE, EX_PROTOCOL, EX_NOPERM, COMMANDS2, oneLine2;
|
|
9141
10364
|
var init_spamd = __esm({
|
|
9142
10365
|
"src/spamd.js"() {
|
|
9143
|
-
|
|
9144
|
-
|
|
10366
|
+
import_node_buffer13 = require("node:buffer");
|
|
10367
|
+
import_node_net7 = __toESM(require("node:net"), 1);
|
|
9145
10368
|
init_headers();
|
|
9146
10369
|
init_server();
|
|
9147
10370
|
init_version();
|
|
@@ -9152,6 +10375,7 @@ var init_spamd = __esm({
|
|
|
9152
10375
|
EX_PROTOCOL = 76;
|
|
9153
10376
|
EX_NOPERM = 77;
|
|
9154
10377
|
COMMANDS2 = /* @__PURE__ */ new Set(["CHECK", "SYMBOLS", "REPORT", "REPORT_IFSPAM", "PROCESS", "HEADERS", "PING", "SKIP", "TELL"]);
|
|
10378
|
+
oneLine2 = (text) => String(text ?? "").replaceAll(/[\p{Cc}\u061C\u200E\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069]+/gu, " ");
|
|
9155
10379
|
}
|
|
9156
10380
|
});
|
|
9157
10381
|
|
|
@@ -9353,21 +10577,21 @@ async function withTimeout(promise, ms, fallback) {
|
|
|
9353
10577
|
}
|
|
9354
10578
|
}
|
|
9355
10579
|
async function toBuffer(source) {
|
|
9356
|
-
if (
|
|
10580
|
+
if (import_node_buffer14.Buffer.isBuffer(source)) {
|
|
9357
10581
|
return source;
|
|
9358
10582
|
}
|
|
9359
10583
|
if (typeof source === "string") {
|
|
9360
|
-
return
|
|
10584
|
+
return import_node_buffer14.Buffer.from(source, "utf8");
|
|
9361
10585
|
}
|
|
9362
10586
|
if (source instanceof Uint8Array) {
|
|
9363
|
-
return
|
|
10587
|
+
return import_node_buffer14.Buffer.from(source);
|
|
9364
10588
|
}
|
|
9365
10589
|
if (source && typeof source[Symbol.asyncIterator] === "function") {
|
|
9366
10590
|
const chunks = [];
|
|
9367
10591
|
for await (const chunk2 of source) {
|
|
9368
|
-
chunks.push(
|
|
10592
|
+
chunks.push(import_node_buffer14.Buffer.isBuffer(chunk2) ? chunk2 : import_node_buffer14.Buffer.from(chunk2));
|
|
9369
10593
|
}
|
|
9370
|
-
return
|
|
10594
|
+
return import_node_buffer14.Buffer.concat(chunks);
|
|
9371
10595
|
}
|
|
9372
10596
|
throw new TypeError("A message must be a Buffer, a string, a Uint8Array or a readable stream");
|
|
9373
10597
|
}
|
|
@@ -9442,12 +10666,12 @@ function fromDomain(mail) {
|
|
|
9442
10666
|
function withHeader(raw) {
|
|
9443
10667
|
const first = raw.subarray(0, 1e3).toString("latin1");
|
|
9444
10668
|
const headerless = raw.length > 0 && !/^(?:[!-9;-~]+[ \t]*:|From |[\r\n])/.test(first);
|
|
9445
|
-
return headerless ?
|
|
10669
|
+
return headerless ? import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from("\r\n"), raw]) : raw;
|
|
9446
10670
|
}
|
|
9447
|
-
var
|
|
10671
|
+
var import_node_buffer14, import_promises2, import_node_util2, debug2, DEFAULTS2, NESTED, MAX_LOOKALIKE_HOSTS, MAX_DECEPTIVE_LINKS, CLAMAV_CONCURRENCY, CLAMAV_TIMEOUT, CLAMAV_LIMITS, MAX_NSFW_IMAGES, MAX_REPUTATION_CACHES, SpamScanner, src_default;
|
|
9448
10672
|
var init_src = __esm({
|
|
9449
10673
|
"src/index.js"() {
|
|
9450
|
-
|
|
10674
|
+
import_node_buffer14 = require("node:buffer");
|
|
9451
10675
|
import_promises2 = require("node:fs/promises");
|
|
9452
10676
|
import_node_util2 = require("node:util");
|
|
9453
10677
|
init_attachments();
|
|
@@ -9456,6 +10680,7 @@ var init_src = __esm({
|
|
|
9456
10680
|
init_classifier();
|
|
9457
10681
|
init_dnsbl();
|
|
9458
10682
|
init_html();
|
|
10683
|
+
init_links();
|
|
9459
10684
|
init_homograph();
|
|
9460
10685
|
init_is_arbitrary();
|
|
9461
10686
|
init_language();
|
|
@@ -9498,6 +10723,19 @@ var init_src = __esm({
|
|
|
9498
10723
|
cloudflare: true,
|
|
9499
10724
|
adult: true,
|
|
9500
10725
|
maxHosts: 25,
|
|
10726
|
+
// Also read the links of the whole message and of what it carries
|
|
10727
|
+
// (attached messages, HTML, SVG and XML files, text files, invitations
|
|
10728
|
+
// and contact cards, documents in iframes and data: URLs) when link
|
|
10729
|
+
// hosts are looked up, for at most five seconds: off by default, as it
|
|
10730
|
+
// reads all of it, up to 50 MB of attachments.
|
|
10731
|
+
attachments: false,
|
|
10732
|
+
// Milliseconds the link lookups may take in all (default: timeout).
|
|
10733
|
+
timeout: void 0,
|
|
10734
|
+
// Also look up host names written in the text without a link or a path
|
|
10735
|
+
// ("evil.example"), which mail clients make links of, as far as there is
|
|
10736
|
+
// room: off by default, as a quoted reply or a signature may name any
|
|
10737
|
+
// site (they are checked for lookalikes either way).
|
|
10738
|
+
hostsInText: false,
|
|
9501
10739
|
// Characters of text read for links (twice as many of HTML): more than
|
|
9502
10740
|
// for the classifier (maxLength), as a link anywhere in a message may be
|
|
9503
10741
|
// followed; a longer message sets results.linksTruncated.
|
|
@@ -9699,7 +10937,10 @@ var init_src = __esm({
|
|
|
9699
10937
|
async scanFile(file, options) {
|
|
9700
10938
|
return this.scan(await (0, import_promises2.readFile)(file), options);
|
|
9701
10939
|
}
|
|
9702
|
-
|
|
10940
|
+
// (`from`: the sender's domain; `carried`: the link hosts of the whole
|
|
10941
|
+
// message and of what it carries, see carriedLinkHosts)
|
|
10942
|
+
async checkLinks(links, config, hosts = [], options = {}) {
|
|
10943
|
+
const { from = "", carried = null } = typeof options === "string" ? { from: options } : options ?? {};
|
|
9703
10944
|
const phishing = [];
|
|
9704
10945
|
const homographs = [];
|
|
9705
10946
|
const seenHosts = /* @__PURE__ */ new Set();
|
|
@@ -9755,18 +10996,23 @@ var init_src = __esm({
|
|
|
9755
10996
|
for (const host of hosts) {
|
|
9756
10997
|
lookalike(host, { source: "text" });
|
|
9757
10998
|
}
|
|
9758
|
-
const
|
|
10999
|
+
const carriedHosts = (carried?.hosts ?? []).map((host) => lookupName(host)).filter(Boolean);
|
|
11000
|
+
for (const host of carriedHosts) {
|
|
11001
|
+
seenHosts.add(host);
|
|
11002
|
+
}
|
|
11003
|
+
const own3 = [...found.filter((link) => link.text), ...found.filter((link) => !link.text), ...bare].map((link) => lookupName(destination(link))).filter(Boolean);
|
|
9759
11004
|
const firsts = /* @__PURE__ */ new Map();
|
|
9760
|
-
for (const host of
|
|
11005
|
+
for (const host of [...own3, ...carriedHosts]) {
|
|
9761
11006
|
const domain = registrableDomain(host);
|
|
9762
11007
|
if (!firsts.has(domain)) {
|
|
9763
11008
|
firsts.set(domain, host);
|
|
9764
11009
|
}
|
|
9765
11010
|
}
|
|
9766
|
-
const checked = [.../* @__PURE__ */ new Set([...firsts.values(), ...
|
|
11011
|
+
const checked = [.../* @__PURE__ */ new Set([...firsts.values(), ...own3, ...carriedHosts])].slice(0, config.phishing.maxHosts);
|
|
9767
11012
|
const domains = [...new Set(checked.map((host) => registrableDomain(host)))];
|
|
9768
11013
|
const blocked = [];
|
|
9769
11014
|
let answered = 0;
|
|
11015
|
+
const linkTimeout = Number(config.phishing.timeout) > 0 ? Number(config.phishing.timeout) : config.timeout;
|
|
9770
11016
|
const cloudflare = async () => {
|
|
9771
11017
|
await withTimeout(Promise.all(checked.map(async (host) => {
|
|
9772
11018
|
const found2 = await this.dns.checkCloudflare([host], { adult: config.phishing.adult });
|
|
@@ -9774,12 +11020,12 @@ var init_src = __esm({
|
|
|
9774
11020
|
if (!found2.unanswered?.length) {
|
|
9775
11021
|
answered++;
|
|
9776
11022
|
}
|
|
9777
|
-
})),
|
|
11023
|
+
})), linkTimeout, null);
|
|
9778
11024
|
return { found: [...blocked], unanswered: checked.length - answered };
|
|
9779
11025
|
};
|
|
9780
11026
|
const [cloudflareResult, listed] = await Promise.all([
|
|
9781
11027
|
config.phishing.cloudflare && checked.length > 0 ? cloudflare() : { found: [], unanswered: 0 },
|
|
9782
|
-
config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain),
|
|
11028
|
+
config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain), linkTimeout, []) : []
|
|
9783
11029
|
]);
|
|
9784
11030
|
for (const { host, category } of cloudflareResult.found) {
|
|
9785
11031
|
phishing.push(finding(category === "malware" ? { type: "malicious_domain", domain: host, message: `Link hostname ${host} is blocked by Cloudflare's malware filtering as phishing or malware` } : { type: "adult_domain", domain: host, message: `Link hostname ${host} was detected by Cloudflare's family filtering to contain adult-related content` }));
|
|
@@ -9795,7 +11041,8 @@ var init_src = __esm({
|
|
|
9795
11041
|
return {
|
|
9796
11042
|
phishing,
|
|
9797
11043
|
homographs,
|
|
9798
|
-
|
|
11044
|
+
// (at least one when the message has more hosts than were read)
|
|
11045
|
+
uncheckedHosts: Math.max(seenHosts.size - checked.length, carried?.more ? 1 : 0),
|
|
9799
11046
|
timedOutHosts: cloudflareResult.unanswered
|
|
9800
11047
|
};
|
|
9801
11048
|
}
|
|
@@ -9967,10 +11214,17 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
|
|
|
9967
11214
|
styled: plainObfuscation.styled || shownObfuscation.styled
|
|
9968
11215
|
};
|
|
9969
11216
|
const unopened = [];
|
|
9970
|
-
const
|
|
11217
|
+
const opened = [];
|
|
11218
|
+
const attached = await expandAttachments(mail.attachments, parseErrors, void 0, { unopened, mails: opened });
|
|
11219
|
+
const carried = config.phishing.attachments === true && (config.phishing.cloudflare || config.dnsbl.domain?.length > 0) ? carriedLinkHosts(mail, {
|
|
11220
|
+
mails: opened,
|
|
11221
|
+
attachments: attached,
|
|
11222
|
+
maxHosts: config.phishing.maxHosts,
|
|
11223
|
+
hostsInText: config.phishing.hostsInText === true
|
|
11224
|
+
}) : null;
|
|
9971
11225
|
const attachments = config.attachments === false ? [] : inspectAttachments(attached).filter((item) => config.macros !== false || !["macro", "pdf_active", "rtf_object"].includes(item.type)).map((item) => finding(item));
|
|
9972
11226
|
const [links, authentication, checkedReputation, dnsbl, virusScan, toxicity, nsfw] = await Promise.all([
|
|
9973
|
-
this.checkLinks(checkedLinks, config, extracted.hosts, fromDomain(mail)),
|
|
11227
|
+
this.checkLinks(checkedLinks, config, extracted.hosts, { from: fromDomain(mail), carried }),
|
|
9974
11228
|
config.authenticationResults && typeof config.authenticationResults === "object" ? normalizeAuthOutput(config.authenticationResults) : config.authentication && session.remoteAddress ? withTimeout(authenticate(raw, {
|
|
9975
11229
|
timeout: config.timeout,
|
|
9976
11230
|
...typeof config.authentication === "object" ? config.authentication : {},
|
|
@@ -10098,6 +11352,14 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
|
|
|
10098
11352
|
// Whether the message has more text than phishing.maxLength, whose
|
|
10099
11353
|
// links were not read.
|
|
10100
11354
|
linksTruncated,
|
|
11355
|
+
// Whether a link host of the message or of what it carries was
|
|
11356
|
+
// never read whole (it runs past where long text is cut to be
|
|
11357
|
+
// read, it goes through more security gateways than are
|
|
11358
|
+
// unwrapped, or it is in more documents than are read), and whether
|
|
11359
|
+
// an attachment was left unread for time: in either case not every
|
|
11360
|
+
// link was checked (see phishing.attachments).
|
|
11361
|
+
linksTooComplex: Boolean(carried?.tooComplex),
|
|
11362
|
+
linksIncomplete: Boolean(carried?.incomplete),
|
|
10101
11363
|
idnHomographAttack: {
|
|
10102
11364
|
detected: links.homographs.length > 0,
|
|
10103
11365
|
domains: links.homographs,
|
|
@@ -10109,6 +11371,9 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
|
|
|
10109
11371
|
language: extracted.language,
|
|
10110
11372
|
tokens: extracted.words,
|
|
10111
11373
|
mail,
|
|
11374
|
+
// (the attachments of the message and of its attached messages, as
|
|
11375
|
+
// read, an attached message's named after it)
|
|
11376
|
+
attached,
|
|
10112
11377
|
version: VERSION,
|
|
10113
11378
|
metrics: { totalTime: time }
|
|
10114
11379
|
};
|