Fix compilation errors: Add missing dependencies, fix module visibility, and update Axum middleware types
Some checks failed
Build MIPS Binary / build (push) Failing after 3m27s

This commit is contained in:
spinline
2026-02-07 14:58:35 +03:00
parent d53d661ad1
commit bb3ec14a75
5 changed files with 142 additions and 7 deletions

5
Cargo.lock generated
View File

@@ -99,9 +99,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.100"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
[[package]]
name = "arbitrary"
@@ -341,6 +341,7 @@ dependencies = [
name = "backend"
version = "0.1.0"
dependencies = [
"anyhow",
"axum 0.8.8",
"axum-extra",
"base64 0.22.1",

View File

@@ -37,3 +37,4 @@ sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite"] }
bcrypt = "0.17.0"
axum-extra = { version = "0.9", features = ["cookie"] }
rand = "0.8"
anyhow = "1.0.101"

View File

@@ -0,0 +1,108 @@
use crate::{db::Db, AppState};
use axum::{
extract::{State, Json},
http::StatusCode,
response::IntoResponse,
};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
use time::Duration;
#[derive(Deserialize, ToSchema)]
pub struct LoginRequest {
username: String,
password: String,
}
#[derive(Serialize)]
pub struct UserResponse {
username: String,
}
#[utoipa::path(
post,
path = "/api/auth/login",
request_body = LoginRequest,
responses(
(status = 200, description = "Login successful"),
(status = 401, description = "Invalid credentials"),
(status = 500, description = "Internal server error")
)
)]
pub async fn login_handler(
State(state): State<AppState>,
jar: CookieJar,
Json(payload): Json<LoginRequest>,
) -> impl IntoResponse {
let user = match state.db.get_user_by_username(&payload.username).await {
Ok(Some(u)) => u,
Ok(None) => return (StatusCode::UNAUTHORIZED, "Invalid credentials").into_response(),
Err(e) => {
tracing::error!("DB error during login: {}", e);
return (StatusCode::INTERNAL_SERVER_ERROR, "Database error").into_response();
}
};
let (user_id, password_hash) = user;
match bcrypt::verify(&payload.password, &password_hash) {
Ok(true) => {
// Create session
let token: String = (0..32).map(|_| {
use rand::{distributions::Alphanumeric, Rng};
rand::thread_rng().sample(Alphanumeric) as char
}).collect();
// Expires in 30 days
let expires_in = 60 * 60 * 24 * 30;
let expires_at = time::OffsetDateTime::now_utc().unix_timestamp() + expires_in;
if let Err(e) = state.db.create_session(user_id, &token, expires_at).await {
tracing::error!("Failed to create session: {}", e);
return (StatusCode::INTERNAL_SERVER_ERROR, "Failed to create session").into_response();
}
let cookie = Cookie::build(("auth_token", token))
.path("/")
.http_only(true)
.same_site(SameSite::Strict)
.max_age(Duration::seconds(expires_in))
.build();
(StatusCode::OK, jar.add(cookie), "Login successful").into_response()
}
_ => (StatusCode::UNAUTHORIZED, "Invalid credentials").into_response(),
}
}
pub async fn logout_handler(
State(state): State<AppState>,
jar: CookieJar,
) -> impl IntoResponse {
if let Some(token) = jar.get("auth_token") {
let _ = state.db.delete_session(token.value()).await;
}
let cookie = Cookie::build(("auth_token", ""))
.path("/")
.http_only(true)
.max_age(Duration::seconds(-1)) // Expire immediately
.build();
(StatusCode::OK, jar.add(cookie), "Logged out").into_response()
}
pub async fn check_auth_handler(
State(state): State<AppState>,
jar: CookieJar,
) -> impl IntoResponse {
if let Some(token) = jar.get("auth_token") {
match state.db.get_session_user(token.value()).await {
Ok(Some(_)) => return StatusCode::OK.into_response(),
_ => {} // Invalid session
}
}
StatusCode::UNAUTHORIZED.into_response()
}

View File

@@ -1,4 +1,4 @@
use crate::{db::Db, AppState};
use crate::AppState;
use axum::{
extract::{State, Json},
http::StatusCode,
@@ -18,6 +18,13 @@ pub struct SetupStatusResponse {
completed: bool,
}
#[utoipa::path(
get,
path = "/api/setup/status",
responses(
(status = 200, description = "Setup status", body = SetupStatusResponse)
)
)]
pub async fn get_setup_status_handler(State(state): State<AppState>) -> impl IntoResponse {
let completed = match state.db.has_users().await {
Ok(has) => has,
@@ -29,6 +36,17 @@ pub async fn get_setup_status_handler(State(state): State<AppState>) -> impl Int
Json(SetupStatusResponse { completed }).into_response()
}
#[utoipa::path(
post,
path = "/api/setup",
request_body = SetupRequest,
responses(
(status = 200, description = "Setup completed"),
(status = 400, description = "Invalid request"),
(status = 403, description = "Setup already completed"),
(status = 500, description = "Internal server error")
)
)]
pub async fn setup_handler(
State(state): State<AppState>,
Json(payload): Json<SetupRequest>,

View File

@@ -15,6 +15,7 @@ use axum::{
extract::Request,
response::Response,
http::StatusCode,
body::Body,
};
use axum_extra::extract::cookie::CookieJar;
use clap::Parser;
@@ -46,7 +47,7 @@ pub struct AppState {
async fn auth_middleware(
state: axum::extract::State<AppState>,
jar: CookieJar,
request: Request,
request: Request<Body>,
next: Next,
) -> Result<Response, StatusCode> {
// Skip auth for public paths
@@ -110,6 +111,8 @@ struct Args {
handlers::get_push_public_key_handler,
handlers::subscribe_push_handler,
handlers::auth::login_handler,
handlers::auth::logout_handler,
handlers::auth::check_auth_handler,
handlers::setup::setup_handler,
handlers::setup::get_setup_status_handler
),
@@ -128,7 +131,8 @@ struct Args {
push::PushSubscription,
push::PushKeys,
handlers::auth::LoginRequest,
handlers::setup::SetupRequest
handlers::setup::SetupRequest,
handlers::setup::SetupStatusResponse
)
),
tags(
@@ -152,6 +156,8 @@ struct ApiDoc;
handlers::get_global_limit_handler,
handlers::set_global_limit_handler,
handlers::auth::login_handler,
handlers::auth::logout_handler,
handlers::auth::check_auth_handler,
handlers::setup::setup_handler,
handlers::setup::get_setup_status_handler
),
@@ -168,7 +174,8 @@ struct ApiDoc;
shared::SetLabelRequest,
shared::GlobalLimitRequest,
handlers::auth::LoginRequest,
handlers::setup::SetupRequest
handlers::setup::SetupRequest,
handlers::setup::SetupStatusResponse
)
),
tags(
@@ -210,7 +217,7 @@ async fn main() {
}
}
let db = match db::Db::new(&args.db_url).await {
let db: db::Db = match db::Db::new(&args.db_url).await {
Ok(db) => db,
Err(e) => {
tracing::error!("Failed to connect to database: {}", e);