diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index ca792809..be3065e4 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -30,6 +30,7 @@ captcha = { workspace = true } anyhow = { workspace = true } tracing = { workspace = true } chrono = { workspace = true } +wav = "1.0.0" [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 615a8a31..7ac3cec7 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -3,6 +3,7 @@ use captcha::Captcha; use lemmy_api_common::{context::LemmyContext, utils::local_site_to_slur_regex}; use lemmy_db_schema::source::local_site::LocalSite; use lemmy_utils::{error::LemmyError, utils::slurs::check_slurs}; +use std::io::Cursor; mod comment; mod comment_report; @@ -22,18 +23,42 @@ pub trait Perform { } /// Converts the captcha to a base64 encoded wav audio file -pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String { +pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result { let letters = captcha.as_wav(); - let mut concat_letters: Vec = Vec::new(); - + // Decode each wav file, concatenate the samples + let mut concat_samples: Vec = Vec::new(); + let mut any_header: Option = None; for letter in letters { - let bytes = letter.unwrap_or_default(); - concat_letters.extend(bytes); + let mut cursor = Cursor::new(letter.unwrap_or_default()); + let (header, samples) = wav::read(&mut cursor)?; + any_header = Some(header); + if let Some(samples16) = samples.as_sixteen() { + concat_samples.extend(samples16); + } else { + return Err(LemmyError::from_message("couldnt_create_audio_captcha")); + } } - // Convert to base64 - base64::encode(concat_letters) + // Encode the concatenated result as a wav file + let mut output_buffer = Cursor::new(vec![]); + let header = match any_header { + Some(header) => header, + None => return Err(LemmyError::from_message("couldnt_create_audio_captcha")), + }; + let wav_write_result = wav::write( + header, + &wav::BitDepth::Sixteen(concat_samples), + &mut output_buffer, + ); + if let Err(e) = wav_write_result { + return Err(LemmyError::from_error_message( + e, + "couldnt_create_audio_captcha", + )); + } + + Ok(base64::encode(output_buffer.into_inner())) } /// Check size of report and remove whitespace diff --git a/crates/api/src/local_user/get_captcha.rs b/crates/api/src/local_user/get_captcha.rs index 13304424..92653cfc 100644 --- a/crates/api/src/local_user/get_captcha.rs +++ b/crates/api/src/local_user/get_captcha.rs @@ -33,7 +33,7 @@ impl Perform for GetCaptcha { let png = captcha.as_base64().expect("failed to generate captcha"); - let wav = captcha_as_wav_base64(&captcha); + let wav = captcha_as_wav_base64(&captcha)?; let captcha_form: CaptchaAnswerForm = CaptchaAnswerForm { answer }; // Stores the captcha item in the db