From d45b9d7caae80ad8384742118cd3587c99c52e79 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:28:04 +1100 Subject: [PATCH 1/4] changes from yonks ago that I forgot to commit --- gateway/src/opcodes/Identify.ts | 2 + webrtc/package-lock.json | 134 +++++++++++++++++++++++++++ webrtc/src/Server.ts | 33 ++++++- webrtc/src/opcodes/Identify.ts | 5 +- webrtc/src/opcodes/SelectProtocol.ts | 66 +++++++------ webrtc/src/start.ts | 7 +- 6 files changed, 201 insertions(+), 46 deletions(-) diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts index eb15c28f..42b3713c 100644 --- a/gateway/src/opcodes/Identify.ts +++ b/gateway/src/opcodes/Identify.ts @@ -34,6 +34,8 @@ import { Recipient } from "@fosscord/util"; // TODO: check if already identified export async function onIdentify(this: WebSocket, data: Payload) { + console.log(data); + clearTimeout(this.readyTimeout); check.call(this, IdentifySchema, data.d); diff --git a/webrtc/package-lock.json b/webrtc/package-lock.json index afba7e76..d09123ee 100644 --- a/webrtc/package-lock.json +++ b/webrtc/package-lock.json @@ -69,11 +69,24 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "node_modules/@types/node": { "version": "15.6.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz", @@ -86,6 +99,11 @@ "integrity": "sha512-GVO0gnmbyO3Oxm2HdPsYUNcyihZE3GyCY8ysMYHuQGfLhGZq89Nm4lSzULWTzZoyHtg+VO/IdrnxZHPnPSGnAg==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + }, "node_modules/@types/ws": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz", @@ -130,6 +148,14 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/awaitqueue": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-2.3.3.tgz", + "integrity": "sha512-RbzQg6VtPUtyErm55iuQLTrBJ2uihy5BKBOEkyBwv67xm5Fn2o/j+Bz+a5BmfSoe2oZ5dcz9Z3fExS8pL+LLhw==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -273,6 +299,14 @@ "node": ">=8.0.0" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -365,6 +399,48 @@ "url": "https://opencollective.com/mediasoup" } }, + "node_modules/mediasoup-sdp-bridge": { + "version": "3.6.5", + "resolved": "git+ssh://git@github.com/versatica/mediasoup-sdp-bridge.git#b1a40b97f27b3fd218334f40448a61d704877952", + "license": "ISC", + "dependencies": { + "@types/debug": "^4.1.5", + "@types/node": "^14.0.5", + "@types/uuid": "^8.0.0", + "awaitqueue": "^2.1.1", + "debug": "^4.1.1", + "h264-profile-level-id": "^1.0.1", + "sdp-transform": "^2.14.0", + "supports-color": "^7.1.0", + "uuid": "^8.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mediasoup" + }, + "peerDependencies": { + "mediasoup": "^3.5.15" + } + }, + "node_modules/mediasoup-sdp-bridge/node_modules/@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" + }, + "node_modules/mediasoup-sdp-bridge/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mediasoup/node_modules/@types/node": { "version": "16.11.19", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.19.tgz", @@ -604,11 +680,24 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "@types/node": { "version": "15.6.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz", @@ -621,6 +710,11 @@ "integrity": "sha512-GVO0gnmbyO3Oxm2HdPsYUNcyihZE3GyCY8ysMYHuQGfLhGZq89Nm4lSzULWTzZoyHtg+VO/IdrnxZHPnPSGnAg==", "dev": true }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + }, "@types/ws": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz", @@ -656,6 +750,11 @@ "sprintf-js": "~1.0.2" } }, + "awaitqueue": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-2.3.3.tgz", + "integrity": "sha512-RbzQg6VtPUtyErm55iuQLTrBJ2uihy5BKBOEkyBwv67xm5Fn2o/j+Bz+a5BmfSoe2oZ5dcz9Z3fExS8pL+LLhw==" + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -741,6 +840,11 @@ "debug": "^4.1.1" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -809,6 +913,36 @@ } } }, + "mediasoup-sdp-bridge": { + "version": "git+ssh://git@github.com/versatica/mediasoup-sdp-bridge.git#b1a40b97f27b3fd218334f40448a61d704877952", + "from": "git+ssh://git@github.com/versatica/mediasoup-sdp-bridge.git#b1a40b97f27b3fd218334f40448a61d704877952", + "requires": { + "@types/debug": "^4.1.5", + "@types/node": "^14.0.5", + "@types/uuid": "^8.0.0", + "awaitqueue": "^2.1.1", + "debug": "^4.1.1", + "h264-profile-level-id": "^1.0.1", + "sdp-transform": "^2.14.0", + "supports-color": "^7.1.0", + "uuid": "^8.1.0" + }, + "dependencies": { + "@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts index 42b82c6a..5b76759a 100644 --- a/webrtc/src/Server.ts +++ b/webrtc/src/Server.ts @@ -19,6 +19,8 @@ export class Server { public mediasoupProducers: MediasoupTypes.Producer[] = []; public mediasoupConsumers: MediasoupTypes.Consumer[] = []; + public testUdp = udp.createSocket("udp6"); + constructor() { this.ws = new WebSocketServer({ port, @@ -45,6 +47,12 @@ export class Server { }); }); + // this.testUdp.bind(50001); + // this.testUdp.on("message", (msg, rinfo) => { + // if (msg[0] === 0 && msg[1] === 1 && msg[2] === 0) { //idk stun? + + // } + // }) } async listen(): Promise { @@ -59,7 +67,7 @@ export class Server { async createWorkers(): Promise { const numWorkers = 1; for (let i = 0; i < numWorkers; i++) { - const worker = await mediasoup.createWorker({ logLevel: "debug" }); + const worker = await mediasoup.createWorker({ logLevel: "debug", logTags: ["dtls", "ice", "info", "message", "bwe"] }); if (!worker) return; worker.on("died", () => { @@ -76,10 +84,24 @@ export class Server { await transport.enableTraceEvent(); - transport.on("connect", () => { - console.log("transport connect") + transport.on('dtlsstatechange', (dtlsstate) => { + console.log(dtlsstate); }) + transport.on("sctpstatechange", (sctpstate) => { + console.log(sctpstate) + }) + + router.observer.on("newrtpobserver", (rtpObserver: MediasoupTypes.RtpObserver) => { + console.log("new RTP observer created [id:%s]", rtpObserver.id); + + // rtpObserver.observer.on("") + }) + + transport.on("connect", () => { + console.log("transport connect"); + }); + transport.observer.on("newproducer", (producer: MediasoupTypes.Producer) => { console.log("new producer created [id:%s]", producer.id); @@ -114,9 +136,10 @@ export class Server { kind: "audio", mimeType: "audio/opus", clockRate: 48000, - channels: 2 + channels: 2, + preferredPayloadType: 111, }, - ] + ], }); this.mediasoupWorkers.push(worker); diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts index 9baa16e3..82a82dc1 100644 --- a/webrtc/src/opcodes/Identify.ts +++ b/webrtc/src/opcodes/Identify.ts @@ -34,11 +34,8 @@ export async function onIdentify(this: Server, socket: WebSocket, data: Identify return socket.close(CLOSECODES.Invalid_intent); var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({ - listenIps: [{ ip: "10.22.64.69" }], + listenIps: [{ ip: "10.22.64.63" }], enableUdp: true, - enableTcp: true, - preferUdp: true, - enableSctp: true, }); socket.send(JSON.stringify({ diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts index dc9d2b88..98899caf 100644 --- a/webrtc/src/opcodes/SelectProtocol.ts +++ b/webrtc/src/opcodes/SelectProtocol.ts @@ -6,7 +6,6 @@ import * as mediasoup from "mediasoup"; import { RtpCodecCapability } from "mediasoup/node/lib/RtpParameters"; import * as sdpTransform from 'sdp-transform'; - /* Sent by client: @@ -68,31 +67,8 @@ import * as sdpTransform from 'sdp-transform'; "rtc_connection_id": "3faa0b80-b3e2-4bae-b291-273801fbb7ab" } } - -Sent by server: - -{ - "op": 4, - "d": { - "video_codec": "H264", - "sdp": " - m=audio 50001 ICE/SDP - a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 - c=IN IP4 109.200.214.158 - a=rtcp:50001 - a=ice-ufrag:CLzn - a=ice-pwd:qEmIcNwigd07mu46Ok0XCh - a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 - a=candidate:1 1 UDP 4261412862 109.200.214.158 50001 typ host - ", - "media_session_id": "807955cb953e98c5b90704cf048e81ec", - "audio_codec": "opus" - } -} - */ - export async function onSelectProtocol(this: Server, socket: WebSocket, data: Payload) { const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities; const codecs = rtpCapabilities.codecs as RtpCodecCapability[]; @@ -124,27 +100,49 @@ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Pa console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities })); - const consumer = this.mediasoupConsumers[0] || await transport.consume({ - producerId: producer.id, - paused: false, - rtpCapabilities, - }); + // const consumer = this.mediasoupConsumers[0] || await transport.consume({ + // producerId: producer.id, + // paused: false, + // rtpCapabilities, + // }); + + /* + { + "video_codec":"H264", + "sdp": + " + m=audio 50010 ICE/SDP + a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 + c=IN IP4 109.200.214.158 + a=rtcp:50010 + a=ice-ufrag:+npq + a=ice-pwd:+jf7jAesMeHHby43FRqWTy + a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 + a=candidate:1 1 UDP 4261412862 109.200.214.158 50010 typ host", + "media_session_id":"59265c94fa13e313492c372c4c8da801 + ", + "audio_codec":"opus" + } + */ socket.send(JSON.stringify({ op: VoiceOPCodes.SESSION_DESCRIPTION, d: { video_codec: videoCodec?.mimeType?.substring(6) || undefined, - mode: "xsalsa20_poly1305_lite", + // mode: "xsalsa20_poly1305_lite", media_session_id: transport.id, audio_codec: audioCodec?.mimeType.substring(6), sdp: `m=audio ${transport.iceCandidates[0].port} ICE/SDP\n` + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` - + `c=IN IPV4 ${transport.iceCandidates[0].ip}\n` - + `a=rtcp: ${transport.iceCandidates[0].port}\n` + + `c=IN IP4 ${transport.iceCandidates[0].ip}\n` + + `t=0 0\n` + + `a=ice-lite\n` + + `a=rtcp-mux\n` + + `a=rtcp:${transport.iceCandidates[0].port}\n` + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n` + `a=ice-pwd:${transport.iceParameters.password}\n` - + `a=fingerprint:sha-1 ${transport.dtlsParameters.fingerprints[0].value}\n` - + `a=candidate:1 1 ${transport.iceCandidates[0].protocol} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${transport.iceCandidates[0].port} typ ${transport.iceCandidates[0].type}` + + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` + + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${transport.iceCandidates[0].port} typ ${transport.iceCandidates[0].type}` } })); } \ No newline at end of file diff --git a/webrtc/src/start.ts b/webrtc/src/start.ts index 98f06ad5..f902ec1b 100644 --- a/webrtc/src/start.ts +++ b/webrtc/src/start.ts @@ -1,9 +1,10 @@ -//testing -process.env.DATABASE = "../bundle/database.db"; - import { config } from "dotenv"; config(); +//testing +process.env.DATABASE = "../bundle/database.db"; +process.env.DEBUG = "mediasoup*" + import { Server } from "./Server"; const server = new Server(); From cf97e182df4d89b758c9c2bea752e59c05c8f0e0 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 5 Apr 2022 00:53:32 +1000 Subject: [PATCH 2/4] Trying my hand at implementing desktop voice, magic packets courtesy of that one reverse engineering discord medium post --- util/src/entities/Member.ts | 6 +- webrtc/package-lock.json | 169 ++++++--------------------- webrtc/package.json | 3 + webrtc/src/Server.ts | 62 ++++++++-- webrtc/src/opcodes/Identify.ts | 16 +-- webrtc/src/opcodes/SelectProtocol.ts | 116 +++++++++++------- 6 files changed, 173 insertions(+), 199 deletions(-) diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts index 928a25d7..a246b891 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts @@ -85,8 +85,8 @@ export class Member extends BaseClassWithoutId { @Column() joined_at: Date; - @Column() - premium_since?: Date; + @Column({ type: "bigint", nullable: true }) + premium_since?: number; @Column() deaf: boolean; @@ -245,7 +245,7 @@ export class Member extends BaseClassWithoutId { nick: undefined, roles: [guild_id], // @everyone role joined_at: new Date(), - premium_since: new Date(), + premium_since: (new Date()).getTime(), deaf: false, mute: false, pending: false, diff --git a/webrtc/package-lock.json b/webrtc/package-lock.json index d09123ee..e6b10d69 100644 --- a/webrtc/package-lock.json +++ b/webrtc/package-lock.json @@ -9,7 +9,10 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@types/libsodium-wrappers": "^0.7.9", "dotenv": "^12.0.4", + "libsodium": "^0.7.10", + "libsodium-wrappers": "^0.7.10", "mediasoup": "^3.9.5", "node-turn": "^0.0.6", "sdp-transform": "^2.14.1", @@ -69,23 +72,15 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "node_modules/@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "dependencies": { - "@types/ms": "*" - } - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + "node_modules/@types/libsodium-wrappers": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz", + "integrity": "sha512-LisgKLlYQk19baQwjkBZZXdJL0KbeTpdEnrAfz5hQACbklCY0gVFnsKUyjfNWF1UQsCSjw93Sj5jSbiO8RPfdw==" }, "node_modules/@types/node": { "version": "15.6.1", @@ -99,11 +94,6 @@ "integrity": "sha512-GVO0gnmbyO3Oxm2HdPsYUNcyihZE3GyCY8ysMYHuQGfLhGZq89Nm4lSzULWTzZoyHtg+VO/IdrnxZHPnPSGnAg==", "dev": true }, - "node_modules/@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" - }, "node_modules/@types/ws": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz", @@ -148,14 +138,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/awaitqueue": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-2.3.3.tgz", - "integrity": "sha512-RbzQg6VtPUtyErm55iuQLTrBJ2uihy5BKBOEkyBwv67xm5Fn2o/j+Bz+a5BmfSoe2oZ5dcz9Z3fExS8pL+LLhw==", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -299,14 +281,6 @@ "node": ">=8.0.0" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -357,6 +331,19 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/libsodium": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", + "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", + "dependencies": { + "libsodium": "^0.7.0" + } + }, "node_modules/log4js": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", @@ -399,48 +386,6 @@ "url": "https://opencollective.com/mediasoup" } }, - "node_modules/mediasoup-sdp-bridge": { - "version": "3.6.5", - "resolved": "git+ssh://git@github.com/versatica/mediasoup-sdp-bridge.git#b1a40b97f27b3fd218334f40448a61d704877952", - "license": "ISC", - "dependencies": { - "@types/debug": "^4.1.5", - "@types/node": "^14.0.5", - "@types/uuid": "^8.0.0", - "awaitqueue": "^2.1.1", - "debug": "^4.1.1", - "h264-profile-level-id": "^1.0.1", - "sdp-transform": "^2.14.0", - "supports-color": "^7.1.0", - "uuid": "^8.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mediasoup" - }, - "peerDependencies": { - "mediasoup": "^3.5.15" - } - }, - "node_modules/mediasoup-sdp-bridge/node_modules/@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" - }, - "node_modules/mediasoup-sdp-bridge/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/mediasoup/node_modules/@types/node": { "version": "16.11.19", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.19.tgz", @@ -680,23 +625,15 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "requires": { - "@types/ms": "*" - } - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + "@types/libsodium-wrappers": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz", + "integrity": "sha512-LisgKLlYQk19baQwjkBZZXdJL0KbeTpdEnrAfz5hQACbklCY0gVFnsKUyjfNWF1UQsCSjw93Sj5jSbiO8RPfdw==" }, "@types/node": { "version": "15.6.1", @@ -710,11 +647,6 @@ "integrity": "sha512-GVO0gnmbyO3Oxm2HdPsYUNcyihZE3GyCY8ysMYHuQGfLhGZq89Nm4lSzULWTzZoyHtg+VO/IdrnxZHPnPSGnAg==", "dev": true }, - "@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" - }, "@types/ws": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz", @@ -750,11 +682,6 @@ "sprintf-js": "~1.0.2" } }, - "awaitqueue": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-2.3.3.tgz", - "integrity": "sha512-RbzQg6VtPUtyErm55iuQLTrBJ2uihy5BKBOEkyBwv67xm5Fn2o/j+Bz+a5BmfSoe2oZ5dcz9Z3fExS8pL+LLhw==" - }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -840,11 +767,6 @@ "debug": "^4.1.1" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -875,6 +797,19 @@ "graceful-fs": "^4.1.6" } }, + "libsodium": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", + "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" + }, + "libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", + "requires": { + "libsodium": "^0.7.0" + } + }, "log4js": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", @@ -913,36 +848,6 @@ } } }, - "mediasoup-sdp-bridge": { - "version": "git+ssh://git@github.com/versatica/mediasoup-sdp-bridge.git#b1a40b97f27b3fd218334f40448a61d704877952", - "from": "git+ssh://git@github.com/versatica/mediasoup-sdp-bridge.git#b1a40b97f27b3fd218334f40448a61d704877952", - "requires": { - "@types/debug": "^4.1.5", - "@types/node": "^14.0.5", - "@types/uuid": "^8.0.0", - "awaitqueue": "^2.1.1", - "debug": "^4.1.1", - "h264-profile-level-id": "^1.0.1", - "sdp-transform": "^2.14.0", - "supports-color": "^7.1.0", - "uuid": "^8.1.0" - }, - "dependencies": { - "@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", diff --git a/webrtc/package.json b/webrtc/package.json index b9bac356..82651b7c 100644 --- a/webrtc/package.json +++ b/webrtc/package.json @@ -19,7 +19,10 @@ "typescript": "^4.3.2" }, "dependencies": { + "@types/libsodium-wrappers": "^0.7.9", "dotenv": "^12.0.4", + "libsodium": "^0.7.10", + "libsodium-wrappers": "^0.7.10", "mediasoup": "^3.9.5", "node-turn": "^0.0.6", "sdp-transform": "^2.14.1", diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts index 5b76759a..67f60f9f 100644 --- a/webrtc/src/Server.ts +++ b/webrtc/src/Server.ts @@ -5,8 +5,8 @@ import OPCodeHandlers, { Payload } from "./opcodes"; import { setHeartbeat } from "./util"; import * as mediasoup from "mediasoup"; import { types as MediasoupTypes } from "mediasoup"; - import udp from "dgram"; +import sodium from "libsodium-wrappers"; var port = Number(process.env.PORT); if (isNaN(port)) port = 3004; @@ -47,19 +47,59 @@ export class Server { }); }); - // this.testUdp.bind(50001); - // this.testUdp.on("message", (msg, rinfo) => { - // if (msg[0] === 0 && msg[1] === 1 && msg[2] === 0) { //idk stun? + this.testUdp.bind(50001); + this.testUdp.on("message", (msg, rinfo) => { + //random key from like, the libsodium examples on npm lol + const decryptKey = sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed"); - // } - // }) + //give me my remote port? + if (sodium.to_hex(msg) == "0001004600000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") { + this.testUdp.send(Buffer.from([rinfo.port, 0]), rinfo.port, rinfo.address); + console.log(`got magic packet to send remote port? ${rinfo.address}:${rinfo.port}`); + return; + } + + //Hello + if (sodium.to_hex(msg) == "0100000000000000") { + console.log(`[UDP] client helloed`); + return; + } + + const nonce = Buffer.concat([msg.slice(-4), Buffer.from("\x00".repeat(20))]); + console.log(`[UDP] nonce for this message: ${nonce}`); + + console.log(sodium.to_hex(msg)); + if (sodium.to_hex(msg).indexOf("80c8000600000001") == 0) { + //call status + const encrypted = msg.slice(8, -4); + const currentPacket = msg.slice(-4); + console.log(`[UDP] Current packet: ${currentPacket}`); + try { + console.log(`[UDP] Encrypted bytes: ${encrypted.toString("base64")}`); + const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, decryptKey); + console.log("[UDP] [ call status ]" + decrypted); + } + catch (e) { + console.error(`[UDP] decrypt failure\n${e}\n${encrypted.toString("base64")}`); + } + return; + } + + try { + const decrypted = sodium.crypto_secretbox_open_easy(msg, nonce, decryptKey); + console.log("[UDP] " + decrypted); + } + catch (e) { + console.error(`[UDP] decrypt failure\n${e}\n${msg.toString("base64")}`); + } + }); } async listen(): Promise { // @ts-ignore await initDatabase(); await Config.init(); - await this.createWorkers(); + //await this.createWorkers(); console.log("[DB] connected"); console.log(`[WebRTC] online on 0.0.0.0:${port}`); } @@ -86,17 +126,17 @@ export class Server { transport.on('dtlsstatechange', (dtlsstate) => { console.log(dtlsstate); - }) + }); transport.on("sctpstatechange", (sctpstate) => { - console.log(sctpstate) - }) + console.log(sctpstate); + }); router.observer.on("newrtpobserver", (rtpObserver: MediasoupTypes.RtpObserver) => { console.log("new RTP observer created [id:%s]", rtpObserver.id); // rtpObserver.observer.on("") - }) + }); transport.on("connect", () => { console.log("transport connect"); diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts index 82a82dc1..68452d4f 100644 --- a/webrtc/src/opcodes/Identify.ts +++ b/webrtc/src/opcodes/Identify.ts @@ -33,18 +33,18 @@ export async function onIdentify(this: Server, socket: WebSocket, data: Identify if (!guild.members.find(x => x.id === user.id)) return socket.close(CLOSECODES.Invalid_intent); - var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({ - listenIps: [{ ip: "10.22.64.63" }], - enableUdp: true, - }); - + // var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({ + // listenIps: [{ ip: "10.22.64.56" }], + // enableUdp: true, + // }); +7 socket.send(JSON.stringify({ op: VoiceOPCodes.READY, d: { - streams: [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: false, }))], + streams: data.d.streams ? [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: false, }))] : undefined, ssrc: Math.floor(Math.random() * 10000), - ip: transport.iceCandidates[0].ip, - port: transport.iceCandidates[0].port, + ip: "127.0.0.1",//transport.iceCandidates[0].ip, + port: 50001,//transport.iceCandidates[0].port, modes: [ "aead_aes256_gcm_rtpsize", "aead_aes256_gcm", diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts index 98899caf..29b9c1f9 100644 --- a/webrtc/src/opcodes/SelectProtocol.ts +++ b/webrtc/src/opcodes/SelectProtocol.ts @@ -5,6 +5,7 @@ import { Server } from "../Server"; import * as mediasoup from "mediasoup"; import { RtpCodecCapability } from "mediasoup/node/lib/RtpParameters"; import * as sdpTransform from 'sdp-transform'; +import sodium from "libsodium-wrappers"; /* @@ -70,42 +71,66 @@ import * as sdpTransform from 'sdp-transform'; */ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Payload) { - const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities; - const codecs = rtpCapabilities.codecs as RtpCodecCapability[]; + // const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities; + // const codecs = rtpCapabilities.codecs as RtpCodecCapability[]; - const transport = this.mediasoupTransports[0]; //whatever + if (data.d.sdp) { + // const transport = this.mediasoupTransports[0]; //whatever - const res = sdpTransform.parse(data.d.sdp); + // const res = sdpTransform.parse(data.d.sdp); - const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video"); - const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio"); + // const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video"); + // const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio"); - const producer = this.mediasoupProducers[0] || await transport.produce({ - kind: "audio", - rtpParameters: { - mid: "audio", - codecs: [{ - clockRate: audioCodec!.clockRate, - payloadType: audioCodec!.preferredPayloadType as number, - mimeType: audioCodec!.mimeType, - channels: audioCodec?.channels, - }], - headerExtensions: res.ext?.map(x => ({ - id: x.value, - uri: x.uri, - })), - }, - paused: false, - }); + // const producer = this.mediasoupProducers[0] || await transport.produce({ + // kind: "audio", + // rtpParameters: { + // mid: "audio", + // codecs: [{ + // clockRate: audioCodec!.clockRate, + // payloadType: audioCodec!.preferredPayloadType as number, + // mimeType: audioCodec!.mimeType, + // channels: audioCodec?.channels, + // }], + // headerExtensions: res.ext?.map(x => ({ + // id: x.value, + // uri: x.uri, + // })), + // }, + // paused: false, + // }); - console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities })); + // console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities })); - // const consumer = this.mediasoupConsumers[0] || await transport.consume({ - // producerId: producer.id, - // paused: false, - // rtpCapabilities, - // }); + // // const consumer = this.mediasoupConsumers[0] || await transport.consume({ + // // producerId: producer.id, + // // paused: false, + // // rtpCapabilities, + // // }); + // socket.send(JSON.stringify({ + // op: VoiceOPCodes.SESSION_DESCRIPTION, + // d: { + // video_codec: videoCodec?.mimeType?.substring(6) || undefined, + // // mode: "xsalsa20_poly1305_lite", + // media_session_id: transport.id, + // audio_codec: audioCodec?.mimeType.substring(6), + // secret_key: sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed").buffer, + // sdp: `m=audio ${50001} ICE/SDP\n` + // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` + // + `c=IN IP4 ${transport.iceCandidates[0].ip}\n` + // + `t=0 0\n` + // + `a=ice-lite\n` + // + `a=rtcp-mux\n` + // + `a=rtcp:${50001}\n` + // + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n` + // + `a=ice-pwd:${transport.iceParameters.password}\n` + // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` + // + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${50001} typ ${transport.iceCandidates[0].type}` + // } + // })); + return; + } /* { "video_codec":"H264", @@ -125,24 +150,25 @@ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Pa } */ + + /* + { + "video_codec": "H264", + "secret_key": [36, 80, 96, 53, 95, 149, 253, 16, 137, 186, 238, 222, 251, 180, 94, 150, 112, 137, 192, 109, 69, 79, 218, 111, 217, 197, 56, 74, 18, 41, 51, 140], + "mode": "aead_aes256_gcm_rtpsize", + "media_session_id": "797575a97a87b63e81e2399348b97ad1", + "audio_codec": "opus" + }; + */ + socket.send(JSON.stringify({ - op: VoiceOPCodes.SESSION_DESCRIPTION, + op:VoiceOPCodes.SESSION_DESCRIPTION, d: { - video_codec: videoCodec?.mimeType?.substring(6) || undefined, - // mode: "xsalsa20_poly1305_lite", - media_session_id: transport.id, - audio_codec: audioCodec?.mimeType.substring(6), - sdp: `m=audio ${transport.iceCandidates[0].port} ICE/SDP\n` - + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` - + `c=IN IP4 ${transport.iceCandidates[0].ip}\n` - + `t=0 0\n` - + `a=ice-lite\n` - + `a=rtcp-mux\n` - + `a=rtcp:${transport.iceCandidates[0].port}\n` - + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n` - + `a=ice-pwd:${transport.iceParameters.password}\n` - + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` - + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${transport.iceCandidates[0].port} typ ${transport.iceCandidates[0].type}` + video_codec: "H264", + secret_key: [...sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed")], + mode: "aead_aes256_gcm_rtpsize", + media_session_id: "blah blah blah", + audio_codec: "opus", } })); } \ No newline at end of file From e2e4c5715ed89ef945f6b1adfb5b8b79ae158ef5 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 22 Apr 2022 15:02:40 +1000 Subject: [PATCH 3/4] Added README, added more UDP decryption stuff --- README.md | 38 ++++++++++++++++++---------- webrtc/src/Server.ts | 28 +++++++++++++------- webrtc/src/opcodes/SelectProtocol.ts | 5 +++- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index f2743ed1..fe03e88e 100644 --- a/README.md +++ b/README.md @@ -14,22 +14,34 @@

-## [About](https://fosscord.com) +# Install +Setup fosscord-server as normal ( existing installations are fine, if you run voice on the same server on port `3004` you don't need to edit the `regions_available_0_endpoint` record of `config` ) -This repository contains: +Note: currently everything about webrtc is commented out ( because I was lazy ) +If you want to test that, you're gonna have to do some fiddling, shouldn't be toooo difficult ( check `SelectProtocols.ts`, `Identify.ts` and theres probably smth in `Server.ts` I forgot about ). Also also make sure you set the `listenIps` in `Identify.ts` properly because otherwise the transport won't start -- [Fosscord HTTP API Server](/api) -- [WebSocket Gateway Server](/gateway) -- [HTTP CDN Server](/cdn) -- [Utility and Database Models](/util) -- [RTC Server](/rtc) -- [WebRTC Server](/webrtc) -- [Admin Dashboard](/dashboard) +```sh +cd webrtc +ts-node src/start.ts # don't think the build script works lol +``` -## [Resources](https://docs.fosscord.com/resources/) +# Current problems / setup / etc: +* Webrtc DTLS fails to properly connect with browser voice. The handshake completes and is labeled completed by chrome://webrtc-internals, however mediasoup drops all RTP packets as the 'handshake is not completed' yet. -- [Contributing](https://docs.fosscord.com/contributing/server/) +* After the desktop client updates it's VoiceState to join a voice channel, upon leaving the VoiceState will not update to match, and the client is prevented from joining any new voice channels. The client also continuously plays the voice disconnected notification sound. [Video demo](https://who-the-fuck-pinged.me/6dlya82Z) +* Desktop client cannot properly connect to voice/media servers due to the above, but also because somewhere in my signalling there is a problem. I haven't looked much into it. +* When the client does magically decide to try to connect, it connects to signalling but then [throws an error client-side about `this.conn.setSelfMute` not being a function](https://media.discordapp.net/attachments/903790443052036117/951099310370615306/unknown.png) -## [Setup](https://docs.fosscord.com/server/setup/) +* I have instead been testing voice using [a fork](https://github.com/tenable/DiscordClient) of the reverse engineered client from [this article](https://medium.com/tenable-techblog/lets-reverse-engineer-discord-1976773f4626), with some slight modifications ( I think it was just changing the email field the client uses to login from `email` -> `login`. Todo: these could be aliases in `fosscord-server`? ) +* This client can join a channel, connect to signalling, and does send packets to the UDP server. However, I can't seem to get decrpytion to work. As far as I know, I'm using the same key I'm sending. It turns out the client converts the `secret_key: Number[]` received into a string, but doing the same on the server-side before passing to the decrpyt method still just complains about a key mismatch. -- [Download](https://github.com/fosscord/fosscord-server/releases) +# Resources: +* [Mediasoup docs](https://mediasoup.org/documentation/v3/), or more specifically the [API docs](https://mediasoup.org/documentation/v3/mediasoup/api/) +* * [Mediasoup SFU video demo](https://github.com/Dirvann/mediasoup-sfu-webrtc-video-rooms) +* [The fork of the reverse engineered voice client](https://github.com/edisionnano/DiscordClient) +* * [discord_voice.node stubs for logging client actions](https://github.com/edisionnano/discord_voice-stub/blob/main/discord_voice.js) +* [Discord.com docs: connecting to voice](https://discord.com/developers/docs/topics/voice-connections#connecting-to-voice) +* [Anatomy of a WebRTC SDP](https://webrtchacks.com/sdp-anatomy/) +* [WebRTC Glossary](https://webrtcglossary.com/) +* * [What is an SFU/MCU](https://webrtcglossary.com/sfu/) +* * [How SDP, how to send DTLS fingerprints](https://blog.actorsfit.com/a?ID=00001-8ebd39ca-2d57-41bc-9743-635373e77167) \ No newline at end of file diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts index 67f60f9f..a43768ac 100644 --- a/webrtc/src/Server.ts +++ b/webrtc/src/Server.ts @@ -19,6 +19,7 @@ export class Server { public mediasoupProducers: MediasoupTypes.Producer[] = []; public mediasoupConsumers: MediasoupTypes.Consumer[] = []; + public decryptKey: number[] = []; public testUdp = udp.createSocket("udp6"); constructor() { @@ -50,7 +51,6 @@ export class Server { this.testUdp.bind(50001); this.testUdp.on("message", (msg, rinfo) => { //random key from like, the libsodium examples on npm lol - const decryptKey = sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed"); //give me my remote port? if (sodium.to_hex(msg) == "0001004600000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") { @@ -66,17 +66,27 @@ export class Server { } const nonce = Buffer.concat([msg.slice(-4), Buffer.from("\x00".repeat(20))]); - console.log(`[UDP] nonce for this message: ${nonce}`); + console.log(`[UDP] nonce for this message: ${nonce.toString("hex")}`); + + console.log(`[UDP] message: ${sodium.to_hex(msg)}`); + + let encrypted; + if (msg.slice(0, 2).indexOf("\x81\xc9") == 0) { + encrypted = msg.slice(0x18, -4); + } + else if (msg.slice(0, 2).indexOf("\x90\x78") == 0) { + encrypted = msg.slice(0x1C, -4); + } + else { + encrypted = msg.slice(0x18, -4); + console.log(`wtf header received: ${encrypted.toString("hex")}`); + } - console.log(sodium.to_hex(msg)); if (sodium.to_hex(msg).indexOf("80c8000600000001") == 0) { //call status - const encrypted = msg.slice(8, -4); - const currentPacket = msg.slice(-4); - console.log(`[UDP] Current packet: ${currentPacket}`); + try { - console.log(`[UDP] Encrypted bytes: ${encrypted.toString("base64")}`); - const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, decryptKey); + const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey)); console.log("[UDP] [ call status ]" + decrypted); } catch (e) { @@ -86,7 +96,7 @@ export class Server { } try { - const decrypted = sodium.crypto_secretbox_open_easy(msg, nonce, decryptKey); + const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey)); console.log("[UDP] " + decrypted); } catch (e) { diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts index 29b9c1f9..75ab4495 100644 --- a/webrtc/src/opcodes/SelectProtocol.ts +++ b/webrtc/src/opcodes/SelectProtocol.ts @@ -161,11 +161,14 @@ export async function onSelectProtocol(this: Server, socket: WebSocket, data: Pa }; */ + this.decryptKey = [...sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES)]; + console.log(this.decryptKey.map(x => String.fromCharCode(x)).join("")); + socket.send(JSON.stringify({ op:VoiceOPCodes.SESSION_DESCRIPTION, d: { video_codec: "H264", - secret_key: [...sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed")], + secret_key: this.decryptKey, mode: "aead_aes256_gcm_rtpsize", media_session_id: "blah blah blah", audio_codec: "opus", From 77b31d79a38447a4a68e5afa8c28345b38d73fef Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sun, 5 Jun 2022 22:02:21 +1000 Subject: [PATCH 4/4] More random bullshit --- webrtc/src/Server.ts | 61 +++++--- webrtc/src/opcodes/Identify.ts | 16 +- webrtc/src/opcodes/SelectProtocol.ts | 211 +++++++++++++++------------ 3 files changed, 167 insertions(+), 121 deletions(-) diff --git a/webrtc/src/Server.ts b/webrtc/src/Server.ts index a43768ac..7a1070b9 100644 --- a/webrtc/src/Server.ts +++ b/webrtc/src/Server.ts @@ -7,6 +7,7 @@ import * as mediasoup from "mediasoup"; import { types as MediasoupTypes } from "mediasoup"; import udp from "dgram"; import sodium from "libsodium-wrappers"; +import { assert } from "console"; var port = Number(process.env.PORT); if (isNaN(port)) port = 3004; @@ -19,7 +20,7 @@ export class Server { public mediasoupProducers: MediasoupTypes.Producer[] = []; public mediasoupConsumers: MediasoupTypes.Consumer[] = []; - public decryptKey: number[] = []; + public decryptKey: Uint8Array; public testUdp = udp.createSocket("udp6"); constructor() { @@ -46,9 +47,20 @@ export class Server { socket.close(CLOSECODES.Unknown_opcode); } }); + + socket.on("close", (code: number, reason: string) => { + console.log(`client closed ${code} ${reason}`); + for (var consumer of this.mediasoupConsumers) consumer.close(); + for (var producer of this.mediasoupProducers) producer.close(); + for (var transport of this.mediasoupTransports) transport.close(); + + this.mediasoupConsumers = []; + this.mediasoupProducers = []; + this.mediasoupTransports = []; + }) }); - this.testUdp.bind(50001); + this.testUdp.bind(60000); this.testUdp.on("message", (msg, rinfo) => { //random key from like, the libsodium examples on npm lol @@ -70,23 +82,28 @@ export class Server { console.log(`[UDP] message: ${sodium.to_hex(msg)}`); - let encrypted; - if (msg.slice(0, 2).indexOf("\x81\xc9") == 0) { - encrypted = msg.slice(0x18, -4); - } - else if (msg.slice(0, 2).indexOf("\x90\x78") == 0) { - encrypted = msg.slice(0x1C, -4); - } - else { - encrypted = msg.slice(0x18, -4); - console.log(`wtf header received: ${encrypted.toString("hex")}`); - } + // let encrypted; + // if (Buffer.from(msg).indexOf("\x81\xc9") == 0) { + // encrypted = msg.slice(0x18, -4); + // } + // else if (Buffer.from(msg).indexOf("\x90\x78") == 0) { + // encrypted = msg.slice(0x1C, -4); + // } + // else { + // encrypted = msg.slice(0x18, -4); + // console.log(`wtf header received: ${encrypted.toString("hex")}`); + // } + + let encrypted = msg; if (sodium.to_hex(msg).indexOf("80c8000600000001") == 0) { //call status + encrypted = encrypted.slice(8, -4); + assert(encrypted.length == 40); + try { - const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey)); + const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Buffer.from(this.decryptKey)); console.log("[UDP] [ call status ]" + decrypted); } catch (e) { @@ -95,13 +112,13 @@ export class Server { return; } - try { - const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Uint8Array.from(this.decryptKey)); - console.log("[UDP] " + decrypted); - } - catch (e) { - console.error(`[UDP] decrypt failure\n${e}\n${msg.toString("base64")}`); - } + // try { + // const decrypted = sodium.crypto_secretbox_open_easy(encrypted, nonce, Buffer.from(this.decryptKey.map(x => String.fromCharCode(x)).join(""))); + // console.log("[UDP] " + decrypted); + // } + // catch (e) { + // console.error(`[UDP] decrypt failure\n${e}\n${msg.toString("base64")}`); + // } }); } @@ -109,7 +126,7 @@ export class Server { // @ts-ignore await initDatabase(); await Config.init(); - //await this.createWorkers(); + await this.createWorkers(); console.log("[DB] connected"); console.log(`[WebRTC] online on 0.0.0.0:${port}`); } diff --git a/webrtc/src/opcodes/Identify.ts b/webrtc/src/opcodes/Identify.ts index 68452d4f..ef0386a7 100644 --- a/webrtc/src/opcodes/Identify.ts +++ b/webrtc/src/opcodes/Identify.ts @@ -33,18 +33,18 @@ export async function onIdentify(this: Server, socket: WebSocket, data: Identify if (!guild.members.find(x => x.id === user.id)) return socket.close(CLOSECODES.Invalid_intent); - // var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({ - // listenIps: [{ ip: "10.22.64.56" }], - // enableUdp: true, - // }); -7 + var transport = this.mediasoupTransports[0] || await this.mediasoupRouters[0].createWebRtcTransport({ + listenIps: [{ ip: "10.22.64.146" }], + enableUdp: true, + }); + socket.send(JSON.stringify({ op: VoiceOPCodes.READY, d: { - streams: data.d.streams ? [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: false, }))] : undefined, + streams: data.d.streams ? [...data.d.streams.map(x => ({ ...x, rtx_ssrc: Math.floor(Math.random() * 10000), ssrc: Math.floor(Math.random() * 10000), active: true, }))] : undefined, ssrc: Math.floor(Math.random() * 10000), - ip: "127.0.0.1",//transport.iceCandidates[0].ip, - port: 50001,//transport.iceCandidates[0].port, + ip: transport.iceCandidates[0].ip, + port: transport.iceCandidates[0].port, modes: [ "aead_aes256_gcm_rtpsize", "aead_aes256_gcm", diff --git a/webrtc/src/opcodes/SelectProtocol.ts b/webrtc/src/opcodes/SelectProtocol.ts index 75ab4495..72fb9c79 100644 --- a/webrtc/src/opcodes/SelectProtocol.ts +++ b/webrtc/src/opcodes/SelectProtocol.ts @@ -7,6 +7,24 @@ import { RtpCodecCapability } from "mediasoup/node/lib/RtpParameters"; import * as sdpTransform from 'sdp-transform'; import sodium from "libsodium-wrappers"; +export interface CodecPayload { + name: string, + type: "audio" | "video", + priority: number, + payload_type: number, + rtx_payload_type: number | null, +} + +export interface SelectProtocolPayload extends Payload { + d: { + codecs: Array, + data: string, // SDP if webrtc + protocol: string, + rtc_connection_id: string, + sdp?: string, // same as data + }; +} + /* Sent by client: @@ -70,108 +88,119 @@ import sodium from "libsodium-wrappers"; } */ -export async function onSelectProtocol(this: Server, socket: WebSocket, data: Payload) { - // const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities; - // const codecs = rtpCapabilities.codecs as RtpCodecCapability[]; - +export async function onSelectProtocol(this: Server, socket: WebSocket, data: SelectProtocolPayload) { if (data.d.sdp) { - // const transport = this.mediasoupTransports[0]; //whatever + const rtpCapabilities = this.mediasoupRouters[0].rtpCapabilities; + const codecs = rtpCapabilities.codecs as RtpCodecCapability[]; - // const res = sdpTransform.parse(data.d.sdp); + const transport = this.mediasoupTransports[0]; //whatever - // const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video"); - // const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio"); + const res = sdpTransform.parse(data.d.sdp); - // const producer = this.mediasoupProducers[0] || await transport.produce({ - // kind: "audio", - // rtpParameters: { - // mid: "audio", - // codecs: [{ - // clockRate: audioCodec!.clockRate, - // payloadType: audioCodec!.preferredPayloadType as number, - // mimeType: audioCodec!.mimeType, - // channels: audioCodec?.channels, - // }], - // headerExtensions: res.ext?.map(x => ({ - // id: x.value, - // uri: x.uri, - // })), - // }, - // paused: false, - // }); + const videoCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "video"); + const audioCodec = this.mediasoupRouters[0].rtpCapabilities.codecs!.find((x: any) => x.kind === "audio"); - // console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities })); + const producer = this.mediasoupProducers[0] || await transport.produce({ + kind: "audio", + rtpParameters: { + mid: "audio", + codecs: [{ + clockRate: audioCodec!.clockRate, + payloadType: audioCodec!.preferredPayloadType as number, + mimeType: audioCodec!.mimeType, + channels: audioCodec?.channels, + }], + headerExtensions: res.ext?.map(x => ({ + id: x.value, + uri: x.uri, + })), + }, + paused: false, + }); - // // const consumer = this.mediasoupConsumers[0] || await transport.consume({ - // // producerId: producer.id, - // // paused: false, - // // rtpCapabilities, - // // }); + console.log("can consume: " + this.mediasoupRouters[0].canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities })); - // socket.send(JSON.stringify({ - // op: VoiceOPCodes.SESSION_DESCRIPTION, - // d: { - // video_codec: videoCodec?.mimeType?.substring(6) || undefined, - // // mode: "xsalsa20_poly1305_lite", - // media_session_id: transport.id, - // audio_codec: audioCodec?.mimeType.substring(6), - // secret_key: sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed").buffer, - // sdp: `m=audio ${50001} ICE/SDP\n` - // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` - // + `c=IN IP4 ${transport.iceCandidates[0].ip}\n` - // + `t=0 0\n` - // + `a=ice-lite\n` - // + `a=rtcp-mux\n` - // + `a=rtcp:${50001}\n` - // + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n` - // + `a=ice-pwd:${transport.iceParameters.password}\n` - // + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` - // + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${50001} typ ${transport.iceCandidates[0].type}` - // } - // })); + const consumer = this.mediasoupConsumers[0] || await transport.consume({ + producerId: producer.id, + paused: false, + rtpCapabilities, + }); + + transport.connect({ + dtlsParameters: { + fingerprints: transport.dtlsParameters.fingerprints, + role: "server", + } + }); + + socket.send(JSON.stringify({ + op: VoiceOPCodes.SESSION_DESCRIPTION, + d: { + video_codec: videoCodec?.mimeType?.substring(6) || undefined, + // mode: "xsalsa20_poly1305_lite", + media_session_id: transport.id, + audio_codec: audioCodec?.mimeType.substring(6), + secret_key: sodium.from_hex("724b092810ec86d7e35c9d067702b31ef90bc43a7b598626749914d6a3e033ed").buffer, + sdp: `m=audio ${50001} ICE/SDP\n` + + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` + + `c=IN IP4 ${transport.iceCandidates[0].ip}\n` + + `t=0 0\n` + + `a=ice-lite\n` + + `a=rtcp-mux\n` + + `a=rtcp:${50001}\n` + + `a=ice-ufrag:${transport.iceParameters.usernameFragment}\n` + + `a=ice-pwd:${transport.iceParameters.password}\n` + + `a=fingerprint:sha-256 ${transport.dtlsParameters.fingerprints.find(x => x.algorithm === "sha-256")?.value}\n` + + `a=candidate:1 1 ${transport.iceCandidates[0].protocol.toUpperCase()} ${transport.iceCandidates[0].priority} ${transport.iceCandidates[0].ip} ${50001} typ ${transport.iceCandidates[0].type}` + } + })); return; } - /* - { - "video_codec":"H264", - "sdp": - " - m=audio 50010 ICE/SDP - a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 - c=IN IP4 109.200.214.158 - a=rtcp:50010 - a=ice-ufrag:+npq - a=ice-pwd:+jf7jAesMeHHby43FRqWTy - a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 - a=candidate:1 1 UDP 4261412862 109.200.214.158 50010 typ host", - "media_session_id":"59265c94fa13e313492c372c4c8da801 - ", - "audio_codec":"opus" - } - */ + else { + /* + { + "video_codec":"H264", + "sdp": + " + m=audio 50010 ICE/SDP + a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 + c=IN IP4 109.200.214.158 + a=rtcp:50010 + a=ice-ufrag:+npq + a=ice-pwd:+jf7jAesMeHHby43FRqWTy + a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87 + a=candidate:1 1 UDP 4261412862 109.200.214.158 50010 typ host", + "media_session_id":"59265c94fa13e313492c372c4c8da801 + ", + "audio_codec":"opus" + } + */ - /* - { - "video_codec": "H264", - "secret_key": [36, 80, 96, 53, 95, 149, 253, 16, 137, 186, 238, 222, 251, 180, 94, 150, 112, 137, 192, 109, 69, 79, 218, 111, 217, 197, 56, 74, 18, 41, 51, 140], - "mode": "aead_aes256_gcm_rtpsize", - "media_session_id": "797575a97a87b63e81e2399348b97ad1", - "audio_codec": "opus" - }; - */ + /* + { + "video_codec": "H264", + "secret_key": [36, 80, 96, 53, 95, 149, 253, 16, 137, 186, 238, 222, 251, 180, 94, 150, 112, 137, 192, 109, 69, 79, 218, 111, 217, 197, 56, 74, 18, 41, 51, 140], + "mode": "aead_aes256_gcm_rtpsize", + "media_session_id": "797575a97a87b63e81e2399348b97ad1", + "audio_codec": "opus" + }; + */ - this.decryptKey = [...sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES)]; - console.log(this.decryptKey.map(x => String.fromCharCode(x)).join("")); + this.decryptKey = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES); - socket.send(JSON.stringify({ - op:VoiceOPCodes.SESSION_DESCRIPTION, - d: { - video_codec: "H264", - secret_key: this.decryptKey, - mode: "aead_aes256_gcm_rtpsize", - media_session_id: "blah blah blah", - audio_codec: "opus", - } - })); + // this.decryptKey = new Array(sodium.crypto_secretbox_KEYBYTES).fill(null).map((x, i) => i + 1); + console.log(this.decryptKey); + + socket.send(JSON.stringify({ + op: VoiceOPCodes.SESSION_DESCRIPTION, + d: { + video_codec: "H264", + secret_key: [...this.decryptKey.values()], + mode: "aead_aes256_gcm_rtpsize", + media_session_id: "blah blah blah", + audio_codec: "opus", + } + })); + } } \ No newline at end of file