fixed db stuff, added user provider

This commit is contained in:
FrenchGithubUser
2025-03-13 22:08:01 +01:00
parent 1f716ee762
commit 42abf2e28e
10 changed files with 90 additions and 13 deletions

2
.env
View File

@@ -8,7 +8,7 @@ ACTIX_PORT=8080
JWT_SECRET=sensitivejwtsecret
PASSWORD_HASH_SECRET=sensitivepasswordhashsecret
# Postgre config
# postgre config
POSTGRESQL_DATABASE=arcadia
POSTGRESQL_USER=arcadia

29
Cargo.lock generated
View File

@@ -253,6 +253,7 @@ dependencies = [
"argon2",
"chrono",
"dotenv",
"futures",
"jsonwebtoken",
"serde",
"serde_json",
@@ -883,6 +884,21 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
@@ -955,6 +971,17 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
@@ -973,8 +1000,10 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",

View File

@@ -18,3 +18,4 @@ chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1.15.1", features = ["serde", "v4"] }
jsonwebtoken = "9.3.1"
argon2 = "0.5.3"
futures = "0.3"

View File

@@ -3,12 +3,13 @@ Arcadia's backend
## Setup
Copy `.env` to `.env.local` and replace the values with yours
- Copy `.env` to `.env.local` and replace the values with yours
- The `docker/` folder contains some containers to various services used by `actix-index`. Feel free to use these or substitutes
### Optional
- Create a database with the name that is specified by the env variable `POSTGRESQL_DATABASE`
The `docker/` folder contains some containers to various services used by `actix-index`. Feel free to use these or a local install of them
- install `sqlx-cli` and run the database migrations : `sqlx migrate run`
## Developing

View File

@@ -29,7 +29,7 @@ CREATE TABLE users
requests_voted BIGINT NOT NULL DEFAULT 0,
average_seeding_time BIGINT NOT NULL DEFAULT 0,
invited BIGINT NOT NULL DEFAULT 0,
invites INT NOT NULL DEFAULT 0
invites SMALLINT NOT NULL DEFAULT 0
);
CREATE TABLE invitations

View File

@@ -55,7 +55,7 @@ pub async fn login(pool: web::Data<PgPool>, user_login: web::Json<Login>) -> Htt
expiration_date = expiration_date + Duration::days(365);
}
let user_claims = Claims {
sub: user.username,
sub: user.id,
exp: expiration_date.timestamp() as usize,
};
let token = encode(

View File

@@ -2,13 +2,16 @@ use actix_web::{HttpResponse, web};
use sqlx::PgPool;
use crate::{
models::invitation::SentInvitation, repositories::invitation_repository::create_invitation,
models::{invitation::SentInvitation, user::User},
repositories::invitation_repository::create_invitation,
};
pub async fn send_invitation(
invitation: web::Json<SentInvitation>,
pool: web::Data<PgPool>,
user: User,
) -> HttpResponse {
println!("{}", user.id);
match create_invitation(&pool, &invitation).await {
Ok(user) => HttpResponse::Created().json(serde_json::json!(user)),
Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({

View File

@@ -32,7 +32,7 @@ pub struct User {
pub requests_voted: i64,
pub average_seeding_time: i64, //in seconds
pub invited: i64,
pub invites: i8,
pub invites: i16,
}
#[derive(Debug, Serialize, Deserialize)]
@@ -52,6 +52,6 @@ pub struct Login {
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
pub sub: String,
pub sub: i32,
pub exp: usize,
}

View File

@@ -1,12 +1,15 @@
use crate::models::user::{Login, Register, User};
use actix_web::web;
use crate::models::user::{Claims, Login, Register, User};
use actix_web::{FromRequest, HttpRequest, dev::Payload, web};
use argon2::{
Argon2,
password_hash::{PasswordHash, PasswordVerifier},
};
use futures::future::{BoxFuture, Ready, err, ok};
use jsonwebtoken::{DecodingKey, Validation, decode};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use std::error::Error;
use std::net::IpAddr;
use std::{env, error::Error};
pub async fn create_user(
pool: &web::Data<PgPool>,
@@ -76,3 +79,43 @@ pub async fn find_user_with_password(
}
}
}
// user provider
impl FromRequest for User {
type Error = actix_web::Error;
type Future = BoxFuture<'static, Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
let pool = req.app_data::<PgPool>().cloned();
let auth_header = req.headers().get("Authorization").cloned();
Box::pin(async move {
if let (Some(pool), Some(auth_value)) = (pool, auth_header) {
if let Ok(auth_str) = auth_value.to_str() {
if auth_str.starts_with("Bearer ") {
let token = &auth_str[7..];
let decoding_key =
DecodingKey::from_secret(env::var("JWT_SECRET").unwrap().as_ref());
let validation = Validation::default();
if let Ok(token_data) = decode::<Claims>(token, &decoding_key, &validation)
{
let user_id = token_data.claims.sub;
let query = "SELECT id, username, email FROM users WHERE id = $1";
let user = sqlx::query_as::<_, User>(query)
.bind(user_id)
.fetch_one(&pool)
.await;
return user.map_err(|_| {
actix_web::error::ErrorUnauthorized("User not found")
});
}
}
}
}
Err(actix_web::error::ErrorUnauthorized("Invalid token"))
})
}
}

View File

@@ -35,7 +35,7 @@ pub async fn create_invitation(
sqlx::Error::Database(db_error) => db_error.message().to_string(),
_ => e.to_string(),
};
Err(format!("User not found").into())
Err(format!("could not send invite").into())
}
}
}