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 libinjection::sqli;
use log::{info, warn};
use crate::call::{Response, ResponseAuthenticate, ResponseDelete, ResponseRegister};
use pbkdf2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Pbkdf2,
};
use crate::call::{Response, ResponseAuthenticate, ResponseDelete, ResponseRegister};
pub struct Backend {
db: sqlite::Connection,
}
#[derive(Debug)]
pub struct Account {
id: i64,
username: String,
salt: String,
password: String,
}
fn is_sql_injection(string: &String) -> bool {
match sqli(string) {
Some((is_injection, _)) => is_injection,
@ -23,16 +30,33 @@ fn is_sql_injection(string: &String) -> bool {
impl Backend {
fn user_exists(&mut self, username: &String) -> Result<bool> {
let mut statement = self.db.prepare(format!(
"SELECT id from Accounts WHERE username='{}';",
"SELECT id FROM Accounts WHERE username='{}';",
username
))?;
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);
}
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> {
if is_sql_injection(username) {
warn!(
@ -70,13 +94,26 @@ impl Backend {
return Ok(Response::Authenticate(ResponseAuthenticate::Rejected));
}
println!(
"<Dummy> Authentication Request: (Username: '{}' | Password: '{}')",
username, password
);
println!(" -> Accepted");
if !self.user_exists(username)? {
warn!("Authentication failed, user `{}` not found", username);
return Ok(Response::Authenticate(ResponseAuthenticate::UserNotFound));
}
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))
}
Err(_) => {
info!("Failed to authenticate `{}` (wrong password)", username);
Ok(Response::Authenticate(ResponseAuthenticate::WrongPassword))
}
}
}
pub fn delete(&mut self, username: &String) -> Result<Response> {
if is_sql_injection(username) {