Compare commits

..

7 Commits

Author SHA1 Message Date
kozabrada123 3a65ff3ffc
Merge a3ea5c0975 into 51c676c000 2024-03-09 18:36:07 +00:00
kozabrada123 a3ea5c0975 chore: remove unused VoiceHandler 2024-03-09 19:35:58 +01:00
kozabrada123 b79f1a7c26 rename voice example 2024-03-09 18:56:08 +01:00
kozabrada123 2f0b0cf3ae add voice examples, make gateway ones clearer 2024-03-09 18:53:24 +01:00
kozabrada123 be0ae1e7fa chore: use matches macro 2024-03-09 13:15:03 +01:00
kozabrada123 000a4ada8a chore: remove unused variable 2024-03-09 13:03:34 +01:00
kozabrada123 4b7724a703 chore: better unimplemented voice modes handling 2024-03-09 12:59:55 +01:00
11 changed files with 451 additions and 189 deletions

View File

@ -2,6 +2,15 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This example showcase how to properly use gateway observers.
//
// To properly run it, you will need to change the token below.
const TOKEN: &str = "";
/// Find the gateway websocket url of the server we want to connect to
const GATEWAY_URL: &str = "wss://gateway.old.server.spacebar.chat/";
use async_trait::async_trait; use async_trait::async_trait;
use chorus::gateway::Gateway; use chorus::gateway::Gateway;
use chorus::{ use chorus::{
@ -36,11 +45,10 @@ impl Observer<GatewayReady> for ExampleObserver {
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
// Find the gateway websocket url of the server we want to connect to let gateway_websocket_url = GATEWAY_URL.to_string();
let websocket_url_spacebar = "wss://gateway.old.server.spacebar.chat/".to_string();
// Initiate the gateway connection // Initiate the gateway connection
let gateway = Gateway::spawn(websocket_url_spacebar).await.unwrap(); let gateway = Gateway::spawn(gateway_websocket_url).await.unwrap();
// Create an instance of our observer // Create an instance of our observer
let observer = ExampleObserver {}; let observer = ExampleObserver {};
@ -59,7 +67,7 @@ async fn main() {
.subscribe(shared_observer); .subscribe(shared_observer);
// Authenticate so we will receive any events // Authenticate so we will receive any events
let token = "SecretToken".to_string(); let token = TOKEN.to_string();
let mut identify = GatewayIdentifyPayload::common(); let mut identify = GatewayIdentifyPayload::common();
identify.token = token; identify.token = token;
gateway.send_identify(identify).await; gateway.send_identify(identify).await;

View File

@ -2,6 +2,16 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This example showcases how to initiate a gateway connection manually
// (e. g. not through ChorusUser)
//
// To properly run it, you will need to modify the token below.
const TOKEN: &str = "";
/// Find the gateway websocket url of the server we want to connect to
const GATEWAY_URL: &str = "wss://gateway.old.server.spacebar.chat/";
use std::time::Duration; use std::time::Duration;
use chorus::gateway::Gateway; use chorus::gateway::Gateway;
@ -15,16 +25,15 @@ use wasmtimer::tokio::sleep;
/// This example creates a simple gateway connection and a session with an Identify event /// This example creates a simple gateway connection and a session with an Identify event
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
// Find the gateway websocket url of the server we want to connect to let gateway_websocket_url = GATEWAY_URL.to_string();
let websocket_url_spacebar = "wss://gateway.old.server.spacebar.chat/".to_string();
// Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another // Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another
let gateway = Gateway::spawn(websocket_url_spacebar).await.unwrap(); let gateway = Gateway::spawn(gateway_websocket_url).await.unwrap();
// At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated // At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated
// Get a token for an account on the server // Get a token for an account on the server
let token = "SecretToken".to_string(); let token = TOKEN.to_string();
// Create an identify event // Create an identify event
// An Identify event is how the server authenticates us and gets info about our os and browser, along with our intents / capabilities // An Identify event is how the server authenticates us and gets info about our os and browser, along with our intents / capabilities

View File

@ -0,0 +1,13 @@
[package]
name = "voice_simple"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = "*"
chorus = { path = "../../", features = ["rt", "client", "voice"] }
tokio = { version = "*", features = ["full"] }
simplelog = "*"
log = "*"

View File

@ -0,0 +1,311 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This example showcases how to use the voice udp channel.
//
// To use this to properly communicate with voice, you will need to bring your own opus bindings
// along with potentially sending some other events, like Speaking
//
// To properly run this example, you will need to change some values below,
// like the token, guild and channel ids.
const TOKEN: &str = "";
const VOICE_GUILD_ID: Option<Snowflake> = None;
const VOICE_CHANNEL_ID: Option<Snowflake> = Some(Snowflake(0_u64));
const GATEWAY_URL: &str = "wss://gateway.discord.gg";
use async_trait::async_trait;
use simplelog::{TermLogger, Config, WriteLogger};
use std::{net::SocketAddrV4, sync::Arc, fs::File, time::Duration};
use chorus::{
gateway::{Observer, Gateway},
types::{
GatewayReady, SelectProtocol, SelectProtocolData, SessionDescription, Snowflake, Speaking,
SpeakingBitflags, SsrcDefinition, VoiceEncryptionMode, VoiceIdentify, VoiceProtocol,
VoiceReady, VoiceServerUpdate, GatewayIdentifyPayload, UpdateVoiceState,
},
voice::{
gateway::{VoiceGateway, VoiceGatewayHandle},
udp::{UdpHandle, UdpHandler},
voice_data::VoiceData,
},
};
use log::{info, LevelFilter};
use tokio::sync::{Mutex, RwLock};
extern crate chorus;
extern crate tokio;
/// Handles inbetween connections between the gateway and udp modules
#[derive(Debug, Clone)]
pub struct VoiceHandler {
pub voice_gateway_connection: Arc<Mutex<Option<VoiceGatewayHandle>>>,
pub voice_udp_connection: Arc<Mutex<Option<UdpHandle>>>,
pub data: Arc<RwLock<VoiceData>>,
}
impl VoiceHandler {
/// Creates a new voicehandler, only initializing the data
pub fn new() -> VoiceHandler {
Self {
data: Arc::new(RwLock::new(VoiceData::default())),
voice_gateway_connection: Arc::new(Mutex::new(None)),
voice_udp_connection: Arc::new(Mutex::new(None)),
}
}
}
impl Default for VoiceHandler {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
// On [VoiceServerUpdate] we get our starting data and url for the voice gateway server.
impl Observer<VoiceServerUpdate> for VoiceHandler {
async fn update(&self, data: &VoiceServerUpdate) {
let mut data_lock = self.data.write().await;
data_lock.server_data = Some(data.clone());
let user_id = data_lock.user_id;
let session_id = data_lock.session_id.clone();
drop(data_lock);
// Create and connect to the voice gateway
let voice_gateway_handle = VoiceGateway::spawn(data.endpoint.clone().unwrap())
.await
.unwrap();
let server_id: Snowflake;
if data.guild_id.is_some() {
server_id = data.guild_id.unwrap();
} else {
server_id = data.channel_id.unwrap();
}
let voice_identify = VoiceIdentify {
server_id,
user_id,
session_id,
token: data.token.clone(),
video: Some(false),
};
voice_gateway_handle.send_identify(voice_identify).await;
let cloned_gateway_handle = voice_gateway_handle.clone();
let mut voice_events = cloned_gateway_handle.events.lock().await;
let self_reference = Arc::new(self.clone());
// Subscribe to voice gateway events
voice_events.voice_ready.subscribe(self_reference.clone());
voice_events
.session_description
.subscribe(self_reference.clone());
voice_events.speaking.subscribe(self_reference.clone());
voice_events
.ssrc_definition
.subscribe(self_reference.clone());
*self.voice_gateway_connection.lock().await = Some(voice_gateway_handle);
}
}
#[async_trait]
// On [VoiceReady] we get info for establishing a UDP connection, and we immedietly need said UDP
// connection for ip discovery.
impl Observer<VoiceReady> for VoiceHandler {
async fn update(&self, data: &VoiceReady) {
let mut data_lock = self.data.write().await;
data_lock.ready_data = Some(data.clone());
drop(data_lock);
// Create a udp connection and perform ip discovery
let udp_handle = UdpHandler::spawn(
self.data.clone(),
std::net::SocketAddr::V4(SocketAddrV4::new(data.ip, data.port)),
data.ssrc,
)
.await
.unwrap();
// Subscribe ourself to receiving rtp data
udp_handle
.events
.lock()
.await
.rtp
.subscribe(Arc::new(self.clone()));
let ip_discovery = self.data.read().await.ip_discovery.clone().unwrap();
*self.voice_udp_connection.lock().await = Some(udp_handle.clone());
let string_ip_address =
String::from_utf8(ip_discovery.address).expect("Ip discovery gave non string ip");
// Send a select protocol, which tells the server where we'll be receiving data and what
// mode to encrypt data in
self.voice_gateway_connection
.lock()
.await
.clone()
.unwrap()
.send_select_protocol(SelectProtocol {
protocol: VoiceProtocol::Udp,
data: SelectProtocolData {
address: string_ip_address,
port: ip_discovery.port,
// There are several other voice encryption modes available, though not all are
// implemented in chorus
mode: VoiceEncryptionMode::Xsalsa20Poly1305,
},
..Default::default()
})
.await;
}
}
#[async_trait]
// Session descryption gives us final info regarding codecs and our encryption key
impl Observer<SessionDescription> for VoiceHandler {
async fn update(&self, data: &SessionDescription) {
let mut data_write = self.data.write().await;
data_write.session_description = Some(data.clone());
drop(data_write);
}
}
#[async_trait]
// Ready is used just to obtain some info, like the user id and session id
impl Observer<GatewayReady> for VoiceHandler {
async fn update(&self, data: &GatewayReady) {
let mut lock = self.data.write().await;
lock.user_id = data.user.id;
lock.session_id = data.session_id.clone();
drop(lock);
}
}
#[async_trait]
// This is the received voice data
impl Observer<chorus::voice::discortp::rtp::Rtp> for VoiceHandler {
async fn update(&self, data: &chorus::voice::discortp::rtp::Rtp) {
info!(
"Received decrypted voice data! {:?} (SSRC: {})",
data.payload.clone(),
data.ssrc,
);
}
}
#[async_trait]
// This event gives extra info about who is speaking
impl Observer<Speaking> for VoiceHandler {
async fn update(&self, data: &Speaking) {
println!(
"Received Speaking! (SRRC: {}, flags: {:?})",
data.ssrc,
SpeakingBitflags::from_bits(data.speaking).unwrap()
);
}
}
#[async_trait]
// This event gives some info about which user has which ssrc
impl Observer<SsrcDefinition> for VoiceHandler {
async fn update(&self, data: &SsrcDefinition) {
println!(
"Received SSRC Definition! (User {} has audio ssrc {})",
data.user_id.unwrap(),
data.audio_ssrc
);
}
}
#[tokio::main]
async fn main() {
simplelog::CombinedLogger::init(vec![
TermLogger::new(
LevelFilter::Debug,
Config::default(),
simplelog::TerminalMode::Mixed,
simplelog::ColorChoice::Auto,
),
WriteLogger::new(
LevelFilter::Trace,
Config::default(),
File::create("latest.log").unwrap(),
),
])
.unwrap();
let gateway = Gateway::spawn(GATEWAY_URL.to_string())
.await
.unwrap();
let mut identify = GatewayIdentifyPayload::common();
identify.token = TOKEN.to_string();
gateway.send_identify(identify).await;
let voice_handler = Arc::new(VoiceHandler::new());
// Voice handler needs voice server update
gateway
.events
.lock()
.await
.voice
.server_update
.subscribe(voice_handler.clone());
// It also needs a bit of the data in ready
gateway
.events
.lock()
.await
.session
.ready
.subscribe(voice_handler.clone());
// Data which channel to update the local user to be joined into.
//
// guild_id and channel_id can be some to join guild voice channels
//
// guild_id can be none and channel id some to join dm calls
//
// both can be none to leave all voice channels
let voice_state_update = UpdateVoiceState {
guild_id: VOICE_GUILD_ID,
channel_id: VOICE_CHANNEL_ID,
self_mute: false,
self_deaf: false,
..Default::default()
};
gateway.send_update_voice_state(voice_state_update).await;
loop {
tokio::time::sleep(Duration::from_millis(1000)).await;
// Potentially send some data here
/*let voice_udp_option = voice_handler.voice_udp_connection.lock().await.clone();
if voice_udp_option.is_some() {
voice_udp_option.unwrap().send_opus_data(0, vec![1, 2, 3, 4, 5]).await.unwrap();
}*/
}
}

View File

@ -144,6 +144,7 @@ custom_error! {
NoData = "We have not set received the necessary data to perform this operation.", NoData = "We have not set received the necessary data to perform this operation.",
// Encryption errors // Encryption errors
EncryptionModeNotImplemented{encryption_mode: String} = "Voice encryption mode {encryption_mode} is not yet implemented.",
NoKey = "Tried to encrypt / decrypt rtp data, but no key has been received yet", NoKey = "Tried to encrypt / decrypt rtp data, but no key has been received yet",
FailedEncryption = "Tried to encrypt rtp data, but failed. Most likely this is an issue chorus' nonce generation. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new", FailedEncryption = "Tried to encrypt rtp data, but failed. Most likely this is an issue chorus' nonce generation. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new",
FailedDecryption = "Tried to decrypt rtp data, but failed. Most likely this is an issue chorus' nonce generation. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new", FailedDecryption = "Tried to decrypt rtp data, but failed. Most likely this is an issue chorus' nonce generation. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new",

View File

@ -88,14 +88,40 @@ pub enum VoiceEncryptionMode {
// Officially Undocumented // Officially Undocumented
/// Not implemented yet, we have no idea what the rtpsize nonces are. /// Not implemented yet, we have no idea what the rtpsize nonces are.
Xsalsa20Poly1305LiteRtpsize, Xsalsa20Poly1305LiteRtpsize,
/// Not implemented yet /// Not implemented yet, we have no idea what the nonce is.
AeadAes256Gcm, AeadAes256Gcm,
/// Not implemented yet /// Not implemented yet, we have no idea what the rtpsize nonces are.
AeadAes256GcmRtpsize, AeadAes256GcmRtpsize,
/// Not implemented yet, we have no idea what the rtpsize nonces are. /// Not implemented yet, we have no idea what the rtpsize nonces are.
AeadXchacha20Poly1305Rtpsize, AeadXchacha20Poly1305Rtpsize,
} }
impl VoiceEncryptionMode {
/// Returns whether this encryption mode uses Xsalsa20Poly1305 encryption.
pub fn is_xsalsa20_poly1305(&self) -> bool {
matches!(
*self,
VoiceEncryptionMode::Xsalsa20Poly1305
| VoiceEncryptionMode::Xsalsa20Poly1305Lite
| VoiceEncryptionMode::Xsalsa20Poly1305Suffix
| VoiceEncryptionMode::Xsalsa20Poly1305LiteRtpsize
)
}
/// Returns whether this encryption mode uses AeadAes256Gcm encryption.
pub fn is_aead_aes256_gcm(&self) -> bool {
matches!(
*self,
VoiceEncryptionMode::AeadAes256Gcm | VoiceEncryptionMode::AeadAes256GcmRtpsize
)
}
/// Returns whether this encryption mode uses AeadXchacha20Poly1305 encryption.
pub fn is_aead_xchacha20_poly1305(&self) -> bool {
*self == VoiceEncryptionMode::AeadXchacha20Poly1305Rtpsize
}
}
/// The possible audio codecs to use /// The possible audio codecs to use
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]

View File

@ -1,159 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use std::{net::SocketAddrV4, sync::Arc};
use async_trait::async_trait;
use tokio::sync::{Mutex, RwLock};
use crate::{
gateway::Observer,
types::{
GatewayReady, SelectProtocol, SelectProtocolData, SessionDescription, Snowflake,
VoiceEncryptionMode, VoiceIdentify, VoiceProtocol, VoiceReady, VoiceServerUpdate,
},
};
use super::{
gateway::{VoiceGateway, VoiceGatewayHandle},
udp::UdpHandle,
udp::UdpHandler,
voice_data::VoiceData,
};
/// Handles inbetween connections between the gateway and udp modules
#[derive(Debug, Clone)]
pub struct VoiceHandler {
pub voice_gateway_connection: Arc<Mutex<Option<VoiceGatewayHandle>>>,
pub voice_udp_connection: Arc<Mutex<Option<UdpHandle>>>,
pub data: Arc<RwLock<VoiceData>>,
}
impl VoiceHandler {
/// Creates a new voicehandler, only initializing the data
pub fn new() -> VoiceHandler {
Self {
data: Arc::new(RwLock::new(VoiceData::default())),
voice_gateway_connection: Arc::new(Mutex::new(None)),
voice_udp_connection: Arc::new(Mutex::new(None)),
}
}
}
impl Default for VoiceHandler {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
// On [VoiceServerUpdate] we get our starting data and url for the voice gateway server.
impl Observer<VoiceServerUpdate> for VoiceHandler {
async fn update(&self, data: &VoiceServerUpdate) {
let mut data_lock = self.data.write().await;
data_lock.server_data = Some(data.clone());
let user_id = data_lock.user_id;
let session_id = data_lock.session_id.clone();
drop(data_lock);
let voice_gateway_handle = VoiceGateway::spawn(data.endpoint.clone().unwrap())
.await
.unwrap();
let server_id: Snowflake;
if data.guild_id.is_some() {
server_id = data.guild_id.unwrap();
} else {
server_id = data.channel_id.unwrap();
}
let voice_identify = VoiceIdentify {
server_id,
user_id,
session_id,
token: data.token.clone(),
video: Some(false),
};
voice_gateway_handle.send_identify(voice_identify).await;
let cloned_gateway_handle = voice_gateway_handle.clone();
let mut voice_events = cloned_gateway_handle.events.lock().await;
let self_reference = Arc::new(self.clone());
voice_events.voice_ready.subscribe(self_reference.clone());
voice_events
.session_description
.subscribe(self_reference.clone());
*self.voice_gateway_connection.lock().await = Some(voice_gateway_handle);
}
}
#[async_trait]
// On [VoiceReady] we get info for establishing a UDP connection, and we immedietly need said UDP
// connection for ip discovery.
impl Observer<VoiceReady> for VoiceHandler {
async fn update(&self, data: &VoiceReady) {
let mut data_lock = self.data.write().await;
data_lock.ready_data = Some(data.clone());
drop(data_lock);
let udp_handle = UdpHandler::spawn(
self.data.clone(),
std::net::SocketAddr::V4(SocketAddrV4::new(data.ip, data.port)),
data.ssrc,
)
.await
.unwrap();
let ip_discovery = self.data.read().await.ip_discovery.clone().unwrap();
*self.voice_udp_connection.lock().await = Some(udp_handle.clone());
let string_ip_address =
String::from_utf8(ip_discovery.address).expect("Ip discovery gave non string ip");
self.voice_gateway_connection
.lock()
.await
.clone()
.unwrap()
.send_select_protocol(SelectProtocol {
protocol: VoiceProtocol::Udp,
data: SelectProtocolData {
address: string_ip_address,
port: ip_discovery.port,
mode: VoiceEncryptionMode::Xsalsa20Poly1305,
},
..Default::default()
})
.await;
}
}
#[async_trait]
// Session descryption gives us final info regarding codecs and our encryption key
impl Observer<SessionDescription> for VoiceHandler {
async fn update(&self, data: &SessionDescription) {
let mut data_write = self.data.write().await;
data_write.session_description = Some(data.clone());
drop(data_write);
}
}
#[async_trait]
impl Observer<GatewayReady> for VoiceHandler {
async fn update(&self, data: &GatewayReady) {
let mut lock = self.data.write().await;
lock.user_id = data.user.id;
lock.session_id = data.session_id.clone();
drop(lock);
}
}

View File

@ -7,8 +7,6 @@
mod crypto; mod crypto;
#[cfg(feature = "voice_gateway")] #[cfg(feature = "voice_gateway")]
pub mod gateway; pub mod gateway;
#[cfg(all(feature = "voice_udp", feature = "voice_gateway"))]
pub mod handler;
#[cfg(feature = "voice_udp")] #[cfg(feature = "voice_udp")]
pub mod udp; pub mod udp;
#[cfg(feature = "voice_udp")] #[cfg(feature = "voice_udp")]

View File

@ -148,32 +148,61 @@ impl UdpHandle {
.last_udp_encryption_nonce .last_udp_encryption_nonce
.unwrap_or_default() .unwrap_or_default()
.wrapping_add(1); .wrapping_add(1);
data_lock.last_udp_encryption_nonce = Some(nonce); data_lock.last_udp_encryption_nonce = Some(nonce);
drop(data_lock); drop(data_lock);
// TODO: Is le correct? This is not documented anywhere // TODO: Is le correct? This is not documented anywhere
let mut bytes = nonce.to_le_bytes().to_vec(); let mut bytes = nonce.to_le_bytes().to_vec();
// This is 4 bytes, it has to be 24, so we need to append 20
// This is 4 bytes, it has to be a different size, appends 0s
while bytes.len() < 24 { while bytes.len() < 24 {
bytes.push(0); bytes.push(0);
} }
bytes bytes
} }
_ => { _ => {
// TODO: Implement aead_aes256_gcm error!(
todo!("This voice encryption mode is not yet implemented."); "This voice encryption mode ({:?}) is not yet implemented.",
session_description.encryption_mode
);
return Err(VoiceUdpError::EncryptionModeNotImplemented {
encryption_mode: format!("{:?}", session_description.encryption_mode),
});
} }
}; };
let nonce = GenericArray::from_slice(&nonce_bytes);
let key = GenericArray::from_slice(&session_description.secret_key); let key = GenericArray::from_slice(&session_description.secret_key);
let encryption_result;
if session_description.encryption_mode.is_xsalsa20_poly1305() {
let nonce = GenericArray::from_slice(&nonce_bytes);
let encryptor = XSalsa20Poly1305::new(key); let encryptor = XSalsa20Poly1305::new(key);
let encryption_result = encryptor.encrypt(nonce, payload); encryption_result = encryptor.encrypt(nonce, payload);
}
// Note: currently unused because I have no idea what the AeadAes256Gcm nonce is
/*else if session_description.encryption_mode.is_aead_aes256_gcm() {
let nonce = GenericArray::from_slice(&nonce_bytes);
let encryptor = Aes256Gcm::new(key);
encryption_result = encryptor.encrypt(nonce, payload);
}*/
else {
error!(
"This voice encryption mode ({:?}) is not yet implemented.",
session_description.encryption_mode
);
return Err(VoiceUdpError::EncryptionModeNotImplemented {
encryption_mode: format!("{:?}", session_description.encryption_mode),
});
}
if encryption_result.is_err() { if encryption_result.is_err() {
// Safety: If encryption errors here, it's chorus' fault, and it makes no sense to // Safety: If encryption fails here, it's chorus' fault, and it makes no sense to
// return the error to the user. // return the error to the user.
// //
// This is not an error the user should account for, which is why we throw it here. // This is not an error the user should account for, which is why we throw it here.

View File

@ -96,8 +96,6 @@ impl UdpHandler {
}); });
} }
let received_size = received_size_or_err.unwrap();
let receieved_ip_discovery = IpDiscoveryPacket::new(&buf).expect("Could not make ipdiscovery packet from received data, something is very wrong. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new"); let receieved_ip_discovery = IpDiscoveryPacket::new(&buf).expect("Could not make ipdiscovery packet from received data, something is very wrong. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new");
debug!( debug!(
@ -188,7 +186,8 @@ impl UdpHandler {
return; return;
} }
_ => { _ => {
unreachable!(); error!("VUDP: Failed to decrypt voice data: {}", err);
return;
} }
} }
} }
@ -306,18 +305,45 @@ impl UdpHandler {
get_xsalsa20_poly1305_lite_nonce(packet_bytes) get_xsalsa20_poly1305_lite_nonce(packet_bytes)
} }
_ => { _ => {
// TODO: Implement aead_aes256_gcm error!(
todo!("This voice encryption mode is not yet implemented."); "This voice encryption mode ({:?}) is not yet implemented.",
session_description.encryption_mode
);
return Err(VoiceUdpError::EncryptionModeNotImplemented {
encryption_mode: format!("{:?}", session_description.encryption_mode),
});
} }
}; };
let nonce = GenericArray::from_slice(&nonce_bytes);
let key = GenericArray::from_slice(&session_description.secret_key); let key = GenericArray::from_slice(&session_description.secret_key);
let decryption_result;
if session_description.encryption_mode.is_xsalsa20_poly1305() {
let nonce = GenericArray::from_slice(&nonce_bytes);
let decryptor = XSalsa20Poly1305::new(key); let decryptor = XSalsa20Poly1305::new(key);
let decryption_result = decryptor.decrypt(nonce, ciphertext.as_ref()); decryption_result = decryptor.decrypt(nonce, ciphertext.as_ref());
}
// Note: currently unused because I have no idea what the AeadAes256Gcm nonce is
/*else if session_description.encryption_mode.is_aead_aes256_gcm() {
let nonce = GenericArray::from_slice(&nonce_bytes);
let decryptor = Aes256Gcm::new(key);
decryption_result = decryptor.decrypt(nonce, ciphertext.as_ref());
}*/
else {
error!(
"This voice encryption mode ({:?}) is not yet implemented.",
session_description.encryption_mode
);
return Err(VoiceUdpError::EncryptionModeNotImplemented {
encryption_mode: format!("{:?}", session_description.encryption_mode),
});
}
// Note: this may seem like we are throwing away valuable error handling data, // Note: this may seem like we are throwing away valuable error handling data,
// but the decryption error provides no extra info. // but the decryption error provides no extra info.