@brilab-mailer/disposable 0.0.1
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/README.md +9 -0
- package/data/wildcard.json +401 -0
- package/data/wildcard.sha256 +1 -0
- package/index.d.ts +5 -0
- package/index.d.ts.map +1 -0
- package/index.js +31 -0
- package/matcher.d.ts +18 -0
- package/matcher.d.ts.map +1 -0
- package/matcher.js +53 -0
- package/package.json +39 -0
- package/scripts/postinstall.cjs +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# disposable
|
|
2
|
+
|
|
3
|
+
## Source: [ivolo/disposable-email-domains](https://github.com/ivolo/disposable-email-domains) — list of disposable email domains used in this library
|
|
4
|
+
|
|
5
|
+
This library was generated with [Nx](https://nx.dev).
|
|
6
|
+
|
|
7
|
+
## Building
|
|
8
|
+
|
|
9
|
+
Run `nx build disposable` to build the library.
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
[
|
|
2
|
+
"0x01.gq",
|
|
3
|
+
"0x01.tk",
|
|
4
|
+
"10mail.org",
|
|
5
|
+
"10mail.tk",
|
|
6
|
+
"33m.co",
|
|
7
|
+
"33mail.com",
|
|
8
|
+
"3dxtras.com",
|
|
9
|
+
"3utilities.com",
|
|
10
|
+
"567map.xyz",
|
|
11
|
+
"8191.at",
|
|
12
|
+
"aa.am",
|
|
13
|
+
"accountsite.me",
|
|
14
|
+
"acmetoy.com",
|
|
15
|
+
"acusupply.com",
|
|
16
|
+
"adultvidlite.com",
|
|
17
|
+
"aji.kr",
|
|
18
|
+
"anonaddy.com",
|
|
19
|
+
"anonaddy.me",
|
|
20
|
+
"anonbox.net",
|
|
21
|
+
"anyalias.com",
|
|
22
|
+
"asanatest1.us",
|
|
23
|
+
"azzawajalla.store",
|
|
24
|
+
"bajetesik.store",
|
|
25
|
+
"band-freier.de",
|
|
26
|
+
"bandband1.com",
|
|
27
|
+
"bangmadid.store",
|
|
28
|
+
"batikbantul.com",
|
|
29
|
+
"bccto.me",
|
|
30
|
+
"bebekpenyet.buzz",
|
|
31
|
+
"bei.kr",
|
|
32
|
+
"bel.kr",
|
|
33
|
+
"beo.kr",
|
|
34
|
+
"bfo.kr",
|
|
35
|
+
"bgsaddrmwn.me",
|
|
36
|
+
"bho.kr",
|
|
37
|
+
"biasaelho.space",
|
|
38
|
+
"biz.st",
|
|
39
|
+
"biz.tm",
|
|
40
|
+
"bko.kr",
|
|
41
|
+
"blacksong.pw",
|
|
42
|
+
"blueauramassage.com",
|
|
43
|
+
"bounceme.net",
|
|
44
|
+
"bum.net",
|
|
45
|
+
"buwosok.tech",
|
|
46
|
+
"buzzndaraiangop2wae.buzz",
|
|
47
|
+
"byui.me",
|
|
48
|
+
"caboodle.buzz",
|
|
49
|
+
"cad.edu.gr",
|
|
50
|
+
"cempue.online",
|
|
51
|
+
"chickenkiller.com",
|
|
52
|
+
"choirul.host",
|
|
53
|
+
"cid.kr",
|
|
54
|
+
"ciran.xyz",
|
|
55
|
+
"cko.kr",
|
|
56
|
+
"cloudns.asia",
|
|
57
|
+
"cloudns.cc",
|
|
58
|
+
"cloudns.cx",
|
|
59
|
+
"cloudns.nz",
|
|
60
|
+
"com.com",
|
|
61
|
+
"coms.hk",
|
|
62
|
+
"comx.cf",
|
|
63
|
+
"craigslist.org",
|
|
64
|
+
"creo.site",
|
|
65
|
+
"creo.tips",
|
|
66
|
+
"creou.dev",
|
|
67
|
+
"crowdpress.it",
|
|
68
|
+
"cu.cc",
|
|
69
|
+
"cua77.xyz",
|
|
70
|
+
"d3vs.net",
|
|
71
|
+
"dadosa.xyz",
|
|
72
|
+
"danuarte.online",
|
|
73
|
+
"darrels.site",
|
|
74
|
+
"daseus.online",
|
|
75
|
+
"dayatan.host",
|
|
76
|
+
"dbo.kr",
|
|
77
|
+
"ddns.net",
|
|
78
|
+
"ddnsfree.com",
|
|
79
|
+
"deail.com",
|
|
80
|
+
"dedyn.io",
|
|
81
|
+
"defaultdomain.ml",
|
|
82
|
+
"discard-email.cf",
|
|
83
|
+
"dko.kr",
|
|
84
|
+
"dlink.cf",
|
|
85
|
+
"dlink.gq",
|
|
86
|
+
"dlyemail.com",
|
|
87
|
+
"dmtc.dev",
|
|
88
|
+
"dmtc.edu.pl",
|
|
89
|
+
"dmtc.press",
|
|
90
|
+
"dns-cloud.net",
|
|
91
|
+
"dns.navy",
|
|
92
|
+
"dnsabr.com",
|
|
93
|
+
"dnses.ro",
|
|
94
|
+
"doy.kr",
|
|
95
|
+
"drope.ml",
|
|
96
|
+
"dropmail.me",
|
|
97
|
+
"dynu.net",
|
|
98
|
+
"dzalaev-advokat.ru",
|
|
99
|
+
"e4ward.com",
|
|
100
|
+
"ediantenan.site",
|
|
101
|
+
"edu.auction",
|
|
102
|
+
"efo.kr",
|
|
103
|
+
"eho.kr",
|
|
104
|
+
"ely.kr",
|
|
105
|
+
"email-temp.com",
|
|
106
|
+
"emailfake.com",
|
|
107
|
+
"emailfake.ml",
|
|
108
|
+
"emailfreedom.ml",
|
|
109
|
+
"emlhub.com",
|
|
110
|
+
"emlpro.com",
|
|
111
|
+
"emltmp.com",
|
|
112
|
+
"emy.kr",
|
|
113
|
+
"enu.kr",
|
|
114
|
+
"eny.kr",
|
|
115
|
+
"epizy.com",
|
|
116
|
+
"escritossad.net",
|
|
117
|
+
"ese.kr",
|
|
118
|
+
"esy.es",
|
|
119
|
+
"ewa.kr",
|
|
120
|
+
"exi.kr",
|
|
121
|
+
"ezyro.com",
|
|
122
|
+
"fackme.gq",
|
|
123
|
+
"fassagforpresident.ga",
|
|
124
|
+
"firste.ml",
|
|
125
|
+
"flu.cc",
|
|
126
|
+
"foy.kr",
|
|
127
|
+
"fr.nf",
|
|
128
|
+
"freeml.net",
|
|
129
|
+
"gadzooks.buzz",
|
|
130
|
+
"gettrials.com",
|
|
131
|
+
"giize.com",
|
|
132
|
+
"gmail.gr.com",
|
|
133
|
+
"gmeil.me",
|
|
134
|
+
"gok.kr",
|
|
135
|
+
"gotdns.ch",
|
|
136
|
+
"gpa.lu",
|
|
137
|
+
"grigio.cf",
|
|
138
|
+
"guardmail.cf",
|
|
139
|
+
"haddo.eu",
|
|
140
|
+
"heliohost.org",
|
|
141
|
+
"higogoya.com",
|
|
142
|
+
"historial.store",
|
|
143
|
+
"hitechinfo.com",
|
|
144
|
+
"hix.kr",
|
|
145
|
+
"hiz.kr",
|
|
146
|
+
"hmail.us",
|
|
147
|
+
"hopto.org",
|
|
148
|
+
"hostingarif.me",
|
|
149
|
+
"idn.vn",
|
|
150
|
+
"iesco.info",
|
|
151
|
+
"igg.biz",
|
|
152
|
+
"ignorelist.com",
|
|
153
|
+
"iki.kr",
|
|
154
|
+
"ilovemyniggers.club",
|
|
155
|
+
"imouto.pro",
|
|
156
|
+
"info.tm",
|
|
157
|
+
"infos.st",
|
|
158
|
+
"irr.kr",
|
|
159
|
+
"isgre.at",
|
|
160
|
+
"it2-mail.tk",
|
|
161
|
+
"jil.kr",
|
|
162
|
+
"jindmail.club",
|
|
163
|
+
"jto.kr",
|
|
164
|
+
"junnuok.com",
|
|
165
|
+
"justemail.ml",
|
|
166
|
+
"kadokawa.top",
|
|
167
|
+
"kantal.buzz",
|
|
168
|
+
"keitin.site",
|
|
169
|
+
"kentel.buzz",
|
|
170
|
+
"kerl.cf",
|
|
171
|
+
"kerl.gq",
|
|
172
|
+
"kikwet.com",
|
|
173
|
+
"kondomeus.site",
|
|
174
|
+
"kozow.com",
|
|
175
|
+
"kranjingan.store",
|
|
176
|
+
"kranjingan.tech",
|
|
177
|
+
"kranjingans.tech",
|
|
178
|
+
"kro.kr",
|
|
179
|
+
"lal.kr",
|
|
180
|
+
"laste.ml",
|
|
181
|
+
"lbe.kr",
|
|
182
|
+
"legundi.site",
|
|
183
|
+
"lei.kr",
|
|
184
|
+
"likevip.net",
|
|
185
|
+
"liopers.link",
|
|
186
|
+
"lko.co.kr",
|
|
187
|
+
"lko.kr",
|
|
188
|
+
"ll47.net",
|
|
189
|
+
"lofteone.ru",
|
|
190
|
+
"lom.kr",
|
|
191
|
+
"longdz.site",
|
|
192
|
+
"longmusic.com",
|
|
193
|
+
"lostandalone.com",
|
|
194
|
+
"loudcannabisapp.com",
|
|
195
|
+
"loy.kr",
|
|
196
|
+
"loyalherceghalom.ml",
|
|
197
|
+
"luk2.com",
|
|
198
|
+
"luksarcenter.ru",
|
|
199
|
+
"luo.kr",
|
|
200
|
+
"lyrics-lagu.me",
|
|
201
|
+
"mail-temp.com",
|
|
202
|
+
"mail0.ga",
|
|
203
|
+
"mailinator.com",
|
|
204
|
+
"mailr.eu",
|
|
205
|
+
"marrone.cf",
|
|
206
|
+
"mbe.kr",
|
|
207
|
+
"mblimbingan.space",
|
|
208
|
+
"mebelnovation.ru",
|
|
209
|
+
"mefound.com",
|
|
210
|
+
"mintemail.com",
|
|
211
|
+
"mishmash.buzz",
|
|
212
|
+
"mko.kr",
|
|
213
|
+
"mlo.kr",
|
|
214
|
+
"mooo.com",
|
|
215
|
+
"motifasidiri.website",
|
|
216
|
+
"mp-j.cf",
|
|
217
|
+
"mp-j.ga",
|
|
218
|
+
"mp-j.gq",
|
|
219
|
+
"mp-j.ml",
|
|
220
|
+
"mp-j.tk",
|
|
221
|
+
"mr-meshkat.com",
|
|
222
|
+
"mrossi.cf",
|
|
223
|
+
"mrossi.gq",
|
|
224
|
+
"mrossi.ml",
|
|
225
|
+
"ms1.email",
|
|
226
|
+
"msdc.co",
|
|
227
|
+
"muabanwin.net",
|
|
228
|
+
"museumplanet.com",
|
|
229
|
+
"my.id",
|
|
230
|
+
"my3mail.cf",
|
|
231
|
+
"my3mail.ga",
|
|
232
|
+
"my3mail.gq",
|
|
233
|
+
"my3mail.ml",
|
|
234
|
+
"my3mail.tk",
|
|
235
|
+
"myddns.me",
|
|
236
|
+
"myeslbookclub.com",
|
|
237
|
+
"mymy.cf",
|
|
238
|
+
"mysafe.ml",
|
|
239
|
+
"mzon.store",
|
|
240
|
+
"n-e.kr",
|
|
241
|
+
"nafko.cf",
|
|
242
|
+
"nctu.me",
|
|
243
|
+
"netmail.tk",
|
|
244
|
+
"netricity.nl",
|
|
245
|
+
"new-mgmt.ga",
|
|
246
|
+
"ngalasmoen.xyz",
|
|
247
|
+
"ngguwokulon.online",
|
|
248
|
+
"njambon.space",
|
|
249
|
+
"nko.kr",
|
|
250
|
+
"now.im",
|
|
251
|
+
"npv.kr",
|
|
252
|
+
"nuo.co.kr",
|
|
253
|
+
"nuo.kr",
|
|
254
|
+
"nut.cc",
|
|
255
|
+
"o-r.kr",
|
|
256
|
+
"oazis.site",
|
|
257
|
+
"obo.kr",
|
|
258
|
+
"ocry.com",
|
|
259
|
+
"office.gy",
|
|
260
|
+
"okezone.bid",
|
|
261
|
+
"one.pl",
|
|
262
|
+
"onlysext.com",
|
|
263
|
+
"oovy.org",
|
|
264
|
+
"oppoesrt.online",
|
|
265
|
+
"orangotango.ml",
|
|
266
|
+
"otherinbox.com",
|
|
267
|
+
"ourhobby.com",
|
|
268
|
+
"owa.kr",
|
|
269
|
+
"owh.ooo",
|
|
270
|
+
"oyu.kr",
|
|
271
|
+
"p-e.kr",
|
|
272
|
+
"pafnuty.com",
|
|
273
|
+
"pandies.space",
|
|
274
|
+
"paqeh.online",
|
|
275
|
+
"pe.hu",
|
|
276
|
+
"petinggiean.tech",
|
|
277
|
+
"peyekkolipi.buzz",
|
|
278
|
+
"poderosamulher.com",
|
|
279
|
+
"poistaa.com",
|
|
280
|
+
"porco.cf",
|
|
281
|
+
"poy.kr",
|
|
282
|
+
"prapto.host",
|
|
283
|
+
"probatelawarizona.com",
|
|
284
|
+
"ptcu.dev",
|
|
285
|
+
"pubgm.website",
|
|
286
|
+
"qbi.kr",
|
|
287
|
+
"qc.to",
|
|
288
|
+
"r-e.kr",
|
|
289
|
+
"ragel.me",
|
|
290
|
+
"rao.kr",
|
|
291
|
+
"reilis.site",
|
|
292
|
+
"rf.gd",
|
|
293
|
+
"ringen.host",
|
|
294
|
+
"rko.kr",
|
|
295
|
+
"rosso.ml",
|
|
296
|
+
"row.kr",
|
|
297
|
+
"rr.nu",
|
|
298
|
+
"rshagor.xyz",
|
|
299
|
+
"s-ly.me",
|
|
300
|
+
"safe-mail.gq",
|
|
301
|
+
"sagun.info",
|
|
302
|
+
"samsueng.site",
|
|
303
|
+
"saucent.online",
|
|
304
|
+
"sborra.tk",
|
|
305
|
+
"schwarzmail.ga",
|
|
306
|
+
"seluang.com",
|
|
307
|
+
"sempak.link",
|
|
308
|
+
"sendaljepit.site",
|
|
309
|
+
"sendangagung.online",
|
|
310
|
+
"servegame.com",
|
|
311
|
+
"shp7.cn",
|
|
312
|
+
"siambretta.com",
|
|
313
|
+
"skodaauto.cf",
|
|
314
|
+
"soju.buzz",
|
|
315
|
+
"solidplai.us",
|
|
316
|
+
"somee.com",
|
|
317
|
+
"spamtrap.ro",
|
|
318
|
+
"spymail.one",
|
|
319
|
+
"ssanphone.me",
|
|
320
|
+
"standeight.com",
|
|
321
|
+
"statuspage.ga",
|
|
322
|
+
"steakbeef.site",
|
|
323
|
+
"stonedogdigital.com",
|
|
324
|
+
"stop-my-spam.pp.ua",
|
|
325
|
+
"storeyee.com",
|
|
326
|
+
"sumanan.site",
|
|
327
|
+
"supere.ml",
|
|
328
|
+
"svblog.com",
|
|
329
|
+
"sytes.net",
|
|
330
|
+
"tandy.co",
|
|
331
|
+
"tangtingtung.tech",
|
|
332
|
+
"teml.net",
|
|
333
|
+
"tempembus.buzz",
|
|
334
|
+
"tempremail.cf",
|
|
335
|
+
"tempremail.tk",
|
|
336
|
+
"tgwrzqr.top",
|
|
337
|
+
"thepieter.com",
|
|
338
|
+
"theworkpc.com",
|
|
339
|
+
"thinktimessolve.info",
|
|
340
|
+
"thumoi.com",
|
|
341
|
+
"tko.co.kr",
|
|
342
|
+
"tko.kr",
|
|
343
|
+
"tmo.kr",
|
|
344
|
+
"tmpeml.com",
|
|
345
|
+
"toh.info",
|
|
346
|
+
"toi.kr",
|
|
347
|
+
"tomcrusenono.host",
|
|
348
|
+
"topikurrohman.xyz",
|
|
349
|
+
"tourbalitravel.com",
|
|
350
|
+
"traveldesk.com",
|
|
351
|
+
"tricakesi.store",
|
|
352
|
+
"trillianpro.com",
|
|
353
|
+
"twilightparadox.com",
|
|
354
|
+
"tyrex.cf",
|
|
355
|
+
"uha.kr",
|
|
356
|
+
"uk.to",
|
|
357
|
+
"uko.kr",
|
|
358
|
+
"umy.kr",
|
|
359
|
+
"unaux.com",
|
|
360
|
+
"undo.it",
|
|
361
|
+
"uny.kr",
|
|
362
|
+
"uola.org",
|
|
363
|
+
"upy.kr",
|
|
364
|
+
"urbanban.com",
|
|
365
|
+
"us.to",
|
|
366
|
+
"usa.cc",
|
|
367
|
+
"uu.gl",
|
|
368
|
+
"uvy.kr",
|
|
369
|
+
"uyu.kr",
|
|
370
|
+
"vay.kr",
|
|
371
|
+
"vba.kr",
|
|
372
|
+
"veo.kr",
|
|
373
|
+
"viola.gq",
|
|
374
|
+
"vivoheroes.xyz",
|
|
375
|
+
"vkbags.in",
|
|
376
|
+
"vo.uk",
|
|
377
|
+
"volvo-xc.tk",
|
|
378
|
+
"vuforia.us",
|
|
379
|
+
"wakultimbo.buzz",
|
|
380
|
+
"web.id",
|
|
381
|
+
"weprof.it",
|
|
382
|
+
"werkuldino.buzz",
|
|
383
|
+
"wil.kr",
|
|
384
|
+
"wingkobabat.buzz",
|
|
385
|
+
"x24hr.com",
|
|
386
|
+
"xiaomie.store",
|
|
387
|
+
"xo.uk",
|
|
388
|
+
"xxi2.com",
|
|
389
|
+
"yarien.eu",
|
|
390
|
+
"yawahid.host",
|
|
391
|
+
"ye.vc",
|
|
392
|
+
"yertxenor.tk",
|
|
393
|
+
"yomail.info",
|
|
394
|
+
"yopmail.com",
|
|
395
|
+
"yoqoyyum.space",
|
|
396
|
+
"youdontcare.com",
|
|
397
|
+
"zalvisual.us",
|
|
398
|
+
"zapto.org",
|
|
399
|
+
"ze.cx",
|
|
400
|
+
"zeroe.ml"
|
|
401
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3b3e9d56e2f98f19f3d7ddf76cd09615531b69616b8aa20520c2aa3bc9bf9bb8
|
package/index.d.ts
ADDED
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AA2BjD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { DisposableMatcher } from './matcher.js';
|
|
5
|
+
function loadWildcardJson() {
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
// dist/index.js -> ../data/wildcard.json (because "data" is shipped)
|
|
9
|
+
const p = path.join(__dirname, '..', 'data', 'wildcard.json');
|
|
10
|
+
const raw = readFileSync(p, 'utf8');
|
|
11
|
+
const json = JSON.parse(raw);
|
|
12
|
+
if (Array.isArray(json))
|
|
13
|
+
return json;
|
|
14
|
+
// In case format changes in the future
|
|
15
|
+
if (json && typeof json === 'object') {
|
|
16
|
+
const anyJson = json;
|
|
17
|
+
if (Array.isArray(anyJson.wildcard))
|
|
18
|
+
return anyJson.wildcard;
|
|
19
|
+
if (Array.isArray(anyJson.domains))
|
|
20
|
+
return anyJson.domains;
|
|
21
|
+
}
|
|
22
|
+
throw new Error('Unsupported wildcard.json format');
|
|
23
|
+
}
|
|
24
|
+
const matcher = new DisposableMatcher(loadWildcardJson());
|
|
25
|
+
export function isDisposableEmail(email) {
|
|
26
|
+
return matcher.isDisposable(email);
|
|
27
|
+
}
|
|
28
|
+
export function isDisposableDomain(domain) {
|
|
29
|
+
return matcher.isDisposable(domain);
|
|
30
|
+
}
|
|
31
|
+
export { DisposableMatcher };
|
package/matcher.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type WildcardEntry = string;
|
|
2
|
+
/**
|
|
3
|
+
* Matches disposable domains from a list that can include wildcard entries.
|
|
4
|
+
* Supported patterns:
|
|
5
|
+
* - "example.com" (exact)
|
|
6
|
+
* - "*.example.com" (any subdomain OR the root; see notes below)
|
|
7
|
+
*
|
|
8
|
+
* NOTE: For practicality, we treat "*.example.com" as matching both:
|
|
9
|
+
* - example.com
|
|
10
|
+
* - anything.example.com
|
|
11
|
+
*/
|
|
12
|
+
export declare class DisposableMatcher {
|
|
13
|
+
private readonly exact;
|
|
14
|
+
private readonly suffixes;
|
|
15
|
+
constructor(entries: WildcardEntry[]);
|
|
16
|
+
isDisposable(emailOrDomain: string): boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=matcher.d.ts.map
|
package/matcher.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AAcnC;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAE7B,OAAO,EAAE,aAAa,EAAE;IAgBpC,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;CAa7C"}
|
package/matcher.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function normalizeDomain(d) {
|
|
2
|
+
return d.trim().toLowerCase().replace(/\.$/, '');
|
|
3
|
+
}
|
|
4
|
+
function extractDomain(emailOrDomain) {
|
|
5
|
+
const v = emailOrDomain.trim();
|
|
6
|
+
const at = v.lastIndexOf('@');
|
|
7
|
+
const domain = at >= 0 ? v.slice(at + 1) : v;
|
|
8
|
+
const norm = normalizeDomain(domain);
|
|
9
|
+
return norm ? norm : null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Matches disposable domains from a list that can include wildcard entries.
|
|
13
|
+
* Supported patterns:
|
|
14
|
+
* - "example.com" (exact)
|
|
15
|
+
* - "*.example.com" (any subdomain OR the root; see notes below)
|
|
16
|
+
*
|
|
17
|
+
* NOTE: For practicality, we treat "*.example.com" as matching both:
|
|
18
|
+
* - example.com
|
|
19
|
+
* - anything.example.com
|
|
20
|
+
*/
|
|
21
|
+
export class DisposableMatcher {
|
|
22
|
+
exact = new Set();
|
|
23
|
+
suffixes = [];
|
|
24
|
+
constructor(entries) {
|
|
25
|
+
for (const raw of entries) {
|
|
26
|
+
const e = normalizeDomain(raw);
|
|
27
|
+
if (!e)
|
|
28
|
+
continue;
|
|
29
|
+
if (e.startsWith('*.')) {
|
|
30
|
+
this.suffixes.push(e.slice(2));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.exact.add(e);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// check longer suffixes first (micro-optimization)
|
|
37
|
+
this.suffixes.sort((a, b) => b.length - a.length);
|
|
38
|
+
}
|
|
39
|
+
isDisposable(emailOrDomain) {
|
|
40
|
+
const domain = extractDomain(emailOrDomain);
|
|
41
|
+
if (!domain)
|
|
42
|
+
return false;
|
|
43
|
+
if (this.exact.has(domain))
|
|
44
|
+
return true;
|
|
45
|
+
for (const s of this.suffixes) {
|
|
46
|
+
if (domain === s)
|
|
47
|
+
return true;
|
|
48
|
+
if (domain.endsWith('.' + s))
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brilab-mailer/disposable",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Fast disposable email/domain detection with bundled wildcard list and optional postinstall refresh.",
|
|
5
|
+
"author": "Bohdan Radchenko <radchenkobs@gmail.com>",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./index.js",
|
|
8
|
+
"module": "./index.js",
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
"./package.json": "./package.json",
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./index.js",
|
|
15
|
+
"default": "./index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"**/*",
|
|
20
|
+
"!**/*.tsbuildinfo",
|
|
21
|
+
"data",
|
|
22
|
+
"scripts"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"email",
|
|
27
|
+
"disposable",
|
|
28
|
+
"validation",
|
|
29
|
+
"domain",
|
|
30
|
+
"blocklist"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"directory": "dist"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"postinstall": "node scripts/postinstall.cjs"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const https = require('node:https');
|
|
5
|
+
const crypto = require('node:crypto');
|
|
6
|
+
|
|
7
|
+
const URL =
|
|
8
|
+
'https://raw.githubusercontent.com/ivolo/disposable-email-domains/master/wildcard.json';
|
|
9
|
+
|
|
10
|
+
const DATA_DIR = path.join(__dirname, '..', 'data');
|
|
11
|
+
const TARGET_JSON = path.join(DATA_DIR, 'wildcard.json');
|
|
12
|
+
const TARGET_SHA = path.join(DATA_DIR, 'wildcard.sha256');
|
|
13
|
+
|
|
14
|
+
const HARD_FAIL = process.env.DISPOSABLE_DOMAINS_HARD_FAIL === '1';
|
|
15
|
+
const TIMEOUT_MS = Number(process.env.DISPOSABLE_DOMAINS_TIMEOUT_MS || 2500);
|
|
16
|
+
|
|
17
|
+
function sha256(buf) {
|
|
18
|
+
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function fetch(url) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const req = https.get(url, { timeout: TIMEOUT_MS }, (res) => {
|
|
24
|
+
if (res.statusCode !== 200) {
|
|
25
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
26
|
+
res.resume();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const chunks = [];
|
|
30
|
+
res.on('data', (c) => chunks.push(c));
|
|
31
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
32
|
+
});
|
|
33
|
+
req.on('timeout', () => req.destroy(new Error('timeout')));
|
|
34
|
+
req.on('error', reject);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
(async () => {
|
|
39
|
+
try {
|
|
40
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
41
|
+
|
|
42
|
+
const buf = await fetch(URL);
|
|
43
|
+
|
|
44
|
+
// basic sanity check (avoid saving HTML/errors)
|
|
45
|
+
const parsed = JSON.parse(buf.toString('utf8'));
|
|
46
|
+
if (!Array.isArray(parsed) || parsed.length < 100) {
|
|
47
|
+
throw new Error('Unexpected JSON format/size');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fs.writeFileSync(TARGET_JSON, buf);
|
|
51
|
+
fs.writeFileSync(TARGET_SHA, sha256(buf), 'utf8');
|
|
52
|
+
|
|
53
|
+
console.log(
|
|
54
|
+
`[disposable-domain-kit] updated wildcard.json (${parsed.length} entries)`
|
|
55
|
+
);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
console.warn(
|
|
58
|
+
`[disposable-domain-kit] could not update list, using bundled snapshot. reason: ${e.message}`
|
|
59
|
+
);
|
|
60
|
+
if (HARD_FAIL) process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
})();
|