Compare commits

...

4 commits

Author SHA1 Message Date
cc07d78325 build: add a run-dev.sh for local testing
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful
2025-05-02 16:23:45 +02:00
2c73a07961 build: use one log file instead of 2 2025-05-02 16:23:11 +02:00
c76fd73179 refactor: move regex code to mod.rs 2025-05-02 16:22:30 +02:00
0ccfa53746 docs: remove left over comment 2025-05-02 16:21:44 +02:00
7 changed files with 67 additions and 28 deletions

36
compose.dev.yml Normal file
View file

@ -0,0 +1,36 @@
version: '3.5'
volumes:
gorb-backend:
gorb-database:
networks:
gorb:
services:
backend:
image: gorb/backend
build:
dockerfile: ./Dockerfile
restart: always
ports:
- 8080:8080
networks:
- gorb
volumes:
- gorb-backend:/gorb
environment:
#- RUST_LOG=debug
- DATABASE_USERNAME=gorb
- DATABASE_PASSWORD=gorb
- DATABASE=gorb
- DATABASE_HOST=database
- DATABASE_PORT=5432
database:
image: postgres:16
restart: always
networks:
- gorb
volumes:
- gorb-database:/var/lib/postgresql/data
environment:
- POSTGRES_USER=gorb
- POSTGRES_PASSWORD=gorb
- POSTGRES_DB=gorb

View file

@ -36,7 +36,6 @@ rotate_log() {
fi fi
} }
rotate_log "/gorb/logs/stdout.log" rotate_log "/gorb/logs/backend.log"
rotate_log "/gorb/logs/stderr.log"
/usr/bin/gorb-backend --config /gorb/config/config.toml > /gorb/logs/stdout.log 2> /gorb/logs/stderr.log /usr/bin/gorb-backend --config /gorb/config/config.toml 2>&1 | tee /gorb/logs/backend.log

9
run-dev.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
podman-compose --file compose.dev.yml up --build
echo "SHUTTING DOWN CONTAINERS"
podman container stop backend_backend_1 backend_database_1
echo "DELETING CONTAINERS"
podman container rm backend_backend_1 backend_database_1

View file

@ -4,11 +4,11 @@ use actix_web::{Error, HttpResponse, error, post, web};
use argon2::{PasswordHash, PasswordVerifier}; use argon2::{PasswordHash, PasswordVerifier};
use futures::StreamExt; use futures::StreamExt;
use log::error; use log::error;
use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
Data, Data,
api::v1::auth::{EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX},
crypto::{generate_access_token, generate_refresh_token}, crypto::{generate_access_token, generate_refresh_token},
}; };
@ -44,19 +44,11 @@ pub async fn response(
let login_information = serde_json::from_slice::<LoginInformation>(&body)?; let login_information = serde_json::from_slice::<LoginInformation>(&body)?;
let email_regex = Regex::new(r"[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?").unwrap(); if !PASSWORD_REGEX.is_match(&login_information.password) {
// FIXME: This regex doesnt seem to be working
let username_regex = Regex::new(r"[a-zA-Z0-9.-_]").unwrap();
// Password is expected to be hashed using SHA3-384
let password_regex = Regex::new(r"[0-9a-f]{96}").unwrap();
if !password_regex.is_match(&login_information.password) {
return Ok(HttpResponse::Forbidden().json(r#"{ "password_hashed": false }"#)); return Ok(HttpResponse::Forbidden().json(r#"{ "password_hashed": false }"#));
} }
if email_regex.is_match(&login_information.username) { if EMAIL_REGEX.is_match(&login_information.username) {
if let Ok(row) = if let Ok(row) =
sqlx::query_as("SELECT CAST(uuid as VARCHAR), password FROM users WHERE email = $1") sqlx::query_as("SELECT CAST(uuid as VARCHAR), password FROM users WHERE email = $1")
.bind(login_information.username) .bind(login_information.username)
@ -75,7 +67,7 @@ pub async fn response(
} }
return Ok(HttpResponse::Unauthorized().finish()); return Ok(HttpResponse::Unauthorized().finish());
} else if username_regex.is_match(&login_information.username) { } else if USERNAME_REGEX.is_match(&login_information.username) {
if let Ok(row) = if let Ok(row) =
sqlx::query_as("SELECT CAST(uuid as VARCHAR), password FROM users WHERE username = $1") sqlx::query_as("SELECT CAST(uuid as VARCHAR), password FROM users WHERE username = $1")
.bind(login_information.username) .bind(login_information.username)

View file

@ -1,10 +1,12 @@
use std::{ use std::{
str::FromStr, str::FromStr,
sync::LazyLock,
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use actix_web::{HttpResponse, Scope, web}; use actix_web::{HttpResponse, Scope, web};
use log::error; use log::error;
use regex::Regex;
use sqlx::Postgres; use sqlx::Postgres;
use uuid::Uuid; use uuid::Uuid;
@ -13,6 +15,16 @@ mod refresh;
mod register; mod register;
mod revoke; mod revoke;
static EMAIL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?").unwrap()
});
// FIXME: This regex doesnt seem to be working
static USERNAME_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"[a-zA-Z0-9.-_]").unwrap());
// Password is expected to be hashed using SHA3-384
static PASSWORD_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"[0-9a-f]{96}").unwrap());
pub fn web() -> Scope { pub fn web() -> Scope {
web::scope("/auth") web::scope("/auth")
.service(register::res) .service(register::res)

View file

@ -7,13 +7,13 @@ use argon2::{
}; };
use futures::StreamExt; use futures::StreamExt;
use log::error; use log::error;
use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use super::login::Response; use super::login::Response;
use crate::{ use crate::{
Data, Data,
api::v1::auth::{EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX},
crypto::{generate_access_token, generate_refresh_token}, crypto::{generate_access_token, generate_refresh_token},
}; };
@ -73,19 +73,14 @@ pub async fn res(mut payload: web::Payload, data: web::Data<Data>) -> Result<Htt
let uuid = Uuid::now_v7(); let uuid = Uuid::now_v7();
let email_regex = Regex::new(r"[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?").unwrap(); if !EMAIL_REGEX.is_match(&account_information.email) {
if !email_regex.is_match(&account_information.email) {
return Ok(HttpResponse::Forbidden().json(ResponseError { return Ok(HttpResponse::Forbidden().json(ResponseError {
email_valid: false, email_valid: false,
..Default::default() ..Default::default()
})); }));
} }
// FIXME: This regex doesnt seem to be working if !USERNAME_REGEX.is_match(&account_information.identifier)
let username_regex = Regex::new(r"[a-zA-Z0-9.-_]").unwrap();
if !username_regex.is_match(&account_information.identifier)
|| account_information.identifier.len() < 3 || account_information.identifier.len() < 3
|| account_information.identifier.len() > 32 || account_information.identifier.len() > 32
{ {
@ -95,10 +90,7 @@ pub async fn res(mut payload: web::Payload, data: web::Data<Data>) -> Result<Htt
})); }));
} }
// Password is expected to be hashed using SHA3-384 if !PASSWORD_REGEX.is_match(&account_information.password) {
let password_regex = Regex::new(r"[0-9a-f]{96}").unwrap();
if !password_regex.is_match(&account_information.password) {
return Ok(HttpResponse::Forbidden().json(ResponseError { return Ok(HttpResponse::Forbidden().json(ResponseError {
password_hashed: false, password_hashed: false,
..Default::default() ..Default::default()

View file

@ -11,7 +11,6 @@ pub mod crypto;
type Error = Box<dyn std::error::Error>; type Error = Box<dyn std::error::Error>;
/// Simple program to greet a person
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
struct Args { struct Args {