Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 16 additions & 14 deletions backend/modules/api/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,14 @@ pub async fn refresh(
};

// Extract Bearer token
let token = if auth_header.starts_with("Bearer ") {
&auth_header[7..]
} else {
return HttpResponse::Unauthorized().json(ErrorResponse {
message: "Invalid authorization format".to_string(),
code: "INVALID_AUTH_FORMAT".to_string(),
});
let token = match auth_header.strip_prefix("Bearer ") {
Some(t) => t,
None => {
return HttpResponse::Unauthorized().json(ErrorResponse {
message: "Invalid authorization format".to_string(),
code: "INVALID_AUTH_FORMAT".to_string(),
});
}
};

// Validate access token and get user info
Expand Down Expand Up @@ -351,13 +352,14 @@ pub async fn logout(
}
};

let token = if auth_header.starts_with("Bearer ") {
&auth_header[7..]
} else {
return HttpResponse::Unauthorized().json(ErrorResponse {
message: "Invalid authorization format".to_string(),
code: "INVALID_AUTH_FORMAT".to_string(),
});
let token = match auth_header.strip_prefix("Bearer ") {
Some(t) => t,
None => {
return HttpResponse::Unauthorized().json(ErrorResponse {
message: "Invalid authorization format".to_string(),
code: "INVALID_AUTH_FORMAT".to_string(),
});
}
};

// Validate the token and extract the actual user ID
Expand Down
2 changes: 0 additions & 2 deletions backend/modules/api/src/test/rate_limit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use actix_governor::{Governor, GovernorConfigBuilder};
use actix_web::{test, web, App, HttpResponse, Responder};
use std::thread;
use std::time::Duration;

async fn mock_handler() -> impl Responder {
HttpResponse::Ok().body("OK")
Expand Down
1 change: 0 additions & 1 deletion backend/modules/api/src/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,6 @@ fn validate_reconnect_token(token: &str) -> Result<Claims, Error> {
#[cfg(test)]
mod tests {
use super::*;
use actix::prelude::*;
use tokio::sync::mpsc::unbounded_channel;

struct TestRecipient {
Expand Down
1 change: 1 addition & 0 deletions backend/modules/chess/src/bitboard/bitboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl Bitboard {
(self.0 & (1 << square)) != 0
}

#[allow(clippy::should_implement_trait)]
pub fn add(self, square: u64) -> Bitboard {
Bitboard(self.0 | (1 << square))
}
Expand Down
1 change: 1 addition & 0 deletions backend/modules/chess/src/bitboard/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#[allow(clippy::module_inception)]
pub mod bitboard;
pub mod board;
1 change: 0 additions & 1 deletion backend/modules/chess/src/pgn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ pub enum GameResult {
Ongoing,
}


impl GameResult {
/// Parse a result string from PGN format
pub fn from_pgn_string(s: &str) -> Result<Self, PgnError> {
Expand Down
1 change: 1 addition & 0 deletions backend/modules/db/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[allow(clippy::module_inception)]
pub mod db {
use sea_orm::{ConnectOptions, Database, DatabaseConnection};

Expand Down
33 changes: 20 additions & 13 deletions backend/modules/dto/src/ai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,31 @@ use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use validator::Validate;
use validator::{Validate, ValidationError};

// Define a regex for validating FEN chess position notation
static FEN_REGEX: Lazy<Regex> = Lazy::new(|| {
static FEN_STRUCTURE: Lazy<Regex> = Lazy::new(|| {
Regex::new(
r"^(?=\S*K)(?=\S*k)([rnbqkpRNBQKP1-8]+/){7}[rnbqkpRNBQKP1-8]+\s[bw]\s(-|[KQkq]+)\s(-|[a-h][36])\s\d+\s\d+$"
).unwrap()
r"^([rnbqkpRNBQKP1-8]+/){7}[rnbqkpRNBQKP1-8]+\s[bw]\s(-|[KQkq]+)\s(-|[a-h][36])\s\d+\s\d+$",
)
.unwrap()
});

fn validate_fen(fen: &str) -> Result<(), ValidationError> {
if !FEN_STRUCTURE.is_match(fen) {
return Err(ValidationError::new("Must be a valid FEN string"));
}
if !fen.contains('K') {
return Err(ValidationError::new("FEN must contain a white king"));
}
if !fen.contains('k') {
return Err(ValidationError::new("FEN must contain a black king"));
}
Ok(())
}

#[derive(Debug, Serialize, Deserialize, ToSchema, Validate)]
pub struct AiSuggestionRequest {
#[validate(regex(
path = "FEN_REGEX",
message = "Must be a valid FEN string in format: [piece placement] [active color] [castling] [en passant] [halfmove clock] [fullmove number]"
))]
#[validate(custom(function = "validate_fen"))]
#[schema(example = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")]
pub fen: String,

Expand Down Expand Up @@ -52,10 +62,7 @@ pub struct AiSuggestionResponse {

#[derive(Debug, Serialize, Deserialize, ToSchema, Validate)]
pub struct PositionAnalysisRequest {
#[validate(regex(
path = "FEN_REGEX",
message = "Must be a valid FEN string in format: [piece placement] [active color] [castling] [en passant] [halfmove clock] [fullmove number]"
))]
#[validate(custom(function = "validate_fen"))]
#[schema(example = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")]
pub fen: String,

Expand Down
2 changes: 1 addition & 1 deletion backend/modules/matchmaking/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl TimeControl {
"bullet" => 60,
"blitz" => 180,
"rapid" => 480,
"standard" | _ => 600,
_ => 600,
}
}

Expand Down
6 changes: 1 addition & 5 deletions backend/modules/security/src/jwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,7 @@ impl JwtService {

/// Extract token from Authorization header
pub fn extract_token_from_header(auth_header: &str) -> Option<String> {
if auth_header.starts_with("Bearer ") {
Some(auth_header[7..].to_string())
} else {
None
}
auth_header.strip_prefix("Bearer ").map(|s| s.to_string())
}
}

Expand Down
1 change: 0 additions & 1 deletion backend/modules/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition = "2021"
[dependencies]
sea-orm = { version = "1.1.0", features = [ "sqlx-postgres", "runtime-tokio-native-tls", "macros", "mock" ] }
uuid = { version = "1", features = ["v4", "serde"] }
bcrypt = "0.15"
argon2 = "0.5"
rand = "0.8"
chrono = { version = "0.4", features = ["serde"] }
Expand Down
1 change: 1 addition & 0 deletions backend/modules/service/src/engine_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use tokio::sync::Mutex;
use uuid::Uuid;

pub struct EngineService {
#[allow(dead_code)]
engines: Arc<Mutex<HashMap<Uuid, Box<dyn Engine>>>>,
engine_path: String,
}
Expand Down
1 change: 1 addition & 0 deletions backend/modules/service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub mod engine_service;
pub mod games;
pub mod helper;
pub mod players;
pub mod user;
25 changes: 25 additions & 0 deletions backend/modules/service/src/players.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,31 @@ pub async fn update_player(id: Uuid, payload: UpdatePlayer) -> Result<player::Mo
Ok(updated_player)
}

pub async fn authenticate_player(
username: String,
password: &str,
) -> Result<player::Model, ApiError> {
let db = get_db().await;

let user = player::Entity::find()
.filter(player::Column::Username.eq(username))
.filter(player::Column::IsEnabled.eq(true))
.one(&db)
.await?;

match user {
Some(usr) => {
let stored_hash = String::from_utf8(usr.password_hash.clone())
.map_err(|_| ApiError::InvalidCredentials)?;
match password::verify_password(password, &stored_hash) {
Ok(()) => Ok(usr),
Err(_) => Err(ApiError::InvalidCredentials),
}
}
None => Err(ApiError::InvalidCredentials),
}
}

pub async fn delete_player(id: Uuid) -> Result<(), ApiError> {
let db = get_db().await;
let existing_player = find_player_by_id(id).await?;
Expand Down
35 changes: 16 additions & 19 deletions backend/modules/service/src/user.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::helper::password;
use chrono::Utc;
use db_entity::user;
use sea_orm::{
ActiveModelTrait, ColumnTrait, DatabaseConnection, DbErr, EntityTrait, ActiveValue,
ActiveModelTrait, ActiveValue, ColumnTrait, DatabaseConnection, DbErr, EntityTrait, QueryFilter,
};
use db_entity::user::{self, Entity as UserEntity};
use chrono::Utc;
use bcrypt::{hash, verify, DEFAULT_COST};


/// User service for authentication and user management
pub struct UserService;
Expand Down Expand Up @@ -37,8 +36,7 @@ impl UserService {
return Err(DbErr::Custom("Email already exists".to_string()));
}

// Hash password
let password_hash = hash(password, DEFAULT_COST)
let password_hash = password::hash_password(password)
.map_err(|_| DbErr::Custom("Failed to hash password".to_string()))?;

let now = Utc::now();
Expand Down Expand Up @@ -70,24 +68,20 @@ impl UserService {

match user {
Some(user_model) => {
// Verify password
match verify(password, &user_model.password_hash) {
Ok(is_valid) => {
if is_valid {
Ok(user_model)
} else {
Err(DbErr::Custom("Invalid password".to_string()))
}
}
Err(_) => Err(DbErr::Custom("Authentication failed".to_string())),
match password::verify_password(password, &user_model.password_hash) {
Ok(()) => Ok(user_model),
Err(_) => Err(DbErr::Custom("Invalid password".to_string())),
}
}
None => Err(DbErr::Custom("User not found".to_string())),
}
}

/// Get user by ID
pub async fn get_by_id(db: &DatabaseConnection, user_id: i32) -> Result<Option<user::Model>, DbErr> {
pub async fn get_by_id(
db: &DatabaseConnection,
user_id: i32,
) -> Result<Option<user::Model>, DbErr> {
user::Entity::find_by_id(user_id).one(db).await
}

Expand All @@ -103,7 +97,10 @@ impl UserService {
}

/// Get user by email
pub async fn get_by_email(db: &DatabaseConnection, email: &str) -> Result<Option<user::Model>, DbErr> {
pub async fn get_by_email(
db: &DatabaseConnection,
email: &str,
) -> Result<Option<user::Model>, DbErr> {
user::Entity::find()
.filter(user::Column::Email.eq(email))
.one(db)
Expand Down
1 change: 0 additions & 1 deletion backend/modules/st_core/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,3 @@ pub struct StellarAssetInfo {
pub fixed_number: u32,
pub display_decimals: u8,
}

2 changes: 1 addition & 1 deletion backend/modules/st_core/src/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ mod tests {

#[test]
fn test_format_ai_metadata() {
let mut metadata = AIMetadata {
let metadata = AIMetadata {
name: " Test AI ".to_string(),
description: " Test Description ".to_string(),
code: "testai".to_string(),
Expand Down
2 changes: 1 addition & 1 deletion backend/modules/st_core/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ mod tests {

#[tokio::test]
async fn test_ai_metadata_formatting() {
let mut metadata = AIMetadata {
let metadata = AIMetadata {
name: " Test AI ".to_string(),
description: " Test Description ".to_string(),
url: "ipfs://QmTest123".to_string(),
Expand Down
2 changes: 1 addition & 1 deletion backend/modules/tournament/src/swiss/pairer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::*;
use std::collections::HashMap;

pub struct SwissPairer {
#[allow(dead_code)]
config: SwissConfig,
}

Expand Down Expand Up @@ -230,7 +231,6 @@ impl SwissPairer {
}

// Color balance preference


self.check_color_preference(player1, player2)
}
Expand Down
Loading
Loading