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,28 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const imapFormalSyntax = require('./imap-formal-syntax');
|
|
4
|
-
const { ParserInstance } = require('./parser-instance');
|
|
5
|
-
|
|
1
|
+
import imapFormalSyntax from './imap-formal-syntax.js';
|
|
2
|
+
import { ParserInstance } from './parser-instance.js';
|
|
6
3
|
/**
|
|
7
4
|
* Parses a raw IMAP command or response buffer into a structured object.
|
|
8
5
|
* Handles edge cases such as null-byte-padded responses from buggy servers and
|
|
9
6
|
* multi-word commands like UID and AUTHENTICATE.
|
|
10
7
|
*
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @param
|
|
14
|
-
* @param
|
|
15
|
-
* @returns
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @returns {number} [return.nullBytesRemoved] - Number of leading null bytes removed, if any.
|
|
8
|
+
* @param command - The raw IMAP command or response data to parse.
|
|
9
|
+
* @param options - Parser options passed through to the underlying ParserInstance and TokenParser.
|
|
10
|
+
* @param options.literalPlus - Whether the LITERAL+ extension is in use.
|
|
11
|
+
* @param options.literals - Pre-parsed literal values extracted from the input stream.
|
|
12
|
+
* @returns A promise that resolves to a parsed response object with `tag` (the IMAP tag, e.g. "*",
|
|
13
|
+
* "+", or a command tag like "A1"), `command` (the IMAP command or response name, e.g. "OK",
|
|
14
|
+
* "FETCH"), `attributes` (parsed attributes of the response) and `nullBytesRemoved` (number of
|
|
15
|
+
* leading null bytes removed, if any).
|
|
20
16
|
*/
|
|
21
|
-
|
|
17
|
+
export default async function parser(command, options) {
|
|
22
18
|
options = options || {};
|
|
23
|
-
|
|
24
19
|
let nullBytesRemoved = 0;
|
|
25
|
-
|
|
26
20
|
// Workaround for buggy IMAP servers that pad responses with leading NUL (\x00) bytes.
|
|
27
21
|
// Some servers (observed in the wild) prepend null bytes to their output, which would
|
|
28
22
|
// cause parsing to fail. We strip them and note how many were removed for diagnostics.
|
|
@@ -36,60 +30,53 @@ module.exports = async (command, options) => {
|
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
32
|
if (firstNonNull === -1) {
|
|
39
|
-
// All bytes are null
|
|
33
|
+
// All bytes are null, treat as a BAD response
|
|
40
34
|
return { tag: '*', command: 'BAD', attributes: [] };
|
|
41
35
|
}
|
|
42
36
|
command = command.slice(firstNonNull);
|
|
43
37
|
nullBytesRemoved = firstNonNull;
|
|
44
38
|
}
|
|
45
|
-
|
|
46
|
-
const parser = new ParserInstance(command, options);
|
|
39
|
+
const parserInstance = new ParserInstance(command, options);
|
|
47
40
|
const response = {};
|
|
48
|
-
|
|
49
41
|
try {
|
|
50
|
-
response.tag = await
|
|
51
|
-
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
response.command = await parser.getCommand();
|
|
55
|
-
|
|
42
|
+
response.tag = await parserInstance.getTag();
|
|
43
|
+
await parserInstance.getSpace();
|
|
44
|
+
response.command = await parserInstance.getCommand();
|
|
56
45
|
if (nullBytesRemoved) {
|
|
57
46
|
response.nullBytesRemoved = nullBytesRemoved;
|
|
58
47
|
}
|
|
59
|
-
|
|
60
48
|
// Some IMAP commands are multi-word: "UID FETCH", "UID STORE", "UID COPY",
|
|
61
49
|
// "UID MOVE", "UID SEARCH", "UID EXPUNGE", and "AUTHENTICATE PLAIN", etc.
|
|
62
50
|
// For these, the first word is consumed as the command, then we read the
|
|
63
51
|
// subcommand and concatenate them (e.g., "UID" + " " + "FETCH" -> "UID FETCH").
|
|
64
52
|
if (['UID', 'AUTHENTICATE'].includes((response.command || '').toUpperCase())) {
|
|
65
|
-
await
|
|
66
|
-
response.command += ' ' + (await
|
|
53
|
+
await parserInstance.getSpace();
|
|
54
|
+
response.command += ' ' + (await parserInstance.getElement(imapFormalSyntax.command()));
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await
|
|
71
|
-
response.attributes = await parser.getAttributes();
|
|
56
|
+
if (parserInstance.remainder.trim().length) {
|
|
57
|
+
await parserInstance.getSpace();
|
|
58
|
+
response.attributes = await parserInstance.getAttributes();
|
|
72
59
|
}
|
|
73
|
-
|
|
74
|
-
if (parser.humanReadable) {
|
|
60
|
+
if (parserInstance.humanReadable) {
|
|
75
61
|
response.attributes = (response.attributes || []).concat({
|
|
76
62
|
type: 'TEXT',
|
|
77
|
-
value:
|
|
63
|
+
value: parserInstance.humanReadable
|
|
78
64
|
});
|
|
79
65
|
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
let error = err;
|
|
69
|
+
if (error.code === 'ParserErrorExchange' && error.parserContext && error.parserContext.value) {
|
|
70
|
+
return error.parserContext.value;
|
|
83
71
|
}
|
|
84
72
|
if (response.tag) {
|
|
85
73
|
// The tag had already been parsed when the rest of the line failed. Expose it
|
|
86
74
|
// so the connection can settle the command this line was addressed to - unlike
|
|
87
75
|
// re-deriving the tag from the raw bytes, this inherits the leading-NUL
|
|
88
76
|
// workaround above.
|
|
89
|
-
|
|
77
|
+
error.parsedTag = response.tag;
|
|
90
78
|
}
|
|
91
|
-
throw
|
|
79
|
+
throw error;
|
|
92
80
|
}
|
|
93
|
-
|
|
94
81
|
return response;
|
|
95
|
-
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Transform, type TransformCallback } from 'node:stream';
|
|
2
|
+
import type { Logger, InternalLogger } from '../types.js';
|
|
3
|
+
export interface ImapStreamOptions {
|
|
4
|
+
/** Connection identifier used for logging */
|
|
5
|
+
cid?: string | undefined;
|
|
6
|
+
/** A pino-compatible logger instance. If not provided, a default child logger is created */
|
|
7
|
+
logger?: Logger | InternalLogger | false | undefined;
|
|
8
|
+
/** If true, logs raw socket data at trace level */
|
|
9
|
+
logRaw?: boolean | undefined;
|
|
10
|
+
/** Whether the connection uses TLS */
|
|
11
|
+
secureConnection?: boolean | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Maximum allowed length (in bytes) of a single line (a response without a literal). Defaults
|
|
14
|
+
* to MAX_LITERAL_SIZE (1GB). Guards against a malicious or broken server that never sends a
|
|
15
|
+
* line terminator, which would otherwise grow the internal line buffer without bound. The line
|
|
16
|
+
* terminator counts toward the limit, and a line exactly at the limit is accepted. Exceeding it
|
|
17
|
+
* is terminal: the stream is destroyed with a `LineTooLarge` error and no further input is parsed.
|
|
18
|
+
*/
|
|
19
|
+
maxLineLength?: number | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Maximum allowed size (in bytes) of a single literal block. Defaults to MAX_LITERAL_SIZE
|
|
22
|
+
* (1GB). Lower it to bound peak memory allocation against a malicious or broken server
|
|
23
|
+
* announcing an oversized literal. A literal exactly at the limit is accepted. Exceeding it is
|
|
24
|
+
* terminal: the stream is destroyed with a `LiteralTooLarge` error, the marker line is not
|
|
25
|
+
* emitted, and no byte of the rejected literal body is parsed as protocol.
|
|
26
|
+
*/
|
|
27
|
+
maxLiteralSize?: number | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Maximum allowed total size (in bytes) of a single assembled response: every line segment and
|
|
30
|
+
* literal of one response combined. Defaults to MAX_RESPONSE_SIZE (2GB), which leaves room
|
|
31
|
+
* above the literal cap for a maximum-size literal plus its marker line. The per-line and
|
|
32
|
+
* per-literal caps alone cannot stop a server that spreads attacker-controlled bytes across an
|
|
33
|
+
* unbounded number of tokens of a single response. Declared literal sizes count when their
|
|
34
|
+
* marker is parsed, so an oversized total is rejected before the literal bytes arrive, and a
|
|
35
|
+
* line still being assembled counts against whatever budget is left. Exceeding the limit is
|
|
36
|
+
* terminal: the stream is destroyed with a `ResponseTooLarge` error and no further input is
|
|
37
|
+
* parsed.
|
|
38
|
+
*/
|
|
39
|
+
maxResponseSize?: number | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A queued input chunk with the transform callback that releases it
|
|
43
|
+
*/
|
|
44
|
+
export interface ImapStreamInputItem {
|
|
45
|
+
chunk: Buffer;
|
|
46
|
+
next: () => void;
|
|
47
|
+
released?: boolean | undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A Transform stream that parses raw IMAP protocol data from a socket into structured
|
|
51
|
+
* command/response objects. Reads binary input, splits it into lines delimited by LF,
|
|
52
|
+
* extracts literal data blocks based on IMAP literal size markers (e.g., "{123}\r\n"),
|
|
53
|
+
* and emits each complete command as a readable object containing the payload Buffer
|
|
54
|
+
* and any associated literal Buffers. Enforces a maximum literal size of 1GB.
|
|
55
|
+
*/
|
|
56
|
+
export declare class ImapStream extends Transform {
|
|
57
|
+
options: ImapStreamOptions;
|
|
58
|
+
cid: string | undefined;
|
|
59
|
+
log: InternalLogger;
|
|
60
|
+
readBytesCounter: number;
|
|
61
|
+
maxLineLength: number;
|
|
62
|
+
maxLiteralSize: number;
|
|
63
|
+
maxResponseSize: number;
|
|
64
|
+
state: number;
|
|
65
|
+
literalWaiting: number;
|
|
66
|
+
inputBuffer: Buffer[];
|
|
67
|
+
lineBuffer: Buffer[];
|
|
68
|
+
lineBytes: number;
|
|
69
|
+
literalBuffer: Buffer[];
|
|
70
|
+
literals: Buffer[];
|
|
71
|
+
responseBytes: number;
|
|
72
|
+
compress: boolean;
|
|
73
|
+
secureConnection: boolean | undefined;
|
|
74
|
+
processingInput: boolean;
|
|
75
|
+
inputQueue: ImapStreamInputItem[];
|
|
76
|
+
activeInput: ImapStreamInputItem | null;
|
|
77
|
+
pendingPush: (() => void) | null;
|
|
78
|
+
/**
|
|
79
|
+
* Creates a new ImapStream instance.
|
|
80
|
+
*
|
|
81
|
+
* @param options - Stream options, see ImapStreamOptions.
|
|
82
|
+
*/
|
|
83
|
+
constructor(options?: ImapStreamOptions | undefined);
|
|
84
|
+
/**
|
|
85
|
+
* Terminally fails the stream. Used for response limit violations and for any other
|
|
86
|
+
* error raised while parsing.
|
|
87
|
+
*
|
|
88
|
+
* The stream is destroyed instead of only emitting `error`: emitting on a Transform leaves
|
|
89
|
+
* it running, so the caller would keep scanning the rejected payload and could emit it as
|
|
90
|
+
* protocol (an oversized literal body contains attacker-chosen CRLF delimited lines).
|
|
91
|
+
* Destroying stops all parsing, drops the offending line, and releases every queued
|
|
92
|
+
* transform callback exactly once (see `_destroy()`).
|
|
93
|
+
*
|
|
94
|
+
* `destroyed` (set synchronously by destroy()) is the single liveness flag every other path
|
|
95
|
+
* checks, so a second failure attempt is a no-op and nothing is parsed after the first.
|
|
96
|
+
*
|
|
97
|
+
* @param err - The error to destroy the stream with.
|
|
98
|
+
* @returns Always false, so callers can `return this.failStream(err)`.
|
|
99
|
+
*/
|
|
100
|
+
failStream(err: Error): false;
|
|
101
|
+
/**
|
|
102
|
+
* Releases a queued input chunk's transform callback exactly once, signalling the writable
|
|
103
|
+
* side that the chunk was consumed. The mirror image of ImapFlow's releaseStreamData(), which
|
|
104
|
+
* releases the readable items this stream pushes downstream.
|
|
105
|
+
*
|
|
106
|
+
* @param item - Queue entry holding the chunk and its transform callback.
|
|
107
|
+
*/
|
|
108
|
+
releaseInput(item: ImapStreamInputItem | null | undefined): void;
|
|
109
|
+
/**
|
|
110
|
+
* Checks whether the given line buffer ends with an IMAP literal size marker
|
|
111
|
+
* (e.g., "{123}\r\n"). If a valid marker is found and the literal size is within
|
|
112
|
+
* the allowed maximum, switches the stream state to LITERAL mode and records
|
|
113
|
+
* the expected number of literal bytes.
|
|
114
|
+
*
|
|
115
|
+
* @param line - The line buffer to check for a trailing literal marker.
|
|
116
|
+
* @returns True if a valid literal marker was found and literal state was activated, false otherwise.
|
|
117
|
+
*/
|
|
118
|
+
checkLiteralMarker(line: Buffer): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Enforces the configured line-length cap for a projected line length. The projected length
|
|
121
|
+
* covers every byte of the line, the line terminator included, whether or not the line was
|
|
122
|
+
* split across input chunks. A line exactly at the limit is accepted.
|
|
123
|
+
*
|
|
124
|
+
* @param lineLength - Total length the current line would reach.
|
|
125
|
+
* @returns True if the line is within the limit, false if the stream was failed.
|
|
126
|
+
*/
|
|
127
|
+
checkLineLength(lineLength: number): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Enforces the configured per-response size cap: the cumulative bytes of every line
|
|
130
|
+
* segment and declared literal of the response currently being assembled. Counting
|
|
131
|
+
* declared literal sizes at marker time means an oversized total is rejected before
|
|
132
|
+
* the literal bytes even arrive. The counter is reset when a response is emitted.
|
|
133
|
+
*
|
|
134
|
+
* @param additionalBytes - Bytes the next token would add to the response.
|
|
135
|
+
* @param peek - Measure only, without committing the bytes to the counter.
|
|
136
|
+
* Used for a line that is still being assembled: its bytes are committed once, when the
|
|
137
|
+
* line completes.
|
|
138
|
+
* @returns True if within the limit, false if the stream was failed.
|
|
139
|
+
*/
|
|
140
|
+
checkResponseSize(additionalBytes: number, peek?: boolean | undefined): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Processes a single input chunk of raw data. In LINE state, scans for LF-terminated
|
|
143
|
+
* lines and checks for literal markers. In LITERAL state, collects the expected number
|
|
144
|
+
* of literal bytes. When a complete command (with all its literals) is assembled, it is
|
|
145
|
+
* pushed downstream as a readable object.
|
|
146
|
+
*
|
|
147
|
+
* @param chunk - The raw data chunk to process.
|
|
148
|
+
* @param startPos - The byte offset within the chunk to start processing from.
|
|
149
|
+
*/
|
|
150
|
+
processInputChunk(chunk: Buffer, startPos?: number | undefined): Promise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* Drains the input queue by processing each queued chunk sequentially.
|
|
153
|
+
* Yields to the event loop every 10 chunks to prevent CPU blocking on
|
|
154
|
+
* large bursts of incoming data.
|
|
155
|
+
*/
|
|
156
|
+
processInput(): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Transform stream implementation. Receives raw data chunks from the writable side,
|
|
159
|
+
* converts strings to Buffers, tracks total bytes read, optionally logs raw data,
|
|
160
|
+
* and queues the chunk for asynchronous processing.
|
|
161
|
+
*
|
|
162
|
+
* @param chunk - The incoming data chunk.
|
|
163
|
+
* @param encoding - The encoding if chunk is a string.
|
|
164
|
+
* @param next - Callback to signal that this chunk has been consumed.
|
|
165
|
+
*/
|
|
166
|
+
_transform(chunk: Buffer | string, encoding: BufferEncoding, next: TransformCallback): void;
|
|
167
|
+
/**
|
|
168
|
+
* Flush implementation called when the writable side ends. Signals completion immediately.
|
|
169
|
+
*
|
|
170
|
+
* @param next - Callback to signal flush completion.
|
|
171
|
+
*/
|
|
172
|
+
_flush(next: TransformCallback): void;
|
|
173
|
+
/**
|
|
174
|
+
* Destroy implementation for cleanup. Clears all internal buffers, drains the input queue
|
|
175
|
+
* by invoking pending callbacks, and forwards the error (if any) to the callback.
|
|
176
|
+
*
|
|
177
|
+
* @param err - The error that caused destruction, or null.
|
|
178
|
+
* @param callback - Callback to signal destruction completion.
|
|
179
|
+
*/
|
|
180
|
+
_destroy(err: Error | null, callback: (error?: Error | null) => void): void;
|
|
181
|
+
}
|