@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.
Files changed (2) hide show
  1. package/index.mjs +50 -48
  2. 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
- debugger;
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
- // Basic format validation (must have @ and domain)
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 || // RFC 5321 local-part max
3463
- domain.length > 255 || // RFC 5321 domain max
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
- localPart.match(/[^\w.!#$%&'*+/=?^`{|}~-]/) !== null // illegal chars in local part
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 number strings (e.g. 1234567890user)
3480
- /[a-z]{20,}/, // very long random letters
3481
- /unsubscribe/i, // rare but classic spam sign
3482
- /free|win|bonus|deal|promo/i, // promotional keywords in address
3483
- /\+\d+$/, // + followed only by numbers (often disposable)
3484
- /^[\d\W_]+$/, // only digits & symbols (very suspicious)
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
- // Add more from disposable lists if needed
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
- // Still allow if it looks like a serious role or branded use
3528
- const seriousPrefixes = ['info', 'support', 'sales', 'contact', 'hello', 'team', 'admin', 'office', 'billing'];
3529
- const prefix = localPart.split('+')[0].split('.')[0]; // rough prefix
3530
-
3531
- if (!seriousPrefixes.some((p) => prefix.includes(p))) {
3532
- // Extra lenient length check for free providers
3533
- if (localPart.length > 24 || localPart.match(/\d{6,}/)) {
3534
- return true;
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
- // Otherwise: free provider but looks somewhat legitimate → not spam
3538
- return false;
3538
+
3539
+ return false; // default: allow typical personal use on Gmail etc.
3539
3540
  }
3540
3541
 
3541
- // // ────────────────────────────────────────────────
3542
- // // 4. Very short / meaningless / bot-like local parts
3543
- // // ────────────────────────────────────────────────
3544
- // if (localPart.length < 3 || localPart.match(/^[a-z\d]{1,4}$/)) {
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
- // // 5. Suspicious TLDs sometimes used in spam (2026 context)
3550
- // // ────────────────────────────────────────────────
3551
- // const suspiciousTlds = ['.top', '.xyz', '.club', '.online', '.site', '.fun', '.buzz'];
3552
- // if (suspiciousTlds.some((tld) => domain.endsWith(tld))) {
3553
- // return true;
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 most checks probably not spam
3558
+ // Passed → likely legitimate
3557
3559
  return false;
3558
3560
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/account_module",
3
- "version": "1.2.1869",
3
+ "version": "1.2.1871",
4
4
  "description": "Xuda Account Server Module",
5
5
  "main": "index.mjs",
6
6
  "dependencies": {