mscdex / node-imap

An IMAP client module for node.js.
MIT License
2.14k stars 379 forks source link

fix: workaround illegal extra bodystructure segments in parseFetch #904

Open AdriandeCita opened 11 months ago

AdriandeCita commented 11 months ago

Recently I came across an odd error in the parser, which looked like this:

TypeError: list[i].toLowerCase is not a function
    at Parser.parseFetch (.../node_modules/imap/lib/Parser.js:433:19)
    at Parser._resUntagged (.../node_modules/imap/lib/Parser.js:257:24)
    at Parser._parse (.../node_modules/imap/lib/Parser.js:137:16)
    at Parser._tryread (.../node_modules/imap/lib/Parser.js:82:15)
    at Parser._parse (.../node_modules/imap/lib/Parser.js:162:10)
    at Parser._tryread (.../node_modules/imap/lib/Parser.js:82:15)
    at Parser._parse (.../node_modules/imap/lib/Parser.js:162:10)
    at Parser._tryread (.../node_modules/imap/lib/Parser.js:82:15)
    at TLSSocket.Parser._cbReadable (.../node_modules/imap/lib/Parser.js:53:12)
    at TLSSocket.emit (node:events:513:28)
error Command failed with exit code 1.

It happened when I was trying to fetch some old messages from an account on mail[.]ru server.

I enabled debug output plus added a few logs from myself, trying to look at what exactly caused the error, and here is what it looked like:

reading chunks of body: 
1.32kb<= '* 385 FETCH (UID 3342 FLAGS () INTERNALDATE "19-Apr-2016 06:56:43 +0000" BODYSTRUCTURE ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 1840 0 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "base64" 168 0 NIL NIL NIL NIL) "alternative" ("boundary" NIL))  BODY[TEXT] {1843}'
3.12kb<= '* 385 FETCH (UID 3342 FLAGS () INTERNALDATE "19-Apr-2016 06:56:43 +0000" BODYSTRUCTURE ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 1840 0 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "base64" 168 0 NIL NIL NIL NIL) "alternative" ("boundary" NIL))  )'

// node_modules/imap/lib/Parser.js
//
// function parseFetch(text, literals, seqno) {
//  var list = parseExpr(text, literals)[0], attrs = {}, m, body;
// console.log(list);

[
  'UID',
  3342,
  'FLAGS',
  [],
  'INTERNALDATE',
  '19-Apr-2016 06:56:43 +0000',
  'BODYSTRUCTURE',
  [
    'text',
    'html',
    [ 'charset', 'utf-8' ],
    null,
    null,
    '7bit',
    1840,
    0,
    null,
    null,
    null,
    null
  ],
  [
    [
      'text',  'html',
      [Array], null,
      null,    'base64',
      168,     0,
      null,    null,
      null,    null
    ],
    'alternative',
    [ 'boundary', null ]
  ]
]

I'm not an expert in IMAP, but that second array with that alternative bodystructure seemed wrong to me. I could not find any reference saying that this is a standard behavior. It looks more like a bug in that specific IMAP server implementation.

The exception turned out quite hard to fight, as it's happening deep in the asynchronous code. And also I didn't care too much about the integrity of this this specific email, so this workaround served me well.

Not sure how useful it is here though, since I'm seemingly the only person so far, facing this specific problem.

mryraghi commented 2 months ago

Hey @AdriandeCita, I ran into the same issue, and it's been a nightmare. Would you be available to fork it and maintain it together? Maybe in TypeScript and solidified