Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix concatenation of audio captcha wav files #3350

Merged
merged 9 commits into from
Jun 30, 2023
1 change: 1 addition & 0 deletions crates/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
39 changes: 32 additions & 7 deletions crates/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String, LemmyError> {
let letters = captcha.as_wav();

let mut concat_letters: Vec<u8> = Vec::new();

// Decode each wav file, concatenate the samples
let mut concat_samples: Vec<i16> = Vec::new();
let mut any_header: Option<wav::Header> = 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"));
}
}

// 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",
));
}

// Convert to base64
base64::encode(concat_letters)
Ok(base64::encode(output_buffer.into_inner()))
}

/// Check size of report and remove whitespace
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/local_user/get_captcha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down