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