diff --git a/Cargo.lock b/Cargo.lock index e184e2a..5112240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,15 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" +dependencies = [ + "serde", +] + [[package]] name = "askama" version = "0.12.1" @@ -331,6 +340,7 @@ name = "citadels" version = "0.7.1" dependencies = [ "anyhow", + "arcstr", "askama", "axum", "axum-core", diff --git a/Cargo.toml b/Cargo.toml index f8bf897..12486a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.20" env_logger = { version = "0.10.1", features = ["color"] } rand_xoshiro = "0.6.0" rand_core = { version = "0.6.4", features = ["getrandom"] } -serde = { version = "1.0.195", features = ["derive","rc"] } +serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" time = "0.3.31" dotenv = { version = "0.15.0", optional = true } @@ -35,6 +35,7 @@ reqwest = { version = "0.12.4", features = ["json"], default-features = false } anyhow = { version = "1.0.83", default-features = true } axum-macros = { version = "0.4.1", optional = true} maud = { version = "0.26.0", features = ["axum"], default-features = false} +arcstr = { version = "1.2.0", features = ["serde"], default-features = false } [features] dev = ["dep:axum-macros"] diff --git a/src/lib.rs b/src/lib.rs index 25cb85d..e1f62cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,3 +13,4 @@ pub mod roles; pub mod server; pub mod templates; pub mod types; +pub mod utils; diff --git a/src/server/auth.rs b/src/server/auth.rs index ea42fa8..2fa7767 100644 --- a/src/server/auth.rs +++ b/src/server/auth.rs @@ -1,13 +1,13 @@ use super::supabase::SignInResponse; use crate::server::{state::AppState, supabase::EmailCreds}; +use arcstr::ArcStr; use axum_extra::extract::{cookie::Cookie, PrivateCookieJar}; -use std::borrow::Cow; -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; #[derive(Clone)] pub struct Session { - pub access_token: Arc, - pub refresh_token: Arc, + pub access_token: ArcStr, + pub refresh_token: ArcStr, } impl Session { @@ -18,7 +18,7 @@ impl Session { } #[derive(Default)] -pub struct Sessions(pub HashMap, Session>); +pub struct Sessions(pub HashMap); impl Sessions { pub fn session_from_cookies(&self, cookies: &PrivateCookieJar) -> Option { @@ -56,9 +56,10 @@ pub async fn login( let session = state.supabase.signin_email(creds).await?; log::info!("Setting session cookie with 1 week expiry"); - let user_id = session.user.id.as_ref().to_owned(); - let mut cookie = Cookie::new("session_id", user_id); - cookie.set_max_age(time::Duration::WEEK); + let cookie = Cookie::build(("session_id", session.user.id.to_string())) + .max_age(time::Duration::WEEK) + .secure(true) + .http_only(true); cookies = cookies.add(cookie); state.add_session(session).await; } @@ -76,8 +77,11 @@ pub async fn signup( anyhow::bail!("Already has a session cookie"); } let session = state.supabase.signup_email(creds).await?; - let cookie = Cookie::build(("session_id", String::from(session.user.id.as_ref()))) - .max_age(time::Duration::WEEK); + + let cookie = Cookie::build(("session_id", session.user.id.to_string())) + .max_age(time::Duration::WEEK) + .secure(true) + .http_only(true); cookies = cookies.add(cookie); state.add_session(session).await; Ok(cookies) diff --git a/src/server/routes.rs b/src/server/routes.rs index afa8786..a8746d7 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -1,3 +1,4 @@ +use super::auth; use crate::actions::{ActionSubmission, ActionTag}; use crate::districts::DistrictName; use crate::game::Game; @@ -25,8 +26,6 @@ use std::collections::{HashMap, HashSet}; use tower_http::services::ServeDir; use tower_http::trace::TraceLayer; -use super::auth; - pub fn get_router(state: AppState) -> Router { Router::new() .route("/", get(get_index)) diff --git a/src/server/supabase.rs b/src/server/supabase.rs index faa7350..85fa79c 100644 --- a/src/server/supabase.rs +++ b/src/server/supabase.rs @@ -1,9 +1,8 @@ +use crate::utils::infer; +use arcstr::ArcStr; use reqwest::Response; use serde::{Deserialize, Serialize}; use std::env; -use std::sync::Arc; - -use super::auth::Session; #[derive(Serialize)] pub struct EmailCreds<'a> { @@ -18,15 +17,15 @@ pub struct RefreshToken<'a> { #[derive(Deserialize)] pub struct SignInResponse { - pub access_token: Arc, - pub refresh_token: Arc, + pub access_token: ArcStr, + pub refresh_token: ArcStr, pub expires_in: u64, pub user: UserSignInResponse, } #[derive(Deserialize)] pub struct UserSignInResponse { - pub id: Arc, + pub id: ArcStr, } #[derive(Clone)] @@ -55,8 +54,8 @@ impl std::fmt::Debug for Secret { #[derive(Clone, Debug)] pub struct SupabaseAnonClient { pub client: reqwest::Client, - pub url: Arc, - pub api_key: Arc, + pub url: ArcStr, + pub api_key: ArcStr, } impl SupabaseAnonClient { @@ -72,7 +71,7 @@ impl SupabaseAnonClient { let response: Response = self .client .post(&format!("{}/auth/v1/signup", self.url)) - .header("apikey", self.api_key.as_ref()) + .header("apikey", infer::<&str>(self.api_key.as_ref())) .header("Content-Type", "application/json") .json(creds) .send() @@ -85,7 +84,7 @@ impl SupabaseAnonClient { let response = self .client .post(&format!("{}/auth/v1/token?grant_type=password", self.url)) - .header("apikey", self.api_key.as_ref()) + .header::<_, &str>("apikey", self.api_key.as_ref()) .header("Content-Type", "application/json") .json(creds) .send() @@ -101,7 +100,7 @@ impl SupabaseAnonClient { "{}/auth/v1/token?grant_type=refresh_token", self.url )) - .header("apikey", self.api_key.as_ref()) + .header("apikey", self.api_key.as_str()) .header("Content-Type", "application/json") .json(&RefreshToken { refresh_token }) .send() @@ -114,7 +113,7 @@ impl SupabaseAnonClient { pub async fn logout(&self, access_token: &str) -> anyhow::Result<()> { self.client .post(&format!("{}/auth/v1/logout", self.url)) - .header("apikey", self.api_key.as_ref()) + .header("apikey", self.api_key.as_str()) .header("Content-Type", "application/json") .bearer_auth(access_token) .send() diff --git a/src/types.rs b/src/types.rs index 6e56b01..a6e053c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,7 @@ +use arcstr::ArcStr; use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use std::fmt::{self, Debug, Display}; -use std::sync::Arc; #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub enum CardSuit { @@ -68,7 +68,7 @@ pub type PlayerId = String; pub type Result = std::result::Result; #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)] -pub struct PlayerName(pub Arc); +pub struct PlayerName(pub ArcStr); impl Borrow for PlayerName { fn borrow(&self) -> &str { @@ -76,7 +76,7 @@ impl Borrow for PlayerName { } } -impl>> From for PlayerName { +impl> From for PlayerName { fn from(str: T) -> Self { PlayerName(str.into()) } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..d42e455 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,5 @@ +/// for when the types are too ambiguous +#[inline] +pub fn infer(t: T) -> T { + t +}