feat(backend): implemented the backend for authentication

This commit is contained in:
antifallobst 2023-08-12 20:47:31 +02:00
parent 3399e4034b
commit 9fc30d8d0a
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
1 changed files with 47 additions and 10 deletions

View File

@ -1,18 +1,25 @@
use anyhow::Result; use anyhow::Result;
use libinjection::sqli; use libinjection::sqli;
use log::{info, warn}; use log::{info, warn};
use crate::call::{Response, ResponseAuthenticate, ResponseDelete, ResponseRegister};
use pbkdf2::{ use pbkdf2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Pbkdf2, Pbkdf2,
}; };
use crate::call::{Response, ResponseAuthenticate, ResponseDelete, ResponseRegister};
pub struct Backend { pub struct Backend {
db: sqlite::Connection, db: sqlite::Connection,
} }
#[derive(Debug)]
pub struct Account {
id: i64,
username: String,
salt: String,
password: String,
}
fn is_sql_injection(string: &String) -> bool { fn is_sql_injection(string: &String) -> bool {
match sqli(string) { match sqli(string) {
Some((is_injection, _)) => is_injection, Some((is_injection, _)) => is_injection,
@ -23,16 +30,33 @@ fn is_sql_injection(string: &String) -> bool {
impl Backend { impl Backend {
fn user_exists(&mut self, username: &String) -> Result<bool> { fn user_exists(&mut self, username: &String) -> Result<bool> {
let mut statement = self.db.prepare(format!( let mut statement = self.db.prepare(format!(
"SELECT id from Accounts WHERE username='{}';", "SELECT id FROM Accounts WHERE username='{}';",
username username
))?; ))?;
for _ in statement.iter() { for _ in statement.iter() {
// yes, a for loop is useless, but don't wanna look
// too deep into the docs, and it works ^^
return Ok(true); return Ok(true);
} }
Ok(false) Ok(false)
} }
fn get_user(&mut self, username: &String) -> Result<Account> {
let mut statement = self.db.prepare(format!(
"SELECT * FROM Accounts WHERE username='{}';",
username
))?;
statement.next()?;
Ok(Account {
id: statement.read::<i64, _>("id").unwrap(),
username: statement.read::<String, _>("username").unwrap(),
salt: statement.read::<String, _>("salt").unwrap(),
password: statement.read::<String, _>("password").unwrap(),
})
}
pub fn register(&mut self, username: &String, password: &String) -> Result<Response> { pub fn register(&mut self, username: &String, password: &String) -> Result<Response> {
if is_sql_injection(username) { if is_sql_injection(username) {
warn!( warn!(
@ -70,13 +94,26 @@ impl Backend {
return Ok(Response::Authenticate(ResponseAuthenticate::Rejected)); return Ok(Response::Authenticate(ResponseAuthenticate::Rejected));
} }
println!( if !self.user_exists(username)? {
"<Dummy> Authentication Request: (Username: '{}' | Password: '{}')", warn!("Authentication failed, user `{}` not found", username);
username, password return Ok(Response::Authenticate(ResponseAuthenticate::UserNotFound));
); }
println!(" -> Accepted");
let account = self.get_user(username)?;
let hash = PasswordHash::new(&account.password)
.map_err(|_| anyhow::Error::msg("Failed to parse the password hash"))?;
match Pbkdf2.verify_password(password.as_bytes(), &hash) {
Ok(_) => {
info!("Successfully authenticated `{}`", username);
Ok(Response::Authenticate(ResponseAuthenticate::Success)) Ok(Response::Authenticate(ResponseAuthenticate::Success))
} }
Err(_) => {
info!("Failed to authenticate `{}` (wrong password)", username);
Ok(Response::Authenticate(ResponseAuthenticate::WrongPassword))
}
}
}
pub fn delete(&mut self, username: &String) -> Result<Response> { pub fn delete(&mut self, username: &String) -> Result<Response> {
if is_sql_injection(username) { if is_sql_injection(username) {