UNPKG

mx-connect

Version:

Establish TCP connection to a MX server with MTA-STS and DANE/TLSA support

285 lines (263 loc) 8.37 kB
'use strict'; const mxConnect = require('../lib/mx-connect'); const { createMockDnsResolver, createMockSocket } = require('./test-utils'); module.exports.basicWithMock = test => { const mockResolver = createMockDnsResolver({ 'test.example.com:MX': { data: [{ exchange: 'mail.example.com', priority: 10 }] }, 'mail.example.com:A': { data: ['192.0.2.1'] }, 'mail.example.com:AAAA': { error: { code: 'ENODATA' } } }); mxConnect( { target: 'test.example.com', dnsOptions: { resolve: mockResolver }, connectHook(delivery, options, callback) { options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, (err, connection) => { test.ifError(err); test.ok(connection.socket); test.equal(connection.host, '192.0.2.1'); test.done(); } ); }; module.exports.addressWithMock = test => { const mockResolver = createMockDnsResolver({ 'example.com:MX': { data: [{ exchange: 'mail.example.com', priority: 10 }] }, 'mail.example.com:A': { data: ['192.0.2.1'] }, 'mail.example.com:AAAA': { error: { code: 'ENODATA' } } }); mxConnect( { target: 'user@example.com', dnsOptions: { resolve: mockResolver }, connectHook(delivery, options, callback) { options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, (err, connection) => { test.ifError(err); test.ok(connection.socket); test.done(); } ); }; module.exports.preResolvedMx = test => { mxConnect( { target: 'test.example.com', mx: [ { exchange: 'mail.example.com', priority: 10, A: ['192.0.2.1'], AAAA: [] } ], connectHook(delivery, options, callback) { options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, (err, connection) => { test.ifError(err); test.ok(connection.socket); test.equal(connection.host, '192.0.2.1'); test.done(); } ); }; module.exports.dnsFailure = test => { const mockResolver = createMockDnsResolver({ 'fail.example.com:MX': { error: { code: 'SERVFAIL' } } }); mxConnect( { target: 'fail.example.com', dnsOptions: { resolve: mockResolver } }, (err, connection) => { test.ok(err); test.ok(!connection); test.equal(err.category, 'dns'); test.done(); } ); }; module.exports.connectionFailure = test => { const mockResolver = createMockDnsResolver({ 'noconnect.example.com:MX': { data: [{ exchange: 'mail.example.com', priority: 10 }] }, 'mail.example.com:A': { data: ['192.0.2.1'] }, 'mail.example.com:AAAA': { error: { code: 'ENODATA' } } }); mxConnect( { target: 'noconnect.example.com', dnsOptions: { resolve: mockResolver }, connectHook(delivery, options, callback) { const err = new Error('Connection refused'); err.code = 'ECONNREFUSED'; return callback(err); } }, (err, connection) => { test.ok(err); test.ok(!connection); test.done(); } ); }; module.exports.mtaStsDisabled = test => { mxConnect( { target: 'test.example.com', mx: [ { exchange: 'mail.example.com', priority: 10, A: ['192.0.2.1'], AAAA: [] } ], mtaSts: { enabled: false }, connectHook(delivery, options, callback) { options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, (err, connection) => { test.ifError(err); test.ok(connection.socket); test.ok(!connection.policyMatch); test.done(); } ); }; module.exports.customPort = test => { let usedPort = null; mxConnect( { target: 'test.example.com', port: 587, mx: [ { exchange: 'mail.example.com', priority: 10, A: ['192.0.2.1'], AAAA: [] } ], connectHook(delivery, options, callback) { usedPort = options.port; options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, err => { test.ifError(err); test.equal(usedPort, 587); test.done(); } ); }; module.exports.mxPriorityOrdering = test => { let connectedHost = null; mxConnect( { target: 'test.example.com', mx: [ { exchange: 'backup.example.com', priority: 20, A: ['192.0.2.2'], AAAA: [] }, { exchange: 'primary.example.com', priority: 10, A: ['192.0.2.1'], AAAA: [] } ], connectHook(delivery, options, callback) { // Track which host was connected to first connectedHost = options.host; options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, (err, connection) => { test.ifError(err); // Should connect to primary first (lower priority number = higher priority) test.equal(connectedHost, '192.0.2.1'); test.equal(connection.host, '192.0.2.1'); test.done(); } ); }; // Promise-based API tests module.exports.promiseBasic = test => { mxConnect({ target: 'test.example.com', mx: [{ exchange: 'mail.example.com', priority: 10, A: ['192.0.2.1'], AAAA: [] }], connectHook(delivery, options, callback) { options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }) .then(connection => { test.ok(connection.socket); test.equal(connection.host, '192.0.2.1'); test.done(); }) .catch(err => { test.ifError(err); test.done(); }); }; module.exports.promiseRejectsOnError = test => { const mockResolver = createMockDnsResolver({ 'fail.example.com:MX': { error: { code: 'SERVFAIL' } } }); mxConnect({ target: 'fail.example.com', dnsOptions: { resolve: mockResolver } }) .then(() => { test.ok(false, 'Should have rejected'); test.done(); }) .catch(err => { test.ok(err); test.equal(err.category, 'dns'); test.done(); }); }; module.exports.promiseReturnsPromiseWithCallback = test => { // Verify that mxConnect returns a promise even when callback is provided const result = mxConnect( { target: 'test.example.com', mx: [{ exchange: 'mail.example.com', priority: 10, A: ['192.0.2.1'], AAAA: [] }], connectHook(delivery, options, callback) { options.socket = createMockSocket({ remoteAddress: options.host }); return callback(); } }, () => { // Callback provided but not used in this test } ); test.ok(result instanceof Promise, 'Should return a promise when callback is provided'); result .then(connection => { test.ok(connection.socket); test.done(); }) .catch(err => { test.ifError(err); test.done(); }); };