🗝
summary refs log tree commit diff
diff options
context:
space:
mode:
authormia <mia@mia.jetzt>2024-04-23 18:40:20 -0700
committermia <mia@mia.jetzt>2024-04-23 18:40:20 -0700
commitb9c1ac1c070f19295c79ad21a7eddf20ea42a49b (patch)
tree82882bdbb9e43d8cce25ef45f7a2ece81f2fe432
parent796b2cafc798a7faa80a007002831a4c40635fe8 (diff)
downloaddissociate-b9c1ac1c070f19295c79ad21a7eddf20ea42a49b.tar.gz
dissociate-b9c1ac1c070f19295c79ad21a7eddf20ea42a49b.zip
falx integration v0.2.0
-rw-r--r--Cargo.lock26
-rw-r--r--Cargo.toml10
-rw-r--r--src/server/config.rs2
-rw-r--r--src/server/falx.rs61
-rw-r--r--src/server/mod.rs12
-rw-r--r--src/server/nginx_check.rs41
6 files changed, 90 insertions, 62 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 021b24f..9f0d6fc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -488,7 +488,7 @@ dependencies = [
 
 [[package]]
 name = "dissociate"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "argon2",
  "axum",
@@ -1369,18 +1369,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.197"
+version = "1.0.198"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.197"
+version = "1.0.198"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1389,9 +1389,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.114"
+version = "1.0.116"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
+checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
 dependencies = [
  "itoa",
  "ryu",
@@ -1586,9 +1586,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.36.0"
+version = "1.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
+checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
 dependencies = [
  "backtrace",
  "bytes",
@@ -1628,9 +1628,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.8.10"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290"
+checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -1649,9 +1649,9 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.22.6"
+version = "0.22.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
+checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
 dependencies = [
  "indexmap",
  "serde",
diff --git a/Cargo.toml b/Cargo.toml
index 7f5317e..319d190 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dissociate"
-version = "0.1.0"
+version = "0.2.0"
 edition = "2021"
 
 [dependencies]
@@ -19,8 +19,8 @@ oxide-auth = "0.5.4"
 oxide-auth-axum = "0.4.0"
 paste = "1.0.14"
 rand = "0.8.5"
-serde = { version = "1.0.197", features = ["derive"] }
-serde_json = "1.0.114"
+serde = { version = "1.0.198", features = ["derive"] }
+serde_json = "1.0.116"
 tap = "1.0.1"
-tokio = { version = "1.36.0", features = ["rt-multi-thread", "macros", "fs"] }
-toml = "0.8.10"
+tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros", "fs"] }
+toml = "0.8.12"
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()
-    }
-}