imapflow 1.7.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +8 -2
- package/dist/cjs/charsets.d.ts +1 -0
- package/dist/cjs/charsets.js +294 -0
- package/dist/cjs/commands/append.d.ts +22 -0
- package/dist/cjs/commands/append.js +151 -0
- package/dist/cjs/commands/authenticate.d.ts +24 -0
- package/dist/cjs/commands/authenticate.js +223 -0
- package/dist/cjs/commands/capability.d.ts +8 -0
- package/dist/cjs/commands/capability.js +32 -0
- package/dist/cjs/commands/close.d.ts +8 -0
- package/dist/cjs/commands/close.js +39 -0
- package/dist/cjs/commands/compress.d.ts +8 -0
- package/dist/cjs/commands/compress.js +56 -0
- package/dist/cjs/commands/copy.d.ts +13 -0
- package/dist/cjs/commands/copy.js +44 -0
- package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
- package/dist/cjs/commands/copyuid-parser.js +32 -0
- package/dist/cjs/commands/create.d.ts +11 -0
- package/dist/cjs/commands/create.js +80 -0
- package/dist/cjs/commands/delete.d.ts +11 -0
- package/dist/cjs/commands/delete.js +40 -0
- package/dist/cjs/commands/enable.d.ts +9 -0
- package/dist/cjs/commands/enable.js +61 -0
- package/dist/cjs/commands/esearch-parser.d.ts +17 -0
- package/dist/cjs/commands/esearch-parser.js +91 -0
- package/dist/cjs/commands/expunge.d.ts +12 -0
- package/dist/cjs/commands/expunge.js +60 -0
- package/dist/cjs/commands/fetch.d.ts +30 -0
- package/dist/cjs/commands/fetch.js +241 -0
- package/dist/cjs/commands/id.d.ts +10 -0
- package/dist/cjs/commands/id.js +80 -0
- package/dist/cjs/commands/idle.d.ts +9 -0
- package/dist/cjs/commands/idle.js +347 -0
- package/dist/cjs/commands/list.d.ts +16 -0
- package/dist/cjs/commands/list.js +518 -0
- package/dist/cjs/commands/login.d.ts +11 -0
- package/dist/cjs/commands/login.js +42 -0
- package/dist/cjs/commands/logout.d.ts +8 -0
- package/dist/cjs/commands/logout.js +47 -0
- package/dist/cjs/commands/move.d.ts +13 -0
- package/dist/cjs/commands/move.js +57 -0
- package/dist/cjs/commands/namespace.d.ts +25 -0
- package/dist/cjs/commands/namespace.js +139 -0
- package/dist/cjs/commands/noop.d.ts +8 -0
- package/dist/cjs/commands/noop.js +22 -0
- package/dist/cjs/commands/quota.d.ts +10 -0
- package/dist/cjs/commands/quota.js +119 -0
- package/dist/cjs/commands/rename.d.ts +12 -0
- package/dist/cjs/commands/rename.js +48 -0
- package/dist/cjs/commands/search.d.ts +15 -0
- package/dist/cjs/commands/search.js +228 -0
- package/dist/cjs/commands/select.d.ts +25 -0
- package/dist/cjs/commands/select.js +250 -0
- package/dist/cjs/commands/starttls.d.ts +8 -0
- package/dist/cjs/commands/starttls.js +30 -0
- package/dist/cjs/commands/status-fields.d.ts +14 -0
- package/dist/cjs/commands/status-fields.js +61 -0
- package/dist/cjs/commands/status.d.ts +12 -0
- package/dist/cjs/commands/status.js +108 -0
- package/dist/cjs/commands/store.d.ts +19 -0
- package/dist/cjs/commands/store.js +93 -0
- package/dist/cjs/commands/subscribe.d.ts +9 -0
- package/dist/cjs/commands/subscribe.js +31 -0
- package/dist/cjs/commands/unsubscribe.d.ts +9 -0
- package/dist/cjs/commands/unsubscribe.js +31 -0
- package/dist/cjs/connection-deadline.d.ts +49 -0
- package/dist/cjs/connection-deadline.js +91 -0
- package/dist/cjs/errors.d.ts +83 -0
- package/dist/cjs/errors.js +13 -0
- package/dist/cjs/handler/imap-compiler.d.ts +24 -0
- package/dist/cjs/handler/imap-compiler.js +285 -0
- package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/cjs/handler/imap-formal-syntax.js +121 -0
- package/dist/cjs/handler/imap-handler.d.ts +9 -0
- package/dist/cjs/handler/imap-handler.js +10 -0
- package/dist/cjs/handler/imap-parser.d.ts +16 -0
- package/dist/cjs/handler/imap-parser.js +90 -0
- package/dist/cjs/handler/imap-stream.d.ts +181 -0
- package/dist/cjs/handler/imap-stream.js +446 -0
- package/dist/cjs/handler/limits.d.ts +25 -0
- package/dist/cjs/handler/limits.js +51 -0
- package/dist/cjs/handler/parser-instance.d.ts +68 -0
- package/dist/cjs/handler/parser-instance.js +223 -0
- package/dist/cjs/handler/token-parser.d.ts +91 -0
- package/dist/cjs/handler/token-parser.js +673 -0
- package/dist/cjs/handler/types.d.ts +91 -0
- package/dist/cjs/handler/types.js +4 -0
- package/dist/cjs/imap-commands.d.ts +16 -0
- package/dist/cjs/imap-commands.js +74 -0
- package/dist/cjs/imap-flow.d.ts +676 -0
- package/dist/cjs/imap-flow.js +3949 -0
- package/dist/cjs/jp-decoder.d.ts +12 -0
- package/dist/cjs/jp-decoder.js +79 -0
- package/dist/cjs/limited-passthrough.d.ts +25 -0
- package/dist/cjs/limited-passthrough.js +54 -0
- package/dist/cjs/logger.d.ts +3 -0
- package/dist/cjs/logger.js +11 -0
- package/dist/cjs/package-info.d.ts +3 -0
- package/dist/cjs/package-info.js +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/proxy-connection.d.ts +33 -0
- package/dist/cjs/proxy-connection.js +392 -0
- package/dist/cjs/search-compiler.d.ts +34 -0
- package/dist/cjs/search-compiler.js +476 -0
- package/dist/cjs/special-use.d.ts +22 -0
- package/dist/cjs/special-use.js +911 -0
- package/dist/cjs/tools.d.ts +427 -0
- package/dist/cjs/tools.js +1496 -0
- package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +386 -516
- package/dist/cjs/types.js +5 -0
- package/dist/esm/charsets.d.ts +1 -0
- package/{lib → dist/esm}/charsets.js +1 -6
- package/dist/esm/commands/append.d.ts +22 -0
- package/{lib → dist/esm}/commands/append.js +22 -52
- package/dist/esm/commands/authenticate.d.ts +24 -0
- package/{lib → dist/esm}/commands/authenticate.js +62 -87
- package/dist/esm/commands/capability.d.ts +8 -0
- package/{lib → dist/esm}/commands/capability.js +6 -9
- package/dist/esm/commands/close.d.ts +8 -0
- package/{lib → dist/esm}/commands/close.js +6 -10
- package/dist/esm/commands/compress.d.ts +8 -0
- package/{lib → dist/esm}/commands/compress.js +7 -11
- package/dist/esm/commands/copy.d.ts +13 -0
- package/{lib → dist/esm}/commands/copy.js +12 -20
- package/dist/esm/commands/copyuid-parser.d.ts +11 -0
- package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
- package/dist/esm/commands/create.d.ts +11 -0
- package/{lib → dist/esm}/commands/create.js +13 -27
- package/dist/esm/commands/delete.d.ts +11 -0
- package/{lib → dist/esm}/commands/delete.js +9 -14
- package/dist/esm/commands/enable.d.ts +9 -0
- package/{lib → dist/esm}/commands/enable.js +23 -30
- package/dist/esm/commands/esearch-parser.d.ts +17 -0
- package/dist/esm/commands/esearch-parser.js +88 -0
- package/dist/esm/commands/expunge.d.ts +12 -0
- package/{lib → dist/esm}/commands/expunge.js +17 -22
- package/dist/esm/commands/fetch.d.ts +30 -0
- package/{lib → dist/esm}/commands/fetch.js +32 -64
- package/dist/esm/commands/id.d.ts +10 -0
- package/{lib → dist/esm}/commands/id.js +17 -23
- package/dist/esm/commands/idle.d.ts +9 -0
- package/{lib → dist/esm}/commands/idle.js +47 -81
- package/dist/esm/commands/list.d.ts +16 -0
- package/{lib → dist/esm}/commands/list.js +56 -121
- package/dist/esm/commands/login.d.ts +11 -0
- package/{lib → dist/esm}/commands/login.js +10 -15
- package/dist/esm/commands/logout.d.ts +8 -0
- package/{lib → dist/esm}/commands/logout.js +9 -11
- package/dist/esm/commands/move.d.ts +13 -0
- package/{lib → dist/esm}/commands/move.js +13 -21
- package/dist/esm/commands/namespace.d.ts +25 -0
- package/{lib → dist/esm}/commands/namespace.js +34 -44
- package/dist/esm/commands/noop.d.ts +8 -0
- package/{lib → dist/esm}/commands/noop.js +6 -7
- package/dist/esm/commands/quota.d.ts +10 -0
- package/{lib → dist/esm}/commands/quota.js +18 -36
- package/dist/esm/commands/rename.d.ts +12 -0
- package/{lib → dist/esm}/commands/rename.js +10 -15
- package/dist/esm/commands/search.d.ts +15 -0
- package/{lib → dist/esm}/commands/search.js +36 -135
- package/dist/esm/commands/select.d.ts +25 -0
- package/{lib → dist/esm}/commands/select.js +33 -64
- package/dist/esm/commands/starttls.d.ts +8 -0
- package/{lib → dist/esm}/commands/starttls.js +6 -8
- package/dist/esm/commands/status-fields.d.ts +14 -0
- package/{lib → dist/esm}/commands/status-fields.js +5 -16
- package/dist/esm/commands/status.d.ts +12 -0
- package/{lib → dist/esm}/commands/status.js +18 -29
- package/dist/esm/commands/store.d.ts +19 -0
- package/{lib → dist/esm}/commands/store.js +24 -37
- package/dist/esm/commands/subscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/subscribe.js +8 -12
- package/dist/esm/commands/unsubscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
- package/dist/esm/connection-deadline.d.ts +49 -0
- package/{lib → dist/esm}/connection-deadline.js +14 -25
- package/dist/esm/errors.d.ts +83 -0
- package/dist/esm/errors.js +9 -0
- package/dist/esm/handler/imap-compiler.d.ts +24 -0
- package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
- package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/esm/handler/imap-formal-syntax.js +117 -0
- package/dist/esm/handler/imap-handler.d.ts +9 -0
- package/dist/esm/handler/imap-handler.js +9 -0
- package/dist/esm/handler/imap-parser.d.ts +16 -0
- package/{lib → dist/esm}/handler/imap-parser.js +31 -44
- package/dist/esm/handler/imap-stream.d.ts +181 -0
- package/{lib → dist/esm}/handler/imap-stream.js +29 -121
- package/dist/esm/handler/limits.d.ts +25 -0
- package/{lib → dist/esm}/handler/limits.js +13 -22
- package/dist/esm/handler/parser-instance.d.ts +68 -0
- package/{lib → dist/esm}/handler/parser-instance.js +19 -47
- package/dist/esm/handler/token-parser.d.ts +91 -0
- package/{lib → dist/esm}/handler/token-parser.js +71 -155
- package/dist/esm/handler/types.d.ts +91 -0
- package/dist/esm/handler/types.js +3 -0
- package/dist/esm/imap-commands.d.ts +16 -0
- package/dist/esm/imap-commands.js +67 -0
- package/dist/esm/imap-flow.d.ts +676 -0
- package/{lib → dist/esm}/imap-flow.js +761 -1789
- package/dist/esm/jp-decoder.d.ts +12 -0
- package/{lib → dist/esm}/jp-decoder.js +6 -21
- package/dist/esm/limited-passthrough.d.ts +25 -0
- package/{lib → dist/esm}/limited-passthrough.js +7 -20
- package/dist/esm/logger.d.ts +3 -0
- package/dist/esm/logger.js +4 -0
- package/dist/esm/package-info.d.ts +3 -0
- package/dist/esm/package-info.js +4 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/proxy-connection.d.ts +33 -0
- package/{lib → dist/esm}/proxy-connection.js +56 -127
- package/dist/esm/search-compiler.d.ts +34 -0
- package/{lib → dist/esm}/search-compiler.js +54 -110
- package/dist/esm/special-use.d.ts +22 -0
- package/dist/esm/special-use.js +907 -0
- package/dist/esm/tools.d.ts +427 -0
- package/dist/esm/tools.js +1446 -0
- package/dist/esm/types.d.ts +828 -0
- package/dist/esm/types.js +4 -0
- package/package.json +60 -20
- package/.gitattributes +0 -1
- package/.github/CODE_OF_CONDUCT.md +0 -76
- package/.github/FUNDING.yml +0 -4
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/.github/contributing.md +0 -17
- package/.github/workflows/release.yaml +0 -36
- package/.github/workflows/stale.yml +0 -29
- package/.github/workflows/test.yml +0 -51
- package/.ncurc.js +0 -4
- package/.prettierignore +0 -4
- package/.prettierrc.js +0 -8
- package/.release-please-manifest.json +0 -3
- package/CLAUDE.md +0 -104
- package/Gruntfile.js +0 -23
- package/eslint.config.js +0 -45
- package/lib/handler/imap-formal-syntax.js +0 -189
- package/lib/handler/imap-handler.js +0 -17
- package/lib/imap-commands.js +0 -45
- package/lib/logger.js +0 -5
- package/lib/special-use.js +0 -923
- package/lib/tools.js +0 -1612
- package/release-please-config.json +0 -10
- package/test/authentication-test.js +0 -101
- package/test/auto-idle-test.js +0 -470
- package/test/bodystructure-test.js +0 -899
- package/test/charsets-test.js +0 -161
- package/test/commands-branches-test.js +0 -1095
- package/test/commands-integration-test.js +0 -11124
- package/test/commands-test.js +0 -73
- package/test/connection-edge-cases-test.js +0 -1828
- package/test/connection-test.js +0 -162
- package/test/copyuid-parser-test.js +0 -173
- package/test/fetch-generator-test.js +0 -218
- package/test/fixtures/fake-timers.js +0 -115
- package/test/fixtures/serialized-mimetorture.js +0 -2738
- package/test/fixtures/test-client.js +0 -101
- package/test/fixtures/test-tls.js +0 -8
- package/test/handler-branches-test.js +0 -310
- package/test/idle-polling-test.js +0 -518
- package/test/imap-compiler-test.js +0 -809
- package/test/imap-flow-compress-test.js +0 -166
- package/test/imap-flow-coverage-test.js +0 -612
- package/test/imap-flow-fetch-download-test.js +0 -909
- package/test/imap-flow-internals-test.js +0 -725
- package/test/imap-flow-methods-test.js +0 -889
- package/test/imap-flow-proxy-paths-test.js +0 -366
- package/test/imap-flow-secure-test.js +0 -573
- package/test/imap-flow-server-test.js +0 -1474
- package/test/imap-formal-syntax-test.js +0 -293
- package/test/imap-parser-test.js +0 -1474
- package/test/imap-stream-edge-cases-test.js +0 -666
- package/test/imap-stream-test.js +0 -177
- package/test/imapflow-test.js +0 -258
- package/test/integration/README.md +0 -52
- package/test/integration/dovecot-test.conf +0 -27
- package/test/integration/rev2-live-test.js +0 -431
- package/test/integration/run-rev2-tests.sh +0 -75
- package/test/integration-test.js +0 -83
- package/test/jp-decoder-test.js +0 -304
- package/test/limited-passthrough-test.js +0 -299
- package/test/memory-cleanup-test.js +0 -144
- package/test/memory-leak-test.js +0 -667
- package/test/parser-limits-test.js +0 -292
- package/test/proxy-connection-test.js +0 -738
- package/test/reliability-improvements-test.js +0 -548
- package/test/search-compiler-test.js +0 -1300
- package/test/search-test.js +0 -329
- package/test/special-use-test.js +0 -418
- package/test/starttls-injection-test.js +0 -181
- package/test/tag-correlation-test.js +0 -333
- package/test/timer-policy-test.js +0 -227
- package/test/token-parser-test.js +0 -456
- package/test/tools-test.js +0 -2013
- package/test/unhandled-rejection-test.js +0 -661
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Exercises connect()'s proxy code path by injecting a mocked proxyConnection
|
|
4
|
-
// (via proxyquire) that returns a cleartext socket connected to an in-process
|
|
5
|
-
// mock IMAP server. Also covers the proxy-setup failure path.
|
|
6
|
-
|
|
7
|
-
const net = require('net');
|
|
8
|
-
const tls = require('tls');
|
|
9
|
-
const proxyquire = require('proxyquire');
|
|
10
|
-
const { cert, key } = require('./fixtures/test-tls');
|
|
11
|
-
const { ImapFlow } = require('../lib/imap-flow');
|
|
12
|
-
|
|
13
|
-
const CAPS = 'IMAP4rev1 ID ENABLE NAMESPACE';
|
|
14
|
-
|
|
15
|
-
// Minimal mock IMAP server (plaintext) sufficient for a full session.
|
|
16
|
-
const createServer = () =>
|
|
17
|
-
net.createServer(socket => {
|
|
18
|
-
socket.on('error', () => {});
|
|
19
|
-
let buf = '';
|
|
20
|
-
socket.on('data', data => {
|
|
21
|
-
buf += data.toString('binary');
|
|
22
|
-
let idx;
|
|
23
|
-
while ((idx = buf.indexOf('\r\n')) >= 0) {
|
|
24
|
-
let line = buf.slice(0, idx);
|
|
25
|
-
buf = buf.slice(idx + 2);
|
|
26
|
-
let parts = line.split(' ');
|
|
27
|
-
let tag = parts[0];
|
|
28
|
-
let cmd = (parts[1] || '').toUpperCase();
|
|
29
|
-
switch (cmd) {
|
|
30
|
-
case 'CAPABILITY':
|
|
31
|
-
socket.write(`* CAPABILITY ${CAPS}\r\n${tag} OK done\r\n`);
|
|
32
|
-
break;
|
|
33
|
-
case 'ID':
|
|
34
|
-
socket.write(`* ID ("name" "mock" "version" "1")\r\n${tag} OK done\r\n`);
|
|
35
|
-
break;
|
|
36
|
-
case 'LOGIN':
|
|
37
|
-
socket.write(`${tag} OK LOGIN done\r\n`);
|
|
38
|
-
break;
|
|
39
|
-
case 'NAMESPACE':
|
|
40
|
-
socket.write(`* NAMESPACE (("" "/")) NIL NIL\r\n${tag} OK done\r\n`);
|
|
41
|
-
break;
|
|
42
|
-
case 'ENABLE':
|
|
43
|
-
socket.write(`${tag} OK done\r\n`);
|
|
44
|
-
break;
|
|
45
|
-
case 'LOGOUT':
|
|
46
|
-
socket.write(`* BYE bye\r\n${tag} OK done\r\n`);
|
|
47
|
-
break;
|
|
48
|
-
default:
|
|
49
|
-
socket.write(`${tag} OK ok\r\n`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
socket.write(`* OK [CAPABILITY ${CAPS}] ready\r\n`);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const listen = server => new Promise(resolve => server.listen(0, '127.0.0.1', () => resolve(server.address().port)));
|
|
57
|
-
|
|
58
|
-
module.exports['Proxy: cleartext connection established through a proxy socket'] = async test => {
|
|
59
|
-
let server = createServer();
|
|
60
|
-
let port = await listen(server);
|
|
61
|
-
|
|
62
|
-
// Mock proxyConnection to hand back a real cleartext socket to our server.
|
|
63
|
-
const { ImapFlow } = proxyquire('../lib/imap-flow', {
|
|
64
|
-
'./proxy-connection': {
|
|
65
|
-
proxyConnection: async () => net.connect(port, '127.0.0.1'),
|
|
66
|
-
detachEarlyErrorHandler: () => {}
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
let client = new ImapFlow({
|
|
71
|
-
host: '127.0.0.1',
|
|
72
|
-
port,
|
|
73
|
-
secure: false,
|
|
74
|
-
proxy: 'socks://127.0.0.1:1080',
|
|
75
|
-
disableAutoIdle: true,
|
|
76
|
-
disableCompression: true,
|
|
77
|
-
logger: false,
|
|
78
|
-
auth: { user: 'test', pass: 'secret' }
|
|
79
|
-
});
|
|
80
|
-
client.on('error', () => {});
|
|
81
|
-
|
|
82
|
-
await client.connect();
|
|
83
|
-
test.ok(client.usable, 'session established over the proxied socket');
|
|
84
|
-
test.ok(client.authenticated);
|
|
85
|
-
|
|
86
|
-
await client.logout();
|
|
87
|
-
client.close();
|
|
88
|
-
server.close();
|
|
89
|
-
test.done();
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
module.exports['Proxy: TLS connection established through a proxy socket'] = async test => {
|
|
93
|
-
let server = tls.createServer({ cert, key }, socket => {
|
|
94
|
-
socket.on('error', () => {});
|
|
95
|
-
let buf = '';
|
|
96
|
-
socket.on('data', data => {
|
|
97
|
-
buf += data.toString('binary');
|
|
98
|
-
let idx;
|
|
99
|
-
while ((idx = buf.indexOf('\r\n')) >= 0) {
|
|
100
|
-
let line = buf.slice(0, idx);
|
|
101
|
-
buf = buf.slice(idx + 2);
|
|
102
|
-
let parts = line.split(' ');
|
|
103
|
-
let tag = parts[0];
|
|
104
|
-
let cmd = (parts[1] || '').toUpperCase();
|
|
105
|
-
if (cmd === 'CAPABILITY') socket.write(`* CAPABILITY ${CAPS}\r\n${tag} OK done\r\n`);
|
|
106
|
-
else if (cmd === 'ID') socket.write(`* ID ("name" "m")\r\n${tag} OK done\r\n`);
|
|
107
|
-
else if (cmd === 'NAMESPACE') socket.write(`* NAMESPACE (("" "/")) NIL NIL\r\n${tag} OK done\r\n`);
|
|
108
|
-
else if (cmd === 'LOGOUT') socket.write(`* BYE bye\r\n${tag} OK done\r\n`);
|
|
109
|
-
else socket.write(`${tag} OK ok\r\n`);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
socket.write(`* OK [CAPABILITY ${CAPS}] ready\r\n`);
|
|
113
|
-
});
|
|
114
|
-
let port = await listen(server);
|
|
115
|
-
|
|
116
|
-
// proxyConnection returns a plaintext TCP socket; the client then wraps it in TLS.
|
|
117
|
-
const { ImapFlow } = proxyquire('../lib/imap-flow', {
|
|
118
|
-
'./proxy-connection': {
|
|
119
|
-
proxyConnection: async () => net.connect(port, '127.0.0.1'),
|
|
120
|
-
detachEarlyErrorHandler: () => {}
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
let client = new ImapFlow({
|
|
125
|
-
host: '127.0.0.1',
|
|
126
|
-
port,
|
|
127
|
-
secure: true,
|
|
128
|
-
servername: 'localhost',
|
|
129
|
-
tls: { rejectUnauthorized: false },
|
|
130
|
-
proxy: 'socks://127.0.0.1:1080',
|
|
131
|
-
disableAutoIdle: true,
|
|
132
|
-
disableCompression: true,
|
|
133
|
-
logger: false,
|
|
134
|
-
auth: { user: 'test', pass: 'secret' }
|
|
135
|
-
});
|
|
136
|
-
client.on('error', () => {});
|
|
137
|
-
|
|
138
|
-
await client.connect();
|
|
139
|
-
test.ok(client.secureConnection, 'TLS handshake over the proxy socket');
|
|
140
|
-
test.ok(client.usable);
|
|
141
|
-
|
|
142
|
-
await client.logout();
|
|
143
|
-
client.close();
|
|
144
|
-
server.close();
|
|
145
|
-
test.done();
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
module.exports['Proxy: a null proxy socket rejects connect'] = async test => {
|
|
149
|
-
const { ImapFlow } = proxyquire('../lib/imap-flow', {
|
|
150
|
-
'./proxy-connection': {
|
|
151
|
-
proxyConnection: async () => null, // proxy setup yields no socket
|
|
152
|
-
detachEarlyErrorHandler: () => {}
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
let client = new ImapFlow({
|
|
157
|
-
host: '127.0.0.1',
|
|
158
|
-
port: 1,
|
|
159
|
-
secure: false,
|
|
160
|
-
proxy: 'socks://127.0.0.1:1080',
|
|
161
|
-
disableAutoIdle: true,
|
|
162
|
-
disableCompression: true,
|
|
163
|
-
logger: false,
|
|
164
|
-
auth: { user: 'test', pass: 'secret' }
|
|
165
|
-
});
|
|
166
|
-
client.on('error', () => {});
|
|
167
|
-
|
|
168
|
-
let err = null;
|
|
169
|
-
try {
|
|
170
|
-
await client.connect();
|
|
171
|
-
} catch (e) {
|
|
172
|
-
err = e;
|
|
173
|
-
}
|
|
174
|
-
test.ok(err, 'connect rejected when proxy returns no socket');
|
|
175
|
-
test.equal(err.code, 'ProxyError');
|
|
176
|
-
|
|
177
|
-
client.close();
|
|
178
|
-
test.done();
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
module.exports['Proxy: proxyConnection throwing rejects connect'] = async test => {
|
|
182
|
-
const { ImapFlow } = proxyquire('../lib/imap-flow', {
|
|
183
|
-
'./proxy-connection': {
|
|
184
|
-
proxyConnection: async () => {
|
|
185
|
-
let e = new Error('SOCKS handshake failed');
|
|
186
|
-
e.code = 'ESOCKS';
|
|
187
|
-
throw e;
|
|
188
|
-
},
|
|
189
|
-
detachEarlyErrorHandler: () => {}
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
let client = new ImapFlow({
|
|
194
|
-
host: '127.0.0.1',
|
|
195
|
-
port: 1,
|
|
196
|
-
secure: false,
|
|
197
|
-
proxy: 'socks://127.0.0.1:1080',
|
|
198
|
-
disableAutoIdle: true,
|
|
199
|
-
disableCompression: true,
|
|
200
|
-
logger: false,
|
|
201
|
-
auth: { user: 'test', pass: 'secret' }
|
|
202
|
-
});
|
|
203
|
-
client.on('error', () => {});
|
|
204
|
-
|
|
205
|
-
let err = null;
|
|
206
|
-
try {
|
|
207
|
-
await client.connect();
|
|
208
|
-
} catch (e) {
|
|
209
|
-
err = e;
|
|
210
|
-
}
|
|
211
|
-
test.ok(err);
|
|
212
|
-
test.equal(err.code, 'ESOCKS');
|
|
213
|
-
|
|
214
|
-
client.close();
|
|
215
|
-
test.done();
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
// ---------------------------------------------------------------------------
|
|
219
|
-
// End to end through a real HTTP CONNECT proxy (ImapFlow's own CONNECT helper)
|
|
220
|
-
// ---------------------------------------------------------------------------
|
|
221
|
-
|
|
222
|
-
// Minimal HTTP CONNECT proxy. `onConnect(socket, headers)` may take over the exchange (used to
|
|
223
|
-
// simulate a proxy that never answers); otherwise the tunnel is established and piped. With
|
|
224
|
-
// `coalesce`, the 200 response is held back until the destination speaks and then written in the
|
|
225
|
-
// same segment as the destination's greeting - which is what a real proxy often does.
|
|
226
|
-
const createHttpProxy = (onConnect, { coalesce = false } = {}) =>
|
|
227
|
-
net.createServer(socket => {
|
|
228
|
-
socket.on('error', () => {});
|
|
229
|
-
let buf = '';
|
|
230
|
-
const onData = data => {
|
|
231
|
-
buf += data.toString('binary');
|
|
232
|
-
let idx = buf.indexOf('\r\n\r\n');
|
|
233
|
-
if (idx < 0) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
socket.removeListener('data', onData);
|
|
237
|
-
let headers = buf.slice(0, idx);
|
|
238
|
-
let rest = buf.slice(idx + 4);
|
|
239
|
-
let authority = (headers.split('\r\n')[0].match(/^CONNECT (\S+)/) || [])[1] || '';
|
|
240
|
-
|
|
241
|
-
if (onConnect && onConnect(socket, headers)) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
let [, targetPort] = authority.split(':');
|
|
246
|
-
let upstream = net.connect(Number(targetPort), '127.0.0.1', () => {
|
|
247
|
-
if (rest) {
|
|
248
|
-
upstream.write(Buffer.from(rest, 'binary'));
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const startTunnel = () => {
|
|
252
|
-
socket.pipe(upstream);
|
|
253
|
-
upstream.pipe(socket);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
if (!coalesce) {
|
|
257
|
-
socket.write('HTTP/1.1 200 Connection established\r\n\r\n');
|
|
258
|
-
return startTunnel();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Hold the CONNECT response until the destination sends something, then emit both
|
|
262
|
-
// in a single write so the client has to preserve the trailing bytes itself.
|
|
263
|
-
upstream.once('data', firstChunk => {
|
|
264
|
-
socket.write(Buffer.concat([Buffer.from('HTTP/1.1 200 Connection established\r\n\r\n'), firstChunk]));
|
|
265
|
-
startTunnel();
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
upstream.on('error', () => socket.destroy());
|
|
269
|
-
};
|
|
270
|
-
socket.on('data', onData);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
module.exports['Proxy: session established through a real HTTP CONNECT proxy'] = async test => {
|
|
274
|
-
let imapServer = createServer();
|
|
275
|
-
let imapPort = await listen(imapServer);
|
|
276
|
-
let proxy = createHttpProxy();
|
|
277
|
-
let proxyPort = await listen(proxy);
|
|
278
|
-
|
|
279
|
-
let client = new ImapFlow({
|
|
280
|
-
host: '127.0.0.1',
|
|
281
|
-
port: imapPort,
|
|
282
|
-
secure: false,
|
|
283
|
-
proxy: `http://127.0.0.1:${proxyPort}`,
|
|
284
|
-
disableAutoIdle: true,
|
|
285
|
-
disableCompression: true,
|
|
286
|
-
logger: false,
|
|
287
|
-
auth: { user: 'test', pass: 'secret' }
|
|
288
|
-
});
|
|
289
|
-
client.on('error', () => {});
|
|
290
|
-
|
|
291
|
-
await client.connect();
|
|
292
|
-
test.ok(client.usable, 'session established through the CONNECT tunnel');
|
|
293
|
-
test.ok(client.authenticated);
|
|
294
|
-
|
|
295
|
-
await client.logout();
|
|
296
|
-
client.close();
|
|
297
|
-
proxy.close();
|
|
298
|
-
imapServer.close();
|
|
299
|
-
test.done();
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
module.exports['Proxy: a greeting coalesced with the CONNECT response is not lost'] = async test => {
|
|
303
|
-
// The proxy answers CONNECT and the destination greeting in one segment. The bytes after the
|
|
304
|
-
// header terminator belong to the tunnel, so they have to reach the parser - otherwise the
|
|
305
|
-
// greeting is swallowed and connect() only fails at the greeting timeout.
|
|
306
|
-
let imapServer = createServer();
|
|
307
|
-
let imapPort = await listen(imapServer);
|
|
308
|
-
let proxy = createHttpProxy(null, { coalesce: true });
|
|
309
|
-
let proxyPort = await listen(proxy);
|
|
310
|
-
|
|
311
|
-
let client = new ImapFlow({
|
|
312
|
-
host: '127.0.0.1',
|
|
313
|
-
port: imapPort,
|
|
314
|
-
secure: false,
|
|
315
|
-
proxy: `http://127.0.0.1:${proxyPort}`,
|
|
316
|
-
greetingTimeout: 1500,
|
|
317
|
-
disableAutoIdle: true,
|
|
318
|
-
disableCompression: true,
|
|
319
|
-
logger: false,
|
|
320
|
-
auth: { user: 'test', pass: 'secret' }
|
|
321
|
-
});
|
|
322
|
-
client.on('error', () => {});
|
|
323
|
-
|
|
324
|
-
await client.connect();
|
|
325
|
-
test.ok(client.usable, 'the coalesced greeting was parsed, so the session came up');
|
|
326
|
-
test.ok(client.capabilities.has('IMAP4rev1'), 'capabilities from the coalesced greeting are present');
|
|
327
|
-
|
|
328
|
-
await client.logout();
|
|
329
|
-
client.close();
|
|
330
|
-
proxy.close();
|
|
331
|
-
imapServer.close();
|
|
332
|
-
test.done();
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
module.exports['Proxy: a stalled proxy negotiation is bounded by connectionTimeout'] = async test => {
|
|
336
|
-
// The proxy accepts the CONNECT request and then goes silent
|
|
337
|
-
let proxy = createHttpProxy(() => true);
|
|
338
|
-
let proxyPort = await listen(proxy);
|
|
339
|
-
|
|
340
|
-
let client = new ImapFlow({
|
|
341
|
-
host: '127.0.0.1',
|
|
342
|
-
port: 143,
|
|
343
|
-
secure: false,
|
|
344
|
-
proxy: `http://127.0.0.1:${proxyPort}`,
|
|
345
|
-
connectionTimeout: 150,
|
|
346
|
-
disableAutoIdle: true,
|
|
347
|
-
disableCompression: true,
|
|
348
|
-
logger: false,
|
|
349
|
-
auth: { user: 'test', pass: 'secret' }
|
|
350
|
-
});
|
|
351
|
-
client.on('error', () => {});
|
|
352
|
-
|
|
353
|
-
let started = Date.now();
|
|
354
|
-
let err = await client.connect().then(
|
|
355
|
-
() => null,
|
|
356
|
-
e => e
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
test.ok(err, 'connect rejected instead of hanging in proxy negotiation');
|
|
360
|
-
test.equal(err.code, 'CONNECT_TIMEOUT', 'the documented connection timeout covers proxy negotiation');
|
|
361
|
-
test.ok(Date.now() - started < 3000, 'the deadline applied to the proxy phase, not only to the transport');
|
|
362
|
-
|
|
363
|
-
client.close();
|
|
364
|
-
proxy.close();
|
|
365
|
-
test.done();
|
|
366
|
-
};
|