Implement logging in
This commit is contained in:
parent
3ce2fb04eb
commit
a00671115e
2 changed files with 40 additions and 5 deletions
2
TODO.md
2
TODO.md
|
|
@ -13,7 +13,7 @@
|
||||||
[x] Add .env file support using the dotenv crate. Load environment variables on server startup.
|
[x] Add .env file support using the dotenv crate. Load environment variables on server startup.
|
||||||
[x] Create a `GET /login` endpoint that returns a simple HTML login form (username and password fields).
|
[x] Create a `GET /login` endpoint that returns a simple HTML login form (username and password fields).
|
||||||
[x] Add a rouille::session manager to set a session cookie.
|
[x] Add a rouille::session manager to set a session cookie.
|
||||||
[ ] Create a `POST /login` endpoint that validates credentials against USERNAME and PASSWORD environment variables.
|
[x] Create a `POST /login` endpoint that validates credentials against USERNAME and PASSWORD environment variables.
|
||||||
[ ] Protect write endpoints (POST /projects, and any future write operations) with authentication. Redirect to /login if not authenticated.
|
[ ] Protect write endpoints (POST /projects, and any future write operations) with authentication. Redirect to /login if not authenticated.
|
||||||
[ ] Add a login button to the front page (GET /projects) that links to /login.
|
[ ] Add a login button to the front page (GET /projects) that links to /login.
|
||||||
[ ] When logged in, show a "Create Project" button on the front page that links to /new-project.
|
[ ] When logged in, show a "Create Project" button on the front page that links to /new-project.
|
||||||
|
|
|
||||||
43
src/main.rs
43
src/main.rs
|
|
@ -1,5 +1,7 @@
|
||||||
use maud::{DOCTYPE, html};
|
use maud::{DOCTYPE, html};
|
||||||
use rouille::{router, try_or_400, session};
|
use rouille::{router, session, try_or_400};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
mod db;
|
mod db;
|
||||||
mod project;
|
mod project;
|
||||||
|
|
@ -13,10 +15,13 @@ fn main() {
|
||||||
|
|
||||||
println!("Starting server on localhost:8080");
|
println!("Starting server on localhost:8080");
|
||||||
|
|
||||||
|
// Track authenticated sessions
|
||||||
|
let authenticated_sessions: Mutex<HashSet<String>> = Mutex::new(HashSet::new());
|
||||||
|
|
||||||
rouille::start_server("localhost:8080", move |request| {
|
rouille::start_server("localhost:8080", move |request| {
|
||||||
// Wrap all requests with session management
|
// Wrap all requests with session management
|
||||||
// This sets a session cookie with a 1-hour timeout
|
// This sets a session cookie with a 1-hour timeout
|
||||||
session::session(request, "SESSION", 3600, |_session| {
|
session::session(request, "SESSION", 3600, |session| {
|
||||||
router!(request,
|
router!(request,
|
||||||
(GET) ["/"] => {
|
(GET) ["/"] => {
|
||||||
rouille::Response::redirect_302("/projects")
|
rouille::Response::redirect_302("/projects")
|
||||||
|
|
@ -32,6 +37,7 @@ fn main() {
|
||||||
(GET) ["/projects"] => display_projects(),
|
(GET) ["/projects"] => display_projects(),
|
||||||
(GET) ["/new-project"] => new_project_form(),
|
(GET) ["/new-project"] => new_project_form(),
|
||||||
(GET) ["/login"] => login_form(),
|
(GET) ["/login"] => login_form(),
|
||||||
|
(POST) ["/login"] => handle_login(request, session, &authenticated_sessions),
|
||||||
(POST) ["/projects"] => create_project(request),
|
(POST) ["/projects"] => create_project(request),
|
||||||
_ => rouille::Response::empty_404()
|
_ => rouille::Response::empty_404()
|
||||||
)
|
)
|
||||||
|
|
@ -47,10 +53,12 @@ fn display_projects() -> rouille::Response {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs() as i64;
|
.as_secs() as i64;
|
||||||
|
|
||||||
let active_projects: Vec<_> = projects.iter()
|
let active_projects: Vec<_> = projects
|
||||||
|
.iter()
|
||||||
.filter(|p| !p.archived && (now - p.last_modified_time) <= STALE_AGE)
|
.filter(|p| !p.archived && (now - p.last_modified_time) <= STALE_AGE)
|
||||||
.collect();
|
.collect();
|
||||||
let stale_projects: Vec<_> = projects.iter()
|
let stale_projects: Vec<_> = projects
|
||||||
|
.iter()
|
||||||
.filter(|p| !p.archived && (now - p.last_modified_time) > STALE_AGE)
|
.filter(|p| !p.archived && (now - p.last_modified_time) > STALE_AGE)
|
||||||
.collect();
|
.collect();
|
||||||
let archived_projects: Vec<_> = projects.iter().filter(|p| p.archived).collect();
|
let archived_projects: Vec<_> = projects.iter().filter(|p| p.archived).collect();
|
||||||
|
|
@ -167,3 +175,30 @@ fn create_project(request: &rouille::Request) -> rouille::Response {
|
||||||
Err(_) => rouille::Response::text("Failed to create project").with_status_code(500),
|
Err(_) => rouille::Response::text("Failed to create project").with_status_code(500),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_login(
|
||||||
|
request: &rouille::Request,
|
||||||
|
session: &session::Session,
|
||||||
|
authenticated_sessions: &Mutex<HashSet<String>>,
|
||||||
|
) -> rouille::Response {
|
||||||
|
let input = try_or_400!(rouille::post_input!(request, {
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Get credentials from environment variables
|
||||||
|
let valid_username = std::env::var("USERNAME").unwrap_or_default();
|
||||||
|
let valid_password = std::env::var("PASSWORD").unwrap_or_default();
|
||||||
|
|
||||||
|
// Validate credentials
|
||||||
|
if input.username == valid_username && input.password == valid_password {
|
||||||
|
// Add session ID to authenticated sessions
|
||||||
|
if let Ok(mut sessions) = authenticated_sessions.lock() {
|
||||||
|
sessions.insert(session.id().to_string());
|
||||||
|
}
|
||||||
|
rouille::Response::redirect_302("/projects")
|
||||||
|
} else {
|
||||||
|
// Invalid credentials - redirect back to login
|
||||||
|
rouille::Response::redirect_302("/login")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue