d489716c9b
This commit introduces the foundation for web-based authentication and user interface. It includes: - **Session Management**: Securely handling user sessions using cryptographically generated tokens, cookies with appropriate security flags, and server-side storage. - **Login/Logout Functionality**: Endpoints for users to log in with their credentials and log out, clearing their session. - **User Interface**: Basic templates for the login page, a list of cases, and a detailed view of a single case, allowing users to navigate and view their data. - **Authorization**: An `AuthenticatedWebUser` extractor to ensure only logged-in users can access protected web routes. - **Configuration**: Added a `cookie_secure` option to the configuration to control the `Secure` flag on session cookies, useful for local development. - **Dependencies**: Added necessary dependencies for password hashing, time handling, and TOML file manipulation. - **Helper Binary**: Included a `hash-password` binary to simplify generating bcrypt hashes for user passwords.
102 lines
2.8 KiB
Rust
102 lines
2.8 KiB
Rust
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
|
|
use axum::body::Body;
|
|
use axum::http::{Request, StatusCode};
|
|
use tower::util::ServiceExt;
|
|
|
|
use doctate_server::config::{Config, User};
|
|
|
|
fn test_config() -> Arc<Config> {
|
|
Arc::new(Config {
|
|
server_port: 3000,
|
|
data_path: "/tmp/doctate-test".into(),
|
|
log_level: "info".into(),
|
|
log_path: "/tmp/doctate-test/logs".into(),
|
|
log_max_days: 90,
|
|
users: vec![User {
|
|
slug: "dr_test".into(),
|
|
api_key: "test-key-123".into(),
|
|
web_password: "unused".into(),
|
|
role: "doctor".into(),
|
|
whisper: Default::default(),
|
|
}],
|
|
api_keys: HashMap::from([("test-key-123".into(), "dr_test".into())]),
|
|
retention_audio_days: 30,
|
|
retention_transcript_days: 30,
|
|
retention_document_days: 0,
|
|
whisper_url: "http://localhost:10300".into(),
|
|
whisper_timeout_seconds: 120,
|
|
ollama_url: "http://localhost:11434".into(),
|
|
ollama_model: "gemma3:4b".into(),
|
|
ollama_keep_alive: 0,
|
|
llm_url: String::new(),
|
|
llm_api_key: String::new(),
|
|
llm_model: String::new(),
|
|
llm_temperature: 0.0,
|
|
session_timeout_hours: 8,
|
|
cookie_secure: false,
|
|
})
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn valid_api_key_returns_user() {
|
|
let app = doctate_server::create_router(test_config());
|
|
|
|
let response = app
|
|
.oneshot(
|
|
Request::builder()
|
|
.uri("/api/debug/whoami")
|
|
.header("X-API-Key", "test-key-123")
|
|
.body(Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
|
.await
|
|
.unwrap();
|
|
let json: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
|
|
assert_eq!(json["slug"], "dr_test");
|
|
assert_eq!(json["role"], "doctor");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn invalid_api_key_returns_401() {
|
|
let app = doctate_server::create_router(test_config());
|
|
|
|
let response = app
|
|
.oneshot(
|
|
Request::builder()
|
|
.uri("/api/debug/whoami")
|
|
.header("X-API-Key", "wrong-key")
|
|
.body(Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn missing_api_key_returns_401() {
|
|
let app = doctate_server::create_router(test_config());
|
|
|
|
let response = app
|
|
.oneshot(
|
|
Request::builder()
|
|
.uri("/api/debug/whoami")
|
|
.body(Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
|
}
|