Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
frame.js97 linesDownload Raw Back to websocket
1'use strict'
2
3const { maxUnsigned16Bit } = require('./constants')
4
5const BUFFER_SIZE = 16386
6
7/** @type {import('crypto')} */
8let crypto
9let buffer = null
10let bufIdx = BUFFER_SIZE
11
12try {
13  crypto = require('node:crypto')
14/* c8 ignore next 3 */
15} catch {
16  crypto = {
17    // not full compatibility, but minimum.
18    randomFillSync: function randomFillSync (buffer, _offset, _size) {
19      for (let i = 0; i < buffer.length; ++i) {
20        buffer[i] = Math.random() * 255 | 0
21      }
22      return buffer
23    }
24  }
25}
26
27function generateMask () {
28  if (bufIdx === BUFFER_SIZE) {
29    bufIdx = 0
30    crypto.randomFillSync((buffer ??= Buffer.allocUnsafe(BUFFER_SIZE)), 0, BUFFER_SIZE)
31  }
32  return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]]
33}
34
35class WebsocketFrameSend {
36  /**
37   * @param {Buffer|undefined} data
38   */
39  constructor (data) {
40    this.frameData = data
41  }
42
43  createFrame (opcode) {
44    const frameData = this.frameData
45    const maskKey = generateMask()
46    const bodyLength = frameData?.byteLength ?? 0
47
48    /** @type {number} */
49    let payloadLength = bodyLength // 0-125
50    let offset = 6
51
52    if (bodyLength > maxUnsigned16Bit) {
53      offset += 8 // payload length is next 8 bytes
54      payloadLength = 127
55    } else if (bodyLength > 125) {
56      offset += 2 // payload length is next 2 bytes
57      payloadLength = 126
58    }
59
60    const buffer = Buffer.allocUnsafe(bodyLength + offset)
61
62    // Clear first 2 bytes, everything else is overwritten
63    buffer[0] = buffer[1] = 0
64    buffer[0] |= 0x80 // FIN
65    buffer[0] = (buffer[0] & 0xF0) + opcode // opcode
66
67    /*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */
68    buffer[offset - 4] = maskKey[0]
69    buffer[offset - 3] = maskKey[1]
70    buffer[offset - 2] = maskKey[2]
71    buffer[offset - 1] = maskKey[3]
72
73    buffer[1] = payloadLength
74
75    if (payloadLength === 126) {
76      buffer.writeUInt16BE(bodyLength, 2)
77    } else if (payloadLength === 127) {
78      // Clear extended payload length
79      buffer[2] = buffer[3] = 0
80      buffer.writeUIntBE(bodyLength, 4, 6)
81    }
82
83    buffer[1] |= 0x80 // MASK
84
85    // mask body
86    for (let i = 0; i < bodyLength; ++i) {
87      buffer[offset + i] = frameData[i] ^ maskKey[i & 3]
88    }
89
90    return buffer
91  }
92}
93
94module.exports = {
95  WebsocketFrameSend
96}
97 
codekingpro/portable-devtools · Team Ai