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;
#[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<LemmyContext>) -> Result<Self::Response, LemmyError>;
}
+/// Converts the captcha to a base64 encoded wav audio file
+pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result<String, LemmyError> {
+ let letters = captcha.as_wav();
+
+ // 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 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)?;
+ }
+ }
+
+ // 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
pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Result<(), LemmyError> {
let slur_regex = &local_site_to_slur_regex(local_site);
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::{
#[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();