@mikkelscheike/email-provider-links 2.7.1 → 2.8.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 +84 -181
- package/dist/alias-detection.js +42 -213
- package/dist/api.d.ts +29 -13
- package/dist/api.js +29 -29
- package/dist/concurrent-dns.d.ts +1 -1
- package/dist/concurrent-dns.js +6 -5
- package/dist/hash-verifier.js +2 -2
- package/dist/loader.d.ts +1 -1
- package/dist/loader.js +16 -5
- package/dist/schema.d.ts +25 -6
- package/dist/schema.js +4 -7
- package/dist/url-validator.js +22 -103
- package/package.json +9 -8
- package/providers/emailproviders.json +837 -288
package/dist/api.d.ts
CHANGED
|
@@ -4,10 +4,26 @@
|
|
|
4
4
|
* Simplified API with better error handling and performance improvements.
|
|
5
5
|
* Clean function names and enhanced error context.
|
|
6
6
|
*/
|
|
7
|
+
export type ProviderType = 'public_provider' | 'custom_provider' | 'proxy_service';
|
|
7
8
|
export interface EmailProvider {
|
|
8
9
|
companyProvider: string;
|
|
9
|
-
loginUrl: string;
|
|
10
|
+
loginUrl: string | null;
|
|
10
11
|
domains: string[];
|
|
12
|
+
type: ProviderType;
|
|
13
|
+
alias?: {
|
|
14
|
+
dots?: {
|
|
15
|
+
ignore: boolean;
|
|
16
|
+
strip: boolean;
|
|
17
|
+
};
|
|
18
|
+
plus?: {
|
|
19
|
+
ignore: boolean;
|
|
20
|
+
strip: boolean;
|
|
21
|
+
};
|
|
22
|
+
case?: {
|
|
23
|
+
ignore: boolean;
|
|
24
|
+
strip: boolean;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
11
27
|
customDomainDetection?: {
|
|
12
28
|
mxPatterns?: string[];
|
|
13
29
|
txtPatterns?: string[];
|
|
@@ -50,14 +66,14 @@ export interface EmailProviderResult {
|
|
|
50
66
|
* @example
|
|
51
67
|
* ```typescript
|
|
52
68
|
* // Consumer email
|
|
53
|
-
* const
|
|
54
|
-
* console.log(
|
|
55
|
-
* console.log(
|
|
69
|
+
* const result = await getEmailProvider('local@domain.tld');
|
|
70
|
+
* console.log(result.provider?.companyProvider); // Provider name
|
|
71
|
+
* console.log(result.loginUrl); // Login URL
|
|
56
72
|
*
|
|
57
73
|
* // Business domain
|
|
58
|
-
* const business = await getEmailProvider('
|
|
59
|
-
* console.log(business.provider?.companyProvider); //
|
|
60
|
-
* console.log(business.detectionMethod); //
|
|
74
|
+
* const business = await getEmailProvider('local@business.tld');
|
|
75
|
+
* console.log(business.provider?.companyProvider); // Detected provider
|
|
76
|
+
* console.log(business.detectionMethod); // Detection method
|
|
61
77
|
*
|
|
62
78
|
* // Error handling
|
|
63
79
|
* const invalid = await getEmailProvider('invalid-email');
|
|
@@ -100,11 +116,11 @@ export declare function getEmailProviderSync(email: string): EmailProviderResult
|
|
|
100
116
|
*
|
|
101
117
|
* @example
|
|
102
118
|
* ```typescript
|
|
103
|
-
* const canonical = normalizeEmail('
|
|
104
|
-
* console.log(canonical); // '
|
|
119
|
+
* const canonical = normalizeEmail('L.O.C.A.L+work@DOMAIN.TLD');
|
|
120
|
+
* console.log(canonical); // 'local@domain.tld'
|
|
105
121
|
*
|
|
106
|
-
* const
|
|
107
|
-
* console.log(
|
|
122
|
+
* const provider = normalizeEmail('local+newsletter@provider.tld');
|
|
123
|
+
* console.log(provider); // 'local@provider.tld'
|
|
108
124
|
* ```
|
|
109
125
|
*/
|
|
110
126
|
export declare function normalizeEmail(email: string): string;
|
|
@@ -120,10 +136,10 @@ export declare function normalizeEmail(email: string): string;
|
|
|
120
136
|
*
|
|
121
137
|
* @example
|
|
122
138
|
* ```typescript
|
|
123
|
-
* const match = emailsMatch('
|
|
139
|
+
* const match = emailsMatch('local@domain.tld', 'l.o.c.a.l+work@domain.tld');
|
|
124
140
|
* console.log(match); // true
|
|
125
141
|
*
|
|
126
|
-
* const different = emailsMatch('
|
|
142
|
+
* const different = emailsMatch('local@domain.tld', 'other@domain.tld');
|
|
127
143
|
* console.log(different); // false
|
|
128
144
|
* ```
|
|
129
145
|
*/
|
package/dist/api.js
CHANGED
|
@@ -29,14 +29,14 @@ const loader_1 = require("./loader");
|
|
|
29
29
|
* @example
|
|
30
30
|
* ```typescript
|
|
31
31
|
* // Consumer email
|
|
32
|
-
* const
|
|
33
|
-
* console.log(
|
|
34
|
-
* console.log(
|
|
32
|
+
* const result = await getEmailProvider('local@domain.tld');
|
|
33
|
+
* console.log(result.provider?.companyProvider); // Provider name
|
|
34
|
+
* console.log(result.loginUrl); // Login URL
|
|
35
35
|
*
|
|
36
36
|
* // Business domain
|
|
37
|
-
* const business = await getEmailProvider('
|
|
38
|
-
* console.log(business.provider?.companyProvider); //
|
|
39
|
-
* console.log(business.detectionMethod); //
|
|
37
|
+
* const business = await getEmailProvider('local@business.tld');
|
|
38
|
+
* console.log(business.provider?.companyProvider); // Detected provider
|
|
39
|
+
* console.log(business.detectionMethod); // Detection method
|
|
40
40
|
*
|
|
41
41
|
* // Error handling
|
|
42
42
|
* const invalid = await getEmailProvider('invalid-email');
|
|
@@ -215,9 +215,9 @@ function getEmailProviderSync(email) {
|
|
|
215
215
|
}
|
|
216
216
|
};
|
|
217
217
|
}
|
|
218
|
-
//
|
|
219
|
-
const {
|
|
220
|
-
const provider =
|
|
218
|
+
// Use cached providers and domain map for efficient lookup
|
|
219
|
+
const { domainMap } = (0, loader_1.loadProviders)();
|
|
220
|
+
const provider = domainMap.get(domain);
|
|
221
221
|
const result = {
|
|
222
222
|
provider: provider || null,
|
|
223
223
|
email,
|
|
@@ -257,11 +257,11 @@ function getEmailProviderSync(email) {
|
|
|
257
257
|
*
|
|
258
258
|
* @example
|
|
259
259
|
* ```typescript
|
|
260
|
-
* const canonical = normalizeEmail('
|
|
261
|
-
* console.log(canonical); // '
|
|
260
|
+
* const canonical = normalizeEmail('L.O.C.A.L+work@DOMAIN.TLD');
|
|
261
|
+
* console.log(canonical); // 'local@domain.tld'
|
|
262
262
|
*
|
|
263
|
-
* const
|
|
264
|
-
* console.log(
|
|
263
|
+
* const provider = normalizeEmail('local+newsletter@provider.tld');
|
|
264
|
+
* console.log(provider); // 'local@provider.tld'
|
|
265
265
|
* ```
|
|
266
266
|
*/
|
|
267
267
|
function normalizeEmail(email) {
|
|
@@ -277,21 +277,21 @@ function normalizeEmail(email) {
|
|
|
277
277
|
}
|
|
278
278
|
let localPart = lowercaseEmail.slice(0, atIndex);
|
|
279
279
|
const domainPart = lowercaseEmail.slice(atIndex + 1);
|
|
280
|
-
//
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
localPart = localPart.
|
|
280
|
+
// Use cached providers for domain lookup
|
|
281
|
+
const { domainMap } = (0, loader_1.loadProviders)();
|
|
282
|
+
const provider = domainMap.get(domainPart);
|
|
283
|
+
if (provider?.alias) {
|
|
284
|
+
// Provider supports aliasing
|
|
285
|
+
if (provider.alias.dots) {
|
|
286
|
+
// Remove all dots from local part (e.g. Gmail)
|
|
287
|
+
localPart = localPart.replace(/\./g, '');
|
|
288
288
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
289
|
+
if (provider.alias.plus) {
|
|
290
|
+
// Remove plus addressing (everything after +)
|
|
291
|
+
const plusIndex = localPart.indexOf('+');
|
|
292
|
+
if (plusIndex !== -1) {
|
|
293
|
+
localPart = localPart.slice(0, plusIndex);
|
|
294
|
+
}
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
return `${localPart}@${domainPart}`;
|
|
@@ -308,10 +308,10 @@ function normalizeEmail(email) {
|
|
|
308
308
|
*
|
|
309
309
|
* @example
|
|
310
310
|
* ```typescript
|
|
311
|
-
* const match = emailsMatch('
|
|
311
|
+
* const match = emailsMatch('local@domain.tld', 'l.o.c.a.l+work@domain.tld');
|
|
312
312
|
* console.log(match); // true
|
|
313
313
|
*
|
|
314
|
-
* const different = emailsMatch('
|
|
314
|
+
* const different = emailsMatch('local@domain.tld', 'other@domain.tld');
|
|
315
315
|
* console.log(different); // false
|
|
316
316
|
* ```
|
|
317
317
|
*/
|
package/dist/concurrent-dns.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements parallel MX/TXT record lookups for 2x faster business domain detection.
|
|
5
5
|
* Uses Promise.allSettled for fault tolerance and intelligent result merging.
|
|
6
6
|
*/
|
|
7
|
-
import { EmailProvider } from './
|
|
7
|
+
import { EmailProvider } from './api';
|
|
8
8
|
/**
|
|
9
9
|
* Configuration for concurrent DNS detection
|
|
10
10
|
*/
|
package/dist/concurrent-dns.js
CHANGED
|
@@ -367,11 +367,12 @@ class ConcurrentDNSDetector {
|
|
|
367
367
|
const mxQuery = queries.find(q => q.type === 'mx' && q.success);
|
|
368
368
|
if (!mxQuery?.records)
|
|
369
369
|
return null;
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
370
|
+
// Get proxy services from provider data
|
|
371
|
+
const proxyProviders = this.providers.filter(p => p.type === 'proxy_service');
|
|
372
|
+
const proxyPatterns = proxyProviders.map(provider => ({
|
|
373
|
+
service: provider.companyProvider,
|
|
374
|
+
patterns: [...(provider.customDomainDetection?.mxPatterns || []), ...(provider.domains || [])].map(p => p.toLowerCase())
|
|
375
|
+
}));
|
|
375
376
|
for (const record of mxQuery.records) {
|
|
376
377
|
const exchange = record.exchange?.toLowerCase() || '';
|
|
377
378
|
for (const proxy of proxyPatterns) {
|
package/dist/hash-verifier.js
CHANGED
|
@@ -27,9 +27,9 @@ const path_1 = require("path");
|
|
|
27
27
|
*/
|
|
28
28
|
const KNOWN_GOOD_HASHES = {
|
|
29
29
|
// SHA-256 hash of the legitimate emailproviders.json
|
|
30
|
-
'emailproviders.json': '
|
|
30
|
+
'emailproviders.json': 'c9c3cb1590820989071ec2bea8a7560496188031f8fa6367153e642315824cdb',
|
|
31
31
|
// You can add hashes for other critical files
|
|
32
|
-
'package.json': '
|
|
32
|
+
'package.json': 'da08eadfe33e8a5c5bcc3db0f0dccc402b4d8ab8440ff57d2e9aa986921ac66d'
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
35
|
* Calculates SHA-256 hash of a file or string content
|
package/dist/loader.d.ts
CHANGED
package/dist/loader.js
CHANGED
|
@@ -29,13 +29,20 @@ const DEFAULT_CONFIG = {
|
|
|
29
29
|
* Convert compressed provider to EmailProvider format
|
|
30
30
|
*/
|
|
31
31
|
function convertProviderToEmailProvider(compressedProvider) {
|
|
32
|
+
if (!compressedProvider.type) {
|
|
33
|
+
console.warn(`Missing type for provider ${compressedProvider.id}`);
|
|
34
|
+
}
|
|
32
35
|
const provider = {
|
|
33
|
-
companyProvider: compressedProvider.
|
|
34
|
-
loginUrl: compressedProvider.
|
|
35
|
-
domains: compressedProvider.domains || []
|
|
36
|
+
companyProvider: compressedProvider.companyProvider,
|
|
37
|
+
loginUrl: compressedProvider.loginUrl || null,
|
|
38
|
+
domains: compressedProvider.domains || [],
|
|
39
|
+
type: compressedProvider.type,
|
|
40
|
+
alias: compressedProvider.alias
|
|
36
41
|
};
|
|
37
|
-
//
|
|
38
|
-
|
|
42
|
+
// Include DNS detection patterns for business email services and proxy services
|
|
43
|
+
const needsCustomDomainDetection = compressedProvider.type === 'custom_provider' ||
|
|
44
|
+
compressedProvider.type === 'proxy_service';
|
|
45
|
+
if (needsCustomDomainDetection && (compressedProvider.mx?.length || compressedProvider.txt?.length)) {
|
|
39
46
|
provider.customDomainDetection = {};
|
|
40
47
|
if (compressedProvider.mx?.length) {
|
|
41
48
|
provider.customDomainDetection.mxPatterns = compressedProvider.mx;
|
|
@@ -92,6 +99,10 @@ function loadProvidersInternal(config = {}) {
|
|
|
92
99
|
console.log(`⚡ Loading completed in ${loadTime}ms`);
|
|
93
100
|
console.log(`📊 Stats: ${providers.length} providers, ${domainCount} domains`);
|
|
94
101
|
}
|
|
102
|
+
if (process.env.NODE_ENV === 'development') {
|
|
103
|
+
const memoryUsageInMB = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
104
|
+
console.log(`🚀 Current memory usage: ${memoryUsageInMB.toFixed(2)} MB`);
|
|
105
|
+
}
|
|
95
106
|
return {
|
|
96
107
|
providers,
|
|
97
108
|
stats: loadingStats
|
package/dist/schema.d.ts
CHANGED
|
@@ -8,22 +8,41 @@
|
|
|
8
8
|
* Provider interface
|
|
9
9
|
* Uses compact field names for smaller JSON size
|
|
10
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* Provider types:
|
|
13
|
+
* - public_provider: Regular email providers (Gmail, Yahoo, etc.)
|
|
14
|
+
* - custom_provider: Business email services (Google Workspace, Microsoft 365)
|
|
15
|
+
* - proxy_service: Email proxy services (Cloudflare, etc.)
|
|
16
|
+
*/
|
|
17
|
+
export type ProviderType = 'public_provider' | 'custom_provider' | 'proxy_service';
|
|
11
18
|
export interface Provider {
|
|
12
19
|
/** Provider ID (short identifier) */
|
|
13
20
|
id: string;
|
|
14
21
|
/** Provider display name */
|
|
15
|
-
|
|
16
|
-
/** Login/webmail URL */
|
|
17
|
-
|
|
22
|
+
companyProvider: string;
|
|
23
|
+
/** Login/webmail URL (or null if not available) */
|
|
24
|
+
loginUrl: string | null;
|
|
18
25
|
/** Email domains (omitted if empty) */
|
|
19
26
|
domains?: string[];
|
|
20
27
|
/** DNS detection patterns (flattened) */
|
|
21
28
|
mx?: string[];
|
|
22
29
|
txt?: string[];
|
|
23
|
-
/**
|
|
30
|
+
/** Provider type */
|
|
31
|
+
type: ProviderType;
|
|
32
|
+
/** Alias rules for username part */
|
|
24
33
|
alias?: {
|
|
25
|
-
dots?:
|
|
26
|
-
|
|
34
|
+
dots?: {
|
|
35
|
+
ignore: boolean;
|
|
36
|
+
strip: boolean;
|
|
37
|
+
};
|
|
38
|
+
plus?: {
|
|
39
|
+
ignore: boolean;
|
|
40
|
+
strip: boolean;
|
|
41
|
+
};
|
|
42
|
+
case?: {
|
|
43
|
+
ignore: boolean;
|
|
44
|
+
strip: boolean;
|
|
45
|
+
};
|
|
27
46
|
};
|
|
28
47
|
}
|
|
29
48
|
/**
|
package/dist/schema.js
CHANGED
|
@@ -51,14 +51,11 @@ function validateProvider(provider) {
|
|
|
51
51
|
if (!provider.id || typeof provider.id !== 'string') {
|
|
52
52
|
errors.push('Provider ID is required and must be a string');
|
|
53
53
|
}
|
|
54
|
-
if (!provider.
|
|
55
|
-
errors.push('
|
|
54
|
+
if (!provider.companyProvider || typeof provider.companyProvider !== 'string') {
|
|
55
|
+
errors.push('Company provider is required and must be a string');
|
|
56
56
|
}
|
|
57
|
-
if (
|
|
58
|
-
errors.push('
|
|
59
|
-
}
|
|
60
|
-
else if (!provider.url.startsWith('https://')) {
|
|
61
|
-
errors.push('Provider URL must use HTTPS');
|
|
57
|
+
if (provider.loginUrl !== null && (typeof provider.loginUrl !== 'string' || !provider.loginUrl.startsWith('https://'))) {
|
|
58
|
+
errors.push('Login URL must be null or a string starting with HTTPS');
|
|
62
59
|
}
|
|
63
60
|
if (provider.domains && !Array.isArray(provider.domains)) {
|
|
64
61
|
errors.push('Domains must be an array');
|
package/dist/url-validator.js
CHANGED
|
@@ -9,106 +9,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.validateEmailProviderUrl = validateEmailProviderUrl;
|
|
10
10
|
exports.validateAllProviderUrls = validateAllProviderUrls;
|
|
11
11
|
exports.auditProviderSecurity = auditProviderSecurity;
|
|
12
|
+
const loader_1 = require("./loader");
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* Get allowlisted domains from provider data
|
|
14
15
|
* Only URLs from these domains will be considered safe.
|
|
15
|
-
*
|
|
16
|
-
* NOTE: This list should be maintained carefully and updated only
|
|
17
|
-
* through security review processes.
|
|
18
16
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'yahoo.fr',
|
|
37
|
-
'yahoo.de',
|
|
38
|
-
'login.yahoo.com',
|
|
39
|
-
// Privacy-focused providers
|
|
40
|
-
'proton.me',
|
|
41
|
-
'protonmail.com',
|
|
42
|
-
'protonmail.ch',
|
|
43
|
-
'tutanota.com',
|
|
44
|
-
'tutanota.de',
|
|
45
|
-
'posteo.de',
|
|
46
|
-
'runbox.com',
|
|
47
|
-
'countermail.com',
|
|
48
|
-
'hushmail.com',
|
|
49
|
-
// Business providers
|
|
50
|
-
'zoho.com',
|
|
51
|
-
'fastmail.com',
|
|
52
|
-
'rackspace.com',
|
|
53
|
-
'apps.rackspace.com',
|
|
54
|
-
// Other legitimate providers
|
|
55
|
-
'aol.com',
|
|
56
|
-
'mail.aol.com',
|
|
57
|
-
'gmx.com',
|
|
58
|
-
'gmx.net',
|
|
59
|
-
'mail.com',
|
|
60
|
-
'yandex.com',
|
|
61
|
-
'yandex.ru',
|
|
62
|
-
'web.de',
|
|
63
|
-
'mail.ru',
|
|
64
|
-
'libero.it',
|
|
65
|
-
'orange.fr',
|
|
66
|
-
'free.fr',
|
|
67
|
-
't-online.de',
|
|
68
|
-
'comcast.net',
|
|
69
|
-
'att.net',
|
|
70
|
-
'verizon.net',
|
|
71
|
-
'bluehost.com',
|
|
72
|
-
'godaddy.com',
|
|
73
|
-
'secureserver.net',
|
|
74
|
-
// Additional providers from security audit
|
|
75
|
-
'kolabnow.com',
|
|
76
|
-
'connect.xfinity.com',
|
|
77
|
-
'login.verizon.com',
|
|
78
|
-
'www.simply.com',
|
|
79
|
-
'www.one.com',
|
|
80
|
-
'mailfence.com',
|
|
81
|
-
'neo.space',
|
|
82
|
-
'mail.126.com',
|
|
83
|
-
'mail.qq.com',
|
|
84
|
-
'mail.sina.com.cn',
|
|
85
|
-
'www.xtra.co.nz',
|
|
86
|
-
'mail.rediff.com',
|
|
87
|
-
'mail.rakuten.co.jp',
|
|
88
|
-
'mail.nifty.com',
|
|
89
|
-
'mail.iij.ad.jp',
|
|
90
|
-
'email.uol.com.br',
|
|
91
|
-
'email.bol.com.br',
|
|
92
|
-
'email.globo.com',
|
|
93
|
-
'webmail.terra.com.br',
|
|
94
|
-
'webmail.movistar.es',
|
|
95
|
-
'webmail.ono.com',
|
|
96
|
-
'webmail.telkom.co.za',
|
|
97
|
-
'webmail.vodacom.co.za',
|
|
98
|
-
'webmail.mtnonline.com',
|
|
99
|
-
'bdmail.net',
|
|
100
|
-
'mail.aamra.com.bd',
|
|
101
|
-
'mail.link3.net',
|
|
102
|
-
'mail.ionos.com',
|
|
103
|
-
'www.icloud.com',
|
|
104
|
-
'icloud.com',
|
|
105
|
-
'mail.hostinger.com',
|
|
106
|
-
'ngx257.inmotionhosting.com',
|
|
107
|
-
'privateemail.com',
|
|
108
|
-
'app.titan.email',
|
|
109
|
-
'tools.siteground.com',
|
|
110
|
-
'portal.hostgator.com'
|
|
111
|
-
];
|
|
17
|
+
function getAllowedDomains() {
|
|
18
|
+
const { providers } = (0, loader_1.loadProviders)();
|
|
19
|
+
const allowedDomains = new Set();
|
|
20
|
+
for (const provider of providers) {
|
|
21
|
+
if (provider.loginUrl) {
|
|
22
|
+
try {
|
|
23
|
+
const url = new URL(provider.loginUrl);
|
|
24
|
+
allowedDomains.add(url.hostname);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Skip invalid URLs
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return allowedDomains;
|
|
33
|
+
}
|
|
112
34
|
/**
|
|
113
35
|
* Suspicious URL patterns that should always be rejected
|
|
114
36
|
*/
|
|
@@ -208,12 +130,9 @@ function validateEmailProviderUrl(url) {
|
|
|
208
130
|
domain
|
|
209
131
|
};
|
|
210
132
|
}
|
|
211
|
-
// Check
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
return domain === allowedDomain || domain.endsWith(`.${allowedDomain}`);
|
|
215
|
-
});
|
|
216
|
-
if (!isAllowed) {
|
|
133
|
+
// Check if the domain is allowed
|
|
134
|
+
const allowedDomains = getAllowedDomains();
|
|
135
|
+
if (!allowedDomains.has(domain)) {
|
|
217
136
|
return {
|
|
218
137
|
isValid: false,
|
|
219
138
|
reason: `Domain '${domain}' is not in the allowlist`,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikkelscheike/email-provider-links",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "TypeScript library for email provider detection with 93 providers (
|
|
3
|
+
"version": "2.8.1",
|
|
4
|
+
"description": "TypeScript library for email provider detection with 93 providers (207 domains), concurrent DNS resolution, optimized performance, 91.75% test coverage, and enterprise security for login and password reset flows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
"!dist/**/*.map"
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
|
+
"clean": "rm -rf dist",
|
|
14
15
|
"verify-hashes": "tsx scripts/verify-hashes.ts",
|
|
15
|
-
"build": "tsx scripts/verify-hashes.ts && tsc",
|
|
16
|
-
"test": "jest
|
|
16
|
+
"build": "npm run clean && tsx scripts/verify-hashes.ts && tsc",
|
|
17
|
+
"test": "jest",
|
|
17
18
|
"test:watch": "jest --watch",
|
|
18
19
|
"test:coverage": "jest --coverage",
|
|
19
20
|
"prepublishOnly": "npm run verify-hashes && npm run build",
|
|
@@ -62,17 +63,17 @@
|
|
|
62
63
|
"access": "public"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@jest/globals": "^30.0.
|
|
66
|
+
"@jest/globals": "^30.0.3",
|
|
66
67
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
67
68
|
"@semantic-release/exec": "^7.1.0",
|
|
68
69
|
"@semantic-release/git": "^10.0.1",
|
|
69
70
|
"@semantic-release/github": "^11.0.3",
|
|
70
|
-
"@semantic-release/npm": "^12.0.
|
|
71
|
+
"@semantic-release/npm": "^12.0.2",
|
|
71
72
|
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
72
73
|
"@types/jest": "^30.0.0",
|
|
73
|
-
"@types/node": "^24.0.
|
|
74
|
+
"@types/node": "^24.0.4",
|
|
74
75
|
"conventional-changelog-conventionalcommits": "^9.0.0",
|
|
75
|
-
"jest": "^30.0.
|
|
76
|
+
"jest": "^30.0.3",
|
|
76
77
|
"semantic-release": "^24.2.5",
|
|
77
78
|
"ts-jest": "^29.4.0",
|
|
78
79
|
"tsx": "^4.20.3",
|