weird login

This commit is contained in:
Philipp Hofer 2025-04-08 23:26:20 +02:00
parent 9c0e3e4fa7
commit 959f6c08df
11 changed files with 288 additions and 36 deletions

110
Cargo.lock generated
View File

@ -17,6 +17,41 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "aes"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aes-gcm"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.3" version = "1.1.3"
@ -274,6 +309,16 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]] [[package]]
name = "concurrent-queue" name = "concurrent-queue"
version = "2.5.0" version = "2.5.0"
@ -295,7 +340,11 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
dependencies = [ dependencies = [
"aes-gcm",
"base64",
"percent-encoding", "percent-encoding",
"rand",
"subtle",
"time", "time",
"version_check", "version_check",
] ]
@ -371,9 +420,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [ dependencies = [
"generic-array", "generic-array",
"rand_core",
"typenum", "typenum",
] ]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.9" version = "0.7.9"
@ -646,6 +705,16 @@ dependencies = [
"wasi 0.14.2+wasi-0.2.4", "wasi 0.14.2+wasi-0.2.4",
] ]
[[package]]
name = "ghash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.31.1" version = "0.31.1"
@ -1011,6 +1080,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.11.0" version = "0.11.0"
@ -1151,9 +1229,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.7" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]
@ -1246,6 +1324,12 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@ -1329,6 +1413,18 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "polyval"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
version = "0.2.0" version = "0.2.0"
@ -2383,6 +2479,16 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]] [[package]]
name = "unsafe-libyaml" name = "unsafe-libyaml"
version = "0.2.11" version = "0.2.11"

View File

@ -5,7 +5,7 @@ edition = "2024"
[dependencies] [dependencies]
axum = "0.8" axum = "0.8"
axum-extra = { version = "0.10", features = [ "cookie" ]} axum-extra = { version = "0.10", features = [ "cookie", "cookie-private" ]}
chrono = { version = "0.4", features = ["serde"]} chrono = { version = "0.4", features = ["serde"]}
dotenv = "0.15" dotenv = "0.15"
maud = { version = "0.27", features = ["axum"] } maud = { version = "0.27", features = ["axum"] }

View File

@ -1,8 +1,6 @@
use crate::page; use crate::{page, AppState};
use axum::{routing::get, Router}; use axum::{routing::get, Router};
use maud::{html, Markup}; use maud::{html, Markup};
use sqlx::SqlitePool;
use std::sync::Arc;
use tower_sessions::Session; use tower_sessions::Session;
pub(crate) mod route; pub(crate) mod route;
@ -35,7 +33,7 @@ async fn index(session: Session) -> Markup {
page(content, session, false).await page(content, session, false).await
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
Router::new() Router::new()
.route("/", get(index)) .route("/", get(index))
.nest("/station", station::routes()) .nest("/station", station::routes())

View File

@ -1,8 +1,10 @@
use crate::admin::{station::Station, team::Team}; use crate::{
admin::{station::Station, team::Team},
AppState,
};
use axum::Router; use axum::Router;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{FromRow, Row, SqlitePool}; use sqlx::{FromRow, Row, SqlitePool};
use std::sync::Arc;
mod web; mod web;
@ -195,6 +197,6 @@ DROP TABLE temp_pos;",
} }
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
web::routes() web::routes()
} }

View File

@ -1,5 +1,5 @@
use super::Route; use super::Route;
use crate::{admin::station::Station, err, page, succ}; use crate::{admin::station::Station, err, page, succ, AppState};
use axum::{ use axum::{
extract::State, extract::State,
response::{IntoResponse, Redirect}, response::{IntoResponse, Redirect},
@ -53,7 +53,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
} }
h2 { "Neue Route" } h2 { "Neue Route" }
form action="/admin/route" method="post" { form action="/admin/route" method="post" {
fieldset role="team" { fieldset role="group" {
input type="text" name="name" placeholder="Routenname" required; input type="text" name="name" placeholder="Routenname" required;
input type="submit" value="Neue Route"; input type="submit" value="Neue Route";
} }
@ -374,7 +374,7 @@ async fn move_station_higher(
Redirect::to(&format!("/admin/route/{route_id}")) Redirect::to(&format!("/admin/route/{route_id}"))
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
Router::new() Router::new()
.route("/", get(index)) .route("/", get(index))
.route("/", post(create)) .route("/", post(create))

View File

@ -1,9 +1,8 @@
use crate::admin::route::Route; use crate::{admin::route::Route, AppState};
use axum::Router; use axum::Router;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool}; use sqlx::{FromRow, SqlitePool};
use std::sync::Arc;
mod web; mod web;
@ -14,7 +13,7 @@ pub(crate) struct Station {
notes: Option<String>, notes: Option<String>,
amount_people: Option<i64>, amount_people: Option<i64>,
last_login: Option<NaiveDateTime>, // TODO use proper timestamp (NaiveDateTime?) last_login: Option<NaiveDateTime>, // TODO use proper timestamp (NaiveDateTime?)
pw: String, pub(crate) pw: String,
lat: Option<f64>, lat: Option<f64>,
lng: Option<f64>, lng: Option<f64>,
} }
@ -139,6 +138,6 @@ impl Station {
} }
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
web::routes() web::routes()
} }

View File

@ -1,4 +1,4 @@
use crate::{admin::station::Station, er, err, partials::page, suc, succ}; use crate::{admin::station::Station, er, err, partials::page, suc, succ, AppState};
use axum::{ use axum::{
extract::State, extract::State,
response::{IntoResponse, Redirect}, response::{IntoResponse, Redirect},
@ -450,7 +450,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
} }
h2 { (t!("station_new")) } h2 { (t!("station_new")) }
form action="/admin/station" method="post" { form action="/admin/station" method="post" {
fieldset role="team" { fieldset role="group" {
input type="text" name="name" placeholder=(t!("station_name")) required; input type="text" name="name" placeholder=(t!("station_name")) required;
input type="submit" value=(t!("station_new")); input type="submit" value=(t!("station_new"));
} }
@ -459,7 +459,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
page(content, session, false).await page(content, session, false).await
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
Router::new() Router::new()
.route("/", get(index)) .route("/", get(index))
.route("/", post(create)) .route("/", post(create))

View File

@ -1,8 +1,10 @@
use crate::admin::{route::Route, station::Station}; use crate::{
admin::{route::Route, station::Station},
AppState,
};
use axum::Router; use axum::Router;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool}; use sqlx::{FromRow, SqlitePool};
use std::sync::Arc;
mod web; mod web;
@ -165,6 +167,6 @@ impl Team {
} }
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
web::routes() web::routes()
} }

View File

@ -1,5 +1,10 @@
use super::{CreateError, Team}; use super::{CreateError, Team};
use crate::{admin::route::Route, admin::station::Station, err, partials::page, pl, succ}; use crate::{
admin::{route::Route, station::Station},
err,
partials::page,
pl, succ, AppState,
};
use axum::{ use axum::{
extract::State, extract::State,
response::{IntoResponse, Redirect}, response::{IntoResponse, Redirect},
@ -497,7 +502,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
} @else { } @else {
form action="/admin/team" method="post" { form action="/admin/team" method="post" {
@if routes.len() == 1 { @if routes.len() == 1 {
fieldset role="team" { fieldset role="group" {
input type="text" name="name" placeholder="Teamnamen" required; input type="text" name="name" placeholder="Teamnamen" required;
input type="hidden" name="route_id" value=(routes[0].id) ; input type="hidden" name="route_id" value=(routes[0].id) ;
input type="submit" value="Neues Team"; input type="submit" value="Neues Team";
@ -519,7 +524,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
page(content, session, false).await page(content, session, false).await
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { pub(super) fn routes() -> Router<AppState> {
Router::new() Router::new()
.route("/", get(index)) .route("/", get(index))
.route("/", post(create)) .route("/", post(create))

View File

@ -4,12 +4,12 @@ extern crate rust_i18n;
i18n!("locales", fallback = "de-AT"); i18n!("locales", fallback = "de-AT");
use admin::station::Station; use admin::station::Station;
use axum::{body::Body, response::Response, routing::get, Router}; use axum::{body::Body, extract::FromRef, response::Response, routing::get, Router};
use partials::page; use partials::page;
use sqlx::SqlitePool; use sqlx::SqlitePool;
use std::sync::Arc; use std::sync::Arc;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tower_sessions::{MemoryStore, SessionManagerLayer}; use tower_sessions::{cookie::Key, MemoryStore, SessionManagerLayer};
pub(crate) mod admin; pub(crate) mod admin;
mod partials; mod partials;
@ -102,11 +102,34 @@ async fn serve_marker_png() -> Response<Body> {
.unwrap() .unwrap()
} }
#[derive(Clone)]
struct AppState {
db: Arc<SqlitePool>,
key: Key,
}
impl FromRef<AppState> for Key {
fn from_ref(state: &AppState) -> Self {
state.key.clone()
}
}
impl FromRef<AppState> for Arc<SqlitePool> {
fn from_ref(state: &AppState) -> Self {
state.db.clone()
}
}
/// Starts the main application. /// Starts the main application.
pub async fn start(listener: TcpListener, db: SqlitePool) { pub async fn start(listener: TcpListener, db: SqlitePool) {
let session_store = MemoryStore::default(); let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store); let session_layer = SessionManagerLayer::new(session_store);
let state = AppState {
db: Arc::new(db),
key: Key::generate(),
};
let app = Router::new() let app = Router::new()
.nest("/s", station::routes()) // TODO: maybe switch to "/" .nest("/s", station::routes()) // TODO: maybe switch to "/"
.nest("/admin", admin::routes()) .nest("/admin", admin::routes())
@ -115,7 +138,7 @@ pub async fn start(listener: TcpListener, db: SqlitePool) {
.route("/leaflet.css", get(serve_leaflet_css)) .route("/leaflet.css", get(serve_leaflet_css))
.route("/leaflet.js", get(serve_leaflet_js)) .route("/leaflet.js", get(serve_leaflet_js))
.route("/marker.png", get(serve_marker_png)) .route("/marker.png", get(serve_marker_png))
.with_state(Arc::new(db)) .with_state(state)
.layer(session_layer); .layer(session_layer);
axum::serve(listener, app).await.unwrap(); axum::serve(listener, app).await.unwrap();

View File

@ -1,12 +1,13 @@
use crate::{err, partials, succ, Station}; use crate::{err, partials, succ, AppState, Station};
use axum::{ use axum::{
extract::State, extract::State,
response::{IntoResponse, Redirect}, response::{IntoResponse, Redirect},
routing::get, routing::{get, post},
Router, Form, Router,
}; };
use axum_extra::extract::CookieJar; use axum_extra::extract::{CookieJar, PrivateCookieJar};
use maud::{html, Markup, PreEscaped}; use maud::{html, Markup, PreEscaped};
use serde::Deserialize;
use sqlx::SqlitePool; use sqlx::SqlitePool;
use std::sync::Arc; use std::sync::Arc;
use tower_sessions::{cookie::Cookie, Session}; use tower_sessions::{cookie::Cookie, Session};
@ -91,8 +92,11 @@ async fn view(
State(db): State<Arc<SqlitePool>>, State(db): State<Arc<SqlitePool>>,
session: Session, session: Session,
jar: CookieJar, jar: CookieJar,
pjar: PrivateCookieJar,
axum::extract::Path(id): axum::extract::Path<i64>, axum::extract::Path(id): axum::extract::Path<i64>,
) -> Result<(CookieJar, Markup), (CookieJar, impl IntoResponse)> { ) -> Result<(CookieJar, PrivateCookieJar, Markup), (CookieJar, PrivateCookieJar, impl IntoResponse)>
{
// Station selector
let (mut jar, current_station_cookie) = get_station_cookie(&db, jar).await; let (mut jar, current_station_cookie) = get_station_cookie(&db, jar).await;
if current_station_cookie.is_none() { if current_station_cookie.is_none() {
jar = jar.add(Cookie::new("station_id", id.to_string())); jar = jar.add(Cookie::new("station_id", id.to_string()));
@ -106,6 +110,7 @@ async fn view(
err!(session, "Du hast versucht eine neue Station zu öffnen obwohl du bereits eine andere Station offen hattest. Welche möchtest du nun verwenden?"); err!(session, "Du hast versucht eine neue Station zu öffnen obwohl du bereits eine andere Station offen hattest. Welche möchtest du nun verwenden?");
return Ok(( return Ok((
jar, jar,
pjar,
decide_between_stations(&current_station_cookie, &station, session).await, decide_between_stations(&current_station_cookie, &station, session).await,
)); ));
} else { } else {
@ -113,12 +118,27 @@ async fn view(
err!(session, "Du hast versucht eine Station öffnen, die es nicht gibt. Nachdem du vorher schonmal eine andere Station (die es gibt) geöffnet hattest, bist du nun zu dieser weitergeleitet worden. Wenn du das nicht willst, logg dich bitte aus."); err!(session, "Du hast versucht eine Station öffnen, die es nicht gibt. Nachdem du vorher schonmal eine andere Station (die es gibt) geöffnet hattest, bist du nun zu dieser weitergeleitet worden. Wenn du das nicht willst, logg dich bitte aus.");
return Err(( return Err((
jar, jar,
pjar,
Redirect::to(&format!("/s/{}", current_station_cookie.id)), Redirect::to(&format!("/s/{}", current_station_cookie.id)),
)); ));
} }
} }
} }
let station = Station::find_by_id(&db, id).await.unwrap(); let station = Station::find_by_id(&db, id).await.unwrap();
let mut pjar = pjar;
// PW Checker
if let Some(pw) = pjar.get("pw") {
if pw.value() != station.pw {
pjar = pjar.remove(Cookie::from("station_id"));
err!(session, "Du hattest einen falschen Code für Station {} gespeichert. Bitte gibt den richtigen ein:", station.name );
return Err((jar, pjar, Redirect::to(&format!("/s/code",))));
}
} else {
return Err((jar, pjar, Redirect::to(&format!("/s/code",))));
}
let content = html! { let content = html! {
nav { nav {
ul { ul {
@ -131,9 +151,75 @@ async fn view(
h1 { "test" } h1 { "test" }
}; };
Ok((jar, partials::page(content, session, false).await)) Ok((jar, pjar, partials::page(content, session, false).await))
} }
async fn code(
State(db): State<Arc<SqlitePool>>,
session: Session,
jar: CookieJar,
pjar: PrivateCookieJar,
) -> Result<(CookieJar, PrivateCookieJar, Markup), (CookieJar, PrivateCookieJar, impl IntoResponse)>
{
let (jar, current_station_cookie) = get_station_cookie(&db, jar).await;
let Some(station) = current_station_cookie else {
return Err((jar, pjar, Redirect::to("/s")));
};
let content = html! {
nav {
ul {
li { strong { (format!("Station {}", station.name)) } }
}
ul {
li { a href="/s/station-logout" { "Station wechseln" } }
}
}
h1 { "Code eingeben" }
form action="/s/station-login" method="post" {
fieldset role="group" {
input type="text" name="pw" placeholder="Code" required;
input type="submit" value="Login";
}
}
};
Ok((jar, pjar, partials::page(content, session, false).await))
}
#[derive(Deserialize)]
struct LoginForm {
pw: String,
}
async fn login(
State(db): State<Arc<SqlitePool>>,
session: Session,
jar: CookieJar,
pjar: PrivateCookieJar,
Form(form): Form<LoginForm>,
) -> (CookieJar, PrivateCookieJar, impl IntoResponse) {
let (jar, current_station_cookie) = get_station_cookie(&db, jar).await;
let Some(station) = current_station_cookie else {
return (jar, pjar, Redirect::to("/s"));
};
let mut pjar = pjar;
if form.pw == station.pw {
pjar = pjar.add(Cookie::new("pw", form.pw));
succ!(
session,
"Erfolgreich eingeloggt, viel Spaß beim bewerten :-)"
);
return (jar, pjar, Redirect::to(&format!("/s/{}", station.id)));
} else {
err!(session, "Falsches Passwort. Probiere es erneut.");
std::thread::sleep(std::time::Duration::from_secs(1));
return (jar, pjar, Redirect::to("/s/code"));
}
}
async fn logout(session: Session, mut jar: CookieJar) -> (CookieJar, impl IntoResponse) { async fn logout(session: Session, mut jar: CookieJar) -> (CookieJar, impl IntoResponse) {
jar = jar.remove(Cookie::from("station_id")); jar = jar.remove(Cookie::from("station_id"));
@ -142,9 +228,40 @@ async fn logout(session: Session, mut jar: CookieJar) -> (CookieJar, impl IntoRe
(jar, Redirect::to("/s")) (jar, Redirect::to("/s"))
} }
pub(super) fn routes() -> Router<Arc<SqlitePool>> { async fn quick_login(
State(db): State<Arc<SqlitePool>>,
session: Session,
jar: CookieJar,
pjar: PrivateCookieJar,
axum::extract::Path((id, code)): axum::extract::Path<(i64, String)>,
) -> (CookieJar, PrivateCookieJar, impl IntoResponse) {
if let Some(station) = Station::find_by_id(&db, id).await {
if station.pw == code {
succ!(
session,
"Erfolgreich eingeloggt, viel Spaß beim bewerten :-)"
);
let mut pjar = pjar.remove(Cookie::from("pw"));
let mut jar = jar.remove(Cookie::from("station_id"));
jar = jar.add(Cookie::new("station_id", id.to_string()));
pjar = pjar.add(Cookie::new("pw", code));
return (jar, pjar, Redirect::to(&format!("/s/{id}")));
}
}
err!(
session,
"Falscher Quick-Einlogg-Link. Bitte nochmal scannen oder deine Station manuell auswählen:"
);
return (jar, pjar, Redirect::to("/s"));
}
pub(super) fn routes() -> Router<AppState> {
Router::new() Router::new()
.route("/", get(station_picker)) .route("/", get(station_picker))
.route("/{id}", get(view)) .route("/{id}", get(view))
.route("/code", get(code))
.route("/{id}/{code}", get(quick_login))
.route("/station-login", post(login))
.route("/station-logout", get(logout)) .route("/station-logout", get(logout))
} }