spamscanner 7.0.9 → 7.0.11
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 +1338 -179
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/esm/arf.js.map +1 -1
- package/dist/esm/cli.js +1266 -123
- package/dist/esm/cli.js.map +4 -4
- package/dist/esm/index.js +1306 -163
- 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 +24 -0
- package/dist/types/parse.d.ts +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.js
|
|
2
|
-
import { Buffer as
|
|
2
|
+
import { Buffer as Buffer14 } from "node:buffer";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { debuglog as debuglog2 } from "node:util";
|
|
5
5
|
|
|
@@ -1107,103 +1107,285 @@ var HomographDetector = class {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
};
|
|
1109
1109
|
|
|
1110
|
+
// src/entities.js
|
|
1111
|
+
var NAMED = [
|
|
1112
|
+
"AElig=c6,AMP=26,Aacute=c1,Abreve=102,Acirc=c2,Acy=410,Afr=1d504,Agrave=c0,Alpha=391,Amacr=100,And=2a",
|
|
1113
|
+
"53,Aogon=104,Aopf=1d538,ApplyFunction=2061,Aring=c5,Ascr=1d49c,Assign=2254,Atilde=c3,Auml=c4,Backsla",
|
|
1114
|
+
"sh=2216,Barv=2ae7,Barwed=2306,Bcy=411,Because=2235,Bernoullis=212c,Beta=392,Bfr=1d505,Bopf=1d539,Bre",
|
|
1115
|
+
"ve=2d8,Bscr=212c,Bumpeq=224e,CHcy=427,COPY=a9,Cacute=106,Cap=22d2,CapitalDifferentialD=2145,Cayleys=",
|
|
1116
|
+
"212d,Ccaron=10c,Ccedil=c7,Ccirc=108,Cconint=2230,Cdot=10a,Cedilla=b8,CenterDot=b7,Cfr=212d,Chi=3a7,C",
|
|
1117
|
+
"ircleDot=2299,CircleMinus=2296,CirclePlus=2295,CircleTimes=2297,ClockwiseContourIntegral=2232,CloseC",
|
|
1118
|
+
"urlyDoubleQuote=201d,CloseCurlyQuote=2019,Colon=2237,Colone=2a74,Congruent=2261,Conint=222f,ContourI",
|
|
1119
|
+
"ntegral=222e,Copf=2102,Coproduct=2210,CounterClockwiseContourIntegral=2233,Cross=2a2f,Cscr=1d49e,Cup",
|
|
1120
|
+
"=22d3,CupCap=224d,DD=2145,DDotrahd=2911,DJcy=402,DScy=405,DZcy=40f,Dagger=2021,Darr=21a1,Dashv=2ae4,",
|
|
1121
|
+
"Dcaron=10e,Dcy=414,Del=2207,Delta=394,Dfr=1d507,DiacriticalAcute=b4,DiacriticalDot=2d9,DiacriticalDo",
|
|
1122
|
+
"ubleAcute=2dd,DiacriticalGrave=60,DiacriticalTilde=2dc,Diamond=22c4,DifferentialD=2146,Dopf=1d53b,Do",
|
|
1123
|
+
"t=a8,DotDot=20dc,DotEqual=2250,DoubleContourIntegral=222f,DoubleDot=a8,DoubleDownArrow=21d3,DoubleLe",
|
|
1124
|
+
"ftArrow=21d0,DoubleLeftRightArrow=21d4,DoubleLeftTee=2ae4,DoubleLongLeftArrow=27f8,DoubleLongLeftRig",
|
|
1125
|
+
"htArrow=27fa,DoubleLongRightArrow=27f9,DoubleRightArrow=21d2,DoubleRightTee=22a8,DoubleUpArrow=21d1,",
|
|
1126
|
+
"DoubleUpDownArrow=21d5,DoubleVerticalBar=2225,DownArrow=2193,DownArrowBar=2913,DownArrowUpArrow=21f5",
|
|
1127
|
+
",DownBreve=311,DownLeftRightVector=2950,DownLeftTeeVector=295e,DownLeftVector=21bd,DownLeftVectorBar",
|
|
1128
|
+
"=2956,DownRightTeeVector=295f,DownRightVector=21c1,DownRightVectorBar=2957,DownTee=22a4,DownTeeArrow",
|
|
1129
|
+
"=21a7,Downarrow=21d3,Dscr=1d49f,Dstrok=110,ENG=14a,ETH=d0,Eacute=c9,Ecaron=11a,Ecirc=ca,Ecy=42d,Edot",
|
|
1130
|
+
"=116,Efr=1d508,Egrave=c8,Element=2208,Emacr=112,EmptySmallSquare=25fb,EmptyVerySmallSquare=25ab,Eogo",
|
|
1131
|
+
"n=118,Eopf=1d53c,Epsilon=395,Equal=2a75,EqualTilde=2242,Equilibrium=21cc,Escr=2130,Esim=2a73,Eta=397",
|
|
1132
|
+
",Euml=cb,Exists=2203,ExponentialE=2147,Fcy=424,Ffr=1d509,FilledSmallSquare=25fc,FilledVerySmallSquar",
|
|
1133
|
+
"e=25aa,Fopf=1d53d,ForAll=2200,Fouriertrf=2131,Fscr=2131,GJcy=403,GT=3e,Gamma=393,Gammad=3dc,Gbreve=1",
|
|
1134
|
+
"1e,Gcedil=122,Gcirc=11c,Gcy=413,Gdot=120,Gfr=1d50a,Gg=22d9,Gopf=1d53e,GreaterEqual=2265,GreaterEqual",
|
|
1135
|
+
"Less=22db,GreaterFullEqual=2267,GreaterGreater=2aa2,GreaterLess=2277,GreaterSlantEqual=2a7e,GreaterT",
|
|
1136
|
+
"ilde=2273,Gscr=1d4a2,Gt=226b,HARDcy=42a,Hacek=2c7,Hat=5e,Hcirc=124,Hfr=210c,HilbertSpace=210b,Hopf=2",
|
|
1137
|
+
"10d,HorizontalLine=2500,Hscr=210b,Hstrok=126,HumpDownHump=224e,HumpEqual=224f,IEcy=415,IJlig=132,IOc",
|
|
1138
|
+
"y=401,Iacute=cd,Icirc=ce,Icy=418,Idot=130,Ifr=2111,Igrave=cc,Im=2111,Imacr=12a,ImaginaryI=2148,Impli",
|
|
1139
|
+
"es=21d2,Int=222c,Integral=222b,Intersection=22c2,InvisibleComma=2063,InvisibleTimes=2062,Iogon=12e,I",
|
|
1140
|
+
"opf=1d540,Iota=399,Iscr=2110,Itilde=128,Iukcy=406,Iuml=cf,Jcirc=134,Jcy=419,Jfr=1d50d,Jopf=1d541,Jsc",
|
|
1141
|
+
"r=1d4a5,Jsercy=408,Jukcy=404,KHcy=425,KJcy=40c,Kappa=39a,Kcedil=136,Kcy=41a,Kfr=1d50e,Kopf=1d542,Ksc",
|
|
1142
|
+
"r=1d4a6,LJcy=409,LT=3c,Lacute=139,Lambda=39b,Lang=27ea,Laplacetrf=2112,Larr=219e,Lcaron=13d,Lcedil=1",
|
|
1143
|
+
"3b,Lcy=41b,LeftAngleBracket=27e8,LeftArrow=2190,LeftArrowBar=21e4,LeftArrowRightArrow=21c6,LeftCeili",
|
|
1144
|
+
"ng=2308,LeftDoubleBracket=27e6,LeftDownTeeVector=2961,LeftDownVector=21c3,LeftDownVectorBar=2959,Lef",
|
|
1145
|
+
"tFloor=230a,LeftRightArrow=2194,LeftRightVector=294e,LeftTee=22a3,LeftTeeArrow=21a4,LeftTeeVector=29",
|
|
1146
|
+
"5a,LeftTriangle=22b2,LeftTriangleBar=29cf,LeftTriangleEqual=22b4,LeftUpDownVector=2951,LeftUpTeeVect",
|
|
1147
|
+
"or=2960,LeftUpVector=21bf,LeftUpVectorBar=2958,LeftVector=21bc,LeftVectorBar=2952,Leftarrow=21d0,Lef",
|
|
1148
|
+
"trightarrow=21d4,LessEqualGreater=22da,LessFullEqual=2266,LessGreater=2276,LessLess=2aa1,LessSlantEq",
|
|
1149
|
+
"ual=2a7d,LessTilde=2272,Lfr=1d50f,Ll=22d8,Lleftarrow=21da,Lmidot=13f,LongLeftArrow=27f5,LongLeftRigh",
|
|
1150
|
+
"tArrow=27f7,LongRightArrow=27f6,Longleftarrow=27f8,Longleftrightarrow=27fa,Longrightarrow=27f9,Lopf=",
|
|
1151
|
+
"1d543,LowerLeftArrow=2199,LowerRightArrow=2198,Lscr=2112,Lsh=21b0,Lstrok=141,Lt=226a,Map=2905,Mcy=41",
|
|
1152
|
+
"c,MediumSpace=205f,Mellintrf=2133,Mfr=1d510,MinusPlus=2213,Mopf=1d544,Mscr=2133,Mu=39c,NJcy=40a,Nacu",
|
|
1153
|
+
"te=143,Ncaron=147,Ncedil=145,Ncy=41d,NegativeMediumSpace=200b,NegativeThickSpace=200b,NegativeThinSp",
|
|
1154
|
+
"ace=200b,NegativeVeryThinSpace=200b,NestedGreaterGreater=226b,NestedLessLess=226a,NewLine=a,Nfr=1d51",
|
|
1155
|
+
"1,NoBreak=2060,NonBreakingSpace=a0,Nopf=2115,Not=2aec,NotCongruent=2262,NotCupCap=226d,NotDoubleVert",
|
|
1156
|
+
"icalBar=2226,NotElement=2209,NotEqual=2260,NotEqualTilde=2242.338,NotExists=2204,NotGreater=226f,Not",
|
|
1157
|
+
"GreaterEqual=2271,NotGreaterFullEqual=2267.338,NotGreaterGreater=226b.338,NotGreaterLess=2279,NotGre",
|
|
1158
|
+
"aterSlantEqual=2a7e.338,NotGreaterTilde=2275,NotHumpDownHump=224e.338,NotHumpEqual=224f.338,NotLeftT",
|
|
1159
|
+
"riangle=22ea,NotLeftTriangleBar=29cf.338,NotLeftTriangleEqual=22ec,NotLess=226e,NotLessEqual=2270,No",
|
|
1160
|
+
"tLessGreater=2278,NotLessLess=226a.338,NotLessSlantEqual=2a7d.338,NotLessTilde=2274,NotNestedGreater",
|
|
1161
|
+
"Greater=2aa2.338,NotNestedLessLess=2aa1.338,NotPrecedes=2280,NotPrecedesEqual=2aaf.338,NotPrecedesSl",
|
|
1162
|
+
"antEqual=22e0,NotReverseElement=220c,NotRightTriangle=22eb,NotRightTriangleBar=29d0.338,NotRightTria",
|
|
1163
|
+
"ngleEqual=22ed,NotSquareSubset=228f.338,NotSquareSubsetEqual=22e2,NotSquareSuperset=2290.338,NotSqua",
|
|
1164
|
+
"reSupersetEqual=22e3,NotSubset=2282.20d2,NotSubsetEqual=2288,NotSucceeds=2281,NotSucceedsEqual=2ab0.",
|
|
1165
|
+
"338,NotSucceedsSlantEqual=22e1,NotSucceedsTilde=227f.338,NotSuperset=2283.20d2,NotSupersetEqual=2289",
|
|
1166
|
+
",NotTilde=2241,NotTildeEqual=2244,NotTildeFullEqual=2247,NotTildeTilde=2249,NotVerticalBar=2224,Nscr",
|
|
1167
|
+
"=1d4a9,Ntilde=d1,Nu=39d,OElig=152,Oacute=d3,Ocirc=d4,Ocy=41e,Odblac=150,Ofr=1d512,Ograve=d2,Omacr=14",
|
|
1168
|
+
"c,Omega=3a9,Omicron=39f,Oopf=1d546,OpenCurlyDoubleQuote=201c,OpenCurlyQuote=2018,Or=2a54,Oscr=1d4aa,",
|
|
1169
|
+
"Oslash=d8,Otilde=d5,Otimes=2a37,Ouml=d6,OverBar=203e,OverBrace=23de,OverBracket=23b4,OverParenthesis",
|
|
1170
|
+
"=23dc,PartialD=2202,Pcy=41f,Pfr=1d513,Phi=3a6,Pi=3a0,PlusMinus=b1,Poincareplane=210c,Popf=2119,Pr=2a",
|
|
1171
|
+
"bb,Precedes=227a,PrecedesEqual=2aaf,PrecedesSlantEqual=227c,PrecedesTilde=227e,Prime=2033,Product=22",
|
|
1172
|
+
"0f,Proportion=2237,Proportional=221d,Pscr=1d4ab,Psi=3a8,QUOT=22,Qfr=1d514,Qopf=211a,Qscr=1d4ac,RBarr",
|
|
1173
|
+
"=2910,REG=ae,Racute=154,Rang=27eb,Rarr=21a0,Rarrtl=2916,Rcaron=158,Rcedil=156,Rcy=420,Re=211c,Revers",
|
|
1174
|
+
"eElement=220b,ReverseEquilibrium=21cb,ReverseUpEquilibrium=296f,Rfr=211c,Rho=3a1,RightAngleBracket=2",
|
|
1175
|
+
"7e9,RightArrow=2192,RightArrowBar=21e5,RightArrowLeftArrow=21c4,RightCeiling=2309,RightDoubleBracket",
|
|
1176
|
+
"=27e7,RightDownTeeVector=295d,RightDownVector=21c2,RightDownVectorBar=2955,RightFloor=230b,RightTee=",
|
|
1177
|
+
"22a2,RightTeeArrow=21a6,RightTeeVector=295b,RightTriangle=22b3,RightTriangleBar=29d0,RightTriangleEq",
|
|
1178
|
+
"ual=22b5,RightUpDownVector=294f,RightUpTeeVector=295c,RightUpVector=21be,RightUpVectorBar=2954,Right",
|
|
1179
|
+
"Vector=21c0,RightVectorBar=2953,Rightarrow=21d2,Ropf=211d,RoundImplies=2970,Rrightarrow=21db,Rscr=21",
|
|
1180
|
+
"1b,Rsh=21b1,RuleDelayed=29f4,SHCHcy=429,SHcy=428,SOFTcy=42c,Sacute=15a,Sc=2abc,Scaron=160,Scedil=15e",
|
|
1181
|
+
",Scirc=15c,Scy=421,Sfr=1d516,ShortDownArrow=2193,ShortLeftArrow=2190,ShortRightArrow=2192,ShortUpArr",
|
|
1182
|
+
"ow=2191,Sigma=3a3,SmallCircle=2218,Sopf=1d54a,Sqrt=221a,Square=25a1,SquareIntersection=2293,SquareSu",
|
|
1183
|
+
"bset=228f,SquareSubsetEqual=2291,SquareSuperset=2290,SquareSupersetEqual=2292,SquareUnion=2294,Sscr=",
|
|
1184
|
+
"1d4ae,Star=22c6,Sub=22d0,Subset=22d0,SubsetEqual=2286,Succeeds=227b,SucceedsEqual=2ab0,SucceedsSlant",
|
|
1185
|
+
"Equal=227d,SucceedsTilde=227f,SuchThat=220b,Sum=2211,Sup=22d1,Superset=2283,SupersetEqual=2287,Supse",
|
|
1186
|
+
"t=22d1,THORN=de,TRADE=2122,TSHcy=40b,TScy=426,Tab=9,Tau=3a4,Tcaron=164,Tcedil=162,Tcy=422,Tfr=1d517,",
|
|
1187
|
+
"Therefore=2234,Theta=398,ThickSpace=205f.200a,ThinSpace=2009,Tilde=223c,TildeEqual=2243,TildeFullEqu",
|
|
1188
|
+
"al=2245,TildeTilde=2248,Topf=1d54b,TripleDot=20db,Tscr=1d4af,Tstrok=166,Uacute=da,Uarr=219f,Uarrocir",
|
|
1189
|
+
"=2949,Ubrcy=40e,Ubreve=16c,Ucirc=db,Ucy=423,Udblac=170,Ufr=1d518,Ugrave=d9,Umacr=16a,UnderBar=5f,Und",
|
|
1190
|
+
"erBrace=23df,UnderBracket=23b5,UnderParenthesis=23dd,Union=22c3,UnionPlus=228e,Uogon=172,Uopf=1d54c,",
|
|
1191
|
+
"UpArrow=2191,UpArrowBar=2912,UpArrowDownArrow=21c5,UpDownArrow=2195,UpEquilibrium=296e,UpTee=22a5,Up",
|
|
1192
|
+
"TeeArrow=21a5,Uparrow=21d1,Updownarrow=21d5,UpperLeftArrow=2196,UpperRightArrow=2197,Upsi=3d2,Upsilo",
|
|
1193
|
+
"n=3a5,Uring=16e,Uscr=1d4b0,Utilde=168,Uuml=dc,VDash=22ab,Vbar=2aeb,Vcy=412,Vdash=22a9,Vdashl=2ae6,Ve",
|
|
1194
|
+
"e=22c1,Verbar=2016,Vert=2016,VerticalBar=2223,VerticalLine=7c,VerticalSeparator=2758,VerticalTilde=2",
|
|
1195
|
+
"240,VeryThinSpace=200a,Vfr=1d519,Vopf=1d54d,Vscr=1d4b1,Vvdash=22aa,Wcirc=174,Wedge=22c0,Wfr=1d51a,Wo",
|
|
1196
|
+
"pf=1d54e,Wscr=1d4b2,Xfr=1d51b,Xi=39e,Xopf=1d54f,Xscr=1d4b3,YAcy=42f,YIcy=407,YUcy=42e,Yacute=dd,Ycir",
|
|
1197
|
+
"c=176,Ycy=42b,Yfr=1d51c,Yopf=1d550,Yscr=1d4b4,Yuml=178,ZHcy=416,Zacute=179,Zcaron=17d,Zcy=417,Zdot=1",
|
|
1198
|
+
"7b,ZeroWidthSpace=200b,Zeta=396,Zfr=2128,Zopf=2124,Zscr=1d4b5,aacute=e1,abreve=103,ac=223e,acE=223e.",
|
|
1199
|
+
"333,acd=223f,acirc=e2,acute=b4,acy=430,aelig=e6,af=2061,afr=1d51e,agrave=e0,alefsym=2135,aleph=2135,",
|
|
1200
|
+
"alpha=3b1,amacr=101,amalg=2a3f,amp=26,and=2227,andand=2a55,andd=2a5c,andslope=2a58,andv=2a5a,ang=222",
|
|
1201
|
+
"0,ange=29a4,angle=2220,angmsd=2221,angmsdaa=29a8,angmsdab=29a9,angmsdac=29aa,angmsdad=29ab,angmsdae=",
|
|
1202
|
+
"29ac,angmsdaf=29ad,angmsdag=29ae,angmsdah=29af,angrt=221f,angrtvb=22be,angrtvbd=299d,angsph=2222,ang",
|
|
1203
|
+
"st=c5,angzarr=237c,aogon=105,aopf=1d552,ap=2248,apE=2a70,apacir=2a6f,ape=224a,apid=224b,apos=27,appr",
|
|
1204
|
+
"ox=2248,approxeq=224a,aring=e5,ascr=1d4b6,ast=2a,asymp=2248,asympeq=224d,atilde=e3,auml=e4,awconint=",
|
|
1205
|
+
"2233,awint=2a11,bNot=2aed,backcong=224c,backepsilon=3f6,backprime=2035,backsim=223d,backsimeq=22cd,b",
|
|
1206
|
+
"arvee=22bd,barwed=2305,barwedge=2305,bbrk=23b5,bbrktbrk=23b6,bcong=224c,bcy=431,bdquo=201e,becaus=22",
|
|
1207
|
+
"35,because=2235,bemptyv=29b0,bepsi=3f6,bernou=212c,beta=3b2,beth=2136,between=226c,bfr=1d51f,bigcap=",
|
|
1208
|
+
"22c2,bigcirc=25ef,bigcup=22c3,bigodot=2a00,bigoplus=2a01,bigotimes=2a02,bigsqcup=2a06,bigstar=2605,b",
|
|
1209
|
+
"igtriangledown=25bd,bigtriangleup=25b3,biguplus=2a04,bigvee=22c1,bigwedge=22c0,bkarow=290d,blackloze",
|
|
1210
|
+
"nge=29eb,blacksquare=25aa,blacktriangle=25b4,blacktriangledown=25be,blacktriangleleft=25c2,blacktria",
|
|
1211
|
+
"ngleright=25b8,blank=2423,blk12=2592,blk14=2591,blk34=2593,block=2588,bne=3d.20e5,bnequiv=2261.20e5,",
|
|
1212
|
+
"bnot=2310,bopf=1d553,bot=22a5,bottom=22a5,bowtie=22c8,boxDL=2557,boxDR=2554,boxDl=2556,boxDr=2553,bo",
|
|
1213
|
+
"xH=2550,boxHD=2566,boxHU=2569,boxHd=2564,boxHu=2567,boxUL=255d,boxUR=255a,boxUl=255c,boxUr=2559,boxV",
|
|
1214
|
+
"=2551,boxVH=256c,boxVL=2563,boxVR=2560,boxVh=256b,boxVl=2562,boxVr=255f,boxbox=29c9,boxdL=2555,boxdR",
|
|
1215
|
+
"=2552,boxdl=2510,boxdr=250c,boxh=2500,boxhD=2565,boxhU=2568,boxhd=252c,boxhu=2534,boxminus=229f,boxp",
|
|
1216
|
+
"lus=229e,boxtimes=22a0,boxuL=255b,boxuR=2558,boxul=2518,boxur=2514,boxv=2502,boxvH=256a,boxvL=2561,b",
|
|
1217
|
+
"oxvR=255e,boxvh=253c,boxvl=2524,boxvr=251c,bprime=2035,breve=2d8,brvbar=a6,bscr=1d4b7,bsemi=204f,bsi",
|
|
1218
|
+
"m=223d,bsime=22cd,bsol=5c,bsolb=29c5,bsolhsub=27c8,bull=2022,bullet=2022,bump=224e,bumpE=2aae,bumpe=",
|
|
1219
|
+
"224f,bumpeq=224f,cacute=107,cap=2229,capand=2a44,capbrcup=2a49,capcap=2a4b,capcup=2a47,capdot=2a40,c",
|
|
1220
|
+
"aps=2229.fe00,caret=2041,caron=2c7,ccaps=2a4d,ccaron=10d,ccedil=e7,ccirc=109,ccups=2a4c,ccupssm=2a50",
|
|
1221
|
+
",cdot=10b,cedil=b8,cemptyv=29b2,cent=a2,centerdot=b7,cfr=1d520,chcy=447,check=2713,checkmark=2713,ch",
|
|
1222
|
+
"i=3c7,cir=25cb,cirE=29c3,circ=2c6,circeq=2257,circlearrowleft=21ba,circlearrowright=21bb,circledR=ae",
|
|
1223
|
+
",circledS=24c8,circledast=229b,circledcirc=229a,circleddash=229d,cire=2257,cirfnint=2a10,cirmid=2aef",
|
|
1224
|
+
",cirscir=29c2,clubs=2663,clubsuit=2663,colon=3a,colone=2254,coloneq=2254,comma=2c,commat=40,comp=220",
|
|
1225
|
+
"1,compfn=2218,complement=2201,complexes=2102,cong=2245,congdot=2a6d,conint=222e,copf=1d554,coprod=22",
|
|
1226
|
+
"10,copy=a9,copysr=2117,crarr=21b5,cross=2717,cscr=1d4b8,csub=2acf,csube=2ad1,csup=2ad0,csupe=2ad2,ct",
|
|
1227
|
+
"dot=22ef,cudarrl=2938,cudarrr=2935,cuepr=22de,cuesc=22df,cularr=21b6,cularrp=293d,cup=222a,cupbrcap=",
|
|
1228
|
+
"2a48,cupcap=2a46,cupcup=2a4a,cupdot=228d,cupor=2a45,cups=222a.fe00,curarr=21b7,curarrm=293c,curlyeqp",
|
|
1229
|
+
"rec=22de,curlyeqsucc=22df,curlyvee=22ce,curlywedge=22cf,curren=a4,curvearrowleft=21b6,curvearrowrigh",
|
|
1230
|
+
"t=21b7,cuvee=22ce,cuwed=22cf,cwconint=2232,cwint=2231,cylcty=232d,dArr=21d3,dHar=2965,dagger=2020,da",
|
|
1231
|
+
"leth=2138,darr=2193,dash=2010,dashv=22a3,dbkarow=290f,dblac=2dd,dcaron=10f,dcy=434,dd=2146,ddagger=2",
|
|
1232
|
+
"021,ddarr=21ca,ddotseq=2a77,deg=b0,delta=3b4,demptyv=29b1,dfisht=297f,dfr=1d521,dharl=21c3,dharr=21c",
|
|
1233
|
+
"2,diam=22c4,diamond=22c4,diamondsuit=2666,diams=2666,die=a8,digamma=3dd,disin=22f2,div=f7,divide=f7,",
|
|
1234
|
+
"divideontimes=22c7,divonx=22c7,djcy=452,dlcorn=231e,dlcrop=230d,dollar=24,dopf=1d555,dot=2d9,doteq=2",
|
|
1235
|
+
"250,doteqdot=2251,dotminus=2238,dotplus=2214,dotsquare=22a1,doublebarwedge=2306,downarrow=2193,downd",
|
|
1236
|
+
"ownarrows=21ca,downharpoonleft=21c3,downharpoonright=21c2,drbkarow=2910,drcorn=231f,drcrop=230c,dscr",
|
|
1237
|
+
"=1d4b9,dscy=455,dsol=29f6,dstrok=111,dtdot=22f1,dtri=25bf,dtrif=25be,duarr=21f5,duhar=296f,dwangle=2",
|
|
1238
|
+
"9a6,dzcy=45f,dzigrarr=27ff,eDDot=2a77,eDot=2251,eacute=e9,easter=2a6e,ecaron=11b,ecir=2256,ecirc=ea,",
|
|
1239
|
+
"ecolon=2255,ecy=44d,edot=117,ee=2147,efDot=2252,efr=1d522,eg=2a9a,egrave=e8,egs=2a96,egsdot=2a98,el=",
|
|
1240
|
+
"2a99,elinters=23e7,ell=2113,els=2a95,elsdot=2a97,emacr=113,empty=2205,emptyset=2205,emptyv=2205,emsp",
|
|
1241
|
+
"=2003,emsp13=2004,emsp14=2005,eng=14b,ensp=2002,eogon=119,eopf=1d556,epar=22d5,eparsl=29e3,eplus=2a7",
|
|
1242
|
+
"1,epsi=3b5,epsilon=3b5,epsiv=3f5,eqcirc=2256,eqcolon=2255,eqsim=2242,eqslantgtr=2a96,eqslantless=2a9",
|
|
1243
|
+
"5,equals=3d,equest=225f,equiv=2261,equivDD=2a78,eqvparsl=29e5,erDot=2253,erarr=2971,escr=212f,esdot=",
|
|
1244
|
+
"2250,esim=2242,eta=3b7,eth=f0,euml=eb,euro=20ac,excl=21,exist=2203,expectation=2130,exponentiale=214",
|
|
1245
|
+
"7,fallingdotseq=2252,fcy=444,female=2640,ffilig=fb03,fflig=fb00,ffllig=fb04,ffr=1d523,filig=fb01,fjl",
|
|
1246
|
+
"ig=66.6a,flat=266d,fllig=fb02,fltns=25b1,fnof=192,fopf=1d557,forall=2200,fork=22d4,forkv=2ad9,fparti",
|
|
1247
|
+
"nt=2a0d,frac12=bd,frac13=2153,frac14=bc,frac15=2155,frac16=2159,frac18=215b,frac23=2154,frac25=2156,",
|
|
1248
|
+
"frac34=be,frac35=2157,frac38=215c,frac45=2158,frac56=215a,frac58=215d,frac78=215e,frasl=2044,frown=2",
|
|
1249
|
+
"322,fscr=1d4bb,gE=2267,gEl=2a8c,gacute=1f5,gamma=3b3,gammad=3dd,gap=2a86,gbreve=11f,gcirc=11d,gcy=43",
|
|
1250
|
+
"3,gdot=121,ge=2265,gel=22db,geq=2265,geqq=2267,geqslant=2a7e,ges=2a7e,gescc=2aa9,gesdot=2a80,gesdoto",
|
|
1251
|
+
"=2a82,gesdotol=2a84,gesl=22db.fe00,gesles=2a94,gfr=1d524,gg=226b,ggg=22d9,gimel=2137,gjcy=453,gl=227",
|
|
1252
|
+
"7,glE=2a92,gla=2aa5,glj=2aa4,gnE=2269,gnap=2a8a,gnapprox=2a8a,gne=2a88,gneq=2a88,gneqq=2269,gnsim=22",
|
|
1253
|
+
"e7,gopf=1d558,grave=60,gscr=210a,gsim=2273,gsime=2a8e,gsiml=2a90,gt=3e,gtcc=2aa7,gtcir=2a7a,gtdot=22",
|
|
1254
|
+
"d7,gtlPar=2995,gtquest=2a7c,gtrapprox=2a86,gtrarr=2978,gtrdot=22d7,gtreqless=22db,gtreqqless=2a8c,gt",
|
|
1255
|
+
"rless=2277,gtrsim=2273,gvertneqq=2269.fe00,gvnE=2269.fe00,hArr=21d4,hairsp=200a,half=bd,hamilt=210b,",
|
|
1256
|
+
"hardcy=44a,harr=2194,harrcir=2948,harrw=21ad,hbar=210f,hcirc=125,hearts=2665,heartsuit=2665,hellip=2",
|
|
1257
|
+
"026,hercon=22b9,hfr=1d525,hksearow=2925,hkswarow=2926,hoarr=21ff,homtht=223b,hookleftarrow=21a9,hook",
|
|
1258
|
+
"rightarrow=21aa,hopf=1d559,horbar=2015,hscr=1d4bd,hslash=210f,hstrok=127,hybull=2043,hyphen=2010,iac",
|
|
1259
|
+
"ute=ed,ic=2063,icirc=ee,icy=438,iecy=435,iexcl=a1,iff=21d4,ifr=1d526,igrave=ec,ii=2148,iiiint=2a0c,i",
|
|
1260
|
+
"iint=222d,iinfin=29dc,iiota=2129,ijlig=133,imacr=12b,image=2111,imagline=2110,imagpart=2111,imath=13",
|
|
1261
|
+
"1,imof=22b7,imped=1b5,in=2208,incare=2105,infin=221e,infintie=29dd,inodot=131,int=222b,intcal=22ba,i",
|
|
1262
|
+
"ntegers=2124,intercal=22ba,intlarhk=2a17,intprod=2a3c,iocy=451,iogon=12f,iopf=1d55a,iota=3b9,iprod=2",
|
|
1263
|
+
"a3c,iquest=bf,iscr=1d4be,isin=2208,isinE=22f9,isindot=22f5,isins=22f4,isinsv=22f3,isinv=2208,it=2062",
|
|
1264
|
+
",itilde=129,iukcy=456,iuml=ef,jcirc=135,jcy=439,jfr=1d527,jmath=237,jopf=1d55b,jscr=1d4bf,jsercy=458",
|
|
1265
|
+
",jukcy=454,kappa=3ba,kappav=3f0,kcedil=137,kcy=43a,kfr=1d528,kgreen=138,khcy=445,kjcy=45c,kopf=1d55c",
|
|
1266
|
+
",kscr=1d4c0,lAarr=21da,lArr=21d0,lAtail=291b,lBarr=290e,lE=2266,lEg=2a8b,lHar=2962,lacute=13a,laempt",
|
|
1267
|
+
"yv=29b4,lagran=2112,lambda=3bb,lang=2329,langd=2991,langle=27e8,lap=2a85,laquo=ab,larr=2190,larrb=21",
|
|
1268
|
+
"e4,larrbfs=291f,larrfs=291d,larrhk=21a9,larrlp=21ab,larrpl=2939,larrsim=2973,larrtl=21a2,lat=2aab,la",
|
|
1269
|
+
"tail=2919,late=2aad,lates=2aad.fe00,lbarr=290c,lbbrk=2772,lbrace=7b,lbrack=5b,lbrke=298b,lbrksld=298",
|
|
1270
|
+
"f,lbrkslu=298d,lcaron=13e,lcedil=13c,lceil=2308,lcub=7b,lcy=43b,ldca=2936,ldquo=201c,ldquor=201e,ldr",
|
|
1271
|
+
"dhar=2967,ldrushar=294b,ldsh=21b2,le=2264,leftarrow=2190,leftarrowtail=21a2,leftharpoondown=21bd,lef",
|
|
1272
|
+
"tharpoonup=21bc,leftleftarrows=21c7,leftrightarrow=2194,leftrightarrows=21c6,leftrightharpoons=21cb,",
|
|
1273
|
+
"leftrightsquigarrow=21ad,leftthreetimes=22cb,leg=22da,leq=2264,leqq=2266,leqslant=2a7d,les=2a7d,lesc",
|
|
1274
|
+
"c=2aa8,lesdot=2a7f,lesdoto=2a81,lesdotor=2a83,lesg=22da.fe00,lesges=2a93,lessapprox=2a85,lessdot=22d",
|
|
1275
|
+
"6,lesseqgtr=22da,lesseqqgtr=2a8b,lessgtr=2276,lesssim=2272,lfisht=297c,lfloor=230a,lfr=1d529,lg=2276",
|
|
1276
|
+
",lgE=2a91,lhard=21bd,lharu=21bc,lharul=296a,lhblk=2584,ljcy=459,ll=226a,llarr=21c7,llcorner=231e,llh",
|
|
1277
|
+
"ard=296b,lltri=25fa,lmidot=140,lmoust=23b0,lmoustache=23b0,lnE=2268,lnap=2a89,lnapprox=2a89,lne=2a87",
|
|
1278
|
+
",lneq=2a87,lneqq=2268,lnsim=22e6,loang=27ec,loarr=21fd,lobrk=27e6,longleftarrow=27f5,longleftrightar",
|
|
1279
|
+
"row=27f7,longmapsto=27fc,longrightarrow=27f6,looparrowleft=21ab,looparrowright=21ac,lopar=2985,lopf=",
|
|
1280
|
+
"1d55d,loplus=2a2d,lotimes=2a34,lowast=2217,lowbar=5f,loz=25ca,lozenge=25ca,lozf=29eb,lpar=28,lparlt=",
|
|
1281
|
+
"2993,lrarr=21c6,lrcorner=231f,lrhar=21cb,lrhard=296d,lrm=200e,lrtri=22bf,lsaquo=2039,lscr=1d4c1,lsh=",
|
|
1282
|
+
"21b0,lsim=2272,lsime=2a8d,lsimg=2a8f,lsqb=5b,lsquo=2018,lsquor=201a,lstrok=142,lt=3c,ltcc=2aa6,ltcir",
|
|
1283
|
+
"=2a79,ltdot=22d6,lthree=22cb,ltimes=22c9,ltlarr=2976,ltquest=2a7b,ltrPar=2996,ltri=25c3,ltrie=22b4,l",
|
|
1284
|
+
"trif=25c2,lurdshar=294a,luruhar=2966,lvertneqq=2268.fe00,lvnE=2268.fe00,mDDot=223a,macr=af,male=2642",
|
|
1285
|
+
",malt=2720,maltese=2720,map=21a6,mapsto=21a6,mapstodown=21a7,mapstoleft=21a4,mapstoup=21a5,marker=25",
|
|
1286
|
+
"ae,mcomma=2a29,mcy=43c,mdash=2014,measuredangle=2221,mfr=1d52a,mho=2127,micro=b5,mid=2223,midast=2a,",
|
|
1287
|
+
"midcir=2af0,middot=b7,minus=2212,minusb=229f,minusd=2238,minusdu=2a2a,mlcp=2adb,mldr=2026,mnplus=221",
|
|
1288
|
+
"3,models=22a7,mopf=1d55e,mp=2213,mscr=1d4c2,mstpos=223e,mu=3bc,multimap=22b8,mumap=22b8,nGg=22d9.338",
|
|
1289
|
+
",nGt=226b.20d2,nGtv=226b.338,nLeftarrow=21cd,nLeftrightarrow=21ce,nLl=22d8.338,nLt=226a.20d2,nLtv=22",
|
|
1290
|
+
"6a.338,nRightarrow=21cf,nVDash=22af,nVdash=22ae,nabla=2207,nacute=144,nang=2220.20d2,nap=2249,napE=2",
|
|
1291
|
+
"a70.338,napid=224b.338,napos=149,napprox=2249,natur=266e,natural=266e,naturals=2115,nbsp=a0,nbump=22",
|
|
1292
|
+
"4e.338,nbumpe=224f.338,ncap=2a43,ncaron=148,ncedil=146,ncong=2247,ncongdot=2a6d.338,ncup=2a42,ncy=43",
|
|
1293
|
+
"d,ndash=2013,ne=2260,neArr=21d7,nearhk=2924,nearr=2197,nearrow=2197,nedot=2250.338,nequiv=2262,nesea",
|
|
1294
|
+
"r=2928,nesim=2242.338,nexist=2204,nexists=2204,nfr=1d52b,ngE=2267.338,nge=2271,ngeq=2271,ngeqq=2267.",
|
|
1295
|
+
"338,ngeqslant=2a7e.338,nges=2a7e.338,ngsim=2275,ngt=226f,ngtr=226f,nhArr=21ce,nharr=21ae,nhpar=2af2,",
|
|
1296
|
+
"ni=220b,nis=22fc,nisd=22fa,niv=220b,njcy=45a,nlArr=21cd,nlE=2266.338,nlarr=219a,nldr=2025,nle=2270,n",
|
|
1297
|
+
"leftarrow=219a,nleftrightarrow=21ae,nleq=2270,nleqq=2266.338,nleqslant=2a7d.338,nles=2a7d.338,nless=",
|
|
1298
|
+
"226e,nlsim=2274,nlt=226e,nltri=22ea,nltrie=22ec,nmid=2224,nopf=1d55f,not=ac,notin=2209,notinE=22f9.3",
|
|
1299
|
+
"38,notindot=22f5.338,notinva=2209,notinvb=22f7,notinvc=22f6,notni=220c,notniva=220c,notnivb=22fe,not",
|
|
1300
|
+
"nivc=22fd,npar=2226,nparallel=2226,nparsl=2afd.20e5,npart=2202.338,npolint=2a14,npr=2280,nprcue=22e0",
|
|
1301
|
+
",npre=2aaf.338,nprec=2280,npreceq=2aaf.338,nrArr=21cf,nrarr=219b,nrarrc=2933.338,nrarrw=219d.338,nri",
|
|
1302
|
+
"ghtarrow=219b,nrtri=22eb,nrtrie=22ed,nsc=2281,nsccue=22e1,nsce=2ab0.338,nscr=1d4c3,nshortmid=2224,ns",
|
|
1303
|
+
"hortparallel=2226,nsim=2241,nsime=2244,nsimeq=2244,nsmid=2224,nspar=2226,nsqsube=22e2,nsqsupe=22e3,n",
|
|
1304
|
+
"sub=2284,nsubE=2ac5.338,nsube=2288,nsubset=2282.20d2,nsubseteq=2288,nsubseteqq=2ac5.338,nsucc=2281,n",
|
|
1305
|
+
"succeq=2ab0.338,nsup=2285,nsupE=2ac6.338,nsupe=2289,nsupset=2283.20d2,nsupseteq=2289,nsupseteqq=2ac6",
|
|
1306
|
+
".338,ntgl=2279,ntilde=f1,ntlg=2278,ntriangleleft=22ea,ntrianglelefteq=22ec,ntriangleright=22eb,ntria",
|
|
1307
|
+
"nglerighteq=22ed,nu=3bd,num=23,numero=2116,numsp=2007,nvDash=22ad,nvHarr=2904,nvap=224d.20d2,nvdash=",
|
|
1308
|
+
"22ac,nvge=2265.20d2,nvgt=3e.20d2,nvinfin=29de,nvlArr=2902,nvle=2264.20d2,nvlt=3c.20d2,nvltrie=22b4.2",
|
|
1309
|
+
"0d2,nvrArr=2903,nvrtrie=22b5.20d2,nvsim=223c.20d2,nwArr=21d6,nwarhk=2923,nwarr=2196,nwarrow=2196,nwn",
|
|
1310
|
+
"ear=2927,oS=24c8,oacute=f3,oast=229b,ocir=229a,ocirc=f4,ocy=43e,odash=229d,odblac=151,odiv=2a38,odot",
|
|
1311
|
+
"=2299,odsold=29bc,oelig=153,ofcir=29bf,ofr=1d52c,ogon=2db,ograve=f2,ogt=29c1,ohbar=29b5,ohm=3a9,oint",
|
|
1312
|
+
"=222e,olarr=21ba,olcir=29be,olcross=29bb,oline=203e,olt=29c0,omacr=14d,omega=3c9,omicron=3bf,omid=29",
|
|
1313
|
+
"b6,ominus=2296,oopf=1d560,opar=29b7,operp=29b9,oplus=2295,or=2228,orarr=21bb,ord=2a5d,order=2134,ord",
|
|
1314
|
+
"erof=2134,ordf=aa,ordm=ba,origof=22b6,oror=2a56,orslope=2a57,orv=2a5b,oscr=2134,oslash=f8,osol=2298,",
|
|
1315
|
+
"otilde=f5,otimes=2297,otimesas=2a36,ouml=f6,ovbar=233d,par=2225,para=b6,parallel=2225,parsim=2af3,pa",
|
|
1316
|
+
"rsl=2afd,part=2202,pcy=43f,percnt=25,period=2e,permil=2030,perp=22a5,pertenk=2031,pfr=1d52d,phi=3c6,",
|
|
1317
|
+
"phiv=3d5,phmmat=2133,phone=260e,pi=3c0,pitchfork=22d4,piv=3d6,planck=210f,planckh=210e,plankv=210f,p",
|
|
1318
|
+
"lus=2b,plusacir=2a23,plusb=229e,pluscir=2a22,plusdo=2214,plusdu=2a25,pluse=2a72,plusmn=b1,plussim=2a",
|
|
1319
|
+
"26,plustwo=2a27,pm=b1,pointint=2a15,popf=1d561,pound=a3,pr=227a,prE=2ab3,prap=2ab7,prcue=227c,pre=2a",
|
|
1320
|
+
"af,prec=227a,precapprox=2ab7,preccurlyeq=227c,preceq=2aaf,precnapprox=2ab9,precneqq=2ab5,precnsim=22",
|
|
1321
|
+
"e8,precsim=227e,prime=2032,primes=2119,prnE=2ab5,prnap=2ab9,prnsim=22e8,prod=220f,profalar=232e,prof",
|
|
1322
|
+
"line=2312,profsurf=2313,prop=221d,propto=221d,prsim=227e,prurel=22b0,pscr=1d4c5,psi=3c8,puncsp=2008,",
|
|
1323
|
+
"qfr=1d52e,qint=2a0c,qopf=1d562,qprime=2057,qscr=1d4c6,quaternions=210d,quatint=2a16,quest=3f,questeq",
|
|
1324
|
+
"=225f,quot=22,rAarr=21db,rArr=21d2,rAtail=291c,rBarr=290f,rHar=2964,race=223d.331,racute=155,radic=2",
|
|
1325
|
+
"21a,raemptyv=29b3,rang=232a,rangd=2992,range=29a5,rangle=27e9,raquo=bb,rarr=2192,rarrap=2975,rarrb=2",
|
|
1326
|
+
"1e5,rarrbfs=2920,rarrc=2933,rarrfs=291e,rarrhk=21aa,rarrlp=21ac,rarrpl=2945,rarrsim=2974,rarrtl=21a3",
|
|
1327
|
+
",rarrw=219d,ratail=291a,ratio=2236,rationals=211a,rbarr=290d,rbbrk=2773,rbrace=7d,rbrack=5d,rbrke=29",
|
|
1328
|
+
"8c,rbrksld=298e,rbrkslu=2990,rcaron=159,rcedil=157,rceil=2309,rcub=7d,rcy=440,rdca=2937,rdldhar=2969",
|
|
1329
|
+
",rdquo=201d,rdquor=201d,rdsh=21b3,real=211c,realine=211b,realpart=211c,reals=211d,rect=25ad,reg=ae,r",
|
|
1330
|
+
"fisht=297d,rfloor=230b,rfr=1d52f,rhard=21c1,rharu=21c0,rharul=296c,rho=3c1,rhov=3f1,rightarrow=2192,",
|
|
1331
|
+
"rightarrowtail=21a3,rightharpoondown=21c1,rightharpoonup=21c0,rightleftarrows=21c4,rightleftharpoons",
|
|
1332
|
+
"=21cc,rightrightarrows=21c9,rightsquigarrow=219d,rightthreetimes=22cc,ring=2da,risingdotseq=2253,rla",
|
|
1333
|
+
"rr=21c4,rlhar=21cc,rlm=200f,rmoust=23b1,rmoustache=23b1,rnmid=2aee,roang=27ed,roarr=21fe,robrk=27e7,",
|
|
1334
|
+
"ropar=2986,ropf=1d563,roplus=2a2e,rotimes=2a35,rpar=29,rpargt=2994,rppolint=2a12,rrarr=21c9,rsaquo=2",
|
|
1335
|
+
"03a,rscr=1d4c7,rsh=21b1,rsqb=5d,rsquo=2019,rsquor=2019,rthree=22cc,rtimes=22ca,rtri=25b9,rtrie=22b5,",
|
|
1336
|
+
"rtrif=25b8,rtriltri=29ce,ruluhar=2968,rx=211e,sacute=15b,sbquo=201a,sc=227b,scE=2ab4,scap=2ab8,scaro",
|
|
1337
|
+
"n=161,sccue=227d,sce=2ab0,scedil=15f,scirc=15d,scnE=2ab6,scnap=2aba,scnsim=22e9,scpolint=2a13,scsim=",
|
|
1338
|
+
"227f,scy=441,sdot=22c5,sdotb=22a1,sdote=2a66,seArr=21d8,searhk=2925,searr=2198,searrow=2198,sect=a7,",
|
|
1339
|
+
"semi=3b,seswar=2929,setminus=2216,setmn=2216,sext=2736,sfr=1d530,sfrown=2322,sharp=266f,shchcy=449,s",
|
|
1340
|
+
"hcy=448,shortmid=2223,shortparallel=2225,shy=ad,sigma=3c3,sigmaf=3c2,sigmav=3c2,sim=223c,simdot=2a6a",
|
|
1341
|
+
",sime=2243,simeq=2243,simg=2a9e,simgE=2aa0,siml=2a9d,simlE=2a9f,simne=2246,simplus=2a24,simrarr=2972",
|
|
1342
|
+
",slarr=2190,smallsetminus=2216,smashp=2a33,smeparsl=29e4,smid=2223,smile=2323,smt=2aaa,smte=2aac,smt",
|
|
1343
|
+
"es=2aac.fe00,softcy=44c,sol=2f,solb=29c4,solbar=233f,sopf=1d564,spades=2660,spadesuit=2660,spar=2225",
|
|
1344
|
+
",sqcap=2293,sqcaps=2293.fe00,sqcup=2294,sqcups=2294.fe00,sqsub=228f,sqsube=2291,sqsubset=228f,sqsubs",
|
|
1345
|
+
"eteq=2291,sqsup=2290,sqsupe=2292,sqsupset=2290,sqsupseteq=2292,squ=25a1,square=25a1,squarf=25aa,squf",
|
|
1346
|
+
"=25aa,srarr=2192,sscr=1d4c8,ssetmn=2216,ssmile=2323,sstarf=22c6,star=2606,starf=2605,straightepsilon",
|
|
1347
|
+
"=3f5,straightphi=3d5,strns=af,sub=2282,subE=2ac5,subdot=2abd,sube=2286,subedot=2ac3,submult=2ac1,sub",
|
|
1348
|
+
"nE=2acb,subne=228a,subplus=2abf,subrarr=2979,subset=2282,subseteq=2286,subseteqq=2ac5,subsetneq=228a",
|
|
1349
|
+
",subsetneqq=2acb,subsim=2ac7,subsub=2ad5,subsup=2ad3,succ=227b,succapprox=2ab8,succcurlyeq=227d,succ",
|
|
1350
|
+
"eq=2ab0,succnapprox=2aba,succneqq=2ab6,succnsim=22e9,succsim=227f,sum=2211,sung=266a,sup=2283,sup1=b",
|
|
1351
|
+
"9,sup2=b2,sup3=b3,supE=2ac6,supdot=2abe,supdsub=2ad8,supe=2287,supedot=2ac4,suphsol=27c9,suphsub=2ad",
|
|
1352
|
+
"7,suplarr=297b,supmult=2ac2,supnE=2acc,supne=228b,supplus=2ac0,supset=2283,supseteq=2287,supseteqq=2",
|
|
1353
|
+
"ac6,supsetneq=228b,supsetneqq=2acc,supsim=2ac8,supsub=2ad4,supsup=2ad6,swArr=21d9,swarhk=2926,swarr=",
|
|
1354
|
+
"2199,swarrow=2199,swnwar=292a,szlig=df,target=2316,tau=3c4,tbrk=23b4,tcaron=165,tcedil=163,tcy=442,t",
|
|
1355
|
+
"dot=20db,telrec=2315,tfr=1d531,there4=2234,therefore=2234,theta=3b8,thetasym=3d1,thetav=3d1,thickapp",
|
|
1356
|
+
"rox=2248,thicksim=223c,thinsp=2009,thkap=2248,thksim=223c,thorn=fe,tilde=2dc,times=d7,timesb=22a0,ti",
|
|
1357
|
+
"mesbar=2a31,timesd=2a30,tint=222d,toea=2928,top=22a4,topbot=2336,topcir=2af1,topf=1d565,topfork=2ada",
|
|
1358
|
+
",tosa=2929,tprime=2034,trade=2122,triangle=25b5,triangledown=25bf,triangleleft=25c3,trianglelefteq=2",
|
|
1359
|
+
"2b4,triangleq=225c,triangleright=25b9,trianglerighteq=22b5,tridot=25ec,trie=225c,triminus=2a3a,tripl",
|
|
1360
|
+
"us=2a39,trisb=29cd,tritime=2a3b,trpezium=23e2,tscr=1d4c9,tscy=446,tshcy=45b,tstrok=167,twixt=226c,tw",
|
|
1361
|
+
"oheadleftarrow=219e,twoheadrightarrow=21a0,uArr=21d1,uHar=2963,uacute=fa,uarr=2191,ubrcy=45e,ubreve=",
|
|
1362
|
+
"16d,ucirc=fb,ucy=443,udarr=21c5,udblac=171,udhar=296e,ufisht=297e,ufr=1d532,ugrave=f9,uharl=21bf,uha",
|
|
1363
|
+
"rr=21be,uhblk=2580,ulcorn=231c,ulcorner=231c,ulcrop=230f,ultri=25f8,umacr=16b,uml=a8,uogon=173,uopf=",
|
|
1364
|
+
"1d566,uparrow=2191,updownarrow=2195,upharpoonleft=21bf,upharpoonright=21be,uplus=228e,upsi=3c5,upsih",
|
|
1365
|
+
"=3d2,upsilon=3c5,upuparrows=21c8,urcorn=231d,urcorner=231d,urcrop=230e,uring=16f,urtri=25f9,uscr=1d4",
|
|
1366
|
+
"ca,utdot=22f0,utilde=169,utri=25b5,utrif=25b4,uuarr=21c8,uuml=fc,uwangle=29a7,vArr=21d5,vBar=2ae8,vB",
|
|
1367
|
+
"arv=2ae9,vDash=22a8,vangrt=299c,varepsilon=3f5,varkappa=3f0,varnothing=2205,varphi=3d5,varpi=3d6,var",
|
|
1368
|
+
"propto=221d,varr=2195,varrho=3f1,varsigma=3c2,varsubsetneq=228a.fe00,varsubsetneqq=2acb.fe00,varsups",
|
|
1369
|
+
"etneq=228b.fe00,varsupsetneqq=2acc.fe00,vartheta=3d1,vartriangleleft=22b2,vartriangleright=22b3,vcy=",
|
|
1370
|
+
"432,vdash=22a2,vee=2228,veebar=22bb,veeeq=225a,vellip=22ee,verbar=7c,vert=7c,vfr=1d533,vltri=22b2,vn",
|
|
1371
|
+
"sub=2282.20d2,vnsup=2283.20d2,vopf=1d567,vprop=221d,vrtri=22b3,vscr=1d4cb,vsubnE=2acb.fe00,vsubne=22",
|
|
1372
|
+
"8a.fe00,vsupnE=2acc.fe00,vsupne=228b.fe00,vzigzag=299a,wcirc=175,wedbar=2a5f,wedge=2227,wedgeq=2259,",
|
|
1373
|
+
"weierp=2118,wfr=1d534,wopf=1d568,wp=2118,wr=2240,wreath=2240,wscr=1d4cc,xcap=22c2,xcirc=25ef,xcup=22",
|
|
1374
|
+
"c3,xdtri=25bd,xfr=1d535,xhArr=27fa,xharr=27f7,xi=3be,xlArr=27f8,xlarr=27f5,xmap=27fc,xnis=22fb,xodot",
|
|
1375
|
+
"=2a00,xopf=1d569,xoplus=2a01,xotime=2a02,xrArr=27f9,xrarr=27f6,xscr=1d4cd,xsqcup=2a06,xuplus=2a04,xu",
|
|
1376
|
+
"tri=25b3,xvee=22c1,xwedge=22c0,yacute=fd,yacy=44f,ycirc=177,ycy=44b,yen=a5,yfr=1d536,yicy=457,yopf=1",
|
|
1377
|
+
"d56a,yscr=1d4ce,yucy=44e,yuml=ff,zacute=17a,zcaron=17e,zcy=437,zdot=17c,zeetrf=2128,zeta=3b6,zfr=1d5",
|
|
1378
|
+
"37,zhcy=436,zigrarr=21dd,zopf=1d56b,zscr=1d4cf,zwj=200d,zwnj=200c"
|
|
1379
|
+
].join("");
|
|
1380
|
+
var NAMED_REFERENCES = new Map(NAMED.split(",").map((entry) => {
|
|
1381
|
+
const [name, codes] = entry.split("=");
|
|
1382
|
+
return [name, String.fromCodePoint(...codes.split(".").map((code) => Number.parseInt(code, 16)))];
|
|
1383
|
+
}));
|
|
1384
|
+
|
|
1110
1385
|
// src/html.js
|
|
1111
1386
|
var 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(" ");
|
|
1112
|
-
var ENTITIES = new Map([
|
|
1113
|
-
...LATIN1.map((name, index) => [name, String.fromCodePoint(160 + index)]),
|
|
1114
|
-
["amp", "&"],
|
|
1115
|
-
["lt", "<"],
|
|
1116
|
-
["gt", ">"],
|
|
1117
|
-
["quot", '"'],
|
|
1118
|
-
["apos", "'"],
|
|
1119
|
-
["AMP", "&"],
|
|
1120
|
-
["LT", "<"],
|
|
1121
|
-
["GT", ">"],
|
|
1122
|
-
["QUOT", '"'],
|
|
1123
|
-
["COPY", "\xA9"],
|
|
1124
|
-
["REG", "\xAE"],
|
|
1125
|
-
["OElig", "\u0152"],
|
|
1126
|
-
["oelig", "\u0153"],
|
|
1127
|
-
["Scaron", "\u0160"],
|
|
1128
|
-
["scaron", "\u0161"],
|
|
1129
|
-
["Yuml", "\u0178"],
|
|
1130
|
-
["fnof", "\u0192"],
|
|
1131
|
-
["circ", "\u02C6"],
|
|
1132
|
-
["tilde", "\u02DC"],
|
|
1133
|
-
["ensp", "\u2002"],
|
|
1134
|
-
["emsp", "\u2003"],
|
|
1135
|
-
["thinsp", "\u2009"],
|
|
1136
|
-
["zwnj", "\u200C"],
|
|
1137
|
-
["zwj", "\u200D"],
|
|
1138
|
-
["lrm", "\u200E"],
|
|
1139
|
-
["rlm", "\u200F"],
|
|
1140
|
-
["ndash", "\u2013"],
|
|
1141
|
-
["mdash", "\u2014"],
|
|
1142
|
-
["lsquo", "\u2018"],
|
|
1143
|
-
["rsquo", "\u2019"],
|
|
1144
|
-
["sbquo", "\u201A"],
|
|
1145
|
-
["ldquo", "\u201C"],
|
|
1146
|
-
["rdquo", "\u201D"],
|
|
1147
|
-
["bdquo", "\u201E"],
|
|
1148
|
-
["dagger", "\u2020"],
|
|
1149
|
-
["Dagger", "\u2021"],
|
|
1150
|
-
["bull", "\u2022"],
|
|
1151
|
-
["hellip", "\u2026"],
|
|
1152
|
-
["permil", "\u2030"],
|
|
1153
|
-
["prime", "\u2032"],
|
|
1154
|
-
["Prime", "\u2033"],
|
|
1155
|
-
["lsaquo", "\u2039"],
|
|
1156
|
-
["rsaquo", "\u203A"],
|
|
1157
|
-
["euro", "\u20AC"],
|
|
1158
|
-
["trade", "\u2122"],
|
|
1159
|
-
["larr", "\u2190"],
|
|
1160
|
-
["uarr", "\u2191"],
|
|
1161
|
-
["rarr", "\u2192"],
|
|
1162
|
-
["darr", "\u2193"],
|
|
1163
|
-
["hearts", "\u2665"],
|
|
1164
|
-
["check", "\u2713"],
|
|
1165
|
-
// The punctuation of a web address, as browsers read these names
|
|
1166
|
-
// ("https://bank.example@evil.example/" goes to evil.example)
|
|
1167
|
-
["Tab", " "],
|
|
1168
|
-
["NewLine", "\n"],
|
|
1169
|
-
["excl", "!"],
|
|
1170
|
-
["num", "#"],
|
|
1171
|
-
["dollar", "$"],
|
|
1172
|
-
["percnt", "%"],
|
|
1173
|
-
["lpar", "("],
|
|
1174
|
-
["rpar", ")"],
|
|
1175
|
-
["ast", "*"],
|
|
1176
|
-
["midast", "*"],
|
|
1177
|
-
["plus", "+"],
|
|
1178
|
-
["comma", ","],
|
|
1179
|
-
["period", "."],
|
|
1180
|
-
["sol", "/"],
|
|
1181
|
-
["colon", ":"],
|
|
1182
|
-
["semi", ";"],
|
|
1183
|
-
["equals", "="],
|
|
1184
|
-
["quest", "?"],
|
|
1185
|
-
["commat", "@"],
|
|
1186
|
-
["lsqb", "["],
|
|
1187
|
-
["lbrack", "["],
|
|
1188
|
-
["bsol", "\\"],
|
|
1189
|
-
["rsqb", "]"],
|
|
1190
|
-
["rbrack", "]"],
|
|
1191
|
-
["Hat", "^"],
|
|
1192
|
-
["lowbar", "_"],
|
|
1193
|
-
["UnderBar", "_"],
|
|
1194
|
-
["grave", "`"],
|
|
1195
|
-
["DiacriticalGrave", "`"],
|
|
1196
|
-
["lcub", "{"],
|
|
1197
|
-
["lbrace", "{"],
|
|
1198
|
-
["verbar", "|"],
|
|
1199
|
-
["vert", "|"],
|
|
1200
|
-
["VerticalLine", "|"],
|
|
1201
|
-
["rcub", "}"],
|
|
1202
|
-
["rbrace", "}"]
|
|
1203
|
-
]);
|
|
1204
1387
|
var LEGACY = /* @__PURE__ */ new Set([...LATIN1, "amp", "lt", "gt", "quot", "AMP", "LT", "GT", "QUOT", "COPY", "REG"]);
|
|
1205
1388
|
var LEGACY_LONGEST = Math.max(...[...LEGACY].map((name) => name.length));
|
|
1206
|
-
var 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(" "));
|
|
1207
1389
|
var 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];
|
|
1208
1390
|
var REFERENCE = /&(?:#([xX])([\da-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z\d]{0,31}))(;?)/g;
|
|
1209
1391
|
function fromCode(code) {
|
|
@@ -1221,8 +1403,8 @@ function decodeEntities(value, { attribute = false } = {}) {
|
|
|
1221
1403
|
if (hex !== void 0 || decimal !== void 0) {
|
|
1222
1404
|
return fromCode(hex === void 0 ? Number.parseInt(decimal, 10) : Number.parseInt(hex, 16));
|
|
1223
1405
|
}
|
|
1224
|
-
if (semicolon &&
|
|
1225
|
-
return
|
|
1406
|
+
if (semicolon && NAMED_REFERENCES.has(name)) {
|
|
1407
|
+
return NAMED_REFERENCES.get(name);
|
|
1226
1408
|
}
|
|
1227
1409
|
let legacy;
|
|
1228
1410
|
for (let length = Math.min(name.length, LEGACY_LONGEST); length >= 2 && legacy === void 0; length--) {
|
|
@@ -1236,7 +1418,7 @@ function decodeEntities(value, { attribute = false } = {}) {
|
|
|
1236
1418
|
if (attribute && /[\da-zA-Z=]/.test(next)) {
|
|
1237
1419
|
return match;
|
|
1238
1420
|
}
|
|
1239
|
-
return
|
|
1421
|
+
return NAMED_REFERENCES.get(legacy) + rest;
|
|
1240
1422
|
});
|
|
1241
1423
|
}
|
|
1242
1424
|
var UNSHOWN = /* @__PURE__ */ new Set(["script", "style", "title", "noembed", "noframes", "iframe"]);
|
|
@@ -2382,7 +2564,7 @@ function endsInsideTag(html, end, link) {
|
|
|
2382
2564
|
return joined !== host && (!isHost(host) || isHost(joined) && registrableDomain(joined) !== registrableDomain(host));
|
|
2383
2565
|
}
|
|
2384
2566
|
var MAX_SHOWN_HTML = 2e5;
|
|
2385
|
-
function extractLinks(text, html, { maxLength = 5e5, bareHosts = false } = {}) {
|
|
2567
|
+
function extractLinks(text, html, { maxLength = 5e5, bareHosts: bareHosts2 = false } = {}) {
|
|
2386
2568
|
text = typeof text === "string" ? foldToAscii(text) : text;
|
|
2387
2569
|
html = typeof html === "string" ? foldToAscii(html) : html;
|
|
2388
2570
|
const links = [];
|
|
@@ -2449,7 +2631,7 @@ ${shown || ""}`;
|
|
|
2449
2631
|
}
|
|
2450
2632
|
add(link);
|
|
2451
2633
|
}
|
|
2452
|
-
if (
|
|
2634
|
+
if (bareHosts2 && index < 2) {
|
|
2453
2635
|
bareLinkHosts(read, (host) => {
|
|
2454
2636
|
bareFound.push(host);
|
|
2455
2637
|
});
|
|
@@ -3234,6 +3416,7 @@ var MACRO_EXTENSIONS = /* @__PURE__ */ new Set(["docm", "dotm", "xlsm", "xltm",
|
|
|
3234
3416
|
var DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set(["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf", "jpg", "jpeg", "png", "gif", "zip", "csv", "odt", "ods", "html", "htm", "mp3", "mp4", "mov", "wav", "eml", "msg", "xml", "json"]);
|
|
3235
3417
|
var TEMPORARY_EXTENSIONS = /* @__PURE__ */ new Set(["tmp"]);
|
|
3236
3418
|
var BIDI_CONTROLS = characterClass([[8234, 8238], [8294, 8297]], "u");
|
|
3419
|
+
var ALL_BIDI_CONTROLS = characterClass([[8234, 8238], [8294, 8297]], "gu");
|
|
3237
3420
|
var ARCHIVE_TYPES = /* @__PURE__ */ new Set(["zip", "rar", "7z", "gz", "bz2", "xz", "cab", "iso", "tar", "zst", "lzh", "ace", "arj"]);
|
|
3238
3421
|
function sniff(buffer) {
|
|
3239
3422
|
if (!Buffer.isBuffer(buffer) || buffer.length < 4) {
|
|
@@ -3417,7 +3600,16 @@ function shorten(name, max = 100) {
|
|
|
3417
3600
|
return characters.length <= max ? name : `${characters.slice(0, max - 41).join("")}\u2026${characters.slice(-40).join("")}`;
|
|
3418
3601
|
}
|
|
3419
3602
|
function extensionOf(name) {
|
|
3420
|
-
const base = trimEndOf(String(name).toLowerCase().split(/[/\\]/).pop(), ". ");
|
|
3603
|
+
const base = trimEndOf(String(name).toLowerCase().replace(ALL_BIDI_CONTROLS, "").split(/[/\\]/).pop(), ". ");
|
|
3604
|
+
const whole = lastExtension(base);
|
|
3605
|
+
const file = base.replace(/^[a-z]:/, "");
|
|
3606
|
+
const colon = file.indexOf(":");
|
|
3607
|
+
if (colon !== -1 && /^(?::?\$data)?$/.test(file.slice(colon + 1))) {
|
|
3608
|
+
return lastExtension(trimEndOf(file.slice(0, colon), ". "));
|
|
3609
|
+
}
|
|
3610
|
+
return whole;
|
|
3611
|
+
}
|
|
3612
|
+
function lastExtension(base) {
|
|
3421
3613
|
const dot = base.lastIndexOf(".");
|
|
3422
3614
|
return dot === -1 ? "" : base.slice(dot + 1).trim();
|
|
3423
3615
|
}
|
|
@@ -3961,7 +4153,8 @@ async function parseWithin(raw, parse = parseMessage, deadline = Date.now() + PA
|
|
|
3961
4153
|
}
|
|
3962
4154
|
}
|
|
3963
4155
|
}
|
|
3964
|
-
async function expandAttachments(attachments = [], errors = [], parse = parseMessage,
|
|
4156
|
+
async function expandAttachments(attachments = [], errors = [], parse = parseMessage, gets = {}) {
|
|
4157
|
+
const { unopened = [], mails = [] } = Array.isArray(gets) ? { unopened: gets } : gets;
|
|
3965
4158
|
const all = [];
|
|
3966
4159
|
const deadline = Date.now() + PARSE_TIMEOUT;
|
|
3967
4160
|
let budget = MAX_NESTED_BYTES;
|
|
@@ -4010,6 +4203,7 @@ async function expandAttachments(attachments = [], errors = [], parse = parseMes
|
|
|
4010
4203
|
if (inner.error) {
|
|
4011
4204
|
errors.push(inner.error);
|
|
4012
4205
|
}
|
|
4206
|
+
mails.push(inner.mail);
|
|
4013
4207
|
await visit(inner.mail.attachments, prefix ? `${prefix}/${name}` : name || "attached message", depth + 1);
|
|
4014
4208
|
}
|
|
4015
4209
|
}
|
|
@@ -5426,8 +5620,917 @@ var Classifier = class _Classifier {
|
|
|
5426
5620
|
}
|
|
5427
5621
|
};
|
|
5428
5622
|
|
|
5429
|
-
// src/
|
|
5623
|
+
// src/links.js
|
|
5624
|
+
import { Buffer as Buffer7 } from "node:buffer";
|
|
5625
|
+
import { isIP as isIP3 } from "node:net";
|
|
5430
5626
|
import { parse as parseDomain3 } from "tldts";
|
|
5627
|
+
var LINK_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
5628
|
+
"href",
|
|
5629
|
+
"src",
|
|
5630
|
+
"srcset",
|
|
5631
|
+
"background",
|
|
5632
|
+
"action",
|
|
5633
|
+
"formaction",
|
|
5634
|
+
"poster",
|
|
5635
|
+
"cite",
|
|
5636
|
+
"longdesc",
|
|
5637
|
+
"xlink:href",
|
|
5638
|
+
"style",
|
|
5639
|
+
"data",
|
|
5640
|
+
"ping",
|
|
5641
|
+
// (of a <meta> refresh: "0;url=https://example.com/")
|
|
5642
|
+
"content",
|
|
5643
|
+
// (a document of its own, see linksOf)
|
|
5644
|
+
"srcdoc"
|
|
5645
|
+
]);
|
|
5646
|
+
var TAG_START = /<[a-z][^\s/>]*/gi;
|
|
5647
|
+
var URL_START = /\b(?:https?:\/\/|www\.)[^\s<>"'`]+/gi;
|
|
5648
|
+
var CSS_URL = /url\(\s*["']?([^()"']*)/gi;
|
|
5649
|
+
var CSS_IMPORT = /@import\s+["']([^"'<>]*)/gi;
|
|
5650
|
+
var LENIENT = /[\s"'/<](href|src|srcset|background|action|formaction|poster|cite|longdesc|xlink:href|style|data|ping|content|srcdoc)\s*=\s*/gi;
|
|
5651
|
+
var IN_WORD2 = /[\p{L}\p{N}\p{M}_%]/u;
|
|
5652
|
+
var NAMESPACES = /* @__PURE__ */ new Set(["www.w3.org", "w3.org"]);
|
|
5653
|
+
var MAX_HOST = 760;
|
|
5654
|
+
var MAX_SEEN = 1e5;
|
|
5655
|
+
var TRAILING = /* @__PURE__ */ new Set([")", ".", ",", ";", ":", "!", "?", "'", '"', "]"]);
|
|
5656
|
+
var DECODE_CHUNK = 1024 * 1024;
|
|
5657
|
+
var CHUNK_OVERLAP = 4096;
|
|
5658
|
+
var MAX_EMBED_DEPTH = 3;
|
|
5659
|
+
var MAX_EMBEDDED = 1e3;
|
|
5660
|
+
var MAX_EMBEDDED_LENGTH = 10 * 1024 * 1024;
|
|
5661
|
+
var MAX_ATTACHED = 100;
|
|
5662
|
+
var MAX_ATTACHED_BYTES = 50 * 1024 * 1024;
|
|
5663
|
+
var MAX_READ_TIME = 5e3;
|
|
5664
|
+
var MAX_SHOWN_BYTES = 4 * 1024 * 1024;
|
|
5665
|
+
function isHostCode2(code) {
|
|
5666
|
+
return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 45 || code === 46;
|
|
5667
|
+
}
|
|
5668
|
+
function isSpace(code) {
|
|
5669
|
+
return code === 32 || code >= 9 && code <= 13;
|
|
5670
|
+
}
|
|
5671
|
+
function urlOf(value) {
|
|
5672
|
+
let href = value.replaceAll(/[\t\n\r]/g, "");
|
|
5673
|
+
let start = 0;
|
|
5674
|
+
let end = href.length;
|
|
5675
|
+
while (start < end && href.codePointAt(start) <= 32) {
|
|
5676
|
+
start++;
|
|
5677
|
+
}
|
|
5678
|
+
while (end > start && href.codePointAt(end - 1) <= 32) {
|
|
5679
|
+
end--;
|
|
5680
|
+
}
|
|
5681
|
+
while (end > start && TRAILING.has(href[end - 1])) {
|
|
5682
|
+
end--;
|
|
5683
|
+
}
|
|
5684
|
+
href = href.slice(start, end);
|
|
5685
|
+
if (/^[\\/]{2}/.test(href)) {
|
|
5686
|
+
href = `https://${href.slice(2)}`;
|
|
5687
|
+
} else if (/^www\./i.test(href)) {
|
|
5688
|
+
href = `http://${href}`;
|
|
5689
|
+
} else if (!/^https?:/i.test(href)) {
|
|
5690
|
+
return null;
|
|
5691
|
+
}
|
|
5692
|
+
try {
|
|
5693
|
+
return new URL(href);
|
|
5694
|
+
} catch {
|
|
5695
|
+
return null;
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
function hostOfUrl(url) {
|
|
5699
|
+
let host = url.hostname.toLowerCase();
|
|
5700
|
+
let dots = host.length;
|
|
5701
|
+
while (dots > 0 && host[dots - 1] === ".") {
|
|
5702
|
+
dots--;
|
|
5703
|
+
}
|
|
5704
|
+
host = host.slice(0, dots);
|
|
5705
|
+
if (host.startsWith("[") && host.endsWith("]")) {
|
|
5706
|
+
host = host.slice(1, -1);
|
|
5707
|
+
}
|
|
5708
|
+
if (!host || NAMESPACES.has(host)) {
|
|
5709
|
+
return null;
|
|
5710
|
+
}
|
|
5711
|
+
return isIP3(host) ? host : lookupName(host);
|
|
5712
|
+
}
|
|
5713
|
+
function hostsOf(value) {
|
|
5714
|
+
const url = urlOf(value);
|
|
5715
|
+
if (!url) {
|
|
5716
|
+
return [];
|
|
5717
|
+
}
|
|
5718
|
+
const host = hostOfUrl(url);
|
|
5719
|
+
const hosts = host ? [host] : [];
|
|
5720
|
+
const target = unwrapLink(url.href);
|
|
5721
|
+
if (target && target.href !== url.href) {
|
|
5722
|
+
const targetHost = hostOfUrl(target);
|
|
5723
|
+
if (targetHost && targetHost !== host) {
|
|
5724
|
+
hosts.push(targetHost);
|
|
5725
|
+
}
|
|
5726
|
+
const further = unwrapLink(target.href);
|
|
5727
|
+
if (further && further.href !== target.href) {
|
|
5728
|
+
hosts.unresolved = true;
|
|
5729
|
+
}
|
|
5730
|
+
}
|
|
5731
|
+
return hosts;
|
|
5732
|
+
}
|
|
5733
|
+
function* attributesOf(html) {
|
|
5734
|
+
TAG_START.lastIndex = 0;
|
|
5735
|
+
let match;
|
|
5736
|
+
while ((match = TAG_START.exec(html)) !== null) {
|
|
5737
|
+
let i = match.index + match[0].length;
|
|
5738
|
+
while (i < html.length && html[i] !== ">") {
|
|
5739
|
+
if (isSpace(html.codePointAt(i)) || html[i] === "/") {
|
|
5740
|
+
i++;
|
|
5741
|
+
continue;
|
|
5742
|
+
}
|
|
5743
|
+
let j = i;
|
|
5744
|
+
while (j < html.length && html[j] !== "=" && html[j] !== ">" && html[j] !== "/" && !isSpace(html.codePointAt(j))) {
|
|
5745
|
+
j++;
|
|
5746
|
+
}
|
|
5747
|
+
const name = html.slice(i, j).toLowerCase();
|
|
5748
|
+
if (j === i) {
|
|
5749
|
+
j++;
|
|
5750
|
+
}
|
|
5751
|
+
while (j < html.length && isSpace(html.codePointAt(j))) {
|
|
5752
|
+
j++;
|
|
5753
|
+
}
|
|
5754
|
+
if (html[j] !== "=") {
|
|
5755
|
+
i = j;
|
|
5756
|
+
continue;
|
|
5757
|
+
}
|
|
5758
|
+
j++;
|
|
5759
|
+
while (j < html.length && isSpace(html.codePointAt(j))) {
|
|
5760
|
+
j++;
|
|
5761
|
+
}
|
|
5762
|
+
let value;
|
|
5763
|
+
if (html[j] === '"' || html[j] === "'") {
|
|
5764
|
+
const close = html.indexOf(html[j], j + 1);
|
|
5765
|
+
const stop = close === -1 ? html.length : close;
|
|
5766
|
+
value = html.slice(j + 1, stop);
|
|
5767
|
+
j = stop + 1;
|
|
5768
|
+
} else {
|
|
5769
|
+
const start = j;
|
|
5770
|
+
while (j < html.length && html[j] !== ">" && !isSpace(html.codePointAt(j))) {
|
|
5771
|
+
j++;
|
|
5772
|
+
}
|
|
5773
|
+
value = html.slice(start, j);
|
|
5774
|
+
}
|
|
5775
|
+
if (name) {
|
|
5776
|
+
yield [name, value];
|
|
5777
|
+
}
|
|
5778
|
+
i = j;
|
|
5779
|
+
}
|
|
5780
|
+
TAG_START.lastIndex = Math.max(i, match.index + 1);
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
function linksOf(name, value, add, embed) {
|
|
5784
|
+
const decoded = decodeEntities(value, { attribute: true });
|
|
5785
|
+
switch (name) {
|
|
5786
|
+
case "srcdoc": {
|
|
5787
|
+
embed(decoded);
|
|
5788
|
+
break;
|
|
5789
|
+
}
|
|
5790
|
+
case "style": {
|
|
5791
|
+
for (const [, link] of decoded.matchAll(CSS_URL)) {
|
|
5792
|
+
add(link);
|
|
5793
|
+
}
|
|
5794
|
+
break;
|
|
5795
|
+
}
|
|
5796
|
+
case "srcset": {
|
|
5797
|
+
for (const candidate of decoded.split(",")) {
|
|
5798
|
+
add(candidate.trim().split(/\s/, 1)[0]);
|
|
5799
|
+
}
|
|
5800
|
+
break;
|
|
5801
|
+
}
|
|
5802
|
+
// (several, separated by spaces)
|
|
5803
|
+
case "ping": {
|
|
5804
|
+
for (const link of decoded.split(/\s+/)) {
|
|
5805
|
+
add(link);
|
|
5806
|
+
}
|
|
5807
|
+
break;
|
|
5808
|
+
}
|
|
5809
|
+
// (only the address of a refresh)
|
|
5810
|
+
case "content": {
|
|
5811
|
+
const match = /(?:^|[\s;,])url\s*=\s*["']?([^\s"';]+)/i.exec(decoded.slice(0, 4096));
|
|
5812
|
+
if (match) {
|
|
5813
|
+
add(match[1]);
|
|
5814
|
+
}
|
|
5815
|
+
break;
|
|
5816
|
+
}
|
|
5817
|
+
default: {
|
|
5818
|
+
add(decoded);
|
|
5819
|
+
}
|
|
5820
|
+
}
|
|
5821
|
+
}
|
|
5822
|
+
var MAX_LENIENT_VALUE = 4096;
|
|
5823
|
+
var UNQUOTED_END = /* @__PURE__ */ new Set(["<", ">", '"', "'", "`", "="]);
|
|
5824
|
+
function lenientLinks(html, add, done, embed) {
|
|
5825
|
+
LENIENT.lastIndex = 0;
|
|
5826
|
+
let match;
|
|
5827
|
+
while (!done() && (match = LENIENT.exec(html)) !== null) {
|
|
5828
|
+
const name = match[1].toLowerCase();
|
|
5829
|
+
let i = LENIENT.lastIndex;
|
|
5830
|
+
let end = i;
|
|
5831
|
+
if (html[i] === '"' || html[i] === "'") {
|
|
5832
|
+
const quote = html[i];
|
|
5833
|
+
i++;
|
|
5834
|
+
end = i;
|
|
5835
|
+
while (end < html.length && html[end] !== quote && html[end] !== "<" && html[end] !== ">") {
|
|
5836
|
+
end++;
|
|
5837
|
+
}
|
|
5838
|
+
if (end < html.length && html[end] !== quote) {
|
|
5839
|
+
const close = html.indexOf(quote, end);
|
|
5840
|
+
if (close !== -1 && close - i <= MAX_LENIENT_VALUE) {
|
|
5841
|
+
linksOf(name, html.slice(i, close), add, embed);
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
} else {
|
|
5845
|
+
while (end < html.length && !isSpace(html.codePointAt(end)) && !UNQUOTED_END.has(html[end])) {
|
|
5846
|
+
end++;
|
|
5847
|
+
}
|
|
5848
|
+
}
|
|
5849
|
+
linksOf(name, html.slice(i, end), add, embed);
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
function endsLink2(text, i) {
|
|
5853
|
+
const code = text.codePointAt(i);
|
|
5854
|
+
if (code < 128) {
|
|
5855
|
+
return isSpace(code) || code === 34 || code === 39 || code === 60 || code === 62 || code === 96;
|
|
5856
|
+
}
|
|
5857
|
+
return /\s/u.test(text[i]);
|
|
5858
|
+
}
|
|
5859
|
+
function linkReader(text) {
|
|
5860
|
+
let read = 0;
|
|
5861
|
+
let space = -1;
|
|
5862
|
+
let scheme = -1;
|
|
5863
|
+
return (start) => {
|
|
5864
|
+
for (; read < start; read++) {
|
|
5865
|
+
if (endsLink2(text, read)) {
|
|
5866
|
+
space = read;
|
|
5867
|
+
} else if (text[read] === "/" && text[read - 1] === "/" && text[read - 2] === ":") {
|
|
5868
|
+
scheme = read;
|
|
5869
|
+
}
|
|
5870
|
+
}
|
|
5871
|
+
return scheme > space;
|
|
5872
|
+
};
|
|
5873
|
+
}
|
|
5874
|
+
function isSchemeless(text, start) {
|
|
5875
|
+
if (start < 2 || text[start - 2] !== "/") {
|
|
5876
|
+
return false;
|
|
5877
|
+
}
|
|
5878
|
+
if (start === 2) {
|
|
5879
|
+
return true;
|
|
5880
|
+
}
|
|
5881
|
+
const before = text[start - 3];
|
|
5882
|
+
return !(before === ":" || before === "/" || isHostCode2(text.codePointAt(start - 3)));
|
|
5883
|
+
}
|
|
5884
|
+
function bareName(name) {
|
|
5885
|
+
const labels = name.split(".");
|
|
5886
|
+
const tld = labels.pop();
|
|
5887
|
+
if (!/^(?:[a-z]{2,24}|xn--[a-z\d-]{1,59})$/i.test(tld)) {
|
|
5888
|
+
return null;
|
|
5889
|
+
}
|
|
5890
|
+
const names = [];
|
|
5891
|
+
while (labels.length > 0 && names.length < 11) {
|
|
5892
|
+
const label = labels.pop();
|
|
5893
|
+
if (!/^[a-z\d-]{1,63}$/i.test(label)) {
|
|
5894
|
+
break;
|
|
5895
|
+
}
|
|
5896
|
+
names.unshift(label);
|
|
5897
|
+
}
|
|
5898
|
+
if (names.length === 0) {
|
|
5899
|
+
return null;
|
|
5900
|
+
}
|
|
5901
|
+
names[0] = names[0].replace(/^-+/, "");
|
|
5902
|
+
if (!names[0]) {
|
|
5903
|
+
return null;
|
|
5904
|
+
}
|
|
5905
|
+
return `${names.join(".")}.${tld}`.toLowerCase();
|
|
5906
|
+
}
|
|
5907
|
+
function isRealName(host) {
|
|
5908
|
+
const parsed = parseDomain3(host);
|
|
5909
|
+
return Boolean(parsed.isIcann && parsed.domain);
|
|
5910
|
+
}
|
|
5911
|
+
function bareHosts(text, add, { done, seen, from = 0, cutEnd = false }) {
|
|
5912
|
+
let previous = -1;
|
|
5913
|
+
const inLink = linkReader(text);
|
|
5914
|
+
for (let slash = text.indexOf("/"); slash !== -1; slash = text.indexOf("/", slash + 1)) {
|
|
5915
|
+
if (done()) {
|
|
5916
|
+
return;
|
|
5917
|
+
}
|
|
5918
|
+
const floor = Math.max(previous + 1, slash - MAX_HOST);
|
|
5919
|
+
previous = slash;
|
|
5920
|
+
let end = slash;
|
|
5921
|
+
while (end > floor && text.codePointAt(end - 1) >= 48 && text.codePointAt(end - 1) <= 57) {
|
|
5922
|
+
end--;
|
|
5923
|
+
}
|
|
5924
|
+
end = end > floor && text[end - 1] === ":" ? end - 1 : slash;
|
|
5925
|
+
let start = end;
|
|
5926
|
+
while (start > floor && isHostCode2(text.codePointAt(start - 1))) {
|
|
5927
|
+
start--;
|
|
5928
|
+
}
|
|
5929
|
+
if (start === end || start < from || cutEnd && slash === text.length - 1) {
|
|
5930
|
+
continue;
|
|
5931
|
+
}
|
|
5932
|
+
if (start > 0 && (IN_WORD2.test(text[start - 1]) || text[start - 1] === "/" && !isSchemeless(text, start)) || inLink(start)) {
|
|
5933
|
+
continue;
|
|
5934
|
+
}
|
|
5935
|
+
while (end > start && text[end - 1] === ".") {
|
|
5936
|
+
end--;
|
|
5937
|
+
}
|
|
5938
|
+
const host = bareName(text.slice(start, end));
|
|
5939
|
+
if (!host || seen.has(host)) {
|
|
5940
|
+
continue;
|
|
5941
|
+
}
|
|
5942
|
+
if (seen.size < MAX_SEEN) {
|
|
5943
|
+
seen.add(host);
|
|
5944
|
+
}
|
|
5945
|
+
if (isRealName(host)) {
|
|
5946
|
+
add(`http://${host}/`);
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
}
|
|
5950
|
+
function looseHosts(text, add, { from = 0, cutEnd = false, seen, done }) {
|
|
5951
|
+
const inLink = linkReader(text);
|
|
5952
|
+
const { length } = text;
|
|
5953
|
+
let i = 0;
|
|
5954
|
+
while (i < length) {
|
|
5955
|
+
if (!isHostCode2(text.codePointAt(i))) {
|
|
5956
|
+
i++;
|
|
5957
|
+
continue;
|
|
5958
|
+
}
|
|
5959
|
+
const start = i;
|
|
5960
|
+
while (i < length && isHostCode2(text.codePointAt(i))) {
|
|
5961
|
+
i++;
|
|
5962
|
+
}
|
|
5963
|
+
let end = i;
|
|
5964
|
+
if (end - start > MAX_HOST || start < from || cutEnd && end === length) {
|
|
5965
|
+
continue;
|
|
5966
|
+
}
|
|
5967
|
+
while (end > start && text[end - 1] === ".") {
|
|
5968
|
+
end--;
|
|
5969
|
+
}
|
|
5970
|
+
const before = start > 0 ? text[start - 1] : "";
|
|
5971
|
+
const after = end < length ? text[end] : "";
|
|
5972
|
+
if (after === "/" || after === "@" || before === "@") {
|
|
5973
|
+
continue;
|
|
5974
|
+
}
|
|
5975
|
+
if (before && (IN_WORD2.test(before) || before === "/" || before === "\\" || before === "&" || before === "#")) {
|
|
5976
|
+
continue;
|
|
5977
|
+
}
|
|
5978
|
+
if (after && after !== "." && IN_WORD2.test(after)) {
|
|
5979
|
+
continue;
|
|
5980
|
+
}
|
|
5981
|
+
const name = text.slice(start, end);
|
|
5982
|
+
if (!name.includes(".") || inLink(start)) {
|
|
5983
|
+
continue;
|
|
5984
|
+
}
|
|
5985
|
+
const lower = name.toLowerCase();
|
|
5986
|
+
if (seen.has(lower)) {
|
|
5987
|
+
continue;
|
|
5988
|
+
}
|
|
5989
|
+
if (seen.size < MAX_SEEN) {
|
|
5990
|
+
seen.add(lower);
|
|
5991
|
+
}
|
|
5992
|
+
if (done()) {
|
|
5993
|
+
return;
|
|
5994
|
+
}
|
|
5995
|
+
const host = bareName(name);
|
|
5996
|
+
if (host && isRealName(host)) {
|
|
5997
|
+
add(host);
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
function* chunksOf(html) {
|
|
6002
|
+
let start = 0;
|
|
6003
|
+
let cutStart = false;
|
|
6004
|
+
while (start < html.length) {
|
|
6005
|
+
const end = Math.min(html.length, start + DECODE_CHUNK);
|
|
6006
|
+
if (end < html.length) {
|
|
6007
|
+
let cut = end;
|
|
6008
|
+
while (cut > end - 65536 && cut > start) {
|
|
6009
|
+
if (html[cut] === "<" || isSpace(html.codePointAt(cut))) {
|
|
6010
|
+
break;
|
|
6011
|
+
}
|
|
6012
|
+
cut--;
|
|
6013
|
+
}
|
|
6014
|
+
if (cut > start && cut > end - 65536) {
|
|
6015
|
+
yield { text: html.slice(start, cut), cutStart, cutEnd: false };
|
|
6016
|
+
start = cut;
|
|
6017
|
+
cutStart = false;
|
|
6018
|
+
continue;
|
|
6019
|
+
}
|
|
6020
|
+
yield { text: html.slice(start, end), cutStart, cutEnd: true };
|
|
6021
|
+
start = end - CHUNK_OVERLAP;
|
|
6022
|
+
cutStart = true;
|
|
6023
|
+
continue;
|
|
6024
|
+
}
|
|
6025
|
+
yield { text: html.slice(start, end), cutStart, cutEnd: false };
|
|
6026
|
+
start = end;
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
function withoutNul(text) {
|
|
6030
|
+
return text.includes("\0") ? `${text}
|
|
6031
|
+
${text.replaceAll("\0", "")}` : text;
|
|
6032
|
+
}
|
|
6033
|
+
function hexValue(code) {
|
|
6034
|
+
if (code >= 48 && code <= 57) {
|
|
6035
|
+
return code - 48;
|
|
6036
|
+
}
|
|
6037
|
+
if (code >= 65 && code <= 70) {
|
|
6038
|
+
return code - 55;
|
|
6039
|
+
}
|
|
6040
|
+
if (code >= 97 && code <= 102) {
|
|
6041
|
+
return code - 87;
|
|
6042
|
+
}
|
|
6043
|
+
return -1;
|
|
6044
|
+
}
|
|
6045
|
+
function percentDecoded(text) {
|
|
6046
|
+
const input = Buffer7.from(text);
|
|
6047
|
+
const output = Buffer7.allocUnsafe(input.length);
|
|
6048
|
+
let length = 0;
|
|
6049
|
+
for (let i = 0; i < input.length; i++) {
|
|
6050
|
+
const high = input[i] === 37 ? hexValue(input[i + 1]) : -1;
|
|
6051
|
+
const low = high === -1 ? -1 : hexValue(input[i + 2]);
|
|
6052
|
+
if (low === -1) {
|
|
6053
|
+
output[length++] = input[i];
|
|
6054
|
+
continue;
|
|
6055
|
+
}
|
|
6056
|
+
output[length++] = high * 16 + low;
|
|
6057
|
+
i += 2;
|
|
6058
|
+
}
|
|
6059
|
+
return output.subarray(0, length);
|
|
6060
|
+
}
|
|
6061
|
+
var UTF16LE = /* @__PURE__ */ new Set(["csunicode", "iso-10646-ucs-2", "ucs-2", "unicode", "unicodefeff", "utf-16", "utf-16le"]);
|
|
6062
|
+
var UTF16BE = /* @__PURE__ */ new Set(["unicodefffe", "utf-16be"]);
|
|
6063
|
+
function swapped(bytes) {
|
|
6064
|
+
return Buffer7.from(bytes.subarray(0, bytes.length - bytes.length % 2)).swap16().toString("utf16le");
|
|
6065
|
+
}
|
|
6066
|
+
function decodeText(content, charset = "") {
|
|
6067
|
+
if (content[0] === 255 && content[1] === 254) {
|
|
6068
|
+
return content.subarray(2).toString("utf16le");
|
|
6069
|
+
}
|
|
6070
|
+
if (content[0] === 254 && content[1] === 255) {
|
|
6071
|
+
return swapped(content.subarray(2));
|
|
6072
|
+
}
|
|
6073
|
+
if (UTF16LE.has(charset)) {
|
|
6074
|
+
return content.toString("utf16le");
|
|
6075
|
+
}
|
|
6076
|
+
return UTF16BE.has(charset) ? swapped(content) : content.toString("utf8");
|
|
6077
|
+
}
|
|
6078
|
+
var DATA_DOCUMENT = /^\s*data:\s*(?:text\/html|application\/xhtml\+xml|image\/svg\+xml|text\/xml|application\/xml)\b([^,]*),/i;
|
|
6079
|
+
function dataDocument(value) {
|
|
6080
|
+
const match = DATA_DOCUMENT.exec(value.slice(0, 1024));
|
|
6081
|
+
if (!match) {
|
|
6082
|
+
return null;
|
|
6083
|
+
}
|
|
6084
|
+
const bytes = percentDecoded(value.slice(match[0].length));
|
|
6085
|
+
const content = /;\s*base64\s*$/i.test(match[1]) ? Buffer7.from(bytes.toString("latin1"), "base64") : bytes;
|
|
6086
|
+
const charset = /;\s*charset\s*=\s*"?([^;"\s]+)/i.exec(match[1]);
|
|
6087
|
+
return decodeText(content, charset ? charset[1].toLowerCase() : "");
|
|
6088
|
+
}
|
|
6089
|
+
var LINE_BREAK = /\r\n?|\n/;
|
|
6090
|
+
var FOLD = /(?:\r\n?|\n)[ \t]/g;
|
|
6091
|
+
var QUOTED_PRINTABLE = /;\s*(?:encoding\s*=\s*)?"?quoted-printable"?\s*(?:;|$)/i;
|
|
6092
|
+
var MEDIA_PROPERTIES = /* @__PURE__ */ new Set(["photo", "logo", "sound", "key", "attach"]);
|
|
6093
|
+
var HTML_PROPERTIES = /^(?:x-alt-desc|styled-description|description|comment)[;:]/i;
|
|
6094
|
+
function readEscapes(text, lenient = false) {
|
|
6095
|
+
let index = text.indexOf("\\");
|
|
6096
|
+
if (index === -1) {
|
|
6097
|
+
return text;
|
|
6098
|
+
}
|
|
6099
|
+
let out = "";
|
|
6100
|
+
let parts = [];
|
|
6101
|
+
let start = 0;
|
|
6102
|
+
while (index !== -1 && index + 1 < text.length) {
|
|
6103
|
+
const next = text[index + 1];
|
|
6104
|
+
if (lenient || "nN,;\\".includes(next)) {
|
|
6105
|
+
parts.push(text.slice(start, index), next === "n" || next === "N" ? "\n" : next);
|
|
6106
|
+
start = index + 2;
|
|
6107
|
+
index = text.indexOf("\\", start);
|
|
6108
|
+
if (parts.length >= 65536) {
|
|
6109
|
+
out += parts.join("");
|
|
6110
|
+
parts = [];
|
|
6111
|
+
}
|
|
6112
|
+
} else {
|
|
6113
|
+
index = text.indexOf("\\", index + 1);
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
6116
|
+
parts.push(text.slice(start));
|
|
6117
|
+
return out + parts.join("");
|
|
6118
|
+
}
|
|
6119
|
+
function valueColon(line) {
|
|
6120
|
+
let colon = line.indexOf(":");
|
|
6121
|
+
let from = 0;
|
|
6122
|
+
for (; ; ) {
|
|
6123
|
+
const quote = line.indexOf('"', from);
|
|
6124
|
+
if (quote === -1 || colon === -1 || colon < quote) {
|
|
6125
|
+
return colon;
|
|
6126
|
+
}
|
|
6127
|
+
const end = line.indexOf('"', quote + 1);
|
|
6128
|
+
if (end === -1) {
|
|
6129
|
+
return -1;
|
|
6130
|
+
}
|
|
6131
|
+
from = end + 1;
|
|
6132
|
+
if (colon < from) {
|
|
6133
|
+
colon = line.indexOf(":", from);
|
|
6134
|
+
}
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
function trimSpaceEnd(text) {
|
|
6138
|
+
let end = text.length;
|
|
6139
|
+
while (end > 0 && (text[end - 1] === " " || text[end - 1] === " ")) {
|
|
6140
|
+
end--;
|
|
6141
|
+
}
|
|
6142
|
+
return end === text.length ? text : text.slice(0, end);
|
|
6143
|
+
}
|
|
6144
|
+
function decodeQuotedPrintable(value, charset) {
|
|
6145
|
+
let decoder;
|
|
6146
|
+
try {
|
|
6147
|
+
decoder = new TextDecoder(charset || "utf8");
|
|
6148
|
+
} catch {
|
|
6149
|
+
decoder = new TextDecoder("utf8");
|
|
6150
|
+
}
|
|
6151
|
+
if (!/[\u0080-\u{10FFFF}]/u.test(value)) {
|
|
6152
|
+
const bytes = Buffer7.from(value, "latin1");
|
|
6153
|
+
let length = 0;
|
|
6154
|
+
for (let index = 0; index < bytes.length; index++) {
|
|
6155
|
+
const hex = bytes[index] === 61 ? value.slice(index + 1, index + 3) : "";
|
|
6156
|
+
if (/^[\da-f]{2}$/i.test(hex)) {
|
|
6157
|
+
bytes[length++] = Number.parseInt(hex, 16);
|
|
6158
|
+
index += 2;
|
|
6159
|
+
} else {
|
|
6160
|
+
bytes[length++] = bytes[index];
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
return decoder.decode(bytes.subarray(0, length));
|
|
6164
|
+
}
|
|
6165
|
+
return value.replaceAll(/(?:=[\da-f]{2})+/gi, (run) => decoder.decode(Buffer7.from(run.replaceAll("=", ""), "hex")));
|
|
6166
|
+
}
|
|
6167
|
+
function quotedPrintableValues(text) {
|
|
6168
|
+
if (!/quoted-printable/i.test(text)) {
|
|
6169
|
+
return text;
|
|
6170
|
+
}
|
|
6171
|
+
const lines2 = text.split(LINE_BREAK);
|
|
6172
|
+
const out = [];
|
|
6173
|
+
for (let i = 0; i < lines2.length; i++) {
|
|
6174
|
+
const line = lines2[i];
|
|
6175
|
+
const colon = valueColon(line);
|
|
6176
|
+
const parameters = colon === -1 ? "" : line.slice(0, colon);
|
|
6177
|
+
if (colon === -1 || !QUOTED_PRINTABLE.test(parameters)) {
|
|
6178
|
+
out.push(line);
|
|
6179
|
+
continue;
|
|
6180
|
+
}
|
|
6181
|
+
const charset = /;\s*charset\s*=\s*"?([\w.:-]+)/i.exec(parameters)?.[1];
|
|
6182
|
+
const parts = [trimSpaceEnd(line.slice(colon + 1))];
|
|
6183
|
+
while (parts.at(-1).endsWith("=") && i + 1 < lines2.length) {
|
|
6184
|
+
parts[parts.length - 1] = parts.at(-1).slice(0, -1);
|
|
6185
|
+
parts.push(trimSpaceEnd(lines2[++i]));
|
|
6186
|
+
}
|
|
6187
|
+
out.push(line.slice(0, colon + 1) + decodeQuotedPrintable(parts.join(""), charset));
|
|
6188
|
+
}
|
|
6189
|
+
return out.join("\n");
|
|
6190
|
+
}
|
|
6191
|
+
function hasQuotedPrintable(text) {
|
|
6192
|
+
const unfolded = text.replaceAll(FOLD, "");
|
|
6193
|
+
if (!/quoted-printable/i.test(unfolded)) {
|
|
6194
|
+
return false;
|
|
6195
|
+
}
|
|
6196
|
+
return unfolded.split(LINE_BREAK).some((line) => {
|
|
6197
|
+
const colon = valueColon(line);
|
|
6198
|
+
return colon !== -1 && QUOTED_PRINTABLE.test(line.slice(0, colon));
|
|
6199
|
+
});
|
|
6200
|
+
}
|
|
6201
|
+
function shownText(text, full = true) {
|
|
6202
|
+
const unfolded = text.replaceAll(FOLD, "");
|
|
6203
|
+
const shown = /* @__PURE__ */ new Set([text, readEscapes(unfolded)]);
|
|
6204
|
+
let decoded = unfolded;
|
|
6205
|
+
if (full) {
|
|
6206
|
+
decoded = quotedPrintableValues(unfolded);
|
|
6207
|
+
if (decoded !== unfolded) {
|
|
6208
|
+
shown.add(readEscapes(decoded));
|
|
6209
|
+
if (unfolded !== text) {
|
|
6210
|
+
shown.add(quotedPrintableValues(text));
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
if (/\\[^nN,;\\]/.test(decoded)) {
|
|
6215
|
+
shown.add(readEscapes(decoded, true));
|
|
6216
|
+
}
|
|
6217
|
+
return [...shown].reverse().join("\n");
|
|
6218
|
+
}
|
|
6219
|
+
function htmlDescriptions(text) {
|
|
6220
|
+
if (!/[<&]|altrep/i.test(text)) {
|
|
6221
|
+
return "";
|
|
6222
|
+
}
|
|
6223
|
+
const html = [];
|
|
6224
|
+
for (const line of text.replaceAll(FOLD, "").split(LINE_BREAK)) {
|
|
6225
|
+
const colon = valueColon(line);
|
|
6226
|
+
if (colon === -1) {
|
|
6227
|
+
continue;
|
|
6228
|
+
}
|
|
6229
|
+
const altrep = /;\s*altrep\s*=\s*"([^"]*)"/i.exec(line.slice(0, colon))?.[1];
|
|
6230
|
+
if (altrep) {
|
|
6231
|
+
html.push(`<iframe src="${altrep.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<")}"></iframe>`);
|
|
6232
|
+
}
|
|
6233
|
+
if (!HTML_PROPERTIES.test(line)) {
|
|
6234
|
+
continue;
|
|
6235
|
+
}
|
|
6236
|
+
const value = readEscapes(line.slice(colon + 1));
|
|
6237
|
+
if (/[<&]/.test(value)) {
|
|
6238
|
+
html.push(value);
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
return html.join("\n");
|
|
6242
|
+
}
|
|
6243
|
+
var BINARY = /;\s*(?:(?:encoding\s*=\s*)?"?(?:b|base64)"?|value\s*=\s*"?binary"?)\s*(?:;|$)/i;
|
|
6244
|
+
function withoutBinaryValues(text) {
|
|
6245
|
+
if (!/base64|binary|encoding\s*=\s*"?b|;\s*b\s*[;:]/i.test(text)) {
|
|
6246
|
+
return text;
|
|
6247
|
+
}
|
|
6248
|
+
const lines2 = text.split(LINE_BREAK);
|
|
6249
|
+
const out = [];
|
|
6250
|
+
for (let i = 0; i < lines2.length; i++) {
|
|
6251
|
+
const line = lines2[i];
|
|
6252
|
+
const colon = valueColon(line);
|
|
6253
|
+
if (colon === -1 || !BINARY.test(line.slice(0, colon))) {
|
|
6254
|
+
out.push(line);
|
|
6255
|
+
continue;
|
|
6256
|
+
}
|
|
6257
|
+
const value = [line.slice(colon + 1)];
|
|
6258
|
+
let next = i + 1;
|
|
6259
|
+
while (next < lines2.length && (lines2[next].startsWith(" ") || lines2[next].startsWith(" "))) {
|
|
6260
|
+
value.push(lines2[next++]);
|
|
6261
|
+
}
|
|
6262
|
+
if (!value.every((part) => /^[\w+/=\s]*$/.test(part))) {
|
|
6263
|
+
for (let index = i; index < next; index++) {
|
|
6264
|
+
out.push(lines2[index]);
|
|
6265
|
+
}
|
|
6266
|
+
i = next - 1;
|
|
6267
|
+
continue;
|
|
6268
|
+
}
|
|
6269
|
+
while (next < lines2.length && lines2[next] !== "" && /^[\w+/=]+$/.test(lines2[next])) {
|
|
6270
|
+
value.push(lines2[next++]);
|
|
6271
|
+
}
|
|
6272
|
+
if (next < lines2.length && lines2[next] === "") {
|
|
6273
|
+
next++;
|
|
6274
|
+
}
|
|
6275
|
+
i = next - 1;
|
|
6276
|
+
const name = line.slice(0, colon).split(";")[0].split(".").pop().trim().toLowerCase();
|
|
6277
|
+
out.push(MEDIA_PROPERTIES.has(name) ? line.slice(0, colon + 1) : line.slice(0, colon + 1) + Buffer7.from(value.join("").replaceAll(/\s/g, ""), "base64").toString("utf8"));
|
|
6278
|
+
}
|
|
6279
|
+
return out.join("\n");
|
|
6280
|
+
}
|
|
6281
|
+
var HTML_TYPES = /* @__PURE__ */ new Set(["text/html", "application/xhtml+xml", "image/svg+xml", "text/xml", "application/xml"]);
|
|
6282
|
+
var HTML_EXTENSIONS = /* @__PURE__ */ new Set(["html", "htm", "shtml", "xhtml", "xht", "svg", "xml"]);
|
|
6283
|
+
var CARD_TYPES = /* @__PURE__ */ new Set(["text/calendar", "text/x-vcalendar", "application/ics", "text/vcard", "text/x-vcard", "text/directory"]);
|
|
6284
|
+
var CARD_EXTENSIONS = /* @__PURE__ */ new Set(["ics", "ical", "ifb", "vcs", "vcf", "vcard"]);
|
|
6285
|
+
var MESSAGE_TYPES = /* @__PURE__ */ new Set(["message/rfc822", "message/global"]);
|
|
6286
|
+
function extensionOf2(filename) {
|
|
6287
|
+
let end = filename.length;
|
|
6288
|
+
while (end > 0 && (filename[end - 1] === "." || filename[end - 1] === " ")) {
|
|
6289
|
+
end--;
|
|
6290
|
+
}
|
|
6291
|
+
const name = filename.slice(0, end).trim().toLowerCase();
|
|
6292
|
+
const index = name.lastIndexOf(".");
|
|
6293
|
+
return index !== -1 && index < name.length - 1 ? name.slice(index + 1) : null;
|
|
6294
|
+
}
|
|
6295
|
+
function extensionsOf(attachment) {
|
|
6296
|
+
const names = [];
|
|
6297
|
+
if (typeof attachment.filename === "string") {
|
|
6298
|
+
names.push(attachment.filename);
|
|
6299
|
+
}
|
|
6300
|
+
const { headers } = attachment;
|
|
6301
|
+
if (headers && typeof headers.get === "function") {
|
|
6302
|
+
for (const [field, parameter] of [["content-type", "name"], ["content-disposition", "filename"]]) {
|
|
6303
|
+
const value = headers.get(field)?.params?.[parameter];
|
|
6304
|
+
if (typeof value === "string" && value !== "") {
|
|
6305
|
+
names.push(value);
|
|
6306
|
+
}
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6309
|
+
return new Set(names.flatMap((name) => [extensionOf2(name), extensionOf(name)]).filter(Boolean));
|
|
6310
|
+
}
|
|
6311
|
+
function charsetOf(attachment) {
|
|
6312
|
+
const { headers } = attachment;
|
|
6313
|
+
const charset = headers && typeof headers.get === "function" ? headers.get("content-type")?.params?.charset : null;
|
|
6314
|
+
return typeof charset === "string" ? charset.toLowerCase() : "";
|
|
6315
|
+
}
|
|
6316
|
+
function documentsOf(attachments, until) {
|
|
6317
|
+
const documents = [];
|
|
6318
|
+
let bytes = 0;
|
|
6319
|
+
let opened = 0;
|
|
6320
|
+
for (const attachment of attachments) {
|
|
6321
|
+
const { content } = attachment ?? {};
|
|
6322
|
+
if (!Buffer7.isBuffer(content) || content.length === 0) {
|
|
6323
|
+
continue;
|
|
6324
|
+
}
|
|
6325
|
+
const type = typeof attachment.contentType === "string" ? attachment.contentType.toLowerCase() : "";
|
|
6326
|
+
const extensions = extensionsOf(attachment);
|
|
6327
|
+
const has = (set) => [...extensions].some((name) => set.has(name));
|
|
6328
|
+
if (MESSAGE_TYPES.has(type) || extensions.has("eml") || extensions.has("u8msg")) {
|
|
6329
|
+
continue;
|
|
6330
|
+
}
|
|
6331
|
+
const isHtml = HTML_TYPES.has(type) || has(HTML_EXTENSIONS);
|
|
6332
|
+
const isCard = !isHtml && (CARD_TYPES.has(type) || has(CARD_EXTENSIONS));
|
|
6333
|
+
const isText = isCard || !isHtml && type === "text/plain";
|
|
6334
|
+
if (!isHtml && !isText) {
|
|
6335
|
+
continue;
|
|
6336
|
+
}
|
|
6337
|
+
if (!isText && ++opened > MAX_ATTACHED || bytes + content.length > MAX_ATTACHED_BYTES) {
|
|
6338
|
+
documents.tooComplex = true;
|
|
6339
|
+
return documents;
|
|
6340
|
+
}
|
|
6341
|
+
if (Date.now() > until) {
|
|
6342
|
+
documents.incomplete = true;
|
|
6343
|
+
return documents;
|
|
6344
|
+
}
|
|
6345
|
+
bytes += content.length;
|
|
6346
|
+
const text = decodeText(content, charsetOf(attachment));
|
|
6347
|
+
if (isHtml) {
|
|
6348
|
+
documents.push({ html: text });
|
|
6349
|
+
continue;
|
|
6350
|
+
}
|
|
6351
|
+
if (!isCard) {
|
|
6352
|
+
documents.push({ text });
|
|
6353
|
+
continue;
|
|
6354
|
+
}
|
|
6355
|
+
const readable = withoutBinaryValues(text);
|
|
6356
|
+
const full = readable.length <= MAX_SHOWN_BYTES;
|
|
6357
|
+
if (!full && hasQuotedPrintable(readable)) {
|
|
6358
|
+
documents.tooComplex = true;
|
|
6359
|
+
continue;
|
|
6360
|
+
}
|
|
6361
|
+
documents.push({ text: shownText(readable, full) });
|
|
6362
|
+
const html = htmlDescriptions(readable);
|
|
6363
|
+
if (html !== "") {
|
|
6364
|
+
documents.push({ html });
|
|
6365
|
+
}
|
|
6366
|
+
}
|
|
6367
|
+
return documents;
|
|
6368
|
+
}
|
|
6369
|
+
function carriedLinkHosts(mail, {
|
|
6370
|
+
mails = [],
|
|
6371
|
+
attachments = [],
|
|
6372
|
+
maxHosts = 250,
|
|
6373
|
+
hostsInText = false
|
|
6374
|
+
} = {}) {
|
|
6375
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
6376
|
+
const loose = /* @__PURE__ */ new Set();
|
|
6377
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6378
|
+
const seenBare = /* @__PURE__ */ new Set();
|
|
6379
|
+
const seenLoose = /* @__PURE__ */ new Set();
|
|
6380
|
+
let more = false;
|
|
6381
|
+
let tooComplex = false;
|
|
6382
|
+
const done = () => more;
|
|
6383
|
+
const looseDone = () => more || loose.size > maxHosts;
|
|
6384
|
+
const addLoose = (host) => {
|
|
6385
|
+
if (!looseDone()) {
|
|
6386
|
+
loose.add(host);
|
|
6387
|
+
}
|
|
6388
|
+
};
|
|
6389
|
+
const until = Date.now() + MAX_READ_TIME;
|
|
6390
|
+
let incomplete = false;
|
|
6391
|
+
const late = () => {
|
|
6392
|
+
if (!incomplete && Date.now() > until) {
|
|
6393
|
+
incomplete = true;
|
|
6394
|
+
}
|
|
6395
|
+
return incomplete;
|
|
6396
|
+
};
|
|
6397
|
+
const carried = documentsOf(attachments, until);
|
|
6398
|
+
tooComplex = Boolean(carried.tooComplex);
|
|
6399
|
+
incomplete = Boolean(carried.incomplete);
|
|
6400
|
+
const queue = [mail, ...mails, ...carried].map((document) => ({ document, depth: 0 }));
|
|
6401
|
+
let depth = 0;
|
|
6402
|
+
let embedded = 0;
|
|
6403
|
+
let embeddedLength = 0;
|
|
6404
|
+
const embed = (html) => {
|
|
6405
|
+
if (depth >= MAX_EMBED_DEPTH || embedded >= MAX_EMBEDDED || embeddedLength + html.length > MAX_EMBEDDED_LENGTH) {
|
|
6406
|
+
tooComplex = true;
|
|
6407
|
+
return;
|
|
6408
|
+
}
|
|
6409
|
+
embedded++;
|
|
6410
|
+
embeddedLength += html.length;
|
|
6411
|
+
queue.push({ document: { html }, depth: depth + 1 });
|
|
6412
|
+
};
|
|
6413
|
+
const add = (value) => {
|
|
6414
|
+
if (more || typeof value !== "string" || value === "" || seen.has(value)) {
|
|
6415
|
+
return;
|
|
6416
|
+
}
|
|
6417
|
+
if (seen.size < MAX_SEEN) {
|
|
6418
|
+
seen.add(value);
|
|
6419
|
+
}
|
|
6420
|
+
if (/^\s*data:/i.test(value)) {
|
|
6421
|
+
const html = dataDocument(value);
|
|
6422
|
+
if (html !== null) {
|
|
6423
|
+
embed(html);
|
|
6424
|
+
}
|
|
6425
|
+
return;
|
|
6426
|
+
}
|
|
6427
|
+
const found = hostsOf(value);
|
|
6428
|
+
if (found.unresolved) {
|
|
6429
|
+
tooComplex = true;
|
|
6430
|
+
}
|
|
6431
|
+
for (const host of found) {
|
|
6432
|
+
if (hosts.has(host)) {
|
|
6433
|
+
continue;
|
|
6434
|
+
}
|
|
6435
|
+
if (hosts.size >= maxHosts) {
|
|
6436
|
+
more = true;
|
|
6437
|
+
return;
|
|
6438
|
+
}
|
|
6439
|
+
hosts.add(host);
|
|
6440
|
+
}
|
|
6441
|
+
};
|
|
6442
|
+
const readText = (source, { cutStart = false, cutEnd = false } = {}) => {
|
|
6443
|
+
for (const match of source.matchAll(URL_START)) {
|
|
6444
|
+
if (more) {
|
|
6445
|
+
break;
|
|
6446
|
+
}
|
|
6447
|
+
if (cutStart && match.index === 0) {
|
|
6448
|
+
continue;
|
|
6449
|
+
}
|
|
6450
|
+
if (cutEnd && match.index + match[0].length === source.length) {
|
|
6451
|
+
const value = match[0];
|
|
6452
|
+
const at = /^www\./i.test(value) ? 0 : value.indexOf("//") + 2;
|
|
6453
|
+
if (/[/?#\\]/.test(value.slice(at))) {
|
|
6454
|
+
add(value);
|
|
6455
|
+
} else if (source.length - match.index > CHUNK_OVERLAP) {
|
|
6456
|
+
tooComplex = true;
|
|
6457
|
+
}
|
|
6458
|
+
continue;
|
|
6459
|
+
}
|
|
6460
|
+
add(match[0]);
|
|
6461
|
+
}
|
|
6462
|
+
const from = cutStart ? 1 : 0;
|
|
6463
|
+
bareHosts(source, add, {
|
|
6464
|
+
done,
|
|
6465
|
+
seen: seenBare,
|
|
6466
|
+
from,
|
|
6467
|
+
cutEnd
|
|
6468
|
+
});
|
|
6469
|
+
if (hostsInText && !looseDone()) {
|
|
6470
|
+
looseHosts(source, addLoose, {
|
|
6471
|
+
from,
|
|
6472
|
+
cutEnd,
|
|
6473
|
+
seen: seenLoose,
|
|
6474
|
+
done: looseDone
|
|
6475
|
+
});
|
|
6476
|
+
}
|
|
6477
|
+
};
|
|
6478
|
+
for (const element of queue) {
|
|
6479
|
+
if (more || late()) {
|
|
6480
|
+
break;
|
|
6481
|
+
}
|
|
6482
|
+
({ depth } = element);
|
|
6483
|
+
const { document } = element;
|
|
6484
|
+
const html = withoutNul(typeof document?.html === "string" ? document.html : "");
|
|
6485
|
+
const text = withoutNul(typeof document?.text === "string" ? document.text : "");
|
|
6486
|
+
for (const [name, value] of attributesOf(html)) {
|
|
6487
|
+
if (more) {
|
|
6488
|
+
break;
|
|
6489
|
+
}
|
|
6490
|
+
if (LINK_ATTRIBUTES.has(name)) {
|
|
6491
|
+
linksOf(name, value, add, embed);
|
|
6492
|
+
}
|
|
6493
|
+
}
|
|
6494
|
+
lenientLinks(html, add, done, embed);
|
|
6495
|
+
for (const pattern of [CSS_URL, CSS_IMPORT]) {
|
|
6496
|
+
for (const [, link] of html.matchAll(pattern)) {
|
|
6497
|
+
if (more) {
|
|
6498
|
+
break;
|
|
6499
|
+
}
|
|
6500
|
+
add(decodeEntities(link, { attribute: true }));
|
|
6501
|
+
}
|
|
6502
|
+
}
|
|
6503
|
+
if (!more) {
|
|
6504
|
+
readText(text);
|
|
6505
|
+
}
|
|
6506
|
+
for (const chunk2 of chunksOf(html)) {
|
|
6507
|
+
if (more || late()) {
|
|
6508
|
+
break;
|
|
6509
|
+
}
|
|
6510
|
+
readText(decodeEntities(chunk2.text), chunk2);
|
|
6511
|
+
}
|
|
6512
|
+
}
|
|
6513
|
+
if (!more && !incomplete) {
|
|
6514
|
+
for (const name of loose) {
|
|
6515
|
+
if (hosts.size >= maxHosts) {
|
|
6516
|
+
break;
|
|
6517
|
+
}
|
|
6518
|
+
const [host] = hostsOf(`http://${name}/`);
|
|
6519
|
+
if (host) {
|
|
6520
|
+
hosts.add(host);
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
6523
|
+
}
|
|
6524
|
+
return {
|
|
6525
|
+
hosts: [...hosts],
|
|
6526
|
+
more,
|
|
6527
|
+
tooComplex,
|
|
6528
|
+
incomplete
|
|
6529
|
+
};
|
|
6530
|
+
}
|
|
6531
|
+
|
|
6532
|
+
// src/is-arbitrary.js
|
|
6533
|
+
import { parse as parseDomain4 } from "tldts";
|
|
5431
6534
|
var GTUBE = "XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X";
|
|
5432
6535
|
var BLOCKED_SUBJECT = /cheecck y0ur acc0untt|\brecorded\s+you\s+(?:masturbating|jerking|touching\s+yourself|watching\s+porn)\b|personal data has leaked|private information has been stolen/i;
|
|
5433
6536
|
var HACKED_SUBJECT = /\byou['’]ve been hacked\b|\baccount is hacked\b|\b(?:i|we)(?:\s+have|['’]ve)?\s+recorded\s+you\b|\brecorded\s+you\s+(?:doing|while|watching|through|on\s+(?:cam|camera|video|webcam))\b/i;
|
|
@@ -5618,13 +6721,13 @@ function joinsDisplay(brand, display, name) {
|
|
|
5618
6721
|
return false;
|
|
5619
6722
|
}
|
|
5620
6723
|
function isOfficial({ brand, official }, domain, display, shared = true) {
|
|
5621
|
-
const parsed =
|
|
6724
|
+
const parsed = parseDomain4(domain);
|
|
5622
6725
|
const name = parsed.domainWithoutSuffix ?? "";
|
|
5623
6726
|
const compact = brand.replaceAll(" ", "");
|
|
5624
6727
|
if (parsed.publicSuffix === compact || compact.length >= 5 && joinsDisplay(brand, display, name) && !JOINED_WORDS.some((word) => name.slice(compact.length).includes(word))) {
|
|
5625
6728
|
return true;
|
|
5626
6729
|
}
|
|
5627
|
-
return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared ||
|
|
6730
|
+
return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || parseDomain4(entry).domain !== null) && (domain === entry || domain.endsWith(`.${entry}`)) : name === entry);
|
|
5628
6731
|
}
|
|
5629
6732
|
function headerString(mail, name) {
|
|
5630
6733
|
const value = mail.headers?.get?.(name);
|
|
@@ -5726,7 +6829,7 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
|
|
|
5726
6829
|
}
|
|
5727
6830
|
} else if (claimed && isWholeName(name, claimed)) {
|
|
5728
6831
|
const domain = claimed[1];
|
|
5729
|
-
const brand = MAILBOXES.has(
|
|
6832
|
+
const brand = MAILBOXES.has(parseDomain4(domain).domainWithoutSuffix) ? null : DISPLAY_BRANDS.find((entry) => isOfficial(entry, domain, "", false) && !isOfficial(entry, session.originalFromAddressDomain, ""));
|
|
5730
6833
|
if (brand) {
|
|
5731
6834
|
hit("FROM_NAME_BRAND", 2, `Display name is an address of "${brand.brand}" but the message is from ${fromRoot}`, "PHISHING");
|
|
5732
6835
|
}
|
|
@@ -5761,7 +6864,7 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
|
|
|
5761
6864
|
}
|
|
5762
6865
|
|
|
5763
6866
|
// src/llm.js
|
|
5764
|
-
import { Buffer as
|
|
6867
|
+
import { Buffer as Buffer8 } from "node:buffer";
|
|
5765
6868
|
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
5766
6869
|
import os from "node:os";
|
|
5767
6870
|
import process from "node:process";
|
|
@@ -6122,7 +7225,7 @@ function authHeaders(config) {
|
|
|
6122
7225
|
case "basic": {
|
|
6123
7226
|
const user = config.username ?? "";
|
|
6124
7227
|
const pass = config.password ?? config.apiKey ?? "";
|
|
6125
|
-
headers.authorization = `Basic ${
|
|
7228
|
+
headers.authorization = `Basic ${Buffer8.from(`${user}:${pass}`).toString("base64")}`;
|
|
6126
7229
|
break;
|
|
6127
7230
|
}
|
|
6128
7231
|
case "x-api-key": {
|
|
@@ -7068,7 +8171,7 @@ function scoreResults(results, options) {
|
|
|
7068
8171
|
var package_default = {
|
|
7069
8172
|
name: "spamscanner",
|
|
7070
8173
|
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.",
|
|
7071
|
-
version: "7.0.
|
|
8174
|
+
version: "7.0.11",
|
|
7072
8175
|
author: "Forward Email (https://forwardemail.net)",
|
|
7073
8176
|
bin: {
|
|
7074
8177
|
spamscanner: "./dist/esm/cli.js"
|
|
@@ -7215,7 +8318,7 @@ var package_default = {
|
|
|
7215
8318
|
var VERSION = package_default.version;
|
|
7216
8319
|
|
|
7217
8320
|
// src/headers.js
|
|
7218
|
-
import { Buffer as
|
|
8321
|
+
import { Buffer as Buffer9 } from "node:buffer";
|
|
7219
8322
|
function foldHeader(name, value, newline = "\r\n") {
|
|
7220
8323
|
const pieces = String(value).split(/(?<=[ ,])/);
|
|
7221
8324
|
const lines2 = [];
|
|
@@ -7250,10 +8353,10 @@ function splitMessage(raw) {
|
|
|
7250
8353
|
const match = /^\r?\n|\r?\n\r?\n/.exec(text);
|
|
7251
8354
|
if (!match) {
|
|
7252
8355
|
const newline2 = text.includes("\n") && !text.includes("\r\n") ? "\n" : "\r\n";
|
|
7253
|
-
return { header: text.replace(/\r?\n$/, ""), body:
|
|
8356
|
+
return { header: text.replace(/\r?\n$/, ""), body: Buffer9.alloc(0), newline: newline2 };
|
|
7254
8357
|
}
|
|
7255
8358
|
const newline = match[0].startsWith("\r") ? "\r\n" : "\n";
|
|
7256
|
-
return { header: text.slice(0, match.index), body: raw.subarray(
|
|
8359
|
+
return { header: text.slice(0, match.index), body: raw.subarray(Buffer9.byteLength(text.slice(0, match.index + match[0].length), "latin1")), newline };
|
|
7257
8360
|
}
|
|
7258
8361
|
var ENCODED_BYTES = 39;
|
|
7259
8362
|
var PLAIN_WORD = 64;
|
|
@@ -7269,14 +8372,14 @@ function subjectTagText(tag, spaceAfter = false) {
|
|
|
7269
8372
|
const words2 = [];
|
|
7270
8373
|
let chunk2 = "";
|
|
7271
8374
|
for (const character of spaceAfter ? `${line} ` : line) {
|
|
7272
|
-
if (
|
|
8375
|
+
if (Buffer9.byteLength(chunk2 + character, "utf8") > ENCODED_BYTES) {
|
|
7273
8376
|
words2.push(chunk2);
|
|
7274
8377
|
chunk2 = "";
|
|
7275
8378
|
}
|
|
7276
8379
|
chunk2 += character;
|
|
7277
8380
|
}
|
|
7278
8381
|
words2.push(chunk2);
|
|
7279
|
-
return words2.map((word) => `=?UTF-8?B?${
|
|
8382
|
+
return words2.map((word) => `=?UTF-8?B?${Buffer9.from(word, "utf8").toString("base64")}?=`).join(" ");
|
|
7280
8383
|
}
|
|
7281
8384
|
function taggedSubject(tag, current, newline = "\r\n") {
|
|
7282
8385
|
const unfolded = current.replaceAll(/\r?\n/g, "");
|
|
@@ -7307,7 +8410,7 @@ function taggedSubject(tag, current, newline = "\r\n") {
|
|
|
7307
8410
|
return lines2.join(newline).slice("Subject: ".length);
|
|
7308
8411
|
}
|
|
7309
8412
|
function rewriteMessage(source, headers = [], options = {}) {
|
|
7310
|
-
const raw =
|
|
8413
|
+
const raw = Buffer9.isBuffer(source) ? source : Buffer9.from(String(source), "utf8");
|
|
7311
8414
|
const { header, body, newline } = splitMessage(raw);
|
|
7312
8415
|
const remove = options.remove ?? /^x-spam-/i;
|
|
7313
8416
|
const lines2 = header === "" ? [] : header.split(/\r?\n/);
|
|
@@ -7332,10 +8435,10 @@ function rewriteMessage(source, headers = [], options = {}) {
|
|
|
7332
8435
|
}
|
|
7333
8436
|
}
|
|
7334
8437
|
}
|
|
7335
|
-
const added = headers.map(([name, value]) => foldHeader(name,
|
|
8438
|
+
const added = headers.map(([name, value]) => foldHeader(name, Buffer9.from(String(value), "utf8").toString("latin1"), newline));
|
|
7336
8439
|
const mbox = kept.length > 0 && kept[0][0].startsWith("From ") ? kept.shift() : [];
|
|
7337
8440
|
const head = [...mbox, ...added, ...kept.map((field) => field.join(newline))].join(newline);
|
|
7338
|
-
return
|
|
8441
|
+
return Buffer9.concat([Buffer9.from(head === "" && header === "" ? newline : `${head}${newline}${newline}`, "latin1"), body]);
|
|
7339
8442
|
}
|
|
7340
8443
|
|
|
7341
8444
|
// src/train.js
|
|
@@ -7343,7 +8446,7 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
7343
8446
|
import path3 from "node:path";
|
|
7344
8447
|
|
|
7345
8448
|
// src/sources.js
|
|
7346
|
-
import { Buffer as
|
|
8449
|
+
import { Buffer as Buffer10 } from "node:buffer";
|
|
7347
8450
|
import { createReadStream } from "node:fs";
|
|
7348
8451
|
import fs from "node:fs/promises";
|
|
7349
8452
|
import path2 from "node:path";
|
|
@@ -7523,7 +8626,7 @@ async function* readJsonl(file, options = {}) {
|
|
|
7523
8626
|
}
|
|
7524
8627
|
async function* walk(directory) {
|
|
7525
8628
|
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
7526
|
-
entries.sort((a, b) =>
|
|
8629
|
+
entries.sort((a, b) => Buffer10.compare(Buffer10.from(a.name), Buffer10.from(b.name)));
|
|
7527
8630
|
for (const entry of entries) {
|
|
7528
8631
|
if (SKIP.has(entry.name) || entry.name.startsWith(".")) {
|
|
7529
8632
|
continue;
|
|
@@ -7548,7 +8651,7 @@ async function* readMessages(source) {
|
|
|
7548
8651
|
const handle = await fs.open(file);
|
|
7549
8652
|
let head;
|
|
7550
8653
|
try {
|
|
7551
|
-
const { buffer, bytesRead } = await handle.read(
|
|
8654
|
+
const { buffer, bytesRead } = await handle.read(Buffer10.alloc(64), 0, 64, 0);
|
|
7552
8655
|
head = buffer.subarray(0, bytesRead).toString("latin1");
|
|
7553
8656
|
} finally {
|
|
7554
8657
|
await handle.close();
|
|
@@ -7672,12 +8775,12 @@ async function evaluate(classifier, examples) {
|
|
|
7672
8775
|
}
|
|
7673
8776
|
|
|
7674
8777
|
// src/milter.js
|
|
7675
|
-
import { Buffer as
|
|
8778
|
+
import { Buffer as Buffer12 } from "node:buffer";
|
|
7676
8779
|
import { EventEmitter } from "node:events";
|
|
7677
8780
|
import net3 from "node:net";
|
|
7678
8781
|
|
|
7679
8782
|
// src/server.js
|
|
7680
|
-
import { Buffer as
|
|
8783
|
+
import { Buffer as Buffer11 } from "node:buffer";
|
|
7681
8784
|
import { timingSafeEqual } from "node:crypto";
|
|
7682
8785
|
import http2 from "node:http";
|
|
7683
8786
|
import net2 from "node:net";
|
|
@@ -7717,8 +8820,8 @@ function sessionFromQuery(query) {
|
|
|
7717
8820
|
return session;
|
|
7718
8821
|
}
|
|
7719
8822
|
function sameToken(given, expected) {
|
|
7720
|
-
const a =
|
|
7721
|
-
const b =
|
|
8823
|
+
const a = Buffer11.from(String(given));
|
|
8824
|
+
const b = Buffer11.from(String(expected));
|
|
7722
8825
|
return a.length === b.length && timingSafeEqual(a, b);
|
|
7723
8826
|
}
|
|
7724
8827
|
function readBody(request, limit) {
|
|
@@ -7738,7 +8841,7 @@ function readBody(request, limit) {
|
|
|
7738
8841
|
reject(error);
|
|
7739
8842
|
return;
|
|
7740
8843
|
}
|
|
7741
|
-
resolve(
|
|
8844
|
+
resolve(Buffer11.concat(chunks));
|
|
7742
8845
|
});
|
|
7743
8846
|
request.on("error", reject);
|
|
7744
8847
|
});
|
|
@@ -7753,7 +8856,7 @@ function createHttpServer(scanner, options = {}) {
|
|
|
7753
8856
|
let active = 0;
|
|
7754
8857
|
const server = http2.createServer(async (request, response) => {
|
|
7755
8858
|
const send = (status, body, headers = {}) => {
|
|
7756
|
-
const isBuffer =
|
|
8859
|
+
const isBuffer = Buffer11.isBuffer(body);
|
|
7757
8860
|
response.writeHead(status, { "content-type": isBuffer ? "message/rfc822" : "application/json; charset=utf-8", "cache-control": "no-store", ...headers });
|
|
7758
8861
|
response.end(isBuffer ? body : `${JSON.stringify(body)}
|
|
7759
8862
|
`);
|
|
@@ -7833,7 +8936,7 @@ function createTcpServer(scanner, options = {}) {
|
|
|
7833
8936
|
const onEnd = async () => {
|
|
7834
8937
|
socket.setTimeout(0);
|
|
7835
8938
|
try {
|
|
7836
|
-
const result = await scanner.scan(
|
|
8939
|
+
const result = await scanner.scan(Buffer11.concat(chunks));
|
|
7837
8940
|
socket.end(json ? `${JSON.stringify(serializeResult(result))}
|
|
7838
8941
|
` : `${result.isSpam ? "SPAM" : "HAM"} ${result.score.toFixed(1)}/${result.threshold.toFixed(1)} ${result.tests.map((test) => test.name).join(",")}
|
|
7839
8942
|
`);
|
|
@@ -7927,12 +9030,12 @@ var PROTOCOL = {
|
|
|
7927
9030
|
HDR_LEADSPC: 1048576
|
|
7928
9031
|
};
|
|
7929
9032
|
var MAX_PACKET = 1024 * 1024;
|
|
7930
|
-
function packet(command, data =
|
|
7931
|
-
const payload =
|
|
7932
|
-
const header =
|
|
9033
|
+
function packet(command, data = Buffer12.alloc(0)) {
|
|
9034
|
+
const payload = Buffer12.isBuffer(data) ? data : Buffer12.from(data, "latin1");
|
|
9035
|
+
const header = Buffer12.alloc(5);
|
|
7933
9036
|
header.writeUInt32BE(payload.length + 1);
|
|
7934
9037
|
header.write(command, 4, "latin1");
|
|
7935
|
-
return
|
|
9038
|
+
return Buffer12.concat([header, payload]);
|
|
7936
9039
|
}
|
|
7937
9040
|
function cstrings(data) {
|
|
7938
9041
|
const parts = data.toString("latin1").split("\0");
|
|
@@ -7942,7 +9045,7 @@ function cstrings(data) {
|
|
|
7942
9045
|
return parts;
|
|
7943
9046
|
}
|
|
7944
9047
|
function cstring(value) {
|
|
7945
|
-
return
|
|
9048
|
+
return Buffer12.from(`${value}\0`, "latin1");
|
|
7946
9049
|
}
|
|
7947
9050
|
function address(value) {
|
|
7948
9051
|
const text = String(value ?? "").trim();
|
|
@@ -7999,7 +9102,7 @@ var MilterSession = class {
|
|
|
7999
9102
|
if (this.buffered < this.needed) {
|
|
8000
9103
|
return;
|
|
8001
9104
|
}
|
|
8002
|
-
let buffer = this.chunks.length === 1 ? this.chunks[0] :
|
|
9105
|
+
let buffer = this.chunks.length === 1 ? this.chunks[0] : Buffer12.concat(this.chunks);
|
|
8003
9106
|
this.needed = 4;
|
|
8004
9107
|
while (buffer.length >= 4) {
|
|
8005
9108
|
const length = buffer.readUInt32BE(0);
|
|
@@ -8044,7 +9147,7 @@ var MilterSession = class {
|
|
|
8044
9147
|
const protocol = data.readUInt32BE(8);
|
|
8045
9148
|
const wanted = ACTIONS.ADDHDRS | ACTIONS.CHGHDRS | ACTIONS.QUARANTINE;
|
|
8046
9149
|
this.leadingSpace = Boolean(protocol & PROTOCOL.HDR_LEADSPC);
|
|
8047
|
-
const reply2 =
|
|
9150
|
+
const reply2 = Buffer12.alloc(12);
|
|
8048
9151
|
reply2.writeUInt32BE(Math.min(version, 6), 0);
|
|
8049
9152
|
reply2.writeUInt32BE(actions & wanted, 4);
|
|
8050
9153
|
reply2.writeUInt32BE(protocol & (PROTOCOL.HDR_LEADSPC | PROTOCOL.NOUNKNOWN), 8);
|
|
@@ -8109,7 +9212,7 @@ var MilterSession = class {
|
|
|
8109
9212
|
if (this.truncated || this.size + data.length > options.maxSize) {
|
|
8110
9213
|
this.truncated = true;
|
|
8111
9214
|
} else {
|
|
8112
|
-
this.body.push(
|
|
9215
|
+
this.body.push(Buffer12.from(data));
|
|
8113
9216
|
this.size += data.length;
|
|
8114
9217
|
}
|
|
8115
9218
|
this.send(RESPONSES.CONTINUE);
|
|
@@ -8144,7 +9247,7 @@ var MilterSession = class {
|
|
|
8144
9247
|
/** @returns {Buffer} */
|
|
8145
9248
|
rawMessage() {
|
|
8146
9249
|
const head = this.headers.map(([name, value]) => `${name}:${this.leadingSpace || value.startsWith(" ") || value.startsWith(" ") ? "" : " "}${value}`).join("\r\n");
|
|
8147
|
-
return
|
|
9250
|
+
return Buffer12.concat([Buffer12.from(this.headers.length > 0 ? `${head}\r
|
|
8148
9251
|
\r
|
|
8149
9252
|
` : "\r\n", "latin1"), ...this.body]);
|
|
8150
9253
|
}
|
|
@@ -8155,9 +9258,9 @@ var MilterSession = class {
|
|
|
8155
9258
|
const key = name.toLowerCase();
|
|
8156
9259
|
counts.set(key, (counts.get(key) || 0) + 1);
|
|
8157
9260
|
if (key.startsWith("x-spam-")) {
|
|
8158
|
-
const index =
|
|
9261
|
+
const index = Buffer12.alloc(4);
|
|
8159
9262
|
index.writeUInt32BE(counts.get(key));
|
|
8160
|
-
this.send(RESPONSES.CHGHEADER,
|
|
9263
|
+
this.send(RESPONSES.CHGHEADER, Buffer12.concat([index, cstring(name), cstring("")]));
|
|
8161
9264
|
}
|
|
8162
9265
|
}
|
|
8163
9266
|
}
|
|
@@ -8180,7 +9283,7 @@ var MilterSession = class {
|
|
|
8180
9283
|
}
|
|
8181
9284
|
this.server.report(error);
|
|
8182
9285
|
this.removeForgedHeaders();
|
|
8183
|
-
this.send(RESPONSES.ADDHEADER,
|
|
9286
|
+
this.send(RESPONSES.ADDHEADER, Buffer12.concat([cstring("X-Spam-Virus-Scan"), cstring(`${this.leadingSpace ? " " : ""}failed`)]));
|
|
8184
9287
|
this.send(RESPONSES.CONTINUE);
|
|
8185
9288
|
this.resetMessage();
|
|
8186
9289
|
return;
|
|
@@ -8201,15 +9304,15 @@ var MilterSession = class {
|
|
|
8201
9304
|
headers.unshift(["Authentication-Results", formatAuthResultsHeader(result.results.authentication, options.hostname)]);
|
|
8202
9305
|
}
|
|
8203
9306
|
for (const [name, value] of headers) {
|
|
8204
|
-
this.send(RESPONSES.ADDHEADER,
|
|
9307
|
+
this.send(RESPONSES.ADDHEADER, Buffer12.concat([cstring(name), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
|
|
8205
9308
|
}
|
|
8206
9309
|
if (result.isSpam && options.subjectTag) {
|
|
8207
9310
|
const subject = this.headers.find(([name]) => name.toLowerCase() === "subject");
|
|
8208
9311
|
const value = taggedSubject(options.subjectTag, subject ? subject[1].trim() : "", "\n");
|
|
8209
9312
|
if (value !== null) {
|
|
8210
|
-
const index =
|
|
9313
|
+
const index = Buffer12.alloc(4);
|
|
8211
9314
|
index.writeUInt32BE(1);
|
|
8212
|
-
this.send(RESPONSES.CHGHEADER,
|
|
9315
|
+
this.send(RESPONSES.CHGHEADER, Buffer12.concat([index, cstring("Subject"), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
|
|
8213
9316
|
}
|
|
8214
9317
|
}
|
|
8215
9318
|
if (result.action === "reject" && options.reject) {
|
|
@@ -8312,7 +9415,7 @@ var MilterServer = class extends EventEmitter {
|
|
|
8312
9415
|
};
|
|
8313
9416
|
|
|
8314
9417
|
// src/spamd.js
|
|
8315
|
-
import { Buffer as
|
|
9418
|
+
import { Buffer as Buffer13 } from "node:buffer";
|
|
8316
9419
|
import net4 from "node:net";
|
|
8317
9420
|
var EX_OK = 0;
|
|
8318
9421
|
var EX_USAGE = 64;
|
|
@@ -8343,7 +9446,7 @@ function reply(code, text, headers = [], body = null) {
|
|
|
8343
9446
|
lines2.push(`Content-length: ${body.length}`);
|
|
8344
9447
|
}
|
|
8345
9448
|
lines2.push(...headers.map(([name, value]) => `${name}: ${value}`), "", "");
|
|
8346
|
-
return body === null ?
|
|
9449
|
+
return body === null ? Buffer13.from(lines2.join("\r\n")) : Buffer13.concat([Buffer13.from(lines2.join("\r\n")), body]);
|
|
8347
9450
|
}
|
|
8348
9451
|
function report(result) {
|
|
8349
9452
|
const lines2 = [
|
|
@@ -8388,11 +9491,11 @@ async function answer(scanner, request, message, options) {
|
|
|
8388
9491
|
return reply(EX_OK, "EX_OK", [verdict]);
|
|
8389
9492
|
}
|
|
8390
9493
|
case "SYMBOLS": {
|
|
8391
|
-
return reply(EX_OK, "EX_OK", [verdict],
|
|
9494
|
+
return reply(EX_OK, "EX_OK", [verdict], Buffer13.from(result.tests.map((test) => test.name).join(",")));
|
|
8392
9495
|
}
|
|
8393
9496
|
case "REPORT":
|
|
8394
9497
|
case "REPORT_IFSPAM": {
|
|
8395
|
-
return reply(EX_OK, "EX_OK", [verdict], command === "REPORT" || result.isSpam ?
|
|
9498
|
+
return reply(EX_OK, "EX_OK", [verdict], command === "REPORT" || result.isSpam ? Buffer13.from(report(result)) : Buffer13.alloc(0));
|
|
8396
9499
|
}
|
|
8397
9500
|
default: {
|
|
8398
9501
|
const rewritten = rewriteMessage(message, spamHeaders(result, { version: VERSION }), { subjectTag: result.isSpam ? options.subjectTag : null });
|
|
@@ -8400,7 +9503,7 @@ async function answer(scanner, request, message, options) {
|
|
|
8400
9503
|
return reply(EX_OK, "EX_OK", [verdict], rewritten);
|
|
8401
9504
|
}
|
|
8402
9505
|
const { header, newline } = splitMessage(rewritten);
|
|
8403
|
-
return reply(EX_OK, "EX_OK", [verdict],
|
|
9506
|
+
return reply(EX_OK, "EX_OK", [verdict], Buffer13.from(`${header}${newline}${newline}`, "latin1"));
|
|
8404
9507
|
}
|
|
8405
9508
|
}
|
|
8406
9509
|
}
|
|
@@ -8415,7 +9518,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
8415
9518
|
...options
|
|
8416
9519
|
};
|
|
8417
9520
|
const server = net4.createServer({ allowHalfOpen: true }, (socket) => {
|
|
8418
|
-
let head =
|
|
9521
|
+
let head = Buffer13.alloc(0);
|
|
8419
9522
|
const chunks = [];
|
|
8420
9523
|
let size = 0;
|
|
8421
9524
|
let request = null;
|
|
@@ -8441,7 +9544,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
8441
9544
|
return;
|
|
8442
9545
|
}
|
|
8443
9546
|
if (!request) {
|
|
8444
|
-
head =
|
|
9547
|
+
head = Buffer13.concat([head, chunk2]);
|
|
8445
9548
|
const end = head.indexOf("\r\n\r\n");
|
|
8446
9549
|
if (end === -1) {
|
|
8447
9550
|
if (head.length > 64 * 1024) {
|
|
@@ -8476,7 +9579,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
8476
9579
|
chunks.push(chunk2);
|
|
8477
9580
|
size += chunk2.length;
|
|
8478
9581
|
if (request.length === null ? ["PING", "SKIP"].includes(request.command) : size >= request.length) {
|
|
8479
|
-
finish(
|
|
9582
|
+
finish(Buffer13.concat(chunks).subarray(0, request.length ?? 0));
|
|
8480
9583
|
} else if (size > settings.maxSize) {
|
|
8481
9584
|
fail(EX_DATAERR, `Message larger than ${settings.maxSize} bytes`);
|
|
8482
9585
|
}
|
|
@@ -8488,7 +9591,7 @@ function createSpamdServer(scanner, options = {}) {
|
|
|
8488
9591
|
if (!request) {
|
|
8489
9592
|
fail(EX_PROTOCOL, "Incomplete request");
|
|
8490
9593
|
} else if (request.length === null) {
|
|
8491
|
-
finish(
|
|
9594
|
+
finish(Buffer13.concat(chunks));
|
|
8492
9595
|
} else {
|
|
8493
9596
|
fail(EX_PROTOCOL, `Message shorter than its Content-length of ${request.length} bytes`);
|
|
8494
9597
|
}
|
|
@@ -8662,21 +9765,21 @@ async function withTimeout(promise, ms, fallback) {
|
|
|
8662
9765
|
}
|
|
8663
9766
|
}
|
|
8664
9767
|
async function toBuffer(source) {
|
|
8665
|
-
if (
|
|
9768
|
+
if (Buffer14.isBuffer(source)) {
|
|
8666
9769
|
return source;
|
|
8667
9770
|
}
|
|
8668
9771
|
if (typeof source === "string") {
|
|
8669
|
-
return
|
|
9772
|
+
return Buffer14.from(source, "utf8");
|
|
8670
9773
|
}
|
|
8671
9774
|
if (source instanceof Uint8Array) {
|
|
8672
|
-
return
|
|
9775
|
+
return Buffer14.from(source);
|
|
8673
9776
|
}
|
|
8674
9777
|
if (source && typeof source[Symbol.asyncIterator] === "function") {
|
|
8675
9778
|
const chunks = [];
|
|
8676
9779
|
for await (const chunk2 of source) {
|
|
8677
|
-
chunks.push(
|
|
9780
|
+
chunks.push(Buffer14.isBuffer(chunk2) ? chunk2 : Buffer14.from(chunk2));
|
|
8678
9781
|
}
|
|
8679
|
-
return
|
|
9782
|
+
return Buffer14.concat(chunks);
|
|
8680
9783
|
}
|
|
8681
9784
|
throw new TypeError("A message must be a Buffer, a string, a Uint8Array or a readable stream");
|
|
8682
9785
|
}
|
|
@@ -8698,6 +9801,19 @@ var DEFAULTS2 = {
|
|
|
8698
9801
|
cloudflare: true,
|
|
8699
9802
|
adult: true,
|
|
8700
9803
|
maxHosts: 25,
|
|
9804
|
+
// Also read the links of the whole message and of what it carries
|
|
9805
|
+
// (attached messages, HTML, SVG and XML files, text files, invitations
|
|
9806
|
+
// and contact cards, documents in iframes and data: URLs) when link
|
|
9807
|
+
// hosts are looked up, for at most five seconds: off by default, as it
|
|
9808
|
+
// reads all of it, up to 50 MB of attachments.
|
|
9809
|
+
attachments: false,
|
|
9810
|
+
// Milliseconds the link lookups may take in all (default: timeout).
|
|
9811
|
+
timeout: void 0,
|
|
9812
|
+
// Also look up host names written in the text without a link or a path
|
|
9813
|
+
// ("evil.example"), which mail clients make links of, as far as there is
|
|
9814
|
+
// room: off by default, as a quoted reply or a signature may name any
|
|
9815
|
+
// site (they are checked for lookalikes either way).
|
|
9816
|
+
hostsInText: false,
|
|
8701
9817
|
// Characters of text read for links (twice as many of HTML): more than
|
|
8702
9818
|
// for the classifier (maxLength), as a link anywhere in a message may be
|
|
8703
9819
|
// followed; a longer message sets results.linksTruncated.
|
|
@@ -8810,7 +9926,7 @@ function fromDomain(mail) {
|
|
|
8810
9926
|
function withHeader(raw) {
|
|
8811
9927
|
const first = raw.subarray(0, 1e3).toString("latin1");
|
|
8812
9928
|
const headerless = raw.length > 0 && !/^(?:[!-9;-~]+[ \t]*:|From |[\r\n])/.test(first);
|
|
8813
|
-
return headerless ?
|
|
9929
|
+
return headerless ? Buffer14.concat([Buffer14.from("\r\n"), raw]) : raw;
|
|
8814
9930
|
}
|
|
8815
9931
|
var SpamScanner = class {
|
|
8816
9932
|
/**
|
|
@@ -8972,7 +10088,10 @@ var SpamScanner = class {
|
|
|
8972
10088
|
async scanFile(file, options) {
|
|
8973
10089
|
return this.scan(await readFile(file), options);
|
|
8974
10090
|
}
|
|
8975
|
-
|
|
10091
|
+
// (`from`: the sender's domain; `carried`: the link hosts of the whole
|
|
10092
|
+
// message and of what it carries, see carriedLinkHosts)
|
|
10093
|
+
async checkLinks(links, config, hosts = [], options = {}) {
|
|
10094
|
+
const { from = "", carried = null } = typeof options === "string" ? { from: options } : options;
|
|
8976
10095
|
const phishing = [];
|
|
8977
10096
|
const homographs = [];
|
|
8978
10097
|
const seenHosts = /* @__PURE__ */ new Set();
|
|
@@ -9028,7 +10147,11 @@ var SpamScanner = class {
|
|
|
9028
10147
|
for (const host of hosts) {
|
|
9029
10148
|
lookalike(host, { source: "text" });
|
|
9030
10149
|
}
|
|
9031
|
-
const
|
|
10150
|
+
const carriedHosts = (carried?.hosts ?? []).map((host) => lookupName(host)).filter(Boolean);
|
|
10151
|
+
for (const host of carriedHosts) {
|
|
10152
|
+
seenHosts.add(host);
|
|
10153
|
+
}
|
|
10154
|
+
const ordered = [.../* @__PURE__ */ new Set([...[...found.filter((link) => link.text), ...found.filter((link) => !link.text), ...bare].map((link) => lookupName(destination(link))).filter(Boolean), ...carriedHosts])];
|
|
9032
10155
|
const firsts = /* @__PURE__ */ new Map();
|
|
9033
10156
|
for (const host of ordered) {
|
|
9034
10157
|
const domain = registrableDomain(host);
|
|
@@ -9040,6 +10163,7 @@ var SpamScanner = class {
|
|
|
9040
10163
|
const domains = [...new Set(checked.map((host) => registrableDomain(host)))];
|
|
9041
10164
|
const blocked = [];
|
|
9042
10165
|
let answered = 0;
|
|
10166
|
+
const linkTimeout = Number(config.phishing.timeout) > 0 ? Number(config.phishing.timeout) : config.timeout;
|
|
9043
10167
|
const cloudflare = async () => {
|
|
9044
10168
|
await withTimeout(Promise.all(checked.map(async (host) => {
|
|
9045
10169
|
const found2 = await this.dns.checkCloudflare([host], { adult: config.phishing.adult });
|
|
@@ -9047,12 +10171,12 @@ var SpamScanner = class {
|
|
|
9047
10171
|
if (!found2.unanswered?.length) {
|
|
9048
10172
|
answered++;
|
|
9049
10173
|
}
|
|
9050
|
-
})),
|
|
10174
|
+
})), linkTimeout, null);
|
|
9051
10175
|
return { found: [...blocked], unanswered: checked.length - answered };
|
|
9052
10176
|
};
|
|
9053
10177
|
const [cloudflareResult, listed] = await Promise.all([
|
|
9054
10178
|
config.phishing.cloudflare && checked.length > 0 ? cloudflare() : { found: [], unanswered: 0 },
|
|
9055
|
-
config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain),
|
|
10179
|
+
config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain), linkTimeout, []) : []
|
|
9056
10180
|
]);
|
|
9057
10181
|
for (const { host, category } of cloudflareResult.found) {
|
|
9058
10182
|
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` }));
|
|
@@ -9068,7 +10192,8 @@ var SpamScanner = class {
|
|
|
9068
10192
|
return {
|
|
9069
10193
|
phishing,
|
|
9070
10194
|
homographs,
|
|
9071
|
-
|
|
10195
|
+
// (at least one when the message has more hosts than were read)
|
|
10196
|
+
uncheckedHosts: Math.max(seenHosts.size - checked.length, carried?.more ? 1 : 0),
|
|
9072
10197
|
timedOutHosts: cloudflareResult.unanswered
|
|
9073
10198
|
};
|
|
9074
10199
|
}
|
|
@@ -9240,10 +10365,17 @@ ${visibleText(html.slice(0, config.maxLength * 2)).text}`, { maxLength: config.m
|
|
|
9240
10365
|
styled: plainObfuscation.styled || shownObfuscation.styled
|
|
9241
10366
|
};
|
|
9242
10367
|
const unopened = [];
|
|
9243
|
-
const
|
|
10368
|
+
const opened = [];
|
|
10369
|
+
const attached = await expandAttachments(mail.attachments, parseErrors, void 0, { unopened, mails: opened });
|
|
10370
|
+
const carried = config.phishing.attachments === true && (config.phishing.cloudflare || config.dnsbl.domain?.length > 0) ? carriedLinkHosts(mail, {
|
|
10371
|
+
mails: opened,
|
|
10372
|
+
attachments: attached,
|
|
10373
|
+
maxHosts: config.phishing.maxHosts,
|
|
10374
|
+
hostsInText: config.phishing.hostsInText === true
|
|
10375
|
+
}) : null;
|
|
9244
10376
|
const attachments = config.attachments === false ? [] : inspectAttachments(attached).filter((item) => config.macros !== false || !["macro", "pdf_active", "rtf_object"].includes(item.type)).map((item) => finding(item));
|
|
9245
10377
|
const [links, authentication, checkedReputation, dnsbl, virusScan, toxicity, nsfw] = await Promise.all([
|
|
9246
|
-
this.checkLinks(checkedLinks, config, extracted.hosts, fromDomain(mail)),
|
|
10378
|
+
this.checkLinks(checkedLinks, config, extracted.hosts, { from: fromDomain(mail), carried }),
|
|
9247
10379
|
config.authenticationResults && typeof config.authenticationResults === "object" ? normalizeAuthOutput(config.authenticationResults) : config.authentication && session.remoteAddress ? withTimeout(authenticate(raw, {
|
|
9248
10380
|
timeout: config.timeout,
|
|
9249
10381
|
...typeof config.authentication === "object" ? config.authentication : {},
|
|
@@ -9371,6 +10503,14 @@ ${visibleText(html.slice(0, config.maxLength * 2)).text}`, { maxLength: config.m
|
|
|
9371
10503
|
// Whether the message has more text than phishing.maxLength, whose
|
|
9372
10504
|
// links were not read.
|
|
9373
10505
|
linksTruncated,
|
|
10506
|
+
// Whether a link host of the message or of what it carries was
|
|
10507
|
+
// never read whole (it runs past where long text is cut to be
|
|
10508
|
+
// read, it goes through more security gateways than are
|
|
10509
|
+
// unwrapped, or it is in more documents than are read), and whether
|
|
10510
|
+
// an attachment was left unread for time: in either case not every
|
|
10511
|
+
// link was checked (see phishing.attachments).
|
|
10512
|
+
linksTooComplex: Boolean(carried?.tooComplex),
|
|
10513
|
+
linksIncomplete: Boolean(carried?.incomplete),
|
|
9374
10514
|
idnHomographAttack: {
|
|
9375
10515
|
detected: links.homographs.length > 0,
|
|
9376
10516
|
domains: links.homographs,
|
|
@@ -9382,6 +10522,9 @@ ${visibleText(html.slice(0, config.maxLength * 2)).text}`, { maxLength: config.m
|
|
|
9382
10522
|
language: extracted.language,
|
|
9383
10523
|
tokens: extracted.words,
|
|
9384
10524
|
mail,
|
|
10525
|
+
// (the attachments of the message and of its attached messages, as
|
|
10526
|
+
// read, an attached message's named after it)
|
|
10527
|
+
attached,
|
|
9385
10528
|
version: VERSION,
|
|
9386
10529
|
metrics: { totalTime: time }
|
|
9387
10530
|
};
|