diff --git a/lib/message-parser.js b/lib/message-parser.js index 414ad1e..3f69061 100644 --- a/lib/message-parser.js +++ b/lib/message-parser.js @@ -118,14 +118,19 @@ class MessageParser { // Check for extra data let leftover = false; - let suffixLocation = buffer.indexOf('0000AA55', 0, 'hex'); - if (suffixLocation === -1) {// Couldn't find 0000AA55 during parse - suffixLocation = buffer.indexOf('00009966', 0, 'hex'); + // Frame end comes from the length field: a search for the suffix bytes + // also matches a sequence number or ciphertext holding those bytes + const frameLength = prefix === 0x00006699 ? + buffer.readUInt32BE(14) + 22 : // Header (18) + length + suffix (4) + buffer.readUInt32BE(12) + 16; // Header (16) + length + + if (buffer.length < frameLength) { + throw new TypeError(`Packet missing payload: frame has length ${frameLength}.`); } - if (suffixLocation !== buffer.length - 4) { - leftover = buffer.slice(suffixLocation + 4); - buffer = buffer.slice(0, suffixLocation + 4); + if (buffer.length > frameLength) { + leftover = buffer.slice(frameLength); + buffer = buffer.slice(0, frameLength); } // Check for suffix diff --git a/test/parser.js b/test/parser.js index 44dad1b..26bfcbe 100644 --- a/test/parser.js +++ b/test/parser.js @@ -209,3 +209,24 @@ test('decode message with two packets 2', t => { t.deepEqual(parsed.payload, payload); t.is(parsed.commandByte, 10); }); + +for (const version of ['3.1', '3.3', '3.4', '3.5']) { + for (const sequenceN of [0x0000AA55, 0x00009966]) { + test(`decode two packets with protocol ${version} and sequence number holding suffix bytes 0x${sequenceN.toString(16)}`, t => { + const payload = {devId: '002004265ccf7fb1b659', dps: {1: true, 2: 0}}; + + const parser = new MessageParser({key: 'bbe88b3f4106d354', version}); + const baseline = parser.parse(parser.encode({data: payload, commandByte: CommandType.DP_QUERY, sequenceN: 1}))[0]; + const encoded = parser.encode({data: payload, commandByte: CommandType.DP_QUERY, sequenceN}); + + const parsed = parser.parse(Buffer.concat([encoded, encoded])); + + t.is(parsed.length, 2); + for (const packet of parsed) { + t.is(packet.sequenceN, sequenceN); + t.is(packet.commandByte, CommandType.DP_QUERY); + t.deepEqual(packet.payload, baseline.payload); + } + }); + } +}