broken only push user data

This commit is contained in:
filipriec
2025-03-24 21:46:04 +01:00
parent 8a248cab58
commit 70d83c284a
13 changed files with 608 additions and 6 deletions

View File

@@ -12,7 +12,7 @@ dotenvy = "0.15.7"
prost = "0.13.5"
serde = { version = "1.0.218", features = ["derive"] }
serde_json = "1.0.140"
sqlx = { version = "0.8.3", features = ["chrono", "postgres", "runtime-tokio", "runtime-tokio-native-tls", "time"] }
sqlx = { version = "0.8.3", features = ["chrono", "postgres", "runtime-tokio", "runtime-tokio-native-tls", "time", "uuid"] }
tokio = { version = "1.43.0", features = ["full", "macros"] }
tonic = "0.12.3"
tonic-reflection = "0.12.3"
@@ -24,6 +24,9 @@ thiserror = "2.0.12"
dashmap = "6.1.0"
lazy_static = "1.5.0"
regex = "1.11.1"
bcrypt = "0.17.0"
validator = { version = "0.20.0", features = ["derive"] }
uuid = { version = "1.16.0", features = ["v4"] }
[lib]
name = "server"

View File

@@ -0,0 +1,38 @@
-- Add migration script here
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(255) NOT NULL UNIQUE,
email VARCHAR(255) UNIQUE,
password_hash VARCHAR(255),
role VARCHAR(20) NOT NULL DEFAULT 'accountant',
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
-- Add an index for faster lookups
CREATE INDEX idx_users_email_username ON users(email, username);
ALTER TABLE users
ADD CONSTRAINT valid_roles CHECK (role IN (
'admin',
'moderator',
'accountant',
'viewer'
));
-- Create JWT sessions table
CREATE TABLE user_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
jwt_token TEXT NOT NULL UNIQUE,
expires_at TIMESTAMPTZ NOT NULL,
revoked BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Add indexes
CREATE INDEX idx_sessions_user ON user_sessions(user_id);
CREATE INDEX idx_sessions_expires ON user_sessions(expires_at);

View File

@@ -0,0 +1,5 @@
// src/auth/handlers.rs
pub mod register;
pub use register::*;

View File

@@ -0,0 +1,61 @@
use bcrypt::{hash, DEFAULT_COST};
use tonic::{Request, Response, Status};
use uuid::Uuid;
use crate::{auth::{models::{RegisterRequest, AuthResponse, AuthError}, db::PgPool}};
pub struct AuthService {
pool: PgPool,
}
impl AuthService {
pub fn new(pool: PgPool) -> Self {
Self { pool }
}
}
#[tonic::async_trait]
impl multieko2::auth::auth_service_server::AuthService for AuthService {
async fn register(
&self,
request: Request<multieko2::auth::RegisterRequest>,
) -> Result<Response<multieko2::auth::AuthResponse>, Status> {
let payload = request.into_inner();
// Validate passwords match
if payload.password != payload.password_confirmation {
return Err(Status::invalid_argument(AuthError::PasswordMismatch.to_string()));
}
// Hash password
let password_hash = hash(payload.password, DEFAULT_COST)
.map_err(|e| Status::internal(AuthError::HashingError(e.to_string()).to_string()))?;
// Insert user
let user = sqlx::query!(
r#"
INSERT INTO users (username, email, password_hash, role)
VALUES ($1, $2, $3, 'accountant')
RETURNING id, username, email, role
"#,
payload.username,
payload.email,
password_hash
)
.fetch_one(&self.pool)
.await
.map_err(|e| {
if e.to_string().contains("duplicate key") {
Status::already_exists(AuthError::UserExists.to_string())
} else {
Status::internal(AuthError::DatabaseError(e.to_string()).to_string())
}
})?;
Ok(Response::new(multieko2::auth::AuthResponse {
id: user.id.to_string(),
username: user.username,
email: user.email,
role: user.role,
}))
}
}

5
server/src/auth/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
// src/auth/mod.rs
pub mod models;
pub mod handlers;

34
server/src/auth/models.rs Normal file
View File

@@ -0,0 +1,34 @@
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use validator::Validate;
#[derive(Debug, Validate, Deserialize)]
pub struct RegisterRequest {
#[validate(length(min = 3, max = 30))]
pub username: String,
#[validate(email)]
pub email: String,
#[validate(length(min = 8))]
pub password: String,
pub password_confirmation: String,
}
#[derive(Debug, Serialize)]
pub struct AuthResponse {
pub id: Uuid,
pub username: String,
pub email: String,
pub role: String,
}
#[derive(Debug, thiserror::Error)]
pub enum AuthError {
#[error("Passwords do not match")]
PasswordMismatch,
#[error("User already exists")]
UserExists,
#[error("Database error: {0}")]
DatabaseError(String),
#[error("Hashing error: {0}")]
HashingError(String),
}

View File

@@ -1,5 +1,6 @@
// src/lib.rs
pub mod db;
pub mod auth;
pub mod server;
pub mod adresar;
pub mod uctovnictvo;