Projektstart

This commit is contained in:
2026-01-22 15:49:12 +01:00
parent 7212eb6f7a
commit 57e5f652f8
10637 changed files with 2598792 additions and 64 deletions

View 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();
};