X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fapi%2Fsrc%2Flib.rs;h=9d3cf211c233ef5da1df63408310b18cb69ef840;hb=92568956353f21649ed9aff68b42699c9d036f30;hp=615a8a3144fdea49e8d7bca4388a79c8c05acd23;hpb=2aef6a5a338c9a6b5764fbc1ae42fa3edf096deb;p=lemmy.git diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 615a8a31..9d3cf211 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -1,8 +1,13 @@ use actix_web::web::Data; +use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine}; 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 lemmy_utils::{ + error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + utils::slurs::check_slurs, +}; +use std::io::Cursor; mod comment; mod comment_report; @@ -16,24 +21,43 @@ mod site; #[async_trait::async_trait(?Send)] pub trait Perform { - type Response: serde::ser::Serialize + Send; + type Response: serde::ser::Serialize + Send + Clone + Sync; async fn perform(&self, context: &Data) -> Result; } /// 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(LemmyErrorType::CouldntCreateAudioCaptcha)?; + } } - // 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(LemmyErrorType::CouldntCreateAudioCaptcha)?, + }; + wav::write( + header, + &wav::BitDepth::Sixteen(concat_samples), + &mut output_buffer, + ) + .with_lemmy_type(LemmyErrorType::CouldntCreateAudioCaptcha)?; + + Ok(base64.encode(output_buffer.into_inner())) } /// Check size of report and remove whitespace @@ -42,16 +66,19 @@ pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Resul check_slurs(reason, slur_regex)?; if reason.is_empty() { - return Err(LemmyError::from_message("report_reason_required")); + return Err(LemmyErrorType::ReportReasonRequired)?; } if reason.chars().count() > 1000 { - return Err(LemmyError::from_message("report_too_long")); + return Err(LemmyErrorType::ReportTooLong)?; } Ok(()) } #[cfg(test)] mod tests { + #![allow(clippy::unwrap_used)] + #![allow(clippy::indexing_slicing)] + use lemmy_api_common::utils::check_validator_time; use lemmy_db_schema::{ source::{ @@ -70,6 +97,7 @@ mod tests { #[serial] async fn test_should_not_validate_user_token_after_password_change() { let pool = &build_db_pool_for_tests().await; + let pool = &mut pool.into(); let secret = Secret::init(pool).await.unwrap(); let settings = &SETTINGS.to_owned();