مرجع API

JavaScript
import SpamScanner from 'spamscanner';             // ESM
const SpamScanner = require('spamscanner');        // CommonJS

const scanner = new SpamScanner(options);
const result = await scanner.scan(rawMessage, scanOptions);

أنشئ ماسحًا واحدًا وأعد استخدامه: فهو يحمّل النموذج مرة واحدة ويخزّن إجابات DNS والنموذج اللغوي مؤقتًا.

الخيارات#

يمكن تمرير كل خيار إلى المُنشئ. ويمكن تمرير معظمها أيضًا إلى scan() لرسالة واحدة، فتُدمج فوق خيارات المُنشئ.

الخيارالقيمة الافتراضيةالمعنى
threshold5الدرجة التي تصبح عندها الرسالة مزعجة
rejectThreshold15الدرجة التي يصبح عندها action هو reject
scores{}النقاط لكل اختبار: مفاتيح إعدادات أو أسماء اختبارات (الاختبارات والدرجات)
classifierالنموذج المرفقClassifier، أو كائن نموذج، أو مسار ملف نموذج، أو false
classifierOptions{}خيارات النموذج المرفق (انظر المصنِّف)
allowedLanguages[]رموز ISO 639-1؛ اللغات الأخرى تحصل على LANGUAGE_NOT_ALLOWED
phishing.cloudflaretrueسؤال محلِّلات Cloudflare الترشيحية عن مضيفي الروابط
phishing.adulttrueسؤال المحلِّل العائلي أيضًا، وهو يحظر مواقع البالغين
phishing.maxHosts25عدد مضيفي الروابط الذين يُبحث عنهم في كل رسالة
phishing.homograph{}brands (يستبدل القائمة المدمجة)، وextraBrands، وallowlist (نطاقات لا تُوسم أبدًا)، وstrictMode
dnsbl{ip: [], domain: []}مناطق قوائم حظر DNS لعنوان IP للعميل ولنطاقات الروابط
dns{servers: null, timeout: 3000}خوادم الأسماء لفحوص DNS (الافتراضي: خوادم النظام)
attachmentstrueفحص المرفقات
macrostrueوسم وحدات الماكرو وملفات PDF النشطة وكائنات RTF
arbitrarytrueتشغيل القواعد
authenticationfalsetrue، أو {dnsServers, timeout, mta, weights}: SPF وDKIM وDMARC وARC
reputationfalse{allowlist, denylist, apiUrl, headers, timeout}
allowlist، denylistعناوين IP أو نطاقات أو عناوين بريد؛ اختصار لـ reputation
clamavfalsetrue (المقبس الافتراضي)، أو {socket} أو {host, port}
llmnullإعدادات النموذج اللغوي، مع mode وminScore وmaxScore
toxicityfalse{model, threshold = 0.7}: نموذج تجيب classify([text]) فيه مثل @tensorflow-models/toxicity
nsfwfalse{model, threshold = 0.6}: نموذج تجيب classify(imageBuffer) فيه مثل nsfwjs
maxLength100000عدد محارف نص المتن المقروءة
timeout10000المللي ثانية المسموح بها لكل فحص شبكي
session{}تفاصيل جلسة SMTP الافتراضية

تأخذ scan() أيضًا session:

JavaScript
await scanner.scan(raw, {
  session: {
    remoteAddress: '203.0.113.5',             // the client's IP address
    resolvedClientHostname: 'mx.example.com', // its verified reverse DNS name
    helo: 'mx.example.com',
    envelope: {
      mailFrom: {address: 'alice@example.com'},
      rcptTo: [{address: 'bob@example.org'}],
    },
  },
});

يمكن للخادم الذي فحص SPFSender Policy Framework: سجل DNS يسرد الخوادم المسموح لها بإرسال البريد باسم نطاق. وDKIM وDMARC وARC مسبقًا (باستخدام mailauth) أن يمرّر نتائجه في authenticationResults، فتُحتسب بدلًا من فحصها مرة أخرى:

JavaScript
import {authenticate} from 'mailauth';

const auth = await authenticate(raw, {ip, helo, sender, mta});
await scanner.scan(raw, {authenticationResults: auth});

الدوال#

الدالةتُرجع
scan(source, options)النتيجة. source هو Buffer أو سلسلة نصية أو Uint8Array أو تدفق قابل للقراءة
scanFile(path, options)النتيجة لملف رسالة
learn(source, 'spam' | 'ham')تعلّم المصنِّف رسالة واحدة
unlearn(source, 'spam' | 'ham')تتراجع عن learn
saveModel(path, options)تكتب المصنِّف إلى ملف (options: minCount، maxFeatures، metadata)
getClassifier()الـ Classifier المستخدم، أو null
getClassification(features)حكم المصنِّف على السمات المأخوذة من getFeatures
getFeatures(mail){features, words, language, script, links, hosts, text, hidden} لرسالة
getTokens(text, locale)كلمات نص
getTokensAndMailFromSource(source){tokens, features, mail}
parse(source){raw, mail}، مع mail من mailparser

في getFeatures، يكون text هو النص الذي يعرضه عميل البريد، ومنه تُقرأ الكلمات، وhidden عدد محارف النص التي يخفيها HTML.

تحتوي scanner.metrics على totalScans وaverageTime وlastScanTime.

النتيجة#

JavaScript
{
  isSpam: true,
  score: 16.25,
  threshold: 5,
  rejectThreshold: 15,
  action: 'reject',                       // 'accept', 'tag' or 'reject'
  message: 'Spam (BAYES_999, PHISHING_LOOKALIKE_DOMAIN, DECEPTIVE_LINK, FROM_NAME_BRAND)',
  tests: [
    {name: 'BAYES_999', score: 6.25, description: 'Classifier spam probability 99.9%'},
    {name: 'PHISHING_LOOKALIKE_DOMAIN', score: 5, description: '"paypa1-secure.top" imitates paypal by swapping characters'},
    // ...
  ],
  results: {
    classification: {probability, category, spam, ham, clues, coverage},
    phishing: [],        // lookalike domains, deceptive links, Cloudflare and URIBL findings
    uncheckedHosts: 0,   // link hosts beyond phishing.maxHosts, not looked up
    attachments: [],     // every attachment finding
    executables: [],     // the executable findings among them
    macros: [],          // macros, active PDFs, RTF objects
    viruses: [],         // ClamAV findings: {filename, virus: [names], message}
    arbitrary: [],       // rules strong enough to mark spam alone
    obfuscation: {invisible, mixed, styled},
    authentication: null, // mailauth's results with a score, when checked
    reputation: null,
    dnsbl: [],           // {zone, value} for each listing
    language: {language, script, notAllowed},
    llm: null,           // the language model's verdict, when asked
    toxicity: [],
    nsfw: [],
    idnHomographAttack: {detected, domains, riskScore},
  },
  links: ['http://paypa1-secure.top/login'],
  language: 'en',
  tokens: ['dear', 'customer', /* ... */],
  mail: {/* the parsed message, from mailparser */},
  version: '7.0.0',
  metrics: {totalTime: 42},
}

النتائج في phishing وattachments وexecutables وmacros وviruses وarbitrary كائنات لها type وmessage. وString(finding) هو الرسالة.

الصادرات#

JavaScript
import SpamScanner, {
  Classifier, getFeatures, segmentWords, detectLanguage,
  LLMClassifier, PROVIDERS, RECOMMENDED_MODELS, CLASSIFIER_MODELS,
  DEFAULT_SCORES, scoreResults, spamHeaders, rewriteMessage,
  loadModel, saveModel, defaultModelPath, loadDefaultModel,
  train, evaluate, readExamples,
  MilterServer, createHttpServer, createTcpServer, createSpamdServer,
  DEFAULTS, VERSION,
} from 'spamscanner';

import ArfParser from 'spamscanner/arf';

المصنِّف#

JavaScript
const classifier = new Classifier({spamCutoff: 0.99, hamCutoff: 0.2});
classifier.learn(getFeatures(mail).features, 'spam');
classifier.classify(features); // {probability, category, spam, ham, clues, coverage}
الخيارالقيمة الافتراضيةالمعنى
strength، unknown0.45، 0.5قيمتا s وx عند Robinson: مدى شدة سحب السمات النادرة نحو 0.5
minDistance0.1تُتجاهل السمات الأقرب إلى 0.5 من هذه القيمة
maxClues150أقوى السمات التي تُجمع في كل رسالة
hamCutoff، spamCutoff0.2، 0.99حدود نطاق unsure
minLanguageExamples، languageShare1000، 0.02عدد رسائل كل فئة اللازم في لغة ما للوصول إلى الثقة الكاملة
languagePriortrueوزن الكلمات مقابل أعداد لغتها نفسها

تتوفر أيضًا merge(other) وtoJSON(options) وClassifier.fromJSON(json) وsize وentries().

التدريب#

JavaScript
import {train, evaluate, saveModel} from 'spamscanner';

const {classifier, spam, ham} = await train({
  spam: ['/mail/Junk'],
  ham: ['/mail/Archive', '/mail/archive.mbox'],
  datasets: [{file: 'extra.csv', textColumn: 'body', labelColumn: 'kind'}],
});
saveModel(classifier, 'model.json');

تأخذ evaluate(classifier, examples) عناصر {label, features}، أو readExamples(sources) التي تقرأ المصادر نفسها التي تقرؤها train، وتُرجع الأعداد، والدقة، والاستدعاء، وF1، والصحة، ومعدلات الإيجابيات الكاذبة والسلبيات الكاذبة وغير المؤكد.

الخوادم#

JavaScript
import SpamScanner, {MilterServer, createHttpServer, createSpamdServer} from 'spamscanner';

const scanner = new SpamScanner({authentication: true});
const milter = new MilterServer(scanner, {reject: true, rejectCode: 451, subjectTag: '[SPAM]'});
milter.on('scan', ({session, result}) => console.log(session.remoteAddress, result.score));
await milter.listen(7831);

createHttpServer(scanner, {token: process.env.SPAMSCANNER_TOKEN}).listen(7832, '127.0.0.1');
createSpamdServer(scanner).listen(783, '127.0.0.1');

تقارير ARF#

تقرأ spamscanner/arf تقارير الإبلاغ عن الإساءة (RFC 5965) وتكتبها، وهي الصيغة التي يستخدمها مزوّدو صناديق البريد للإبلاغ عن شكاوى البريد المزعج:

JavaScript
import ArfParser from 'spamscanner/arf';

const report = await ArfParser.parse(rawReport);
console.log(report.feedbackType, report.sourceIp, report.originalHeaders.subject);

const raw = ArfParser.create({
  feedbackType: 'abuse', userAgent: 'MyService/1.0',
  from: 'abuse@example.com', to: 'fbl@example.net',
  originalMessage, sourceIp: '192.0.2.1',
});

تُرجع ArfParser.tryParse() القيمة null بدل رمي استثناء للرسائل التي ليست تقارير، وتفحص isArfMessage(mail) رسالة محلَّلة.

عدّل هذه الصفحة على GitHub · Markdown ·