diff options
author | mia <mia@mia.jetzt> | 2024-04-23 18:40:20 -0700 |
---|---|---|
committer | mia <mia@mia.jetzt> | 2024-04-23 18:40:20 -0700 |
commit | b9c1ac1c070f19295c79ad21a7eddf20ea42a49b (patch) | |
tree | 82882bdbb9e43d8cce25ef45f7a2ece81f2fe432 /src/server | |
parent | 796b2cafc798a7faa80a007002831a4c40635fe8 (diff) | |
download | dissociate-b9c1ac1c070f19295c79ad21a7eddf20ea42a49b.tar.gz dissociate-b9c1ac1c070f19295c79ad21a7eddf20ea42a49b.zip |
falx integration v0.2.0
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/config.rs | 2 | ||||
-rw-r--r-- | src/server/falx.rs | 61 | ||||
-rw-r--r-- | src/server/mod.rs | 12 | ||||
-rw-r--r-- | src/server/nginx_check.rs | 41 |
4 files changed, 72 insertions, 44 deletions
diff --git a/src/server/config.rs b/src/server/config.rs index 4563f34..31d1e1f 100644 --- a/src/server/config.rs +++ b/src/server/config.rs @@ -1,6 +1,7 @@ use std::net::SocketAddr; use std::path::{Path, PathBuf}; +use cursive::reexports::ahash::HashSet; use eyre::Context; use tap::Pipe; @@ -10,6 +11,7 @@ pub struct Config { pub web_base: String, pub cookie_domain: Option<String>, pub admin_socket: PathBuf, + pub handoffs: HashSet<String>, pub data: PathBuf, } diff --git a/src/server/falx.rs b/src/server/falx.rs new file mode 100644 index 0000000..03a8a0b --- /dev/null +++ b/src/server/falx.rs @@ -0,0 +1,61 @@ +use axum::{ + extract::{Path, State}, + http::{HeaderMap, StatusCode, Uri}, + response::{IntoResponse, Response}, + routing::get, + Router, +}; +use axum_extra::extract::CookieJar; + +use crate::server::store::Store; + +use super::{ApiState, Handoffs}; + +pub fn bind(app: Router<ApiState>) -> Router<ApiState> { + app.route("/check/:token/:scope", get(check_)) + .route("/handoff", get(handoff)) +} + +#[axum::debug_handler(state = ApiState)] +async fn check_( + Path((token, scope)): Path<(String, String)>, + State(store): State<Store>, +) -> Response { + let Some(name) = store.check_token(&token).await else { + return StatusCode::UNAUTHORIZED.into_response(); + }; + let Some(account) = store.get_account(&name).await else { + return StatusCode::UNAUTHORIZED.into_response(); + }; + if account.scopes.contains(&scope) { + StatusCode::OK.into_response() + } else { + StatusCode::FORBIDDEN.into_response() + } +} + +#[axum::debug_handler(state = ApiState)] +async fn handoff( + jar: CookieJar, + State(Handoffs(handoffs)): State<Handoffs>, + headers: HeaderMap, +) -> Response { + let Some(origin) = headers.get("Origin") else { + return (StatusCode::BAD_REQUEST, "Missing Origin header").into_response(); + }; + let Some(origin) = origin + .to_str() + .ok() + .and_then(|origin| origin.parse::<Uri>().ok()) + .and_then(|origin| origin.host().map(ToString::to_string)) + else { + return (StatusCode::BAD_REQUEST, "Malformed Origin header").into_response(); + }; + if !handoffs.contains(&origin) { + return (StatusCode::FORBIDDEN, "Origin not registered for handoff").into_response(); + } + let Some(token) = jar.get("dissociate-token") else { + return (StatusCode::UNAUTHORIZED, "Authenticate cookie missing").into_response(); + }; + return (StatusCode::OK, token.value().to_string()).into_response(); +} diff --git a/src/server/mod.rs b/src/server/mod.rs index d9b3beb..81dc519 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,11 +1,11 @@ mod admin; mod config; +mod falx; mod login; -mod nginx_check; mod panel; mod store; -use std::{future::IntoFuture, path::PathBuf}; +use std::{future::IntoFuture, path::PathBuf, sync::Arc}; use axum::{ body::Body, @@ -16,6 +16,7 @@ use axum::{ Router, }; use axum_extra::extract::CookieJar; +use cursive::reexports::ahash::HashSet; use eyre::Context; use maud::{html, PreEscaped}; use tap::Pipe; @@ -41,12 +42,13 @@ pub async fn serve() -> eyre::Result<()> { let app = Router::new() .pipe(login::bind) - .pipe(nginx_check::bind) + .pipe(falx::bind) .pipe(panel::bind) .with_state(ApiState { store, cookie_domain: CookieDomain(config.cookie_domain), web_base: WebBase(config.web_base), + handoffs: Handoffs(Arc::new(config.handoffs)), }) .fallback(get(|| async { render_html( @@ -72,6 +74,7 @@ struct ApiState { pub store: Store, pub cookie_domain: CookieDomain, pub web_base: WebBase, + pub handoffs: Handoffs, } #[derive(Clone)] @@ -80,6 +83,9 @@ struct CookieDomain(Option<String>); #[derive(Clone)] struct WebBase(String); +#[derive(Clone)] +struct Handoffs(Arc<HashSet<String>>); + fn render_html(head: PreEscaped<impl AsRef<str>>, body: PreEscaped<impl AsRef<str>>) -> Response { let html = html! { (PreEscaped("<!doctype html>")) diff --git a/src/server/nginx_check.rs b/src/server/nginx_check.rs deleted file mode 100644 index 7b67f26..0000000 --- a/src/server/nginx_check.rs +++ /dev/null @@ -1,41 +0,0 @@ -// for ngx_http_auth_request_module authentication -// make sure you have cookie_domain set properly -// depends on https://git.mia.jetzt/sysconf/tree/patches/nginx_auth_redirect.patch - -use axum::{ - extract::{Path, State}, - http::StatusCode, - response::{IntoResponse, Redirect, Response}, - routing::get, - Router, -}; -use axum_extra::extract::CookieJar; - -use crate::server::{account_auth, store::Store}; - -use super::{ApiState, WebBase}; - -pub fn bind(app: Router<ApiState>) -> Router<ApiState> { - app.route("/nginx_check/:scope", get(nginx_check)) -} - -#[axum::debug_handler(state = ApiState)] -async fn nginx_check( - jar: CookieJar, - Path(scope): Path<String>, - State(store): State<Store>, - State(WebBase(web_base)): State<WebBase>, -) -> Response { - let nevermind = || Redirect::to(&format!("{web_base}/logout")).into_response(); - let Some(name) = account_auth(&jar, &store).await else { - return nevermind(); - }; - let Some(account) = store.get_account(&name).await else { - return nevermind(); - }; - if account.scopes.contains(&scope) { - StatusCode::OK.into_response() - } else { - StatusCode::FORBIDDEN.into_response() - } -} |