mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-08-02 12:24:52 +02:00
steam login
This commit is contained in:
parent
6e456a6596
commit
fc5cd1d24f
12 changed files with 926 additions and 70 deletions
122
src/main.rs
122
src/main.rs
|
|
@ -3,19 +3,26 @@ mod config;
|
|||
mod data;
|
||||
mod error;
|
||||
mod pages;
|
||||
mod session;
|
||||
|
||||
pub use crate::config::Config;
|
||||
use crate::config::Listen;
|
||||
use crate::data::demo::{Demo, ListDemo};
|
||||
use crate::data::steam_id::SteamId;
|
||||
use crate::data::user::User;
|
||||
use crate::pages::about::AboutPage;
|
||||
use crate::pages::demo::DemoPage;
|
||||
use crate::pages::index::Index;
|
||||
use crate::pages::render;
|
||||
use crate::session::{SessionData, COOKIE_NAME};
|
||||
use asset::{serve_compiled, serve_static};
|
||||
use axum::extract::{MatchedPath, Path};
|
||||
use axum::http::Request;
|
||||
use async_session::{MemoryStore, Session, SessionStore};
|
||||
use axum::extract::{MatchedPath, Path, RawQuery};
|
||||
use axum::headers::Cookie;
|
||||
use axum::http::header::{LOCATION, SET_COOKIE};
|
||||
use axum::http::{HeaderValue, Request, StatusCode};
|
||||
use axum::response::IntoResponse;
|
||||
use axum::{extract::State, routing::get, Router, Server};
|
||||
use axum::{extract::State, routing::get, Router, Server, TypedHeader};
|
||||
pub use error::Error;
|
||||
use hyperlocal::UnixServerExt;
|
||||
use maud::Markup;
|
||||
|
|
@ -25,8 +32,9 @@ use std::fs::{remove_file, set_permissions, Permissions};
|
|||
use std::net::SocketAddr;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::sync::Arc;
|
||||
use steam_openid::SteamOpenId;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing::{info, info_span};
|
||||
use tracing::{error, info, info_span};
|
||||
use tracing_subscriber::{
|
||||
fmt::layer, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer,
|
||||
};
|
||||
|
|
@ -35,6 +43,8 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
|
|||
|
||||
struct App {
|
||||
connection: PgPool,
|
||||
openid: SteamOpenId,
|
||||
pub session_store: MemoryStore,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
|
@ -50,7 +60,14 @@ async fn main() -> Result<()> {
|
|||
let config = Config::load(&config)?;
|
||||
let connection = config.database.connect().await?;
|
||||
|
||||
let state = Arc::new(App { connection });
|
||||
let session_store = MemoryStore::new();
|
||||
|
||||
let state = Arc::new(App {
|
||||
connection,
|
||||
openid: SteamOpenId::new(&config.site.url, "/login/callback")
|
||||
.expect("invalid steam login url"),
|
||||
session_store: session_store.clone(),
|
||||
});
|
||||
|
||||
let app = Router::new()
|
||||
.route("/", get(index))
|
||||
|
|
@ -58,6 +75,9 @@ async fn main() -> Result<()> {
|
|||
.route("/images/logo.png", get(serve_static!("../images/logo.png")))
|
||||
.route("/images/logo.svg", get(serve_static!("../images/logo.svg")))
|
||||
.route("/about", get(about))
|
||||
.route("/login/callback", get(login_callback))
|
||||
.route("/login", get(login))
|
||||
.route("/logout", get(logout))
|
||||
.route("/:id", get(demo))
|
||||
.layer(
|
||||
TraceLayer::new_for_http().make_span_with(|request: &Request<_>| {
|
||||
|
|
@ -99,20 +119,100 @@ async fn main() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn index(State(app): State<Arc<App>>) -> Result<Markup> {
|
||||
async fn index(State(app): State<Arc<App>>, session: SessionData) -> Result<Markup> {
|
||||
let demos = ListDemo::list(&app.connection, None).await?;
|
||||
Ok(render(Index { demos }))
|
||||
Ok(render(Index { demos }, session))
|
||||
}
|
||||
|
||||
async fn about(State(_app): State<Arc<App>>) -> Result<Markup> {
|
||||
Ok(render(AboutPage { key: None }))
|
||||
async fn about(State(_app): State<Arc<App>>, session: SessionData) -> Result<Markup> {
|
||||
Ok(render(
|
||||
AboutPage {
|
||||
key: session.token(),
|
||||
},
|
||||
session,
|
||||
))
|
||||
}
|
||||
|
||||
async fn demo(State(app): State<Arc<App>>, Path(id): Path<u32>) -> Result<Markup> {
|
||||
async fn demo(
|
||||
State(app): State<Arc<App>>,
|
||||
Path(id): Path<u32>,
|
||||
session: SessionData,
|
||||
) -> Result<Markup> {
|
||||
let demo = Demo::by_id(&app.connection, id)
|
||||
.await?
|
||||
.ok_or(Error::NotFound)?;
|
||||
Ok(render(DemoPage { demo }))
|
||||
Ok(render(DemoPage { demo }, session))
|
||||
}
|
||||
|
||||
async fn login_callback(
|
||||
State(app): State<Arc<App>>,
|
||||
RawQuery(query): RawQuery,
|
||||
) -> Result<impl IntoResponse> {
|
||||
let query = query.as_deref().unwrap_or_default();
|
||||
let steam_id = app.openid.verify(query).await.map_err(|e| {
|
||||
error!("{e:?}");
|
||||
Error::SteamAuth
|
||||
})?;
|
||||
let steam_id = SteamId::new(steam_id);
|
||||
let user = User::get(&app.connection, steam_id).await?;
|
||||
let mut session = Session::new();
|
||||
session
|
||||
.insert("user", user)
|
||||
.expect("failed to serialize user");
|
||||
let cookie = app
|
||||
.session_store
|
||||
.store_session(session)
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
Ok((
|
||||
StatusCode::FOUND,
|
||||
[
|
||||
(
|
||||
SET_COOKIE,
|
||||
HeaderValue::from_str(&format!(
|
||||
"{}={}; HttpOnly; SameSite=Lax; Path=/",
|
||||
COOKIE_NAME, cookie
|
||||
))
|
||||
.expect("invalid cookie"),
|
||||
),
|
||||
(LOCATION, HeaderValue::from_static("/")),
|
||||
],
|
||||
))
|
||||
}
|
||||
|
||||
async fn login(State(app): State<Arc<App>>) -> impl IntoResponse {
|
||||
(
|
||||
StatusCode::FOUND,
|
||||
[(
|
||||
LOCATION,
|
||||
HeaderValue::from_str(app.openid.get_redirect_url()).unwrap(),
|
||||
)],
|
||||
)
|
||||
}
|
||||
|
||||
async fn logout(
|
||||
State(app): State<Arc<App>>,
|
||||
cookie: Option<TypedHeader<Cookie>>,
|
||||
) -> impl IntoResponse {
|
||||
if let Some(session_cookie) = cookie.as_deref().and_then(|cookie| cookie.get(COOKIE_NAME)) {
|
||||
if let Ok(Some(cookie)) = app.session_store.load_session(session_cookie.into()).await {
|
||||
let _ = app.session_store.destroy_session(cookie);
|
||||
}
|
||||
}
|
||||
(
|
||||
StatusCode::FOUND,
|
||||
[
|
||||
(
|
||||
SET_COOKIE,
|
||||
HeaderValue::from_str(&format!(
|
||||
"{}=; HttpOnly; SameSite=Lax; expires=Thu, 01 Jan 1970 00:00:00 GMT",
|
||||
COOKIE_NAME
|
||||
))
|
||||
.expect("invalid cookie"),
|
||||
),
|
||||
(LOCATION, HeaderValue::from_str("/").unwrap()),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
async fn handler_404() -> impl IntoResponse {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue