Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

haraka-plugin-rspamd

Package Overview
Dependencies
Maintainers
4
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

haraka-plugin-rspamd - npm Package Compare versions

Comparing version 1.2.0 to 1.3.0

9

Changes.md
### Unreleased
### [1.3.0] - 2023-02-23
- add: defer options, similar to spamassassin.js #32
- es6: replace Object.keys().forEach with for...of
- fix: wrap milter header adds in try/catch, fixes #28
### [1.2.0] - 2022-10-14

@@ -68,1 +75,3 @@

[1.1.9]: https://github.com/haraka/haraka-plugin-rspamd/releases/tag/1.1.9
[1.2.0]: https://github.com/haraka/haraka-plugin-rspamd/releases/tag/1.2.0
[1.3.0]: https://github.com/haraka/haraka-plugin-rspamd/releases/tag/1.3.0

188

index.js

@@ -29,2 +29,4 @@ 'use strict';

'+smtp_message.enabled',
'-defer.error',
'-defer.timeout',
],

@@ -35,28 +37,28 @@ }, () => {

if (!plugin.cfg.reject.message) {
plugin.cfg.reject.message = 'Detected as spam';
if (!this.cfg.reject.message) {
this.cfg.reject.message = 'Detected as spam';
}
if (!plugin.cfg.soft_reject.message) {
plugin.cfg.soft_reject.message = 'Deferred by policy';
if (!this.cfg.soft_reject.message) {
this.cfg.soft_reject.message = 'Deferred by policy';
}
if (!plugin.cfg.spambar) {
plugin.cfg.spambar = { positive: '+', negative: '-', neutral: '/' };
if (!this.cfg.spambar) {
this.cfg.spambar = { positive: '+', negative: '-', neutral: '/' };
}
if (!plugin.cfg.main.port) plugin.cfg.main.port = 11333;
if (!plugin.cfg.main.host) plugin.cfg.main.host = 'localhost';
if (!this.cfg.main.port) this.cfg.main.port = 11333;
if (!this.cfg.main.host) this.cfg.main.host = 'localhost';
if (!plugin.cfg.main.add_headers) {
if (plugin.cfg.main.always_add_headers === true) {
plugin.cfg.main.add_headers = 'always';
if (!this.cfg.main.add_headers) {
if (this.cfg.main.always_add_headers === true) {
this.cfg.main.add_headers = 'always';
}
else {
plugin.cfg.main.add_headers = 'sometimes';
this.cfg.main.add_headers = 'sometimes';
}
}
if (!plugin.cfg.subject) {
plugin.cfg.subject = "[SPAM] %s";
if (!this.cfg.subject) {
this.cfg.subject = "[SPAM] %s";
}

@@ -66,3 +68,2 @@ }

exports.get_options = function (connection) {
const plugin = this;

@@ -77,8 +78,8 @@ // https://rspamd.com/doc/architecture/protocol.html

if (plugin.cfg.main.unix_socket) {
options.socketPath = plugin.cfg.main.unix_socket;
if (this.cfg.main.unix_socket) {
options.socketPath = this.cfg.main.unix_socket;
}
else {
options.port = plugin.cfg.main.port;
options.host = plugin.cfg.main.host;
options.port = this.cfg.main.port;
options.host = this.cfg.main.host;
}

@@ -125,4 +126,4 @@

options.headers.Rcpt = [];
for (let i=0; i < rcpts.length; i++) {
options.headers.Rcpt.push(rcpts[i].address());
for (const rcpt of rcpts) {
options.headers.Rcpt.push(rcpt.address());
}

@@ -148,5 +149,4 @@

exports.get_smtp_message = function (r) {
const plugin = this;
if (!plugin.cfg.smtp_message.enabled || !r.data.messages) return;
if (!this.cfg.smtp_message.enabled || !r.data.messages) return;
if (typeof(r.data.messages) !== 'object') return;

@@ -159,8 +159,7 @@ if (!r.data.messages.smtp_message) return;

exports.do_rewrite = function (connection, data) {
const plugin = this;
if (!plugin.cfg.rewrite_subject.enabled) return false;
if (!this.cfg.rewrite_subject.enabled) return false;
if (data.action !== 'rewrite subject') return false;
const rspamd_subject = data.subject || plugin.cfg.subject;
const rspamd_subject = data.subject || this.cfg.subject;
const old_subject = connection.transaction.header.get('Subject') || '';

@@ -174,5 +173,4 @@ const new_subject = rspamd_subject.replace('%s', old_subject);

exports.add_dkim_header = function (connection, data) {
const plugin = this;
if (!plugin.cfg.dkim.enabled) return;
if (!this.cfg.dkim.enabled) return;
if (!data['dkim-signature']) return;

@@ -184,36 +182,40 @@

exports.do_milter_headers = function (connection, data) {
const plugin = this;
if (!plugin.cfg.rmilter_headers.enabled) return;
if (!this.cfg.rmilter_headers.enabled) return;
if (!data.milter) return;
if (data.milter.remove_headers) {
Object.keys(data.milter.remove_headers).forEach((key) => {
for (const key of Object.keys(data.milter.remove_headers)) {
connection.transaction.remove_header(key);
})
}
}
if (data.milter.add_headers) {
connection.logdebug(`milter.add_headers: ${JSON.stringify(data.milter.add_headers)}`, plugin);
Object.keys(data.milter.add_headers).forEach((key) => {
const header_values = data.milter.add_headers[key];
if (!header_values) return;
try {
connection.logdebug(this, `milter.add_headers: ${JSON.stringify(data.milter.add_headers)}`);
for (const key of Object.keys(data.milter.add_headers)) {
const header_values = data.milter.add_headers[key];
if (!header_values) return;
if (Object.prototype.toString.call(header_values) == '[object Array]') {
header_values.forEach(function (header_value, header_index) {
if (typeof header_value === 'object') {
connection.transaction.add_header(key, header_value.value);
}
else {
connection.transaction.add_header(key, header_value);
}
});
if (Object.prototype.toString.call(header_values) == '[object Array]') {
header_values.forEach(function (header_value, header_index) {
if (typeof header_value === 'object') {
connection.transaction.add_header(key, header_value.value);
}
else {
connection.transaction.add_header(key, header_value);
}
});
}
else if (typeof header_values === 'object') {
connection.transaction.add_header(key, header_values.value);
}
else {
connection.transaction.add_header(key, header_values);
}
}
else if (typeof header_values === 'object') {
connection.transaction.add_header(key, header_values.value);
}
else {
connection.transaction.add_header(key, header_values);
}
})
}
catch (err) {
connection.errorlog(this, `milter.addheaders error: ${err}`)
}
}

@@ -236,2 +238,3 @@ }

calledNext=true;
if (!connection?.transaction) return;
next(code, msg);

@@ -241,5 +244,5 @@ }

timer = setTimeout(() => {
if (!connection) return;
if (!connection.transaction) return;
if (!connection?.transaction) return;
connection.transaction.results.add(plugin, {err: 'timeout'});
if (plugin.cfg.defer.timeout) return nextOnce(DENYSOFT, 'Rspamd scan timeout');
nextOnce();

@@ -256,4 +259,9 @@ }, timeout * 1000);

res.on('end', () => {
if (!connection.transaction) return nextOnce(); //client gone
const r = plugin.parse_response(rawData, connection);
if (!r || !r.data || !r.log) return nextOnce();
if (!r || !r.data || !r.log) {
if (plugin.cfg.defer.error) return nextOnce(DENYSOFT, 'Rspamd scan error');
return nextOnce();
}

@@ -263,4 +271,2 @@ r.log.emit = true; // spit out a log entry

if (!connection.transaction) return nextOnce();
connection.transaction.results.add(plugin, r.log);

@@ -290,4 +296,5 @@ if (r.data.symbols) connection.transaction.results.add(plugin, { symbols: r.data.symbols });

req.on('error', (err) => {
if (!connection || !connection.transaction) return;
if (!connection?.transaction) return nextOnce(); // client gone
connection.transaction.results.add(plugin, { err: err.message});
if (plugin.cfg.defer.error) return nextOnce(DENYSOFT, 'Rspamd scan error');
nextOnce();

@@ -301,27 +308,26 @@ });

exports.should_check = function (connection) {
const plugin = this;
let result = true; // default
if (plugin.cfg.check.authenticated == false && connection.notes.auth_user) {
connection.transaction.results.add(plugin, { skip: 'authed'});
if (this.cfg.check.authenticated == false && connection.notes.auth_user) {
connection.transaction.results.add(this, { skip: 'authed'});
result = false;
}
if (plugin.cfg.check.relay == false && connection.relaying) {
connection.transaction.results.add(plugin, { skip: 'relay'});
if (this.cfg.check.relay == false && connection.relaying) {
connection.transaction.results.add(this, { skip: 'relay'});
result = false;
}
if (plugin.cfg.check.local_ip == false && connection.remote.is_local) {
connection.transaction.results.add(plugin, { skip: 'local_ip'});
if (this.cfg.check.local_ip == false && connection.remote.is_local) {
connection.transaction.results.add(this, { skip: 'local_ip'});
result = false;
}
if (plugin.cfg.check.private_ip == false && connection.remote.is_private) {
if (plugin.cfg.check.local_ip == true && connection.remote.is_local) {
if (this.cfg.check.private_ip == false && connection.remote.is_private) {
if (this.cfg.check.local_ip == true && connection.remote.is_local) {
// local IPs are included in private IPs
}
else {
connection.transaction.results.add(plugin, { skip: 'private_ip'});
connection.transaction.results.add(this, { skip: 'private_ip'});
result = false;

@@ -335,3 +341,2 @@ }

exports.wants_reject = function (connection, data) {
const plugin = this;

@@ -341,6 +346,6 @@ if (data.action !== 'reject') return false;

if (connection.notes.auth_user) {
if (plugin.cfg.reject.authenticated == false) return false;
if (this.cfg.reject.authenticated == false) return false;
}
else {
if (plugin.cfg.reject.spam == false) return false;
if (this.cfg.reject.spam == false) return false;
}

@@ -352,6 +357,5 @@

exports.wants_headers_added = function (rspamd_data) {
const plugin = this;
if (plugin.cfg.main.add_headers === 'never') return false;
if (plugin.cfg.main.add_headers === 'always') return true;
if (this.cfg.main.add_headers === 'never') return false;
if (this.cfg.main.add_headers === 'always') return true;

@@ -364,3 +368,2 @@ // implicit add_headers=sometimes, based on rspamd response

exports.get_clean = function (data, connection) {
const plugin = this;
const clean = { symbols: {} };

@@ -377,3 +380,3 @@

// unhandled type
connection.logerror(plugin, a);
connection.logerror(this, a);
})

@@ -383,3 +386,4 @@ }

// objects that may exist
['action', 'is_skipped', 'required_score', 'score'].forEach((key) => {
const skip_keys = ['action', 'is_skipped', 'required_score', 'score'];
for (const key of skip_keys) {
switch (typeof data[key]) {

@@ -392,8 +396,9 @@ case 'boolean':

default:
connection.loginfo(plugin, `skipping unhandled: ${ typeof data[key]}`);
connection.loginfo(this, `skipping unhandled: ${typeof data[key]}`);
}
});
}
// arrays which might be present
['urls', 'emails', 'messages'].forEach(b => {
const arrays = ['urls', 'emails', 'messages'];
for (const b of arrays) {
// collapse to comma separated string, so values get logged

@@ -413,3 +418,3 @@ if (!data[b]) return;

}
});
}

@@ -420,4 +425,2 @@ return clean;

exports.parse_response = function (rawData, connection) {
const plugin = this;
if (!rawData) return;

@@ -430,4 +433,4 @@

catch (err) {
connection.transaction.results.add(plugin, {
err: `parse failure: ${ err.message}`
connection.transaction.results.add(this, {
err: `parse failure: ${err.message}`
});

@@ -440,5 +443,3 @@ return;

if (Object.keys(data).length === 1 && data.error) {
connection.transaction.results.add(plugin, {
err: data.error
});
connection.transaction.results.add(this, { err: data.error });
return;

@@ -449,3 +450,3 @@ }

data,
'log' : plugin.get_clean(data, connection),
'log' : this.get_clean(data, connection),
};

@@ -455,6 +456,5 @@ }

exports.add_headers = function (connection, data) {
const plugin = this;
const cfg = plugin.cfg;
const cfg = this.cfg;
if (!plugin.wants_headers_added(data)) return;
if (!this.wants_headers_added(data)) return;

@@ -484,3 +484,3 @@ if (cfg.header && cfg.header.bar) {

if (data.symbols[k].score) {
prettySymbols.push(`${data.symbols[k].name }(${ data.symbols[k].score })`);
prettySymbols.push(`${data.symbols[k].name}(${data.symbols[k].score})`);
}

@@ -495,4 +495,4 @@ }

connection.transaction.remove_header(cfg.header.score);
connection.transaction.add_header(cfg.header.score, `${ data.score}`);
connection.transaction.add_header(cfg.header.score, `${data.score}`);
}
}
{
"name": "haraka-plugin-rspamd",
"version": "1.2.0",
"version": "1.3.0",
"description": "Haraka plugin for rspamd",

@@ -5,0 +5,0 @@ "main": "index.js",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc