mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-08 17:02:22 +02:00
random encrypt secret generation
hls redirect fix
This commit is contained in:
@@ -43,6 +43,7 @@ pub(in crate::api) async fn handle_hls_stream_request(app_state: &Arc<AppState>,
|
||||
match request::download_text_content(Arc::clone(&app_state.http_client), input, &url, None).await {
|
||||
Ok((content, response_url)) => {
|
||||
let rewrite_hls_props = RewriteHlsProps {
|
||||
secret: &app_state.config.t_encrypt_secret,
|
||||
base_url: &server_info.get_base_url(),
|
||||
content: &content,
|
||||
hls_url: response_url,
|
||||
@@ -74,7 +75,7 @@ async fn hls_api_stream(
|
||||
return create_custom_video_stream_response(&app_state.config, &CustomVideoStreamType::UserConnectionsExhausted).into_response();
|
||||
}
|
||||
|
||||
let Ok(hls_url) = crypto_utils::decrypt_text(¶ms.token) else { return axum::http::StatusCode::BAD_REQUEST.into_response(); };
|
||||
let Ok(hls_url) = crypto_utils::decrypt_text(&app_state.config.t_encrypt_secret, ¶ms.token) else { return axum::http::StatusCode::BAD_REQUEST.into_response(); };
|
||||
|
||||
let target_name = &target.name;
|
||||
let virtual_id = params.stream_id;
|
||||
|
||||
@@ -223,8 +223,8 @@ async fn xtream_player_api_stream(
|
||||
// debug_if_enabled!("Redirecting stream request to {}", sanitize_sensitive_info(redirect_url));
|
||||
// return redirect(redirect_url).into_response();
|
||||
// }
|
||||
if pli.item_type == PlaylistItemType::LiveDash {
|
||||
let redirect_url = &replace_url_extension(&pli.url, DASH_EXT);
|
||||
if is_hls_request || pli.item_type == PlaylistItemType::LiveDash {
|
||||
let redirect_url = if is_hls_request { &replace_url_extension(&pli.url, HLS_EXT) } else { &replace_url_extension(&pli.url, DASH_EXT) };
|
||||
debug_if_enabled!("Redirecting stream request to {}", sanitize_sensitive_info(redirect_url));
|
||||
return redirect(redirect_url).into_response();
|
||||
}
|
||||
|
||||
@@ -1558,6 +1558,8 @@ pub struct Config {
|
||||
pub t_provider_connections_exhausted_video: Option<Arc<Vec<u8>>>,
|
||||
#[serde(skip)]
|
||||
pub t_access_token_secret: [u8;32],
|
||||
#[serde(skip)]
|
||||
pub t_encrypt_secret: [u8;16],
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -1796,6 +1798,7 @@ impl Config {
|
||||
|
||||
pub fn prepare(&mut self) -> Result<(), M3uFilterError> {
|
||||
self.t_access_token_secret = generate_secret();
|
||||
self.t_encrypt_secret = <&[u8] as TryInto<[u8;16]>>::try_into(&generate_secret()[0..16]).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
let work_dir = &self.working_dir;
|
||||
self.working_dir = file_utils::get_working_path(work_dir);
|
||||
self.prepare_custom_stream_response();
|
||||
|
||||
@@ -6,6 +6,7 @@ pub const HLS_PREFIX: &str = "hls";
|
||||
|
||||
|
||||
pub struct RewriteHlsProps<'a> {
|
||||
pub secret: &'a [u8;16],
|
||||
pub base_url: &'a str,
|
||||
pub content: &'a str,
|
||||
pub hls_url: String,
|
||||
@@ -30,6 +31,8 @@ fn rewrite_hls_url(input: &str, replacement: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO # line can have URI parts whcih shuld rewritten too
|
||||
|
||||
pub fn rewrite_hls(user: &ProxyUserCredentials, props: &RewriteHlsProps) -> String {
|
||||
let username = &user.username;
|
||||
let password = &user.password;
|
||||
@@ -38,9 +41,9 @@ pub fn rewrite_hls(user: &ProxyUserCredentials, props: &RewriteHlsProps) -> Stri
|
||||
if line.starts_with('#') {
|
||||
result.push(line.to_string());
|
||||
} else if let Ok(token) = if line.starts_with("http") {
|
||||
encrypt_text(line)
|
||||
encrypt_text(props.secret, line)
|
||||
} else {
|
||||
encrypt_text(&rewrite_hls_url(&props.hls_url, line))
|
||||
encrypt_text(props.secret, &rewrite_hls_url(&props.hls_url, line))
|
||||
} {
|
||||
result.push(format!("{}/{HLS_PREFIX}/{username}/{password}/{}/{}/{token}", props.base_url, props.input_id, props.virtual_id));
|
||||
}
|
||||
|
||||
@@ -3,13 +3,10 @@ use base64::{engine::general_purpose, Engine as _};
|
||||
use rand::Rng;
|
||||
use crate::m3u_filter_error::{M3uFilterError, M3uFilterErrorKind};
|
||||
|
||||
const SECRET_KEY: &[u8; 16] = b"my-secret-32-byt"; // 32 bytes = AES-256
|
||||
|
||||
pub fn encrypt_text(text: &str) -> Result<String, M3uFilterError> {
|
||||
pub fn encrypt_text(secret: &[u8;16], text: &str) -> Result<String, M3uFilterError> {
|
||||
let iv: [u8; 16] = rand::rng().random(); // Random IV (AES-CBC 16 Bytes)
|
||||
let cipher = Cipher::aes_128_cbc();
|
||||
|
||||
let mut crypter = Crypter::new(cipher, Mode::Encrypt, SECRET_KEY, Some(&iv)).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
let mut crypter = Crypter::new(cipher, Mode::Encrypt, secret, Some(&iv)).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
let mut ciphertext = vec![0; text.len() + cipher.block_size()];
|
||||
let mut count = crypter.update(text.as_bytes(), &mut ciphertext).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
count += crypter.finalize(&mut ciphertext[count..]).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
@@ -21,12 +18,11 @@ pub fn encrypt_text(text: &str) -> Result<String, M3uFilterError> {
|
||||
Ok(general_purpose::URL_SAFE_NO_PAD.encode(out))
|
||||
}
|
||||
|
||||
pub fn decrypt_text(encrypted_text: &str) -> Result<String, M3uFilterError> {
|
||||
pub fn decrypt_text(secret: &[u8;16], encrypted_text: &str) -> Result<String, M3uFilterError> {
|
||||
let data = general_purpose::URL_SAFE_NO_PAD.decode(encrypted_text).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
let (iv, ciphertext) = data.split_at(16); // first 16 bytes IV
|
||||
let cipher = Cipher::aes_128_cbc();
|
||||
|
||||
let mut crypter = Crypter::new(cipher, Mode::Decrypt, SECRET_KEY, Some(iv)).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
let mut crypter = Crypter::new(cipher, Mode::Decrypt, secret, Some(iv)).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
let mut decrypted = vec![0; ciphertext.len() + cipher.block_size()];
|
||||
let mut count = crypter.update(ciphertext, &mut decrypted).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
count += crypter.finalize(&mut decrypted[count..]).map_err(|err| M3uFilterError::new(M3uFilterErrorKind::Info, err.to_string()))?;
|
||||
@@ -37,13 +33,15 @@ pub fn decrypt_text(encrypted_text: &str) -> Result<String, M3uFilterError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::Rng;
|
||||
use crate::utils::crypto_utils::{decrypt_text, encrypt_text};
|
||||
|
||||
#[test]
|
||||
fn test_encrypt() {
|
||||
let secret: [u8; 16] = rand::rng().random(); // Random IV (AES-CBC 16 Bytes)
|
||||
let plain = "hello world";
|
||||
let encrypted = encrypt_text(&plain);
|
||||
let decrypted = decrypt_text(&encrypted.unwrap()).unwrap();
|
||||
let encrypted = encrypt_text(&secret, &plain);
|
||||
let decrypted = decrypt_text(&secret, &encrypted.unwrap()).unwrap();
|
||||
|
||||
assert_eq!(decrypted, plain);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user