From d218f845bfe343796ff26bb55487f05740f5f8d6 Mon Sep 17 00:00:00 2001 From: cod Date: Sat, 16 Mar 2024 17:44:04 +0300 Subject: [PATCH 1/5] Update Categories.json --- src/core/config/Categories.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 8e300c7689..ee823a35ed 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -72,7 +72,8 @@ "CBOR Decode", "Caret/M-decode", "Rison Encode", - "Rison Decode" + "Rison Decode", + "WebSocket Decode" ] }, { From 0bbb3b61799c422558416062845241b1d4bfa799 Mon Sep 17 00:00:00 2001 From: cod Date: Sat, 16 Mar 2024 17:44:32 +0300 Subject: [PATCH 2/5] Create WebSocketDecode.mjs --- src/core/operations/WebSocketDecode.mjs | 116 ++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/core/operations/WebSocketDecode.mjs diff --git a/src/core/operations/WebSocketDecode.mjs b/src/core/operations/WebSocketDecode.mjs new file mode 100644 index 0000000000..99705f56f8 --- /dev/null +++ b/src/core/operations/WebSocketDecode.mjs @@ -0,0 +1,116 @@ +/** + * @author cod [sysenter.dev@gmail.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { WEBSOCKET_OPCODE } from "../lib/WebSocket.mjs"; + +/** WebSocket */ +class WebSocketDecode extends Operation { + + /** + * Default constructor + */ + constructor() { + super(); + + this.name = "WebSocket Decode"; + this.module = "Code"; + this.description = "Converts a WebSocket encoded to JSON. WebSocket is computer communitions protocol, providing simultaneous two-way communication channels"; + this.infoURL = "https://wikipedia.org/wiki/WebSocket"; + this.inputType = "ArrayBuffer"; + this.outputType = "JSON"; + this.args = []; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {JSON} + */ + run(input, args) { + try { + let pos = 0; + const buf = Buffer.from(new Uint8Array(input)); + + if (buf.length < 2) { + throw new OperationError("Expected size: 2 bytes"); + } + + let b0 = buf[0]; + let b1 = buf[1]; + + const fin = (b0 & 0x80) === 0x80 ? true : false; + const opcode = WEBSOCKET_OPCODE[b0 & 0x7f]; + let payloadLength = (b1 & 0x7f); + + pos = 2; + const mask = (b1 & 0x80) === 0x80 ? true : false; + const mask_size = (mask) ? 4 : 0; + + if (payloadLength < 126) { + /** payload is less of 126 bytes */ + if (buf.length < (pos + payloadLength + mask_size)) + throw new OperationError(`Expected size: ${(pos + payloadLength + mask_size)}`); + } else if (payloadLength == 126) { + /** payload is 2 bytes */ + pos += 2; + payloadLength = buf.readUInt16BE(2); + + if (buf.length < (pos + payloadLength + mask_size)) + throw new OperationError(`Expected size: ${(pos + payloadLength + mask_size)}`); + + } else if (payloadLength == 127) { + pos += 8; + payloadLength = buf.readUInt64BE(2); + + if (buf.length < (pos + payloadLength + mask_size)) + throw new OperationError(`Expected size: ${(pos + payloadLength + mask_size)}`); + } + + let maskBytes = Buffer.alloc(4); + + if (mask) { + maskBytes[0] = buf[pos]; + maskBytes[1] = buf[pos+1]; + maskBytes[2] = buf[pos+2]; + maskBytes[3] = buf[pos+3]; + pos += 4; + } + + let payload = buf.slice(pos, buf.length); + + if (mask) { + for(var i = 0; i < payload.length; i++) { + payload[i] = payload[i] ^ maskBytes[i % 4]; + } + } + + let content; + + if ((b0 & 1) === 1) { + content = payload.toString(); + } else { + content = payload.toString('hex'); + } + + const ws = { + fin: fin, + opcode: opcode, + mask_present: mask, + mask: maskBytes.toString('hex'), + payloadLength: payloadLength, + payload: content + }; + + return ws; + } catch (err) { + throw new OperationError(`Could not decode WebSocket to JSON: ${err}`); + } + } +} + +export default WebSocketDecode; From 7c813e0be95991554fc0ddd0fc7a11f65a22861c Mon Sep 17 00:00:00 2001 From: cod Date: Sat, 16 Mar 2024 17:44:53 +0300 Subject: [PATCH 3/5] Create WebSocket.mjs --- src/core/lib/WebSocket.mjs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/core/lib/WebSocket.mjs diff --git a/src/core/lib/WebSocket.mjs b/src/core/lib/WebSocket.mjs new file mode 100644 index 0000000000..502ddcd5dc --- /dev/null +++ b/src/core/lib/WebSocket.mjs @@ -0,0 +1,9 @@ +/** + * WebSocket operation resources. + * + * @author cod [sysenter.dev@gmail.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +export const WEBSOCKET_OPCODE = ["continuation frame", "text frame", "binary frame", "rsv3", "rsv4", "rsv5", "rsv6", "rsv7", "ping", "pong", "rsvb", "rsvc", "rsvd", "rsve", "rsvf"]; From 14875dba347658d93876165ce95e6915f33cba1a Mon Sep 17 00:00:00 2001 From: cod Date: Mon, 23 Sep 2024 11:35:52 +0200 Subject: [PATCH 4/5] Annotation from CI --- src/core/operations/WebSocketDecode.mjs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/core/operations/WebSocketDecode.mjs b/src/core/operations/WebSocketDecode.mjs index 99705f56f8..baedfe703a 100644 --- a/src/core/operations/WebSocketDecode.mjs +++ b/src/core/operations/WebSocketDecode.mjs @@ -40,8 +40,8 @@ class WebSocketDecode extends Operation { throw new OperationError("Expected size: 2 bytes"); } - let b0 = buf[0]; - let b1 = buf[1]; + const b0 = buf[0]; + const b1 = buf[1]; const fin = (b0 & 0x80) === 0x80 ? true : false; const opcode = WEBSOCKET_OPCODE[b0 & 0x7f]; @@ -49,26 +49,26 @@ class WebSocketDecode extends Operation { pos = 2; const mask = (b1 & 0x80) === 0x80 ? true : false; - const mask_size = (mask) ? 4 : 0; + const maskSize = (mask) ? 4 : 0; if (payloadLength < 126) { /** payload is less of 126 bytes */ - if (buf.length < (pos + payloadLength + mask_size)) - throw new OperationError(`Expected size: ${(pos + payloadLength + mask_size)}`); - } else if (payloadLength == 126) { + if (buf.length < (pos + payloadLength + maskSize)) + throw new OperationError(`Expected size: ${(pos + payloadLength + maskSize)}`); + } else if (payloadLength === 126) { /** payload is 2 bytes */ pos += 2; payloadLength = buf.readUInt16BE(2); - if (buf.length < (pos + payloadLength + mask_size)) - throw new OperationError(`Expected size: ${(pos + payloadLength + mask_size)}`); + if (buf.length < (pos + payloadLength + maskSize)) + throw new OperationError(`Expected size: ${(pos + payloadLength + maskSize)}`); - } else if (payloadLength == 127) { + } else if (payloadLength === 127) { pos += 8; payloadLength = buf.readUInt64BE(2); - if (buf.length < (pos + payloadLength + mask_size)) - throw new OperationError(`Expected size: ${(pos + payloadLength + mask_size)}`); + if (buf.length < (pos + payloadLength + maskSize)) + throw new OperationError(`Expected size: ${(pos + payloadLength + maskSize)}`); } let maskBytes = Buffer.alloc(4); From c268891bbf7ba71bde1025e4e4d4c183fea76ef7 Mon Sep 17 00:00:00 2001 From: cod Date: Mon, 23 Sep 2024 11:40:15 +0200 Subject: [PATCH 5/5] lint --- src/core/operations/WebSocketDecode.mjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/operations/WebSocketDecode.mjs b/src/core/operations/WebSocketDecode.mjs index baedfe703a..041123d961 100644 --- a/src/core/operations/WebSocketDecode.mjs +++ b/src/core/operations/WebSocketDecode.mjs @@ -71,7 +71,7 @@ class WebSocketDecode extends Operation { throw new OperationError(`Expected size: ${(pos + payloadLength + maskSize)}`); } - let maskBytes = Buffer.alloc(4); + const maskBytes = Buffer.alloc(4); if (mask) { maskBytes[0] = buf[pos]; @@ -81,10 +81,10 @@ class WebSocketDecode extends Operation { pos += 4; } - let payload = buf.slice(pos, buf.length); + const payload = buf.slice(pos, buf.length); if (mask) { - for(var i = 0; i < payload.length; i++) { + for (let i = 0; i < payload.length; i++) { payload[i] = payload[i] ^ maskBytes[i % 4]; } } @@ -94,14 +94,14 @@ class WebSocketDecode extends Operation { if ((b0 & 1) === 1) { content = payload.toString(); } else { - content = payload.toString('hex'); + content = payload.toString("hex"); } const ws = { fin: fin, opcode: opcode, - mask_present: mask, - mask: maskBytes.toString('hex'), + maskPresent: mask, + mask: maskBytes.toString("hex"), payloadLength: payloadLength, payload: content };