2023-09-20 14:49:54 +00:00
use crate ::error ::{ LemmyErrorExt , LemmyErrorType , LemmyResult } ;
2023-02-16 04:05:14 +00:00
use itertools ::Itertools ;
use once_cell ::sync ::Lazy ;
2023-06-27 11:03:30 +00:00
use regex ::{ Regex , RegexBuilder } ;
2023-02-16 04:05:14 +00:00
use url ::Url ;
2023-10-24 14:47:02 +00:00
// From here: https://github.com/vector-im/element-android/blob/develop/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt#L35
2023-02-16 04:05:14 +00:00
static VALID_MATRIX_ID_REGEX : Lazy < Regex > = Lazy ::new ( | | {
2023-12-21 11:13:24 +00:00
Regex ::new ( r "^@[A-Za-z0-9\x21-\x39\x3B-\x7F]+:[A-Za-z0-9.-]+(:[0-9]{2,5})?$" )
2023-10-24 14:47:02 +00:00
. expect ( " compile regex " )
2023-02-16 04:05:14 +00:00
} ) ;
// taken from https://en.wikipedia.org/wiki/UTM_parameters
static CLEAN_URL_PARAMS_REGEX : Lazy < Regex > = Lazy ::new ( | | {
Regex ::new ( r "^utm_source|utm_medium|utm_campaign|utm_term|utm_content|gclid|gclsrc|dclid|fbclid$" )
. expect ( " compile regex " )
} ) ;
2023-10-24 14:48:00 +00:00
const ALLOWED_POST_URL_SCHEMES : [ & str ; 3 ] = [ " http " , " https " , " magnet " ] ;
2023-06-27 11:03:30 +00:00
2023-04-15 14:45:11 +00:00
const BODY_MAX_LENGTH : usize = 10000 ;
2023-06-26 08:47:01 +00:00
const POST_BODY_MAX_LENGTH : usize = 50000 ;
2023-04-15 14:45:11 +00:00
const BIO_MAX_LENGTH : usize = 300 ;
2023-06-27 11:03:30 +00:00
const SITE_NAME_MAX_LENGTH : usize = 20 ;
const SITE_NAME_MIN_LENGTH : usize = 1 ;
const SITE_DESCRIPTION_MAX_LENGTH : usize = 150 ;
2023-07-04 10:41:58 +00:00
//Invisible unicode characters, taken from https://invisible-characters.com/
const FORBIDDEN_DISPLAY_CHARS : [ char ; 53 ] = [
'\u{0009}' ,
'\u{00a0}' ,
'\u{00ad}' ,
'\u{034f}' ,
'\u{061c}' ,
'\u{115f}' ,
'\u{1160}' ,
'\u{17b4}' ,
'\u{17b5}' ,
'\u{180e}' ,
'\u{2000}' ,
'\u{2001}' ,
'\u{2002}' ,
'\u{2003}' ,
'\u{2004}' ,
'\u{2005}' ,
'\u{2006}' ,
'\u{2007}' ,
'\u{2008}' ,
'\u{2009}' ,
'\u{200a}' ,
'\u{200b}' ,
'\u{200c}' ,
'\u{200d}' ,
'\u{200e}' ,
'\u{200f}' ,
'\u{202f}' ,
'\u{205f}' ,
'\u{2060}' ,
'\u{2061}' ,
'\u{2062}' ,
'\u{2063}' ,
'\u{2064}' ,
'\u{206a}' ,
'\u{206b}' ,
'\u{206c}' ,
'\u{206d}' ,
'\u{206e}' ,
'\u{206f}' ,
'\u{3000}' ,
'\u{2800}' ,
'\u{3164}' ,
'\u{feff}' ,
'\u{ffa0}' ,
'\u{1d159}' ,
'\u{1d173}' ,
'\u{1d174}' ,
'\u{1d175}' ,
'\u{1d176}' ,
'\u{1d177}' ,
'\u{1d178}' ,
'\u{1d179}' ,
'\u{1d17a}' ,
] ;
2023-02-16 04:05:14 +00:00
fn has_newline ( name : & str ) -> bool {
name . contains ( '\n' )
}
2023-04-15 14:45:11 +00:00
pub fn is_valid_actor_name ( name : & str , actor_name_max_length : usize ) -> LemmyResult < ( ) > {
2023-10-24 20:25:52 +00:00
static VALID_ACTOR_NAME_REGEX_EN : Lazy < Regex > =
Lazy ::new ( | | Regex ::new ( r "^[a-zA-Z0-9_]{3,}$" ) . expect ( " compile regex " ) ) ;
static VALID_ACTOR_NAME_REGEX_AR : Lazy < Regex > =
Lazy ::new ( | | Regex ::new ( r "^[\p{Arabic}0-9_]{3,}$" ) . expect ( " compile regex " ) ) ;
static VALID_ACTOR_NAME_REGEX_RU : Lazy < Regex > =
Lazy ::new ( | | Regex ::new ( r "^[\p{Cyrillic}0-9_]{3,}$" ) . expect ( " compile regex " ) ) ;
let check = name . chars ( ) . count ( ) < = actor_name_max_length & & ! has_newline ( name ) ;
// Only allow characters from a single alphabet per username. This avoids problems with lookalike
// characters like `o` which looks identical in Latin and Cyrillic, and can be used to imitate
// other users. Checks for additional alphabets can be added in the same way.
let lang_check = VALID_ACTOR_NAME_REGEX_EN . is_match ( name )
| | VALID_ACTOR_NAME_REGEX_AR . is_match ( name )
| | VALID_ACTOR_NAME_REGEX_RU . is_match ( name ) ;
if ! check | | ! lang_check {
2023-07-10 14:50:07 +00:00
Err ( LemmyErrorType ::InvalidName . into ( ) )
2023-04-15 14:45:11 +00:00
} else {
Ok ( ( ) )
}
2023-02-16 04:05:14 +00:00
}
2023-10-24 14:57:40 +00:00
fn has_3_permitted_display_chars ( name : & str ) -> bool {
let mut num_non_fdc : i8 = 0 ;
for c in name . chars ( ) {
if ! FORBIDDEN_DISPLAY_CHARS . contains ( & c ) {
num_non_fdc + = 1 ;
if num_non_fdc > = 3 {
break ;
}
}
}
if num_non_fdc > = 3 {
return true ;
}
false
}
2023-02-16 04:05:14 +00:00
// Can't do a regex here, reverse lookarounds not supported
2023-04-15 14:45:11 +00:00
pub fn is_valid_display_name ( name : & str , actor_name_max_length : usize ) -> LemmyResult < ( ) > {
2023-10-24 14:57:40 +00:00
let check = ! name . starts_with ( '@' )
& & ! name . starts_with ( FORBIDDEN_DISPLAY_CHARS )
2023-02-16 04:05:14 +00:00
& & name . chars ( ) . count ( ) < = actor_name_max_length
2023-10-24 14:57:40 +00:00
& & ! has_newline ( name )
& & has_3_permitted_display_chars ( name ) ;
2023-04-15 14:45:11 +00:00
if ! check {
2023-07-10 14:50:07 +00:00
Err ( LemmyErrorType ::InvalidDisplayName . into ( ) )
2023-04-15 14:45:11 +00:00
} else {
Ok ( ( ) )
}
}
pub fn is_valid_matrix_id ( matrix_id : & str ) -> LemmyResult < ( ) > {
let check = VALID_MATRIX_ID_REGEX . is_match ( matrix_id ) & & ! has_newline ( matrix_id ) ;
if ! check {
2023-07-10 14:50:07 +00:00
Err ( LemmyErrorType ::InvalidMatrixId . into ( ) )
2023-04-15 14:45:11 +00:00
} else {
Ok ( ( ) )
}
2023-02-16 04:05:14 +00:00
}
2023-04-15 14:45:11 +00:00
pub fn is_valid_post_title ( title : & str ) -> LemmyResult < ( ) > {
2024-01-15 14:33:39 +00:00
let length = title . trim ( ) . chars ( ) . count ( ) ;
2023-11-27 09:46:03 +00:00
let check = ( 3 ..= 200 ) . contains ( & length ) & & ! has_newline ( title ) ;
2023-04-15 14:45:11 +00:00
if ! check {
2023-07-10 14:50:07 +00:00
Err ( LemmyErrorType ::InvalidPostTitle . into ( ) )
2023-04-15 14:45:11 +00:00
} else {
Ok ( ( ) )
}
2023-02-16 04:05:14 +00:00
}
2023-04-15 14:45:11 +00:00
/// This could be post bodies, comments, or any description field
2023-06-26 08:47:01 +00:00
pub fn is_valid_body_field ( body : & Option < String > , post : bool ) -> LemmyResult < ( ) > {
2023-04-15 14:45:11 +00:00
if let Some ( body ) = body {
2023-10-05 20:39:07 +00:00
if post {
max_length_check ( body , POST_BODY_MAX_LENGTH , LemmyErrorType ::InvalidBodyField ) ? ;
2023-06-26 08:47:01 +00:00
} else {
2023-10-05 20:39:07 +00:00
max_length_check ( body , BODY_MAX_LENGTH , LemmyErrorType ::InvalidBodyField ) ? ;
2023-06-26 08:47:01 +00:00
} ;
2023-04-15 14:45:11 +00:00
}
2023-10-05 20:39:07 +00:00
Ok ( ( ) )
2023-04-15 14:45:11 +00:00
}
pub fn is_valid_bio_field ( bio : & str ) -> LemmyResult < ( ) > {
2023-07-10 14:50:07 +00:00
max_length_check ( bio , BIO_MAX_LENGTH , LemmyErrorType ::BioLengthOverflow )
2023-06-27 11:03:30 +00:00
}
/// Checks the site name length, the limit as defined in the DB.
pub fn site_name_length_check ( name : & str ) -> LemmyResult < ( ) > {
2023-10-05 20:39:07 +00:00
min_length_check ( name , SITE_NAME_MIN_LENGTH , LemmyErrorType ::SiteNameRequired ) ? ;
max_length_check (
2023-06-27 11:03:30 +00:00
name ,
SITE_NAME_MAX_LENGTH ,
2023-07-10 14:50:07 +00:00
LemmyErrorType ::SiteNameLengthOverflow ,
2023-06-27 11:03:30 +00:00
)
}
/// Checks the site description length, the limit as defined in the DB.
pub fn site_description_length_check ( description : & str ) -> LemmyResult < ( ) > {
max_length_check (
description ,
SITE_DESCRIPTION_MAX_LENGTH ,
2023-07-10 14:50:07 +00:00
LemmyErrorType ::SiteDescriptionLengthOverflow ,
2023-06-27 11:03:30 +00:00
)
}
2023-10-05 20:39:07 +00:00
/// Check minumum and maximum length of input string. If the string is too short or too long, the
/// corresponding error is returned.
///
/// HTML frontends specify maximum input length using `maxlength` attribute.
/// For consistency we use the same counting method (UTF-16 code units).
/// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength
fn max_length_check ( item : & str , max_length : usize , max_msg : LemmyErrorType ) -> LemmyResult < ( ) > {
let len = item . encode_utf16 ( ) . count ( ) ;
if len > max_length {
Err ( max_msg . into ( ) )
2023-06-27 11:03:30 +00:00
} else {
Ok ( ( ) )
}
}
2023-10-05 20:39:07 +00:00
fn min_length_check ( item : & str , min_length : usize , min_msg : LemmyErrorType ) -> LemmyResult < ( ) > {
let len = item . encode_utf16 ( ) . count ( ) ;
if len < min_length {
2023-07-10 14:50:07 +00:00
Err ( min_msg . into ( ) )
2023-04-15 14:45:11 +00:00
} else {
Ok ( ( ) )
}
2023-02-16 04:05:14 +00:00
}
2023-06-27 11:03:30 +00:00
/// Attempts to build a regex and check it for common errors before inserting into the DB.
pub fn build_and_check_regex ( regex_str_opt : & Option < & str > ) -> LemmyResult < Option < Regex > > {
regex_str_opt . map_or_else (
| | Ok ( None ::< Regex > ) ,
| regex_str | {
if regex_str . is_empty ( ) {
// If the proposed regex is empty, return as having no regex at all; this is the same
// behavior that happens downstream before the write to the database.
return Ok ( None ::< Regex > ) ;
}
RegexBuilder ::new ( regex_str )
. case_insensitive ( true )
. build ( )
2023-07-10 14:50:07 +00:00
. with_lemmy_type ( LemmyErrorType ::InvalidRegex )
2023-06-27 11:03:30 +00:00
. and_then ( | regex | {
// NOTE: It is difficult to know, in the universe of user-crafted regex, which ones
// may match against any string text. To keep it simple, we'll match the regex
// against an innocuous string - a single number - which should help catch a regex
// that accidentally matches against all strings.
if regex . is_match ( " 1 " ) {
2023-08-31 13:01:08 +00:00
Err ( LemmyErrorType ::PermissiveRegex . into ( ) )
} else {
Ok ( Some ( regex ) )
2023-06-27 11:03:30 +00:00
}
} )
} ,
)
}
2023-02-16 04:05:14 +00:00
pub fn clean_url_params ( url : & Url ) -> Url {
let mut url_out = url . clone ( ) ;
if url . query ( ) . is_some ( ) {
let new_query = url
. query_pairs ( )
. filter ( | q | ! CLEAN_URL_PARAMS_REGEX . is_match ( & q . 0 ) )
. map ( | q | format! ( " {} = {} " , q . 0 , q . 1 ) )
. join ( " & " ) ;
url_out . set_query ( Some ( & new_query ) ) ;
}
url_out
}
2023-06-21 20:14:12 +00:00
pub fn check_site_visibility_valid (
current_private_instance : bool ,
current_federation_enabled : bool ,
new_private_instance : & Option < bool > ,
new_federation_enabled : & Option < bool > ,
) -> LemmyResult < ( ) > {
let private_instance = new_private_instance . unwrap_or ( current_private_instance ) ;
let federation_enabled = new_federation_enabled . unwrap_or ( current_federation_enabled ) ;
if private_instance & & federation_enabled {
2023-08-31 13:01:08 +00:00
Err ( LemmyErrorType ::CantEnablePrivateInstanceAndFederationTogether . into ( ) )
} else {
Ok ( ( ) )
2023-06-21 20:14:12 +00:00
}
}
2023-07-06 12:29:51 +00:00
pub fn check_url_scheme ( url : & Option < Url > ) -> LemmyResult < ( ) > {
if let Some ( url ) = url {
2023-10-24 14:48:00 +00:00
if ! ALLOWED_POST_URL_SCHEMES . contains ( & url . scheme ( ) ) {
2023-08-31 13:01:08 +00:00
Err ( LemmyErrorType ::InvalidUrlScheme . into ( ) )
} else {
Ok ( ( ) )
2023-07-06 12:29:51 +00:00
}
2023-08-31 13:01:08 +00:00
} else {
Ok ( ( ) )
2023-07-06 12:29:51 +00:00
}
}
2023-02-16 04:05:14 +00:00
#[ cfg(test) ]
mod tests {
2023-07-17 15:04:14 +00:00
#![ allow(clippy::unwrap_used) ]
#![ allow(clippy::indexing_slicing) ]
2023-07-10 14:50:07 +00:00
use crate ::{
error ::LemmyErrorType ,
utils ::validation ::{
build_and_check_regex ,
check_site_visibility_valid ,
check_url_scheme ,
clean_url_params ,
is_valid_actor_name ,
is_valid_bio_field ,
is_valid_display_name ,
is_valid_matrix_id ,
is_valid_post_title ,
site_description_length_check ,
site_name_length_check ,
BIO_MAX_LENGTH ,
SITE_DESCRIPTION_MAX_LENGTH ,
SITE_NAME_MAX_LENGTH ,
} ,
2023-02-16 04:05:14 +00:00
} ;
2024-01-04 09:47:18 +00:00
use pretty_assertions ::assert_eq ;
2023-02-16 04:05:14 +00:00
use url ::Url ;
#[ test ]
fn test_clean_url_params ( ) {
let url = Url ::parse ( " https://example.com/path/123?utm_content=buffercf3b2&utm_medium=social&username=randomuser&id=123 " ) . unwrap ( ) ;
let cleaned = clean_url_params ( & url ) ;
let expected = Url ::parse ( " https://example.com/path/123?username=randomuser&id=123 " ) . unwrap ( ) ;
assert_eq! ( expected . to_string ( ) , cleaned . to_string ( ) ) ;
let url = Url ::parse ( " https://example.com/path/123 " ) . unwrap ( ) ;
let cleaned = clean_url_params ( & url ) ;
assert_eq! ( url . to_string ( ) , cleaned . to_string ( ) ) ;
}
#[ test ]
fn regex_checks ( ) {
2023-04-15 14:45:11 +00:00
assert! ( is_valid_post_title ( " hi " ) . is_err ( ) ) ;
assert! ( is_valid_post_title ( " him " ) . is_ok ( ) ) ;
2023-11-27 09:46:03 +00:00
assert! ( is_valid_post_title ( " him " ) . is_ok ( ) ) ;
2023-04-15 14:45:11 +00:00
assert! ( is_valid_post_title ( " n \n \n \n \n another " ) . is_err ( ) ) ;
assert! ( is_valid_post_title ( " hello there! \n this is a test. " ) . is_err ( ) ) ;
assert! ( is_valid_post_title ( " hello there! this is a test. " ) . is_ok ( ) ) ;
2023-11-27 09:46:03 +00:00
assert! ( is_valid_post_title ( ( " 12345 " . repeat ( 40 ) + " x " ) . as_str ( ) ) . is_err ( ) ) ;
assert! ( is_valid_post_title ( " 12345 " . repeat ( 40 ) . as_str ( ) ) . is_ok ( ) ) ;
assert! ( is_valid_post_title ( ( ( " 12345 " . repeat ( 40 ) ) + " " ) . as_str ( ) ) . is_ok ( ) ) ;
2023-02-16 04:05:14 +00:00
}
#[ test ]
fn test_valid_actor_name ( ) {
let actor_name_max_length = 20 ;
2023-04-15 14:45:11 +00:00
assert! ( is_valid_actor_name ( " Hello_98 " , actor_name_max_length ) . is_ok ( ) ) ;
assert! ( is_valid_actor_name ( " ten " , actor_name_max_length ) . is_ok ( ) ) ;
2023-10-24 20:25:52 +00:00
assert! ( is_valid_actor_name ( " تجريب " , actor_name_max_length ) . is_ok ( ) ) ;
assert! ( is_valid_actor_name ( " تجريب_123 " , actor_name_max_length ) . is_ok ( ) ) ;
assert! ( is_valid_actor_name ( " Владимир " , actor_name_max_length ) . is_ok ( ) ) ;
// mixed scripts
assert! ( is_valid_actor_name ( " تجريب_abc " , actor_name_max_length ) . is_err ( ) ) ;
assert! ( is_valid_actor_name ( " В ла д_abc" , actor_name_max_length ) . is_err ( ) ) ;
// dash
2023-04-15 14:45:11 +00:00
assert! ( is_valid_actor_name ( " Hello-98 " , actor_name_max_length ) . is_err ( ) ) ;
2023-10-24 20:25:52 +00:00
// too short
2023-04-15 14:45:11 +00:00
assert! ( is_valid_actor_name ( " a " , actor_name_max_length ) . is_err ( ) ) ;
2023-10-24 20:25:52 +00:00
// empty
2023-04-15 14:45:11 +00:00
assert! ( is_valid_actor_name ( " " , actor_name_max_length ) . is_err ( ) ) ;
2023-02-16 04:05:14 +00:00
}
#[ test ]
fn test_valid_display_name ( ) {
let actor_name_max_length = 20 ;
2023-04-15 14:45:11 +00:00
assert! ( is_valid_display_name ( " hello @there " , actor_name_max_length ) . is_ok ( ) ) ;
assert! ( is_valid_display_name ( " @hello there " , actor_name_max_length ) . is_err ( ) ) ;
2023-10-24 14:57:40 +00:00
assert! ( is_valid_display_name ( " \u{200d} hello " , actor_name_max_length ) . is_err ( ) ) ;
assert! ( is_valid_display_name (
" \u{1f3f3} \u{fe0f} \u{200d} \u{26a7} \u{fe0f} Name " ,
actor_name_max_length
)
. is_ok ( ) ) ;
assert! ( is_valid_display_name ( " \u{2003} 1 \u{ffa0} 2 \u{200d} " , actor_name_max_length ) . is_err ( ) ) ;
2023-02-16 04:05:14 +00:00
// Make sure zero-space with an @ doesn't work
2023-04-15 14:45:11 +00:00
assert! (
is_valid_display_name ( & format! ( " {} @my name is " , '\u{200b}' ) , actor_name_max_length ) . is_err ( )
) ;
2023-02-16 04:05:14 +00:00
}
#[ test ]
fn test_valid_post_title ( ) {
2023-04-15 14:45:11 +00:00
assert! ( is_valid_post_title ( " Post Title " ) . is_ok ( ) ) ;
2024-01-15 14:33:39 +00:00
assert! ( is_valid_post_title (
" აშშ ითხოვს ირანს დაუყოვნებლივ გაანთავისუფლოს დაკავებული ნავთობის ტანკერი "
)
. is_ok ( ) ) ;
2023-04-15 14:45:11 +00:00
assert! ( is_valid_post_title ( " POST TITLE 😃😃😃😃😃 " ) . is_ok ( ) ) ;
assert! ( is_valid_post_title ( " \n \n \n \n " ) . is_err ( ) ) ; // tabs/spaces/newlines
2023-02-16 04:05:14 +00:00
}
#[ test ]
fn test_valid_matrix_id ( ) {
2023-04-15 14:45:11 +00:00
assert! ( is_valid_matrix_id ( " @dess:matrix.org " ) . is_ok ( ) ) ;
2023-12-21 11:13:24 +00:00
assert! ( is_valid_matrix_id ( " @dess_:matrix.org " ) . is_ok ( ) ) ;
2023-10-24 14:47:02 +00:00
assert! ( is_valid_matrix_id ( " @dess:matrix.org:443 " ) . is_ok ( ) ) ;
2023-04-15 14:45:11 +00:00
assert! ( is_valid_matrix_id ( " dess:matrix.org " ) . is_err ( ) ) ;
assert! ( is_valid_matrix_id ( " @dess:matrix.org " ) . is_err ( ) ) ;
assert! ( is_valid_matrix_id ( " @dess:matrix.org t " ) . is_err ( ) ) ;
2023-10-24 14:47:02 +00:00
assert! ( is_valid_matrix_id ( " @dess:matrix.org t " ) . is_err ( ) ) ;
2023-02-16 04:05:14 +00:00
}
2023-03-02 20:37:41 +00:00
2023-06-27 11:03:30 +00:00
#[ test ]
fn test_valid_site_name ( ) {
let valid_names = [
( 0 .. SITE_NAME_MAX_LENGTH ) . map ( | _ | 'A' ) . collect ::< String > ( ) ,
String ::from ( " A " ) ,
] ;
let invalid_names = [
(
& ( 0 .. SITE_NAME_MAX_LENGTH + 1 )
. map ( | _ | 'A' )
. collect ::< String > ( ) ,
2023-07-10 14:50:07 +00:00
LemmyErrorType ::SiteNameLengthOverflow ,
2023-06-27 11:03:30 +00:00
) ,
2023-07-10 14:50:07 +00:00
( & String ::new ( ) , LemmyErrorType ::SiteNameRequired ) ,
2023-06-27 11:03:30 +00:00
] ;
valid_names . iter ( ) . for_each ( | valid_name | {
assert! (
site_name_length_check ( valid_name ) . is_ok ( ) ,
" Expected {} of length {} to be Ok. " ,
valid_name ,
valid_name . len ( )
)
} ) ;
invalid_names
. iter ( )
2023-07-10 14:50:07 +00:00
. for_each ( | ( invalid_name , expected_err ) | {
2023-06-27 11:03:30 +00:00
let result = site_name_length_check ( invalid_name ) ;
assert! ( result . is_err ( ) ) ;
assert! (
2023-07-10 20:44:14 +00:00
result . unwrap_err ( ) . error_type . eq ( & expected_err . clone ( ) ) ,
2023-06-27 11:03:30 +00:00
" Testing {}, expected error {} " ,
invalid_name ,
expected_err
) ;
} ) ;
}
#[ test ]
fn test_valid_bio ( ) {
assert! ( is_valid_bio_field ( & ( 0 .. BIO_MAX_LENGTH ) . map ( | _ | 'A' ) . collect ::< String > ( ) ) . is_ok ( ) ) ;
let invalid_result =
is_valid_bio_field ( & ( 0 .. BIO_MAX_LENGTH + 1 ) . map ( | _ | 'A' ) . collect ::< String > ( ) ) ;
assert! (
invalid_result . is_err ( )
& & invalid_result
. unwrap_err ( )
2023-07-10 14:50:07 +00:00
. error_type
2023-07-10 20:44:14 +00:00
. eq ( & LemmyErrorType ::BioLengthOverflow )
2023-06-27 11:03:30 +00:00
) ;
}
#[ test ]
fn test_valid_site_description ( ) {
assert! ( site_description_length_check (
& ( 0 .. SITE_DESCRIPTION_MAX_LENGTH )
. map ( | _ | 'A' )
. collect ::< String > ( )
)
. is_ok ( ) ) ;
let invalid_result = site_description_length_check (
& ( 0 .. SITE_DESCRIPTION_MAX_LENGTH + 1 )
. map ( | _ | 'A' )
. collect ::< String > ( ) ,
) ;
assert! (
invalid_result . is_err ( )
& & invalid_result
. unwrap_err ( )
2023-07-10 14:50:07 +00:00
. error_type
2023-07-10 20:44:14 +00:00
. eq ( & LemmyErrorType ::SiteDescriptionLengthOverflow )
2023-06-27 11:03:30 +00:00
) ;
}
#[ test ]
fn test_valid_slur_regex ( ) {
let valid_regexes = [ & None , & Some ( " " ) , & Some ( " (foo|bar) " ) ] ;
valid_regexes . iter ( ) . for_each ( | regex | {
let result = build_and_check_regex ( regex ) ;
assert! ( result . is_ok ( ) , " Testing regex: {:?} " , regex ) ;
} ) ;
}
#[ test ]
fn test_too_permissive_slur_regex ( ) {
let match_everything_regexes = [
2023-07-10 14:50:07 +00:00
( & Some ( " [ " ) , LemmyErrorType ::InvalidRegex ) ,
( & Some ( " (foo|bar|) " ) , LemmyErrorType ::PermissiveRegex ) ,
( & Some ( " .* " ) , LemmyErrorType ::PermissiveRegex ) ,
2023-06-27 11:03:30 +00:00
] ;
match_everything_regexes
. iter ( )
2023-07-10 14:50:07 +00:00
. for_each ( | ( regex_str , expected_err ) | {
2023-06-27 11:03:30 +00:00
let result = build_and_check_regex ( regex_str ) ;
assert! ( result . is_err ( ) ) ;
assert! (
2023-07-10 20:44:14 +00:00
result . unwrap_err ( ) . error_type . eq ( & expected_err . clone ( ) ) ,
2023-06-27 11:03:30 +00:00
" Testing regex {:?}, expected error {} " ,
regex_str ,
expected_err
) ;
} ) ;
}
2023-06-21 20:14:12 +00:00
#[ test ]
fn test_check_site_visibility_valid ( ) {
assert! ( check_site_visibility_valid ( true , true , & None , & None ) . is_err ( ) ) ;
assert! ( check_site_visibility_valid ( true , false , & None , & Some ( true ) ) . is_err ( ) ) ;
assert! ( check_site_visibility_valid ( false , true , & Some ( true ) , & None ) . is_err ( ) ) ;
assert! ( check_site_visibility_valid ( false , false , & Some ( true ) , & Some ( true ) ) . is_err ( ) ) ;
assert! ( check_site_visibility_valid ( true , false , & None , & None ) . is_ok ( ) ) ;
assert! ( check_site_visibility_valid ( false , true , & None , & None ) . is_ok ( ) ) ;
assert! ( check_site_visibility_valid ( false , false , & Some ( true ) , & None ) . is_ok ( ) ) ;
assert! ( check_site_visibility_valid ( false , false , & None , & Some ( true ) ) . is_ok ( ) ) ;
}
2023-07-06 12:29:51 +00:00
#[ test ]
fn test_check_url_scheme ( ) {
assert! ( check_url_scheme ( & None ) . is_ok ( ) ) ;
assert! ( check_url_scheme ( & Some ( Url ::parse ( " http://example.com " ) . unwrap ( ) ) ) . is_ok ( ) ) ;
assert! ( check_url_scheme ( & Some ( Url ::parse ( " https://example.com " ) . unwrap ( ) ) ) . is_ok ( ) ) ;
2023-10-24 14:48:00 +00:00
assert! ( check_url_scheme ( & Some ( Url ::parse ( " https://example.com " ) . unwrap ( ) ) ) . is_ok ( ) ) ;
2023-07-06 12:29:51 +00:00
assert! ( check_url_scheme ( & Some ( Url ::parse ( " ftp://example.com " ) . unwrap ( ) ) ) . is_err ( ) ) ;
assert! ( check_url_scheme ( & Some ( Url ::parse ( " javascript:void " ) . unwrap ( ) ) ) . is_err ( ) ) ;
2023-10-24 14:48:00 +00:00
let magnet_link = " magnet:?xt=urn:btih:4b390af3891e323778959d5abfff4b726510f14c&dn=Ravel%20Complete%20Piano%20Sheet%20Music%20-%20Public%20Domain&tr=udp%3A%2F%2Fopen.tracker.cl%3A1337%2Fannounce " ;
assert! ( check_url_scheme ( & Some ( Url ::parse ( magnet_link ) . unwrap ( ) ) ) . is_ok ( ) ) ;
2023-07-06 12:29:51 +00:00
}
2023-02-16 04:05:14 +00:00
}