@xuda.io/account_module 1.2.1840 → 1.2.1841

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 +116 -4
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -2153,9 +2153,7 @@ export const add_contact = async function (req, job_id, headers) {
2153
2153
 
2154
2154
  set_account_profile_picture(uid, contact_uid, metadata, job_id, headers, account_profile_info);
2155
2155
  } else {
2156
- if (email.contains('unsubscribe', '+') || email.length > 20) {
2157
- is_spam = true;
2158
- }
2156
+ is_spam = isLikelySpamEmail(email);
2159
2157
 
2160
2158
  // contact without use account
2161
2159
  cached_contact = await get_xuda_cache(uid, 'contact', email, 'metadata');
@@ -2165,7 +2163,7 @@ export const add_contact = async function (req, job_id, headers) {
2165
2163
  // }
2166
2164
 
2167
2165
  if (_.isEmpty(cached_contact)) {
2168
- if (metadata.subject && !metadata.is_sent && !metadata.is_answered && !metadata.not_junk) {
2166
+ if (!is_spam && metadata.subject && !metadata.is_sent && !metadata.is_answered && !metadata.not_junk) {
2169
2167
  // email_type_info = await ai_module.detect_email_type(uid, name, email, account_profile_info, '', metadata?.subject);
2170
2168
  // is_spam = email_type_info.email_type === 'spam' || email_type_info.email_type === 'promotional';
2171
2169
  is_spam = await ai_module.is_spam_email(uid, email, metadata.subject, account_profile_info);
@@ -3500,3 +3498,117 @@ export const process_accounts_emails = async function () {
3500
3498
  email_module.process_emails({ uid: account_doc._id });
3501
3499
  }
3502
3500
  };
3501
+
3502
+ function isLikelySpamEmail(email) {
3503
+ if (!email || typeof email !== 'string') return true; // Invalid input → treat as spam
3504
+
3505
+ const lower = email.toLowerCase().trim();
3506
+
3507
+ // Basic format validation (must have @ and domain)
3508
+ if (!lower.includes('@') || lower.split('@').length !== 2) return true;
3509
+
3510
+ const [localPart, domain] = lower.split('@');
3511
+
3512
+ if (!localPart || !domain) return true;
3513
+
3514
+ // ────────────────────────────────────────────────
3515
+ // 1. Obvious syntax / format red flags
3516
+ // ────────────────────────────────────────────────
3517
+ if (
3518
+ localPart.length > 64 || // RFC 5321 local-part max
3519
+ domain.length > 255 || // RFC 5321 domain max
3520
+ localPart.startsWith('.') ||
3521
+ localPart.endsWith('.') ||
3522
+ localPart.includes('..') ||
3523
+ domain.includes('..') ||
3524
+ domain.startsWith('-') ||
3525
+ domain.endsWith('-') ||
3526
+ localPart.match(/[^\w.!#$%&'*+/=?^`{|}~-]/) !== null // illegal chars in local part
3527
+ ) {
3528
+ return true;
3529
+ }
3530
+
3531
+ // ────────────────────────────────────────────────
3532
+ // 2. Very common spam patterns in local part
3533
+ // ────────────────────────────────────────────────
3534
+ const spamPatterns = [
3535
+ /\d{8,}/, // long number strings (e.g. 1234567890user)
3536
+ /[a-z]{10,}/, // very long random letters
3537
+ /unsubscribe/i, // rare but classic spam sign
3538
+ /free|win|bonus|deal|promo/i, // promotional keywords in address
3539
+ /\+\d+$/, // + followed only by numbers (often disposable)
3540
+ /^[\d\W_]+$/, // only digits & symbols (very suspicious)
3541
+ ];
3542
+
3543
+ if (spamPatterns.some((p) => p.test(localPart))) {
3544
+ return true;
3545
+ }
3546
+
3547
+ // ────────────────────────────────────────────────
3548
+ // 3. Common free / disposable / temporary providers
3549
+ // (update this list periodically – 2026 common ones)
3550
+ // ────────────────────────────────────────────────
3551
+ const freeOrDisposableDomains = new Set([
3552
+ 'gmail.com',
3553
+ 'yahoo.com',
3554
+ 'hotmail.com',
3555
+ 'outlook.com',
3556
+ 'aol.com',
3557
+ 'icloud.com',
3558
+ 'proton.me',
3559
+ 'protonmail.com',
3560
+ 'mail.com',
3561
+ 'yandex.com',
3562
+ 'ymail.com',
3563
+ 'rocketmail.com',
3564
+ 'gmx.com',
3565
+ 'gmx.net',
3566
+ 'web.de',
3567
+ 'live.com',
3568
+ 'msn.com',
3569
+ 'inbox.com',
3570
+ 'zoho.com',
3571
+ 'tutanota.com',
3572
+ 'tempmail.com',
3573
+ '10minutemail.com',
3574
+ 'guerrillamail.com',
3575
+ 'trashmail.com',
3576
+ 'mailinator.com',
3577
+ 'yopmail.com',
3578
+ 'sharklasers.com',
3579
+ // Add more from disposable lists if needed
3580
+ ]);
3581
+
3582
+ if (freeOrDisposableDomains.has(domain)) {
3583
+ // Still allow if it looks like a serious role or branded use
3584
+ const seriousPrefixes = ['info', 'support', 'sales', 'contact', 'hello', 'team', 'admin', 'office', 'billing'];
3585
+ const prefix = localPart.split('+')[0].split('.')[0]; // rough prefix
3586
+
3587
+ if (!seriousPrefixes.some((p) => prefix.includes(p))) {
3588
+ // Extra lenient length check for free providers
3589
+ if (localPart.length > 24 || localPart.match(/\d{6,}/)) {
3590
+ return true;
3591
+ }
3592
+ }
3593
+ // Otherwise: free provider but looks somewhat legitimate → not spam
3594
+ return false;
3595
+ }
3596
+
3597
+ // ────────────────────────────────────────────────
3598
+ // 4. Very short / meaningless / bot-like local parts
3599
+ // ────────────────────────────────────────────────
3600
+ if (localPart.length < 3 || localPart.match(/^[a-z\d]{1,4}$/)) {
3601
+ return true; // e.g. a1@b.com, xyz@temp.com
3602
+ }
3603
+
3604
+ // ────────────────────────────────────────────────
3605
+ // 5. Suspicious TLDs sometimes used in spam (2026 context)
3606
+ // ────────────────────────────────────────────────
3607
+ const suspiciousTlds = ['.top', '.xyz', '.club', '.online', '.site', '.fun', '.buzz'];
3608
+ if (suspiciousTlds.some((tld) => domain.endsWith(tld))) {
3609
+ return true;
3610
+ }
3611
+
3612
+ // Passed most checks → probably not spam
3613
+ return false;
3614
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/account_module",
3
- "version": "1.2.1840",
3
+ "version": "1.2.1841",
4
4
  "description": "Xuda Account Server Module",
5
5
  "main": "index.mjs",
6
6
  "dependencies": {