Projektstart
This commit is contained in:
541
backend/node_modules/imapflow/test/proxy-connection-test.js
generated
vendored
Normal file
541
backend/node_modules/imapflow/test/proxy-connection-test.js
generated
vendored
Normal file
@@ -0,0 +1,541 @@
|
||||
'use strict';
|
||||
|
||||
const proxyquire = require('proxyquire').noCallThru();
|
||||
|
||||
// Mock socket object
|
||||
const createMockSocket = () => ({
|
||||
on: () => {},
|
||||
write: () => {},
|
||||
end: () => {},
|
||||
destroy: () => {}
|
||||
});
|
||||
|
||||
// Mock logger
|
||||
const createMockLogger = () => {
|
||||
const logs = { info: [], error: [] };
|
||||
return {
|
||||
info: msg => logs.info.push(msg),
|
||||
error: msg => logs.error.push(msg),
|
||||
_logs: logs
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// HTTP Proxy Tests
|
||||
// ============================================
|
||||
|
||||
module.exports['Proxy Connection: HTTP proxy success'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(null, mockSocket);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
const socket = await proxyConnection(logger, 'http://proxy.example.com:8080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(socket, mockSocket);
|
||||
test.equal(logger._logs.info.length, 1);
|
||||
test.ok(logger._logs.info[0].msg.includes('HTTP proxy'));
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: HTTPS proxy success'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(null, mockSocket);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
const socket = await proxyConnection(logger, 'https://proxy.example.com:8080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(socket, mockSocket);
|
||||
test.equal(logger._logs.info.length, 1);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: HTTP proxy with password hides it in logs'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(null, mockSocket);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'http://user:secret123@proxy.example.com:8080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(logger._logs.info.length, 1);
|
||||
test.ok(!logger._logs.info[0].proxyUrl.includes('secret123'));
|
||||
test.ok(logger._logs.info[0].proxyUrl.includes('(hidden)'));
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: HTTP proxy failure'] = async test => {
|
||||
const logger = createMockLogger();
|
||||
const testError = new Error('Connection refused');
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(testError);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
try {
|
||||
await proxyConnection(logger, 'http://proxy.example.com:8080', '192.168.1.1', 993);
|
||||
test.ok(false, 'Should have thrown');
|
||||
} catch (err) {
|
||||
test.equal(err, testError);
|
||||
test.equal(logger._logs.error.length, 1);
|
||||
test.ok(logger._logs.error[0].msg.includes('Failed'));
|
||||
}
|
||||
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: HTTP proxy failure hides password'] = async test => {
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(new Error('Failed'));
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
try {
|
||||
await proxyConnection(logger, 'http://user:secret@proxy.example.com:8080', '192.168.1.1', 993);
|
||||
} catch (err) {
|
||||
// Error expected - we just need to verify logging
|
||||
err.expected = true;
|
||||
test.ok(!logger._logs.error[0].proxyUrl.includes('secret'));
|
||||
test.ok(logger._logs.error[0].proxyUrl.includes('(hidden)'));
|
||||
}
|
||||
|
||||
test.done();
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// SOCKS Proxy Tests
|
||||
// ============================================
|
||||
|
||||
module.exports['Proxy Connection: SOCKS5 proxy success'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.type, 5);
|
||||
test.equal(opts.command, 'connect');
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
const socket = await proxyConnection(logger, 'socks5://proxy.example.com:1080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(socket, mockSocket);
|
||||
test.equal(logger._logs.info.length, 1);
|
||||
test.ok(logger._logs.info[0].msg.includes('SOCKS proxy'));
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS proxy (defaults to SOCKS5)'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.type, 5); // Default to SOCKS5
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks://proxy.example.com:1080', '192.168.1.1', 993);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS4 proxy'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.type, 4);
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks4://proxy.example.com:1080', '192.168.1.1', 993);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS4a proxy'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.type, 4);
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks4a://proxy.example.com:1080', '192.168.1.1', 993);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS proxy with authentication'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.userId, 'testuser');
|
||||
test.equal(opts.proxy.password, 'testpass');
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks5://testuser:testpass@proxy.example.com:1080', '192.168.1.1', 993);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS proxy hides password in logs'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async () => ({ socket: mockSocket })
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks5://user:secretpass@proxy.example.com:1080', '192.168.1.1', 993);
|
||||
|
||||
test.ok(!logger._logs.info[0].proxyUrl.includes('secretpass'));
|
||||
test.ok(logger._logs.info[0].proxyUrl.includes('(hidden)'));
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS proxy default port'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.port, 1080); // Default SOCKS port
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks5://proxy.example.com', '192.168.1.1', 993);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS proxy failure'] = async test => {
|
||||
const logger = createMockLogger();
|
||||
const testError = new Error('SOCKS connection failed');
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async () => {
|
||||
throw testError;
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
try {
|
||||
await proxyConnection(logger, 'socks5://proxy.example.com:1080', '192.168.1.1', 993);
|
||||
test.ok(false, 'Should have thrown');
|
||||
} catch (err) {
|
||||
test.equal(err, testError);
|
||||
test.equal(logger._logs.error.length, 1);
|
||||
test.ok(logger._logs.error[0].msg.includes('Failed'));
|
||||
}
|
||||
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS proxy failure hides password'] = async test => {
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async () => {
|
||||
throw new Error('Failed');
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
try {
|
||||
await proxyConnection(logger, 'socks5://user:secret@proxy.example.com:1080', '192.168.1.1', 993);
|
||||
} catch (err) {
|
||||
// Error expected - we just need to verify logging
|
||||
err.expected = true;
|
||||
test.ok(!logger._logs.error[0].proxyUrl.includes('secret'));
|
||||
test.ok(logger._logs.error[0].proxyUrl.includes('(hidden)'));
|
||||
}
|
||||
|
||||
test.done();
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// DNS Resolution Tests
|
||||
// ============================================
|
||||
|
||||
module.exports['Proxy Connection: Resolves hostname to IP'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
let resolvedHost = null;
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
resolvedHost = host;
|
||||
cb(null, mockSocket);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: {
|
||||
promises: {
|
||||
resolve: async hostname => {
|
||||
if (hostname === 'mail.example.com') {
|
||||
return ['93.184.216.34'];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
net: { isIP: host => /^\d+\.\d+\.\d+\.\d+$/.test(host) }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'http://proxy.example.com:8080', 'mail.example.com', 993);
|
||||
|
||||
test.equal(resolvedHost, '93.184.216.34');
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: Skips DNS for IP addresses'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
let dnsResolveCalled = false;
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(null, mockSocket);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: {
|
||||
promises: {
|
||||
resolve: async () => {
|
||||
dnsResolveCalled = true;
|
||||
return ['127.0.0.1'];
|
||||
}
|
||||
}
|
||||
},
|
||||
net: { isIP: () => true } // Pretend it's already an IP
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'http://proxy.example.com:8080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(dnsResolveCalled, false);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS resolves proxy hostname'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
let proxyHostResolved = null;
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
proxyHostResolved = opts.proxy.host;
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: {
|
||||
promises: {
|
||||
resolve: async hostname => {
|
||||
if (hostname === 'proxy.example.com') {
|
||||
return ['10.0.0.1'];
|
||||
}
|
||||
return ['127.0.0.1'];
|
||||
}
|
||||
}
|
||||
},
|
||||
net: { isIP: host => /^\d+\.\d+\.\d+\.\d+$/.test(host) }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks5://proxy.example.com:1080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(proxyHostResolved, '10.0.0.1');
|
||||
test.done();
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// Edge Cases
|
||||
// ============================================
|
||||
|
||||
module.exports['Proxy Connection: Unknown protocol returns undefined'] = async test => {
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
const result = await proxyConnection(logger, 'ftp://proxy.example.com:21', '192.168.1.1', 993);
|
||||
|
||||
test.equal(result, undefined);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: HTTP proxy with no socket returned'] = async test => {
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
cb(null, null); // No socket
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
const socket = await proxyConnection(logger, 'http://proxy.example.com:8080', '192.168.1.1', 993);
|
||||
|
||||
test.equal(socket, null);
|
||||
// No log when socket is null
|
||||
test.equal(logger._logs.info.length, 0);
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: DNS returns empty result'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
let usedHost = null;
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': (url, port, host, cb) => {
|
||||
usedHost = host;
|
||||
cb(null, mockSocket);
|
||||
},
|
||||
socks: { SocksClient: {} },
|
||||
dns: {
|
||||
promises: {
|
||||
resolve: async () => [] // Empty result
|
||||
}
|
||||
},
|
||||
net: { isIP: () => false }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'http://proxy.example.com:8080', 'mail.example.com', 993);
|
||||
|
||||
// Should keep original hostname when DNS returns empty
|
||||
test.equal(usedHost, 'mail.example.com');
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports['Proxy Connection: SOCKS with username only'] = async test => {
|
||||
const mockSocket = createMockSocket();
|
||||
const logger = createMockLogger();
|
||||
|
||||
const { proxyConnection } = proxyquire('../lib/proxy-connection', {
|
||||
'nodemailer/lib/smtp-connection/http-proxy-client': () => {},
|
||||
socks: {
|
||||
SocksClient: {
|
||||
createConnection: async opts => {
|
||||
test.equal(opts.proxy.userId, 'testuser');
|
||||
test.equal(opts.proxy.password, ''); // Empty string from URL parsing
|
||||
return { socket: mockSocket };
|
||||
}
|
||||
}
|
||||
},
|
||||
dns: { promises: { resolve: async () => ['127.0.0.1'] } },
|
||||
net: { isIP: () => true }
|
||||
});
|
||||
|
||||
await proxyConnection(logger, 'socks5://testuser@proxy.example.com:1080', '192.168.1.1', 993);
|
||||
test.done();
|
||||
};
|
||||
Reference in New Issue
Block a user