Username checking
This commit is contained in:
@@ -17,3 +17,4 @@ sha3 = "0.10.8"
|
|||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
mail-send = "0.4.8"
|
mail-send = "0.4.8"
|
||||||
|
regex = "1.10.5"
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
|
use std::env;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use mail_send::{Credentials, SmtpClientBuilder};
|
use mail_send::{Credentials, SmtpClientBuilder};
|
||||||
use mail_send::mail_builder::MessageBuilder;
|
use mail_send::mail_builder::MessageBuilder;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use regex::Regex;
|
||||||
use sha3::{Digest, Sha3_256};
|
use sha3::{Digest, Sha3_256};
|
||||||
use sha3::digest::Update;
|
use sha3::digest::Update;
|
||||||
use sqlx::{MySql, Pool, Row};
|
use sqlx::{MySql, Pool, Row};
|
||||||
use sqlx::mysql::{MySqlQueryResult, MySqlRow};
|
|
||||||
use tarpc::context::Context;
|
use tarpc::context::Context;
|
||||||
|
|
||||||
use crate::types::{AuthEmail, AuthUser, ErrorCode, RealmAuth};
|
use crate::types::{AuthEmail, AuthUser, ErrorCode, RealmAuth};
|
||||||
@@ -19,6 +21,7 @@ pub struct RealmAuthServer {
|
|||||||
pub auth_email: AuthEmail,
|
pub auth_email: AuthEmail,
|
||||||
pub template_html: String,
|
pub template_html: String,
|
||||||
pub template_txt: String,
|
pub template_txt: String,
|
||||||
|
pub domain: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RealmAuthServer {
|
impl RealmAuthServer {
|
||||||
@@ -29,6 +32,7 @@ impl RealmAuthServer {
|
|||||||
auth_email,
|
auth_email,
|
||||||
template_html: std::fs::read_to_string("./login_email.html").expect("A login_email.html file is needed"),
|
template_html: std::fs::read_to_string("./login_email.html").expect("A login_email.html file is needed"),
|
||||||
template_txt: std::fs::read_to_string("./login_email.txt").expect("A login_email.txt file is needed"),
|
template_txt: std::fs::read_to_string("./login_email.txt").expect("A login_email.txt file is needed"),
|
||||||
|
domain: env::var("DOMAIN").expect("DOMAIN must be set"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +142,26 @@ impl RealmAuthServer {
|
|||||||
Err(_) => Err(InvalidUsername)
|
Err(_) => Err(InvalidUsername)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_username_valid(&self, username: &str) -> bool {
|
||||||
|
if !username.starts_with('@') || !username.contains(':') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = &username[1..username.find(':').unwrap()];
|
||||||
|
let domain = &username[username.find(':').unwrap()+1..];
|
||||||
|
|
||||||
|
let re = Regex::new(r"^[a-zA-Z0-9]+$").unwrap();
|
||||||
|
if !re.is_match(name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !domain.eq(&self.domain) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RealmAuth for RealmAuthServer {
|
impl RealmAuth for RealmAuthServer {
|
||||||
@@ -167,7 +191,9 @@ impl RealmAuth for RealmAuthServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn create_account_flow(self, _: Context, username: String, email: String) -> Result<(), ErrorCode> {
|
async fn create_account_flow(self, _: Context, username: String, email: String) -> Result<(), ErrorCode> {
|
||||||
//TODO: USERNAME FORMATTING!
|
if !self.is_username_valid(&username) {
|
||||||
|
return Err(InvalidUsername)
|
||||||
|
}
|
||||||
|
|
||||||
if self.is_username_taken(&username).await? {
|
if self.is_username_taken(&username).await? {
|
||||||
return Err(UsernameTaken)
|
return Err(UsernameTaken)
|
||||||
@@ -178,7 +204,7 @@ impl RealmAuth for RealmAuthServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let code = self.gen_login_code();
|
let code = self.gen_login_code();
|
||||||
let _ = self.send_login_message(&username, &email, code).await?;
|
self.send_login_message(&username, &email, code).await?;
|
||||||
|
|
||||||
let result = sqlx::query("INSERT INTO user (username, email, avatar, login_code, tokens) VALUES (?, ?, '', ?, '')")
|
let result = sqlx::query("INSERT INTO user (username, email, avatar, login_code, tokens) VALUES (?, ?, '', ?, '')")
|
||||||
.bind(&username).bind(&email).bind(code).execute(&self.db_pool).await;
|
.bind(&username).bind(&email).bind(code).execute(&self.db_pool).await;
|
||||||
@@ -320,8 +346,9 @@ impl RealmAuth for RealmAuthServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn change_username(self, _: Context, username: String, token: String, new_username: String) -> Result<(), ErrorCode> {
|
async fn change_username(self, _: Context, username: String, token: String, new_username: String) -> Result<(), ErrorCode> {
|
||||||
//TODO: USERNAME FORMATTING!
|
if !self.is_username_valid(&new_username) {
|
||||||
|
return Err(InvalidUsername)
|
||||||
|
}
|
||||||
|
|
||||||
if !self.is_authorized(&username, &token).await? {
|
if !self.is_authorized(&username, &token).await? {
|
||||||
return Err(Unauthorized)
|
return Err(Unauthorized)
|
||||||
|
|||||||
@@ -18,10 +18,7 @@ pub trait RealmAuth {
|
|||||||
|
|
||||||
//NOTE: Anyone can call
|
//NOTE: Anyone can call
|
||||||
async fn get_avatar_for_user(username: String) -> Result<String, ErrorCode>;
|
async fn get_avatar_for_user(username: String) -> Result<String, ErrorCode>;
|
||||||
//TODO:
|
// TODO: OAuth login, check against email, store token, take avatar: Google, Apple, GitHub, Discord
|
||||||
// Create account
|
|
||||||
// Change username
|
|
||||||
// OAuth login, check against email, store token, take avatar: Google, Apple, GitHub, Discord
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
|||||||
Reference in New Issue
Block a user