Something went wrong. Try again.
remote mailbox into muse
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293import { createHash, randomBytes } from 'node:crypto';import { EventEmitter } from 'node:events';import type { IncomingMessage } from 'node:http';import type { Socket } from 'node:net';
export class WebSocketPeer extends EventEmitter { readonly socket: Socket; readonly masked: boolean; private buffer: Buffer = Buffer.alloc(0); closed = false; awaitingPong = false;
constructor(socket: Socket, { masked, head = Buffer.alloc(0) }: { masked: boolean; head?: Buffer }) { super(); this.socket = socket; this.masked = masked; this.buffer = Buffer.alloc(0); this.closed = false; this.awaitingPong = false; socket.on('data', chunk => this.consume(chunk)); socket.on('close', () => { this.closed = true; this.emit('close'); }); socket.on('error', error => this.emit('error', error)); if (head.length) queueMicrotask(() => this.consume(head)); } sendFrame(opcode: number, payload: Buffer | string = Buffer.alloc(0)): void { if (this.closed) return; if (!Buffer.isBuffer(payload)) payload = Buffer.from(payload); if (payload.length > 65535) throw new Error('websocket frame too large'); const header = payload.length < 126 ? Buffer.alloc(this.masked ? 6 : 2) : Buffer.alloc(this.masked ? 8 : 4); header[0] = 0x80 | opcode; header[1] = (this.masked ? 0x80 : 0) | (payload.length < 126 ? payload.length : 126); let offset = 2; if (payload.length >= 126) { header.writeUInt16BE(payload.length, offset); offset += 2; } if (this.masked) { const mask = randomBytes(4); mask.copy(header, offset); payload = Buffer.from(payload); for (let i = 0; i < payload.length; i++) payload[i] ^= mask[i % 4]; } this.socket.write(Buffer.concat([header, payload])); } sendJSON(value: unknown): void { this.sendFrame(1, JSON.stringify(value)); } ping(): void { this.awaitingPong = true; this.sendFrame(9); } close(code = 1000, reason = ''): void { if (this.closed) return; const reasonBytes = Buffer.from(reason); const body = Buffer.alloc(2 + reasonBytes.length); body.writeUInt16BE(code); reasonBytes.copy(body, 2); this.sendFrame(8, body); this.closed = true; this.socket.end(); setTimeout(() => this.socket.destroy(), 1000).unref(); } consume(chunk: Buffer): void { this.buffer = Buffer.concat([this.buffer, chunk]); if (this.buffer.length > 131072) { this.close(1009); return; } while (this.buffer.length >= 2) { const first = this.buffer[0], second = this.buffer[1]; const opcode = first & 15, isMasked = !!(second & 0x80), lengthCode = second & 127; if ((first & 0x70) || !(first & 0x80) || isMasked === this.masked || lengthCode === 127) { this.close(1002); return; } const extended = lengthCode === 126 ? 2 : 0; const headerSize = 2 + extended + (isMasked ? 4 : 0); if (this.buffer.length < headerSize) return; const length = extended ? this.buffer.readUInt16BE(2) : lengthCode; if (length > 65535 || (opcode >= 8 && length > 125)) { this.close(1002); return; } if (this.buffer.length < headerSize + length) return; const mask = isMasked ? this.buffer.subarray(headerSize - 4, headerSize) : null; const payload = Buffer.from(this.buffer.subarray(headerSize, headerSize + length)); this.buffer = this.buffer.subarray(headerSize + length); if (mask) for (let i = 0; i < payload.length; i++) payload[i] ^= mask[i % 4]; if (opcode === 8) { const code = payload.length >= 2 ? payload.readUInt16BE() : 1000; this.emit('closeFrame', code, payload.subarray(2).toString('utf8')); this.close(code); return; } if (opcode === 9) this.sendFrame(10, payload); else if (opcode === 10) { this.awaitingPong = false; this.emit('pong'); } else if (opcode === 1) { try { this.emit('message', JSON.parse(payload.toString('utf8'))); } catch { this.close(1007); return; } } else { this.close(1003); return; } } }}
export function acceptUpgrade(req: IncomingMessage, socket: Socket, head: Buffer): WebSocketPeer | null { const key = req.headers['sec-websocket-key']; const connection = req.headers.connection; if (req.method !== 'GET' || req.headers.upgrade?.toLowerCase() !== 'websocket' || typeof connection !== 'string' || !connection.toLowerCase().split(',').map(x => x.trim()).includes('upgrade') || req.headers['sec-websocket-version'] !== '13' || typeof key !== 'string' || Buffer.from(key, 'base64').length !== 16) return null; const accept = createHash('sha1').update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest('base64'); socket.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${accept}\r\n\r\n`); return new WebSocketPeer(socket, { masked: false, head });}