From 469ca6f718438b09f63dd2865cd8dc6c9c7c9bef Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 18 Jan 2024 15:31:32 +0100 Subject: [PATCH] working login and logout --- Cargo.toml | 3 +-- Trunk.toml | 2 +- src/backend/api/user.rs | 1 + src/frontend/api.rs | 32 ++++++++++++-------------------- src/frontend/app.rs | 9 ++++----- src/frontend/components/nav.rs | 23 +++++++---------------- src/frontend/pages/article.rs | 7 +++++++ src/main.rs | 2 +- tests/common.rs | 11 +---------- 9 files changed, 35 insertions(+), 55 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4aa2058..f5e5b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ uuid = { version = "1.6.1", features = ["serde"] } tower-http = { version = "0.4.0", features = ["cors", "fs"], optional = true } serde = { version = "1.0.192", features = ["derive"] } url = { version = "2.4.1", features = ["serde"] } -reqwest = { version = "0.11.22", features = ["json"] } +reqwest = { version = "0.11.22", features = ["json", "cookies"] } log = "0.4" tracing = "0.1.40" once_cell = "1.18.0" @@ -68,7 +68,6 @@ time = "0.3.31" [dev-dependencies] pretty_assertions = "1.4.0" -reqwest = { version = "0.11.22", features = ["cookies"] } [package.metadata.leptos] output-name = "ibis" diff --git a/Trunk.toml b/Trunk.toml index 101f859..10005a7 100644 --- a/Trunk.toml +++ b/Trunk.toml @@ -3,4 +3,4 @@ filehash = false target = "assets/index.html" [[proxy]] -backend = "http://[::1]:8131" +backend = "http://127.0.0.1:8131" diff --git a/src/backend/api/user.rs b/src/backend/api/user.rs index 9b0788a..9598c03 100644 --- a/src/backend/api/user.rs +++ b/src/backend/api/user.rs @@ -91,6 +91,7 @@ fn create_cookie(jwt: String, data: &Data) -> Cookie<'static> { .same_site(SameSite::Strict) .path("/") .http_only(true) + .secure(true) .expires(Expiration::DateTime( OffsetDateTime::now_utc() + Duration::weeks(52), )) diff --git a/src/frontend/api.rs b/src/frontend/api.rs index f8d2363..60b3a39 100644 --- a/src/frontend/api.rs +++ b/src/frontend/api.rs @@ -6,13 +6,10 @@ use crate::common::{DbArticle, GetArticleData}; use crate::common::{DbInstance, FollowInstance, InstanceView, SearchArticleData}; use crate::frontend::error::MyResult; use anyhow::anyhow; -use once_cell::sync::Lazy; use reqwest::{Client, RequestBuilder, StatusCode}; use serde::{Deserialize, Serialize}; use url::Url; -pub static CLIENT: Lazy = Lazy::new(Client::new); - #[derive(Clone)] pub struct ApiClient { client: Client, @@ -116,8 +113,9 @@ impl ApiClient { let resolve_form = ResolveObject { id: Url::parse(&format!("http://{}", follow_instance))?, }; - let instance_resolved: DbInstance = - get_query(&self.hostname, "instance/resolve", Some(resolve_form)).await?; + let instance_resolved: DbInstance = self + .get_query("instance/resolve", Some(resolve_form)) + .await?; // send follow let follow_form = FollowInstance { @@ -170,35 +168,29 @@ impl ApiClient { pub async fn resolve_article(&self, id: Url) -> MyResult { let resolve_object = ResolveObject { id }; - get_query(&self.hostname, "article/resolve", Some(resolve_object)).await + self.get_query("article/resolve", Some(resolve_object)) + .await } pub async fn resolve_instance(&self, id: Url) -> MyResult { let resolve_object = ResolveObject { id }; - get_query(&self.hostname, "instance/resolve", Some(resolve_object)).await + self.get_query("instance/resolve", Some(resolve_object)) + .await } } -async fn get_query(hostname: &str, endpoint: &str, query: Option) -> MyResult +async fn handle_json_res(#[allow(unused_mut)] mut req: RequestBuilder) -> MyResult where T: for<'de> Deserialize<'de>, - R: Serialize, { - let mut req = CLIENT.get(format!("http://{}/api/v1/{}", hostname, endpoint)); - if let Some(query) = query { - req = req.query(&query); + #[cfg(not(feature = "ssr"))] + { + req = req.fetch_credentials_include(); } - handle_json_res::(req).await -} - -async fn handle_json_res(req: RequestBuilder) -> MyResult -where - T: for<'de> Deserialize<'de>, -{ let res = req.send().await?; let status = res.status(); let text = res.text().await?; - if status == reqwest::StatusCode::OK { + if status == StatusCode::OK { Ok(serde_json::from_str(&text).map_err(|e| anyhow!("Json error on {text}: {e}"))?) } else { Err(anyhow!("API error: {text}").into()) diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 45ea374..aa723a4 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -43,10 +43,9 @@ impl GlobalState { create_local_resource( move || (), |_| async move { - if let Ok(my_profile) = GlobalState::api_client().my_profile().await { - expect_context::>() - .update(|state| state.my_profile = Some(my_profile.clone())) - }; + let my_profile = GlobalState::api_client().my_profile().await.ok(); + expect_context::>() + .update(|state| state.my_profile = my_profile.clone()); }, ); } @@ -54,7 +53,7 @@ impl GlobalState { #[component] pub fn App() -> impl IntoView { - let backend_hostname = "localhost:8080".to_string(); + let backend_hostname = "127.0.0.1:8080".to_string(); provide_meta_context(); let backend_hostname = GlobalState { diff --git a/src/frontend/components/nav.rs b/src/frontend/components/nav.rs index b12ef71..5eb4a25 100644 --- a/src/frontend/components/nav.rs +++ b/src/frontend/components/nav.rs @@ -6,6 +6,12 @@ use leptos_router::*; #[component] pub fn Nav() -> impl IntoView { let global_state = use_context::>().unwrap(); + let logout_action = create_action(move |_| async move { + GlobalState::api_client().logout().await.unwrap(); + expect_context::>() + .get_untracked() + .update_my_profile(); + }); view! { } } - -fn do_logout() { - dbg!("do logout"); - create_action(move |()| async move { - dbg!("run logout action"); - GlobalState::api_client().logout().await.unwrap(); - expect_context::>() - .get() - .update_my_profile(); - }); -} diff --git a/src/frontend/pages/article.rs b/src/frontend/pages/article.rs index b95d364..5abdab6 100644 --- a/src/frontend/pages/article.rs +++ b/src/frontend/pages/article.rs @@ -26,12 +26,19 @@ pub fn Article() -> impl IntoView { }, ); + let global_state = use_context::>().unwrap(); + let (count, set_count) = create_signal(0); view! { {move || article.get().map(|article| view! {

{article.article.title}

+ + +
{article.article.text}
})} diff --git a/src/main.rs b/src/main.rs index 40089c1..31b8ea8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ pub async fn main() -> ibis_lib::backend::error::MyResult<()> { .filter_module("ibis", LevelFilter::Info) .init(); let database_url = "postgres://ibis:password@localhost:5432/ibis"; - ibis_lib::backend::start("localhost:8131", database_url).await?; + ibis_lib::backend::start("127.0.0.1:8131", database_url).await?; Ok(()) } diff --git a/tests/common.rs b/tests/common.rs index d192609..1fbafe8 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -115,16 +115,7 @@ impl IbisInstance { username: username.to_string(), password: "hunter2".to_string(), }; - // use a separate http client for each backend instance, with cookie store for auth - // how to pass the client/hostname to api client methods? - // probably create a struct ApiClient(hostname, client) with all api methods in impl - // TODO: seems that cookie isnt being stored? or maybe wrong hostname? - let jar = Arc::new(Jar::default()); - let client = ClientBuilder::new() - .cookie_store(true) - .cookie_provider(jar.clone()) - .build() - .unwrap(); + let client = ClientBuilder::new().cookie_store(true).build().unwrap(); let api_client = ApiClient::new(client, hostname.clone()); api_client.register(form).await.unwrap(); Self {