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",