@xuda.io/account_module 1.2.1868 → 1.2.1870
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/index.mjs +49 -48
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -3443,55 +3443,47 @@ export const process_accounts_emails = async function () {
|
|
|
3443
3443
|
};
|
|
3444
3444
|
|
|
3445
3445
|
function isLikelySpamEmail(email) {
|
|
3446
|
-
|
|
3447
|
-
if (!email || typeof email !== 'string') return true; // Invalid input → treat as spam
|
|
3446
|
+
if (!email || typeof email !== 'string') return true;
|
|
3448
3447
|
|
|
3449
3448
|
const lower = email.toLowerCase().trim();
|
|
3450
3449
|
|
|
3451
|
-
//
|
|
3450
|
+
// Must have exactly one @ and non-empty parts
|
|
3452
3451
|
if (!lower.includes('@') || lower.split('@').length !== 2) return true;
|
|
3453
3452
|
|
|
3454
3453
|
const [localPart, domain] = lower.split('@');
|
|
3455
3454
|
|
|
3456
3455
|
if (!localPart || !domain) return true;
|
|
3457
3456
|
|
|
3458
|
-
//
|
|
3459
|
-
// 1. Obvious syntax / format red flags
|
|
3460
|
-
// ────────────────────────────────────────────────
|
|
3457
|
+
// 1. Obvious syntax/format red flags (RFC 5321/5322 inspired)
|
|
3461
3458
|
if (
|
|
3462
|
-
localPart.length > 64 ||
|
|
3463
|
-
domain.length > 255 ||
|
|
3459
|
+
localPart.length > 64 ||
|
|
3460
|
+
domain.length > 255 ||
|
|
3464
3461
|
localPart.startsWith('.') ||
|
|
3465
3462
|
localPart.endsWith('.') ||
|
|
3466
3463
|
localPart.includes('..') ||
|
|
3467
3464
|
domain.includes('..') ||
|
|
3468
3465
|
domain.startsWith('-') ||
|
|
3469
3466
|
domain.endsWith('-') ||
|
|
3470
|
-
|
|
3467
|
+
/[^\w.!#$%&'*+/=?^`{|}~-]/.test(localPart) // illegal chars
|
|
3471
3468
|
) {
|
|
3472
3469
|
return true;
|
|
3473
3470
|
}
|
|
3474
3471
|
|
|
3475
|
-
//
|
|
3476
|
-
// 2. Very common spam patterns in local part
|
|
3477
|
-
// ────────────────────────────────────────────────
|
|
3472
|
+
// 2. Common spam patterns in local part
|
|
3478
3473
|
const spamPatterns = [
|
|
3479
|
-
/\d{8,}/, // long
|
|
3480
|
-
/[a-z]{
|
|
3481
|
-
/unsubscribe/i,
|
|
3482
|
-
/free|win|bonus|deal|promo/i,
|
|
3483
|
-
/\+\d+$/, // + followed only by
|
|
3484
|
-
/^[\d\W_]+$/, // only digits
|
|
3474
|
+
/\d{8,}/, // long consecutive digits
|
|
3475
|
+
/[a-z]{20,}/, // very long random lowercase (raised threshold)
|
|
3476
|
+
/unsubscribe/i,
|
|
3477
|
+
/free|win|bonus|deal|promo/i,
|
|
3478
|
+
/\+\d+$/, // + followed only by digits
|
|
3479
|
+
/^[\d\W_]+$/, // only digits/symbols/underscores
|
|
3485
3480
|
];
|
|
3486
3481
|
|
|
3487
3482
|
if (spamPatterns.some((p) => p.test(localPart))) {
|
|
3488
3483
|
return true;
|
|
3489
3484
|
}
|
|
3490
3485
|
|
|
3491
|
-
//
|
|
3492
|
-
// 3. Common free / disposable / temporary providers
|
|
3493
|
-
// (update this list periodically – 2026 common ones)
|
|
3494
|
-
// ────────────────────────────────────────────────
|
|
3486
|
+
// 3. Free / major disposable providers
|
|
3495
3487
|
const freeOrDisposableDomains = new Set([
|
|
3496
3488
|
'gmail.com',
|
|
3497
3489
|
'yahoo.com',
|
|
@@ -3520,39 +3512,48 @@ function isLikelySpamEmail(email) {
|
|
|
3520
3512
|
'mailinator.com',
|
|
3521
3513
|
'yopmail.com',
|
|
3522
3514
|
'sharklasers.com',
|
|
3523
|
-
//
|
|
3515
|
+
// For real disposables: load dynamically from https://raw.githubusercontent.com/disposable/disposable/master/domains.txt
|
|
3516
|
+
// or https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/main/disposable_email_blocklist.conf
|
|
3517
|
+
// Example: fetch once on startup and build a larger Set
|
|
3524
3518
|
]);
|
|
3525
3519
|
|
|
3526
3520
|
if (freeOrDisposableDomains.has(domain)) {
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
const
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3521
|
+
const cleanLocal = localPart.split('+')[0]; // ignore +tag completely
|
|
3522
|
+
|
|
3523
|
+
const seriousPrefixes = ['info', 'support', 'sales', 'contact', 'hello', 'team', 'admin', 'office', 'billing', 'help', 'service', 'orders', 'bookings', 'quotes', 'enquiries', 'noreply', 'no-reply', 'business', 'shop', 'store'];
|
|
3524
|
+
|
|
3525
|
+
// Better detection: any segment contains a serious keyword
|
|
3526
|
+
const parts = cleanLocal.split(/[\.-]/);
|
|
3527
|
+
const looksLikeRoleOrBrand = seriousPrefixes.some((p) => parts.some((part) => part.includes(p)));
|
|
3528
|
+
|
|
3529
|
+
if (looksLikeRoleOrBrand) {
|
|
3530
|
+
return false; // trusted-looking on free provider
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3533
|
+
// Extra scrutiny if not role-like
|
|
3534
|
+
if (cleanLocal.length > 24 || /\d{6,}/.test(cleanLocal)) {
|
|
3535
|
+
return true;
|
|
3536
3536
|
}
|
|
3537
|
-
|
|
3538
|
-
return false;
|
|
3537
|
+
|
|
3538
|
+
return false; // default: allow typical personal use on Gmail etc.
|
|
3539
3539
|
}
|
|
3540
3540
|
|
|
3541
|
-
//
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
// return true; // e.g. a1@b.com, xyz@temp.com
|
|
3546
|
-
// }
|
|
3541
|
+
// 4. Very short / meaningless / bot-like local parts
|
|
3542
|
+
if (localPart.length < 2 || /^[a-z\d]{1,5}$/.test(localPart)) {
|
|
3543
|
+
return true; // e.g. a1@, xyz12@, but allow real short like "tim@"
|
|
3544
|
+
}
|
|
3547
3545
|
|
|
3548
|
-
//
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
//
|
|
3546
|
+
// 5. Suspicious new/low-trust TLDs (still relevant in 2026)
|
|
3547
|
+
const suspiciousTlds = ['.top', '.xyz', '.club', '.online', '.site', '.fun', '.buzz', '.shop', '.store', '.live', '.digital', '.monster'];
|
|
3548
|
+
if (suspiciousTlds.some((tld) => domain.endsWith(tld))) {
|
|
3549
|
+
return true;
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
// Extra: very long local parts are rare for humans
|
|
3553
|
+
if (localPart.length > 40) {
|
|
3554
|
+
return true;
|
|
3555
|
+
}
|
|
3555
3556
|
|
|
3556
|
-
// Passed
|
|
3557
|
+
// Passed → likely legitimate
|
|
3557
3558
|
return false;
|
|
3558
3559
|
}
|