Skip to content
Snippets Groups Projects
voip.rs 1.74 KiB
Newer Older
  • Learn to ignore specific revisions
  • use std::time::{Duration, SystemTime};
    
    
    🥺's avatar
    🥺 committed
    use base64::{engine::general_purpose, Engine as _};
    
    use conduit::utils;
    
    Timo Kösters's avatar
    Timo Kösters committed
    use hmac::{Hmac, Mac};
    
    use ruma::{api::client::voip::get_turn_server_info, SecondsSinceUnixEpoch, UserId};
    
    
    use crate::{services, Result, Ruma};
    
    const RANDOM_USER_ID_LENGTH: usize = 10;
    
    
    type HmacSha1 = Hmac<Sha1>;
    
    /// # `GET /_matrix/client/r0/voip/turnServer`
    ///
    /// TODO: Returns information about the recommended turn server.
    
    pub(crate) async fn turn_server_route(
    
    	body: Ruma<get_turn_server_info::v3::Request>,
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
    ) -> Result<get_turn_server_info::v3::Response> {
    
    	let turn_secret = services().globals.turn_secret().clone();
    
    	let (username, password) = if !turn_secret.is_empty() {
    		let expiry = SecondsSinceUnixEpoch::from_system_time(
    
    			SystemTime::now()
    				.checked_add(Duration::from_secs(services().globals.turn_ttl()))
    				.expect("TURN TTL should not get this high"),
    
    		)
    		.expect("time is valid");
    
    
    		let user = body.sender_user.unwrap_or_else(|| {
    			UserId::parse_with_server_name(
    				utils::random_string(RANDOM_USER_ID_LENGTH).to_lowercase(),
    				&services().globals.config.server_name,
    			)
    			.unwrap()
    		});
    
    		let username: String = format!("{}:{}", expiry.get(), user);
    
    
    		let mut mac = HmacSha1::new_from_slice(turn_secret.as_bytes()).expect("HMAC can take key of any size");
    		mac.update(username.as_bytes());
    
    		let password: String = general_purpose::STANDARD.encode(mac.finalize().into_bytes());
    
    		(username, password)
    	} else {
    		(
    			services().globals.turn_username().clone(),
    			services().globals.turn_password().clone(),
    		)
    	};
    
    	Ok(get_turn_server_info::v3::Response {
    		username,
    		password,
    		uris: services().globals.turn_uris().to_vec(),
    		ttl: Duration::from_secs(services().globals.turn_ttl()),
    	})