this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

The goofball

+171 -24
+3
.gitignore
··· 30 30 # Added by cargo 31 31 32 32 /target 33 + # Added by me 33 34 /client/priv/static/lumina_client*.css 34 35 /client/priv/static/lumina_client*.mjs 36 + instance.sqlite 37 + .env
+64 -10
server/src/client_communication.rs
··· 1 - use crate::AppState; 2 1 use crate::user::User; 2 + use crate::{AppState, LuminaError}; 3 3 use cynthia_con::CynthiaColors; 4 4 extern crate rocket; 5 5 use rocket::State; 6 + use tracing::info; 6 7 use ws; 7 8 8 9 #[get("/connection")] ··· 16 17 user: None, 17 18 }; 18 19 while let Some(message) = stream.next().await { 19 - println!("Received message: {:?}", message); 20 20 match message? { 21 21 ws::Message::Text(msg) => { 22 22 match msg.as_str() { ··· 37 37 username, 38 38 password, 39 39 }) => { 40 + println!( 41 + "Register request: {} {}", 42 + email.clone().color_orange(), 43 + username.clone().color_bright_cyan() 44 + ); 45 + 40 46 // register the user 41 47 { 42 48 let appstate = state.0.clone(); 43 49 let db = &appstate.1.lock().await; 44 - match User::create_user(email, username, password, db).await 50 + match User::create_user(email.clone(), username.clone(), password, db).await 45 51 { 46 52 Ok(user) => { 53 + info!( 54 + "User created: {}", 55 + user.clone().username.color_bright_cyan() 56 + ); 47 57 match User::create_session_token(user, db).await { 48 58 Ok((token, user)) => { 49 59 client_session_data.user = ··· 57 67 ))) 58 68 .await; 59 69 } 60 - Err(_e) => { 70 + Err(e) => { 71 + match e { 72 + LuminaError::Postgres(e) => 73 + error!("Error creating session token: {:?}", e), 74 + 75 + LuminaError::SqlitePool(e) => 76 + warn!("Error creating session token: {:?}", e) 77 + , 78 + _ => {} 79 + } 80 + 61 81 // I would return a more specific error message 62 82 // to the client here, but if the server knows the 63 83 // error, the client should know the error twice as ··· 72 92 } 73 93 } 74 94 75 - Err(_e) => { 95 + Err(e) => { 96 + match e { 97 + LuminaError::RegisterUsernameInUse => { 98 + warn!( 99 + "{} User {} already exists", 100 + "[RegistrationError]" 101 + .color_bright_red(), 102 + username.clone().color_bright_cyan() 103 + ); 104 + } 105 + LuminaError::RegisterEmailNotValid => { 106 + warn!( 107 + "{} Email {} is not valid", 108 + "[RegistrationError]" 109 + .color_bright_red(), 110 + email.clone().color_bright_cyan() 111 + ); 112 + } 113 + LuminaError::RegisterUsernameInvalid(why) => { 114 + warn!( 115 + "{} Username {} is not valid: {}", 116 + "[RegistrationError]" 117 + .color_bright_red(), 118 + username.clone().color_bright_cyan(), 119 + why 120 + ); 121 + } 122 + LuminaError::RegisterPasswordNotValid(why) => { 123 + warn!( 124 + "{} Password is not valid: {}", 125 + "[RegistrationError]".color_bright_red(), 126 + why 127 + ); 128 + } 129 + _ => {} 130 + } 131 + 76 132 // I would return a more specific error message 77 133 // to the client here, but if the server knows the 78 134 // error, the client should know the error twice as ··· 90 146 } 91 147 Ok(jsonmsg) => { 92 148 let _ = stream.send(ws::Message::from("unknown")).await; 93 - eprintln!( 94 - "todo: {}", 95 - format!("Handle message: {:?}", jsonmsg).color_error_red() 96 - ); 149 + todo!("Handle message: {:?}", jsonmsg); 97 150 } 98 - Err(_e) => { 151 + Err(e) => { 152 + error!("Error deserialising message: {:?}", e); 99 153 let _ = stream.send(ws::Message::from("unknown")).await; 100 154 } 101 155 },
+3 -3
server/src/errors.rs
··· 13 13 BcryptError(bcrypt::BcryptError), 14 14 RegisterEmailInUse, 15 15 RegisterUsernameInUse, 16 - EmailNotValid, 17 - RegisterUsernameInvalid, 18 - PasswordNotValid, 16 + RegisterEmailNotValid, 17 + RegisterUsernameInvalid(String), 18 + RegisterPasswordNotValid(String), 19 19 LoginInvalid, 20 20 UUidError(uuid::Error), 21 21 }
+101 -11
server/src/user.rs
··· 1 1 use crate::{LuminaError, database::DbConn}; 2 + use cynthia_con::CynthiaColors; 2 3 use std::str::FromStr; 4 + use tracing::info; 3 5 use uuid::Uuid; 4 6 5 7 #[derive(Debug, Clone)] ··· 15 17 password: String, 16 18 db: &DbConn, 17 19 ) -> Result<User, LuminaError> { 18 - if { 20 + match { 19 21 let mut check_results = vec![]; 20 22 { 21 - check_results.push(username.len() > 4); 22 - check_results.push(username.len() < 20); 23 - check_results.push(username.chars().all(char::is_alphanumeric)); 24 - check_results.push(username.chars().all(char::is_lowercase)); 23 + check_results.push(( 24 + username.len() > 4, 25 + "Username must be at least 5 characters long", 26 + )); 27 + check_results.push(( 28 + username.len() < 20, 29 + "Username must be less than 20 characters long", 30 + )); 31 + // Make sure the username does not contain any special characters, but underscores or dashes are allowed 32 + check_results.push((!username.contains('@'), "Username cannot contain '@'")); 33 + check_results.push((!username.contains('!'), "Username cannot contain '!'")); 34 + check_results.push((!username.contains('#'), "Username cannot contain '#'")); 35 + check_results.push((!username.contains('$'), "Username cannot contain '$'")); 36 + check_results.push((!username.contains('%'), "Username cannot contain '%'")); 37 + check_results.push((!username.contains('^'), "Username cannot contain '^'")); 38 + check_results.push((!username.contains('&'), "Username cannot contain '&'")); 39 + check_results.push((!username.contains('*'), "Username cannot contain '*'")); 40 + check_results.push((!username.contains('('), "Username cannot contain '('")); 41 + check_results.push((!username.contains(')'), "Username cannot contain ')'")); 42 + // check_results.push(( 43 + // username.chars().all(char::is_lowercase), 44 + // "Username must be all lowercase", 45 + // )); 46 + // This false-positive's on the last check, so it's commented out for now, replacing it with a replacement check 47 + check_results.push(( 48 + username.chars().all(|x| { 49 + // No case check on special 50 + if !x.is_alphabetic() { 51 + return true; 52 + } else { 53 + return x.is_lowercase(); 54 + } 55 + }), 56 + "Username must be alphanumeric, with underscores and dashes allowed", 57 + )); 25 58 } 26 - check_results.contains(&false) 59 + check_results.iter().find(|x| x.0 == false).map(|x| x.1) 27 60 } { 28 - return Err(LuminaError::RegisterUsernameInvalid); 61 + Some(v) => { 62 + return Err(LuminaError::RegisterUsernameInvalid(v.to_string())); 63 + } 64 + None => {} 29 65 } 30 66 // Check if the email is valid 31 67 if { ··· 53 89 } 54 90 check_results.contains(&false) 55 91 } { 56 - return Err(LuminaError::EmailNotValid); 92 + return Err(LuminaError::RegisterEmailNotValid); 57 93 } 94 + // Now do that again but with reasons, like for username: 95 + match { 96 + let mut check_results = vec![]; 97 + { 98 + check_results.push(( 99 + password.len() > 7, 100 + "Password must be at least 8 characters long", 101 + )); 102 + check_results.push(( 103 + password.len() < 100, 104 + "Password must be less than 100 characters long", 105 + )); 106 + check_results.push(( 107 + password.chars().any(char::is_uppercase), 108 + "Password must contain at least one uppercase letter", 109 + )); 110 + check_results.push(( 111 + password.chars().any(char::is_lowercase), 112 + "Password must contain at least one lowercase letter", 113 + )); 114 + check_results.push(( 115 + password.chars().any(char::is_numeric), 116 + "Password must contain at least one number", 117 + )); 118 + check_results.push(( 119 + !password.chars().all(char::is_alphanumeric), 120 + "Password must contain at least one special character", 121 + )); 122 + } 123 + check_results.iter().find(|x| x.0 == false).map(|x| x.1) 124 + } { 125 + Some(v) => { 126 + return Err(LuminaError::RegisterPasswordNotValid(v.to_string())); 127 + } 128 + None => {} 129 + } 130 + 58 131 // hash the password 59 132 let password = 60 133 bcrypt::hash(password, bcrypt::DEFAULT_COST).map_err(LuminaError::BcryptError)?; ··· 147 220 username: user.get(2), 148 221 }) 149 222 } 150 - DbConn::SqliteConnectionPool(_) => { 151 - todo!() 152 - } 223 + DbConn::SqliteConnectionPool(pool) => pool 224 + .get() 225 + .map_err(LuminaError::SqlitePool)? 226 + .query_row( 227 + &format!("SELECT * FROM users WHERE {} = ?1", identifyer_type), 228 + &[&identifier], 229 + |row| { 230 + let a: String = row.get(0)?; 231 + Ok(User { 232 + id: Uuid::from_str(a.as_str()).unwrap(), 233 + email: row.get(1)?, 234 + username: row.get(2)?, 235 + }) 236 + }, 237 + ) 238 + .map_err(LuminaError::Sqlite), 153 239 } 154 240 } 155 241 pub async fn create_session_token( ··· 167 253 ) 168 254 .await 169 255 .map_err(LuminaError::Postgres)?; 256 + info!( 257 + "New session created by {}", 258 + user.clone().username.color_bright_cyan() 259 + ); 170 260 Ok((session_key, user)) 171 261 } 172 262 DbConn::SqliteConnectionPool(_) => {