Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Access #596

Merged
merged 6 commits into from

2 participants

@msimerson
Collaborator
  1. load config with a callback so changes to access.ini are picked up immediately

  2. for 'any' domain matching, also check the From header

  3. load lists into objects (vs arrays), for much faster runtime access

@smfreegard smfreegard merged commit e665a9a into from
@msimerson msimerson deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 10, 2014
  1. @msimerson
  2. @msimerson
  3. @msimerson

    access: load config with a callback

    msimerson authored
    so changes to the config file are picked up immediately
  4. @msimerson

    access: added some "make it faster" juice

    msimerson authored
    load lists into objects (vs arrays), for much faster runtime access
  5. @msimerson
  6. @msimerson
This page is out of date. Refresh to see the latest.
Showing with 173 additions and 186 deletions.
  1. +86 −65 plugins/access.js
  2. +87 −121 tests/plugins/access.js
View
151 plugins/access.js
@@ -1,5 +1,6 @@
// access plugin
var net_utils = require('./net_utils');
+var utils = require('./utils');
exports.register = function() {
var plugin = this;
@@ -28,6 +29,7 @@ exports.register = function() {
['connect','helo','ehlo','mail','rcpt'].forEach(function (hook) {
plugin.register_hook(hook, 'any');
});
+ plugin.register_hook('data_post', 'data_any');
}
};
@@ -69,44 +71,47 @@ exports.init_config = function() {
},
};
- var cfg = plugin.config.get('access.ini', {
- booleans: [
- '+check.any',
- '+check.conn',
- '-check.helo',
- '+check.mail',
- '+check.rcpt',
- ],
- });
-
- plugin.cfg.check = cfg.check;
- if (cfg.deny_msg) {
- for (var p in plugin.cfg.deny_msg) {
- if (cfg.deny_msg[p]) plugin.cfg.deny_msg[p] = cfg.deny_msg[p];
+ var load_access_ini = function() {
+ var cfg = plugin.config.get('access.ini', {
+ booleans: [
+ '+check.any',
+ '+check.conn',
+ '-check.helo',
+ '+check.mail',
+ '+check.rcpt',
+ ],
+ }, load_access_ini);
+
+ plugin.cfg.check = cfg.check;
+ if (cfg.deny_msg) {
+ for (var p in plugin.cfg.deny_msg) {
+ if (cfg.deny_msg[p]) plugin.cfg.deny_msg[p] = cfg.deny_msg[p];
+ }
}
- }
- // backwards compatibility
- var mf_cfg = plugin.config.get('mail_from.access.ini');
- if (mf_cfg && mf_cfg.general && mf_cfg.general.deny_msg) {
- plugin.cfg.deny_msg.mail = mf_cfg.general.deny_msg;
- }
- var rcpt_cfg = plugin.config.get('rcpt_to.access.ini');
- if (rcpt_cfg && rcpt_cfg.general && rcpt_cfg.general.deny_msg) {
- plugin.cfg.deny_msg.rcpt = rcpt_cfg.general.deny_msg;
- }
- var rdns_cfg = this.config.get('connect.rdns_access.ini');
- if (rdns_cfg && rdns_cfg.general && rdns_cfg.general.deny_msg) {
- plugin.cfg.deny_msg.conn = rdns_cfg.general.deny_msg;
- }
+ // backwards compatibility
+ var mf_cfg = plugin.config.get('mail_from.access.ini');
+ if (mf_cfg && mf_cfg.general && mf_cfg.general.deny_msg) {
+ plugin.cfg.deny_msg.mail = mf_cfg.general.deny_msg;
+ }
+ var rcpt_cfg = plugin.config.get('rcpt_to.access.ini');
+ if (rcpt_cfg && rcpt_cfg.general && rcpt_cfg.general.deny_msg) {
+ plugin.cfg.deny_msg.rcpt = rcpt_cfg.general.deny_msg;
+ }
+ var rdns_cfg = plugin.config.get('connect.rdns_access.ini');
+ if (rdns_cfg && rdns_cfg.general && rdns_cfg.general.deny_msg) {
+ plugin.cfg.deny_msg.conn = rdns_cfg.general.deny_msg;
+ }
+ };
+ load_access_ini();
};
exports.init_lists = function () {
var plugin = this;
plugin.list = {
- black: { conn: [], helo: [], mail: [], rcpt: [] },
- white: { conn: [], helo: [], mail: [], rcpt: [] },
- domain: { any: [] },
+ black: { conn: {}, helo: {}, mail: {}, rcpt: {} },
+ white: { conn: {}, helo: {}, mail: {}, rcpt: {} },
+ domain: { any: {} },
};
plugin.list_re = {
black: {},
@@ -145,9 +150,13 @@ exports.any = function (next, connection, params) {
connection.logerror(plugin, "no domain!");
return next();
}
+ if (!/\./.test(domain)) {
+ connection.loginfo(plugin, "invalid domain: " + domain);
+ return next();
+ }
var org_domain = net_utils.get_organizational_domain(domain);
if (!org_domain) {
- connection.logerror(plugin, "no org domain from domain " + domain);
+ connection.logerror(plugin, "no org domain from " + domain);
return next();
}
@@ -337,25 +346,42 @@ exports.rcpt_to_access = function(next, connection, params) {
return next();
};
-exports.valid_regexes = function (list, file) {
- var valid = [];
- for (var i=0; i<list.length; i++) {
- try {
- new RegExp(list[i]);
- }
- catch (e) {
- this.logerror(this, "invalid regex in " + file + ", " + list[i]);
- continue;
- }
- valid.push(list[i]);
+exports.data_any = function(next, connection) {
+ var plugin = this;
+ if (!plugin.cfg.check.data) return next();
+
+ var hdr_from = connection.transaction.header.get('From');
+ if (!hdr_from) {
+ connection.transaction.results.add(plugin, {fail: 'data(missing_from)'});
+ return next();
+ }
+
+ var hdr_addr = (require('address-rfc2822').parse(hdr_from))[0];
+ var hdr_dom = net_utils.get_organizational_domain(hdr_addr.host());
+
+ var file = plugin.cfg.domain.any;
+ if (plugin.in_list('domain', 'any', '!'+hdr_dom)) {
+ connection.results.add(plugin, {pass: file, whitelist: true, emit: true});
+ return next();
}
- return valid;
+
+ if (plugin.in_list('domain', 'any', hdr_dom)) {
+ connection.results.add(plugin, {fail: file+'('+hdr_dom+')', blacklist: true, emit: true});
+ return next(DENY, "Email from that domain is not accepted here.");
+ }
+
+ connection.results.add(plugin, {pass: 'any', emit: true});
+ return next();
};
exports.in_list = function (type, phase, address) {
var plugin = this;
- if (!plugin.list[type][phase]) return false;
- return (plugin.list[type][phase].indexOf(address) === -1) ? false : true;
+ if (!plugin.list[type][phase]) {
+ console.log("phase not defined: " + phase);
+ return false;
+ }
+ if (plugin.list[type][phase][address]) return true;
+ return false;
};
exports.in_re_list = function (type, phase, address) {
@@ -367,6 +393,8 @@ exports.in_re_list = function (type, phase, address) {
exports.in_file = function (file_name, address, connection) {
var plugin = this;
+ // using indexOf on an array here is about 20x slower than testing against
+ // a key in an object
connection.logdebug(plugin, 'checking ' + address + ' against ' + file_name);
return (plugin.config.get(file_name, 'list').indexOf(address) === -1) ? false : true;
};
@@ -376,7 +404,7 @@ exports.in_re_file = function (file_name, address) {
// badly if affected performance. It took 8.5x longer to run than
// in_re_list.
this.logdebug(this, 'checking ' + address + ' against ' + file_name);
- var re_list = this.valid_regexes(this.config.get(file_name, 'list'), file_name);
+ var re_list = utils.valid_regexes(this.config.get(file_name, 'list'), file_name);
for (var i=0; i<re_list.length; i++) {
if (new RegExp('^' + re_list[i] + '$', 'i').test(address)) return true;
}
@@ -394,20 +422,17 @@ exports.load_file = function (type, phase) {
plugin.loginfo(plugin, "loading " + file_name);
// load config with a self-referential callback
- var list = plugin.config.get(file_name, 'list', function () {
- load_em_high();
- });
-
- // convert list items to LC at load, so we don't have to a run time
- for (var i=0; i<list.length; i++) {
- if (list[i] !== list[i].toLowerCase()) list[i] = list[i].toLowerCase();
- }
+ var list = plugin.config.get(file_name, 'list', load_em_high);
// init the list store, type is white or black
if (!plugin.list) plugin.list = {};
if (!plugin.list[type]) plugin.list[type] = {};
- plugin.list[type][phase] = list;
+ // toLower when loading spends a fraction of a second at load time
+ // to save millions of seconds during run time.
+ for (var i=0; i<list.length; i++) {
+ plugin.list[type][list[i].toLowerCase()] = true;
+ }
}
load_em_high();
};
@@ -422,9 +447,7 @@ exports.load_re_file = function (type, phase) {
var file_name = plugin.cfg.re[type][phase];
plugin.loginfo(plugin, "loading " + file_name);
- var regex_list = plugin.valid_regexes(
- plugin.config.get(file_name, 'list', function () {
- load_re(); }));
+ var regex_list = utils.valid_regexes(plugin.config.get(file_name, 'list', load_re));
// initialize the list store
if (!plugin.list_re) plugin.list_re = {};
@@ -446,24 +469,22 @@ exports.load_domain_file = function (type, phase) {
var file_name = plugin.cfg[type][phase];
plugin.loginfo(plugin, "loading " + file_name);
- var list = plugin.config.get(file_name, 'list', function() {
- load_domains();
- });
+ var list = plugin.config.get(file_name, 'list', load_domains);
// init the list store, if needed
if (!plugin.list) plugin.list = {};
if (!plugin.list[type]) plugin.list[type] = {};
- // convert list items to LC at load, so we don't have to at run time
+ // convert list items to LC at load (much faster than at run time)
for (var i=0; i<list.length; i++) {
if (list[i][0] === '!') { // whitelist entry
- plugin.list[type][phase].push(list[i].toLowerCase());
+ plugin.list[type][phase][list[i].toLowerCase()] = true;
continue;
}
var d = net_utils.get_organizational_domain(list[i]);
if (!d) continue;
- plugin.list[type][phase].push(d.toLowerCase());
+ plugin.list[type][phase][d.toLowerCase()] = true;
}
}
load_domains();
View
208 tests/plugins/access.js
@@ -34,7 +34,7 @@ exports.in_list = {
setUp : _set_up,
tearDown : _tear_down,
'white, mail': function (test) {
- var list = ['matt@exam.ple','matt@example.com'];
+ var list = {'matt@exam.ple':true,'matt@example.com':true};
this.plugin.cfg = { white: { mail: 'test no file' }};
this.plugin.list = { white: { mail: list }};
test.expect(3);
@@ -44,7 +44,7 @@ exports.in_list = {
test.done();
},
'white, rcpt': function (test) {
- var list = ['matt@exam.ple','matt@example.com'];
+ var list = {'matt@exam.ple':true,'matt@example.com':true};
this.plugin.cfg = { re: { white: { rcpt: 'test file name' }}};
this.plugin.list = { white: { rcpt: list }};
test.expect(3);
@@ -54,7 +54,7 @@ exports.in_list = {
test.done();
},
'white, helo': function (test) {
- var list = ['matt@exam.ple','matt@example.com'];
+ var list = {'matt@exam.ple':true,'matt@example.com':true};
this.plugin.cfg = { re: { white: { helo: 'test file name' }}};
this.plugin.list = { white: { helo: list }};
test.expect(3);
@@ -64,7 +64,7 @@ exports.in_list = {
test.done();
},
'black, mail': function (test) {
- var list = ['matt@exam.ple','matt@example.com'];
+ var list = {'matt@exam.ple':true,'matt@example.com':true};
this.plugin.cfg = { re: { black: { mail: 'test file name' }}};
this.plugin.list = { black: { mail: list }};
test.expect(3);
@@ -74,7 +74,7 @@ exports.in_list = {
test.done();
},
'black, rcpt': function (test) {
- var list = ['matt@exam.ple','matt@example.com'];
+ var list = {'matt@exam.ple':true,'matt@example.com':true};
this.plugin.cfg = { re: { black: { rcpt: 'test file name' }}};
this.plugin.list = { black: { rcpt: list }};
test.expect(3);
@@ -84,7 +84,7 @@ exports.in_list = {
test.done();
},
'black, helo': function (test) {
- var list = ['matt@exam.ple','matt@example.com'];
+ var list = {'matt@exam.ple':true,'matt@example.com':true};
this.plugin.cfg = { re: { black: { helo: 'test file name' }}};
this.plugin.list = { black: { helo: list }};
test.expect(3);
@@ -160,23 +160,6 @@ exports.in_re_list = {
},
};
-exports.valid_regexes = {
- setUp : _set_up,
- tearDown : _tear_down,
- 'valid': function (test) {
- var re_list = ['.*\.exam.ple','.*\.example.com'];
- test.expect(1);
- test.deepEqual(re_list, this.plugin.valid_regexes(re_list));
- test.done();
- },
- 'invalid': function (test) {
- var re_list = ['*\.exam.ple','.*\.example.com'];
- test.expect(1);
- test.deepEqual(['.*\.example.com'], this.plugin.valid_regexes(re_list));
- test.done();
- },
-};
-
exports.load_re_file = {
setUp : _set_up,
tearDown : _tear_down,
@@ -223,13 +206,12 @@ exports.rdns_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- // console.log(outer.connection.results);
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.results.get('access').pass.length);
+ var cb = function (rc) {
+ // console.log(this.connection.results);
+ test.equal(undefined, rc);
+ test.ok(this.connection.results.get('access').pass.length);
test.done();
- };
+ }.bind(this);
this.connection.remote_ip='1.1.1.1';
this.connection.remote_host='host.example.com';
this.plugin.rdns_access(cb, this.connection);
@@ -238,48 +220,45 @@ exports.rdns_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- // console.log(outer.connection.results.get('access'));
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.results.get('access').pass.length);
- // test.ok(outer.connection.results.has('access', 'pass', /white/));
+ var cb = function (rc) {
+ // console.log(this.connection.results.get('access'));
+ test.equal(undefined, rc);
+ test.ok(this.connection.results.get('access').pass.length);
+ // test.ok(this.connection.results.has('access', 'pass', /white/));
test.done();
- };
+ }.bind(this);
this.connection.remote_ip='1.1.1.1';
this.connection.remote_host='host.example.com';
- this.plugin.list.white.conn.push('host.example.com');
+ this.plugin.list.white.conn['host.example.com']=true;
this.plugin.rdns_access(cb, this.connection);
},
'blacklist': function (test) {
test.expect(3);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- // console.log(outer.connection.results.get('access'));
- test.equal(DENYDISCONNECT, arguments[0]);
- test.equal("host.example.com [1.1.1.1] You are not allowed to connect", arguments[1]);
- test.ok(outer.connection.results.get('access').fail.length);
+ var cb = function (rc, msg) {
+ // console.log(this.connection.results.get('access'));
+ test.equal(DENYDISCONNECT, rc);
+ test.equal("host.example.com [1.1.1.1] You are not allowed to connect", msg);
+ test.ok(this.connection.results.get('access').fail.length);
test.done();
- };
+ }.bind(this);
this.connection.remote_ip='1.1.1.1';
this.connection.remote_host='host.example.com';
- this.plugin.list.black.conn.push('host.example.com');
+ this.plugin.list.black.conn['host.example.com']=true;
this.plugin.rdns_access(cb, this.connection);
},
'blacklist regex': function (test) {
test.expect(3);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- // console.log(outer.connection.results.get('access'));
- test.equal(DENYDISCONNECT, arguments[0]);
- test.equal("host.antispam.com [1.1.1.1] You are not allowed to connect", arguments[1]);
- test.ok(outer.connection.results.get('access').fail.length);
+ var cb = function (rc, msg) {
+ // console.log(this.connection.results.get('access'));
+ test.equal(DENYDISCONNECT, rc);
+ test.equal("host.antispam.com [1.1.1.1] You are not allowed to connect", msg);
+ test.ok(this.connection.results.get('access').fail.length);
test.done();
- };
+ }.bind(this);
this.connection.remote_ip='1.1.1.1';
this.connection.remote_host='host.antispam.com';
var black = [ '.*spam.com' ];
@@ -295,13 +274,12 @@ exports.helo_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- // console.log(outer.connection.results.get('access'));
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.results.get('access').pass.length);
+ var cb = function (rc) {
+ // console.log(this.connection.results.get('access'));
+ test.equal(undefined, rc);
+ test.ok(this.connection.results.get('access').pass.length);
test.done();
- };
+ }.bind(this);
this.plugin.cfg.check.helo=true;
this.plugin.helo_access(cb, this.connection, 'host.example.com');
},
@@ -309,13 +287,12 @@ exports.helo_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(DENY, arguments[0]);
- // console.log(outer.connection.results.get('access'));
- test.ok(outer.connection.results.get('access').fail.length);
+ var cb = function (rc) {
+ test.equal(DENY, rc);
+ // console.log(this.connection.results.get('access'));
+ test.ok(this.connection.results.get('access').fail.length);
test.done();
- };
+ }.bind(this);
var black = [ '.*spam.com' ];
this.plugin.list_re.black.helo = new RegExp('^(' + black.join('|') + ')$', 'i');
this.plugin.helo_access(cb, this.connection, 'bad.spam.com');
@@ -329,50 +306,46 @@ exports.mail_from_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').pass.length);
+ var cb = function (rc) {
+ test.equal(undefined, rc);
+ test.ok(this.connection.transaction.results.get('access').pass.length);
test.done();
- };
+ }.bind(this);
this.plugin.mail_from_access(cb, this.connection, [new Address('<list@unknown.com>')]);
},
'whitelisted addr': function (test) {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').pass.length);
+ var cb = function (rc) {
+ test.equal(undefined, rc);
+ test.ok(this.connection.transaction.results.get('access').pass.length);
test.done();
- };
- this.plugin.list.white.mail.push('list@harakamail.com');
+ }.bind(this);
+ this.plugin.list.white.mail['list@harakamail.com']=true;
this.plugin.mail_from_access(cb, this.connection, [new Address('<list@harakamail.com>')]);
},
'blacklisted addr': function (test) {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(DENY, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').fail.length);
+ var cb = function (rc) {
+ test.equal(DENY, rc);
+ test.ok(this.connection.transaction.results.get('access').fail.length);
test.done();
- };
- this.plugin.list.black.mail.push('list@badmail.com');
+ }.bind(this);
+ this.plugin.list.black.mail['list@badmail.com']=true;
this.plugin.mail_from_access(cb, this.connection, [new Address('<list@badmail.com>')]);
},
'blacklisted domain': function (test) {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(DENY, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').fail.length);
+ var cb = function (rc) {
+ test.equal(DENY, rc);
+ test.ok(this.connection.transaction.results.get('access').fail.length);
test.done();
- };
+ }.bind(this);
var black = [ '.*@spam.com' ];
this.plugin.list_re.black.mail = new RegExp('^(' + black.join('|') + ')$', 'i');
this.plugin.mail_from_access(cb, this.connection, [new Address('<bad@spam.com>')]);
@@ -381,13 +354,12 @@ exports.mail_from_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').pass.length);
+ var cb = function (rc) {
+ test.equal(undefined, rc);
+ test.ok(this.connection.transaction.results.get('access').pass.length);
test.done();
- };
- this.plugin.list.white.mail.push('special@spam.com');
+ }.bind(this);
+ this.plugin.list.white.mail['special@spam.com']=true;
var black = [ '.*@spam.com' ];
this.plugin.list_re.black.mail = new RegExp('^(' + black.join('|') + ')$', 'i');
this.plugin.mail_from_access(cb, this.connection, [new Address('<special@spam.com>')]);
@@ -401,50 +373,46 @@ exports.rcpt_to_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').pass.length);
+ var cb = function (rc) {
+ test.equal(undefined, rc);
+ test.ok(this.connection.transaction.results.get('access').pass.length);
test.done();
- };
+ }.bind(this);
this.plugin.rcpt_to_access(cb, this.connection, [new Address('<user@example.com>')]);
},
'whitelisted addr': function (test) {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').pass.length);
+ var cb = function (rc) {
+ test.equal(undefined, rc);
+ test.ok(this.connection.transaction.results.get('access').pass.length);
test.done();
- };
- this.plugin.list.white.rcpt.push('user@example.com');
+ }.bind(this);
+ this.plugin.list.white.rcpt['user@example.com']=true;
this.plugin.rcpt_to_access(cb, this.connection, [new Address('<user@example.com>')]);
},
'blacklisted addr': function (test) {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(DENY, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').fail.length);
+ var cb = function (rc) {
+ test.equal(DENY, rc);
+ test.ok(this.connection.transaction.results.get('access').fail.length);
test.done();
- };
- this.plugin.list.black.rcpt.push('user@badmail.com');
+ }.bind(this);
+ this.plugin.list.black.rcpt['user@badmail.com']=true;
this.plugin.rcpt_to_access(cb, this.connection, [new Address('<user@badmail.com>')]);
},
'blacklisted domain': function (test) {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(DENY, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').fail.length);
+ var cb = function (rc) {
+ test.equal(DENY, rc);
+ test.ok(this.connection.transaction.results.get('access').fail.length);
test.done();
- };
+ }.bind(this);
var black = [ '.*@spam.com' ];
this.plugin.list_re.black.rcpt = new RegExp('^(' + black.join('|') + ')$', 'i');
this.plugin.rcpt_to_access(cb, this.connection, [new Address('<bad@spam.com>')]);
@@ -453,16 +421,14 @@ exports.rcpt_to_access = {
test.expect(2);
this.plugin.init_config();
this.plugin.init_lists();
- var outer = this;
- var cb = function () {
- test.equal(undefined, arguments[0]);
- test.ok(outer.connection.transaction.results.get('access').pass.length);
+ var cb = function (rc) {
+ test.equal(undefined, rc);
+ test.ok(this.connection.transaction.results.get('access').pass.length);
test.done();
- };
- this.plugin.list.white.rcpt.push('special@spam.com');
+ }.bind(this);
+ this.plugin.list.white.rcpt['special@spam.com'] = true;
var black = [ '.*@spam.com' ];
this.plugin.list_re.black.rcpt = new RegExp('^(' + black.join('|') + ')$', 'i');
this.plugin.rcpt_to_access(cb, this.connection, [new Address('<special@spam.com>')]);
},
};
-
Something went wrong with that request. Please try again.