imapflow 1.0.184 → 1.0.186

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.186](https://github.com/postalsys/imapflow/compare/v1.0.185...v1.0.186) (2025-04-20)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **parsing:** Limit the depth of nested input ([c6cd7ce](https://github.com/postalsys/imapflow/commit/c6cd7cef9f9b8a1ff137a08e8aebf2555e596a23))
9
+
10
+ ## [1.0.185](https://github.com/postalsys/imapflow/compare/v1.0.184...v1.0.185) (2025-04-14)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **search:** add a `not` option for search options ([#281](https://github.com/postalsys/imapflow/issues/281)) ([000686b](https://github.com/postalsys/imapflow/commit/000686b2ace1ef0e21cca64d8e056d1f7f7f8914))
16
+
3
17
  ## [1.0.184](https://github.com/postalsys/imapflow/compare/v1.0.183...v1.0.184) (2025-03-11)
4
18
 
5
19
 
@@ -9,6 +9,10 @@ module.exports = async (connection, destination, content, flags, idate) => {
9
9
  return;
10
10
  }
11
11
 
12
+ if (typeof content === 'string') {
13
+ content = Buffer.from(content);
14
+ }
15
+
12
16
  if (connection.capabilities.has('APPENDLIMIT')) {
13
17
  let appendLimit = connection.capabilities.get('APPENDLIMIT');
14
18
  if (typeof appendLimit === 'number' && appendLimit < content.length) {
@@ -40,9 +44,6 @@ module.exports = async (connection, destination, content, flags, idate) => {
40
44
 
41
45
  let isLiteral8 = false;
42
46
  if (connection.capabilities.has('BINARY') && !connection.disableBinary) {
43
- if (typeof content === 'string') {
44
- content = Buffer.from(content);
45
- }
46
47
  // Value is literal8 if it contains NULL bytes. The server must support the BINARY extension
47
48
  // and if it does not then send the value as a regular literal and hope for the best
48
49
  isLiteral8 = content.indexOf(Buffer.from([0])) >= 0;
@@ -11,7 +11,7 @@ module.exports = async (connection, path) => {
11
11
 
12
12
  path = normalizePath(connection, path);
13
13
 
14
- if (connection.states.SELECTED && connection.mailbox.path === path) {
14
+ if (connection.state === connection.states.SELECTED && connection.mailbox.path === path) {
15
15
  await connection.run('CLOSE');
16
16
  }
17
17
 
@@ -12,7 +12,7 @@ module.exports = async (connection, path, newPath) => {
12
12
  path = normalizePath(connection, path);
13
13
  newPath = normalizePath(connection, newPath);
14
14
 
15
- if (connection.states.SELECTED && connection.mailbox.path === path) {
15
+ if (connection.state === connection.states.SELECTED && connection.mailbox.path === path) {
16
16
  await connection.run('CLOSE');
17
17
  }
18
18
 
@@ -15,6 +15,8 @@ const STATE_TEXT = 0x007;
15
15
  const RE_DIGITS = /^\d+$/;
16
16
  const RE_SINGLE_DIGIT = /^\d$/;
17
17
 
18
+ const MAX_NODE_DEPTH = 25;
19
+
18
20
  class TokenParser {
19
21
  constructor(parent, startPos, str, options) {
20
22
  this.str = (str || '').toString();
@@ -116,6 +118,16 @@ class TokenParser {
116
118
 
117
119
  if (parentNode) {
118
120
  node.parentNode = parentNode;
121
+ node.depth = parentNode.depth + 1;
122
+ } else {
123
+ node.depth = 0;
124
+ }
125
+
126
+ if (node.depth > MAX_NODE_DEPTH) {
127
+ let error = new Error('Too much nesting in IMAP string');
128
+ error.code = 'MAX_IMAP_NESTING_REACHED';
129
+ error._imapStr = this.str;
130
+ throw error;
119
131
  }
120
132
 
121
133
  if (typeof startPos === 'number') {
package/lib/imap-flow.js CHANGED
@@ -281,6 +281,8 @@ class ImapFlow extends EventEmitter {
281
281
  this.socket = false;
282
282
  this.writeSocket = false;
283
283
 
284
+ this.isClosed = false;
285
+
284
286
  this.states = states;
285
287
  this.state = this.states.NOT_AUTHENTICATED;
286
288
 
@@ -391,7 +393,7 @@ class ImapFlow extends EventEmitter {
391
393
  }
392
394
 
393
395
  write(chunk) {
394
- if (this.socket.destroyed) {
396
+ if (!this.socket || this.socket.destroyed) {
395
397
  // do not write after connection end or logout
396
398
  const error = new Error('Socket is already closed');
397
399
  error.code = 'NoConnection';
@@ -507,7 +509,7 @@ class ImapFlow extends EventEmitter {
507
509
  }
508
510
 
509
511
  async exec(command, attributes, options) {
510
- if (this.socket.destroyed) {
512
+ if (!this.socket || this.socket.destroyed) {
511
513
  let error = new Error('Connection closed');
512
514
  error.code = 'EConnectionClosed';
513
515
  throw error;
@@ -873,7 +875,7 @@ class ImapFlow extends EventEmitter {
873
875
  };
874
876
 
875
877
  Object.defineProperty(this.writeSocket, 'destroyed', {
876
- get: () => this.socket.destroyed
878
+ get: () => !this.socket || this.socket.destroyed
877
879
  });
878
880
 
879
881
  // we need to force flush deflated data to socket so we can't
@@ -1990,6 +1992,7 @@ class ImapFlow extends EventEmitter {
1990
1992
  * @property {String} [keyword] Matches messages that have the custom flag set
1991
1993
  * @property {String} [unKeyword] Matches messages that do not have the custom flag set
1992
1994
  * @property {Object.<string, Boolean|String>} [header] Matches messages with header key set if value is `true` (**NB!** not supported by all servers) or messages where header partially matches a string value
1995
+ * @property {SearchObject} [not] A {@link SearchObject} object. It must not match.
1993
1996
  * @property {SearchObject[]} [or] An array of 2 or more {@link SearchObject} objects. At least on of these must match
1994
1997
  */
1995
1998
 
@@ -2480,7 +2483,7 @@ class ImapFlow extends EventEmitter {
2480
2483
 
2481
2484
  let res;
2482
2485
  while ((res = await getNext())) {
2483
- if (this.isClosed || this.socket.destroyed) {
2486
+ if (this.isClosed || !this.socket || this.socket.destroyed) {
2484
2487
  let error = new Error('Connection closed');
2485
2488
  error.code = 'EConnectionClosed';
2486
2489
  throw error;
@@ -3000,7 +3003,7 @@ class ImapFlow extends EventEmitter {
3000
3003
  return false;
3001
3004
  }
3002
3005
 
3003
- if (this.socket.destroyed) {
3006
+ if (!this.socket || this.socket.destroyed) {
3004
3007
  const error = new Error('Connection not available');
3005
3008
  error.code = 'NoConnection';
3006
3009
  throw error;
@@ -3069,7 +3072,7 @@ class ImapFlow extends EventEmitter {
3069
3072
  const lock = this.locks.shift();
3070
3073
  const { resolve, reject, path, options, lockId } = lock;
3071
3074
 
3072
- if (!this.usable || this.socket.destroyed) {
3075
+ if (!this.usable || !this.socket || this.socket.destroyed) {
3073
3076
  this.log.trace({ msg: 'Failed to acquire mailbox lock', path, lockId, idling: this.idling });
3074
3077
  // reject all
3075
3078
  let error = new Error('Connection not available');
@@ -190,6 +190,19 @@ module.exports.searchCompiler = (connection, query) => {
190
190
  }
191
191
  break;
192
192
 
193
+ case 'NOT':
194
+ {
195
+ if (!params[term]) {
196
+ break;
197
+ }
198
+
199
+ if (typeof params[term] === 'object') {
200
+ attributes.push({ type: 'ATOM', value: 'NOT' });
201
+ walk(params[term]);
202
+ }
203
+ }
204
+ break;
205
+
193
206
  case 'OR':
194
207
  {
195
208
  if (!params[term] || !Array.isArray(params[term]) || !params[term].length) {
package/lib/tools.js CHANGED
@@ -849,10 +849,9 @@ const tools = {
849
849
  },
850
850
 
851
851
  packMessageRange(list) {
852
- if (typeof uidList === 'string')
853
- if (!Array.isArray(list)) {
854
- list = [].concat(list || []);
855
- }
852
+ if (!Array.isArray(list)) {
853
+ list = [].concat(list || []);
854
+ }
856
855
 
857
856
  if (!list.length) {
858
857
  return '';
package/lib/types.d.ts CHANGED
@@ -904,6 +904,7 @@ declare type SequenceString = string;
904
904
  * @property [keyword] - Matches messages that have the custom flag set
905
905
  * @property [unKeyword] - Matches messages that do not have the custom flag set
906
906
  * @property [header] - Matches messages with header key set if value is `true` (**NB!** not supported by all servers) or messages where header partially matches a string value
907
+ * @property [not] - A {@link SearchObject} object. It must not match.
907
908
  * @property [or] - An array of 2 or more {@link SearchObject} objects. At least on of these must match
908
909
  */
909
910
  declare type SearchObject = {
@@ -940,6 +941,7 @@ declare type SearchObject = {
940
941
  header?: {
941
942
  [key: string]: Boolean | String;
942
943
  };
944
+ not?: SearchObject;
943
945
  or?: SearchObject[];
944
946
  };
945
947
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imapflow",
3
- "version": "1.0.184",
3
+ "version": "1.0.186",
4
4
  "description": "IMAP Client for Node",
5
5
  "main": "./lib/imap-flow.js",
6
6
  "scripts": {
@@ -1125,8 +1125,6 @@ module.exports['Process non-standard unicode filename property'] = test => {
1125
1125
 
1126
1126
  let bodyStruct = parseBodystructure(attribute);
1127
1127
 
1128
- console.log(JSON.stringify(bodyStruct, false, 2));
1129
-
1130
1128
  test.deepEqual(bodyStruct.childNodes[1].dispositionParameters.filename, 'Trang_ghi_âm (8) (1).xlsx');
1131
1129
  test.done();
1132
1130
  };
@@ -981,7 +981,6 @@ module.exports['IMAP Parser, NO with a dot'] = test =>
981
981
  module.exports['IMAP Parser, no tag or response (Exchange)'] = test =>
982
982
  asyncWrapper(test, async test => {
983
983
  let parsed = await parser('Server Unavailable. 15');
984
- console.log(parsed);
985
984
  test.equal(parsed.command, 'BAD');
986
985
  test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Server Unavailable. 15' }]);
987
986
  });
@@ -1237,3 +1236,16 @@ module.exports['IMAP Parser, FETCH with BODYSTRUCTURE'] = test =>
1237
1236
  ]
1238
1237
  ]);
1239
1238
  });
1239
+
1240
+ module.exports['IMAP Parser, FETCH with BODYSTRUCTURE'] = test =>
1241
+ asyncWrapper(test, async test => {
1242
+ try {
1243
+ let parsed = await parser('* 1 FETCH (UID 1 (((((((((((((((((((((((((');
1244
+ test.ok(!parsed);
1245
+ } catch (err) {
1246
+ test.ok(err);
1247
+ if (err.code !== 'MAX_IMAP_NESTING_REACHED') {
1248
+ throw err;
1249
+ }
1250
+ }
1251
+ });