feat(web): refresh token every hour, small refactor

This commit is contained in:
əlemi 2024-06-07 05:26:22 +02:00
parent ad7c643762
commit 4d2906bf78
Signed by: alemi
GPG key ID: A4895B84D311642C
2 changed files with 51 additions and 45 deletions

View file

@ -1,6 +1,5 @@
use leptos::*;
use leptos_router::*;
use reqwest::Method;
use crate::prelude::*;
use leptos_use::{storage::use_local_storage, use_cookie, utils::{FromToStringCodec, JsonCodec}};
@ -36,36 +35,21 @@ pub fn App() -> impl IntoView {
let title_target = move || if auth.present() { "/web/home" } else { "/web/server" };
if let Some(tok) = token.get_untracked() {
spawn_local(async move {
// refresh token first, or verify that we're still authed
match reqwest::Client::new()
.request(Method::PATCH, format!("{URL_BASE}/auth"))
.json(&serde_json::json!({"token": tok}))
.send()
.await
{
Err(e) => tracing::error!("could not refresh token: {e}"),
Ok(res) => match res.error_for_status() {
Err(e) => tracing::error!("server rejected refresh: {e}"),
Ok(doc) => match doc.json::<AuthResponse>().await {
Err(e) => tracing::error!("failed parsing auth response: {e}"),
Ok(auth) => {
set_token.set(Some(auth.token));
set_userid.set(Some(auth.user));
},
}
}
}
local_tl.more(auth); // public outbox never contains private posts
spawn_local(async move {
// refresh token first, or verify that we're still authed
if Auth::refresh(auth.token, set_token, set_userid).await {
home_tl.more(auth); // home inbox requires auth to be read
}
server_tl.more(auth); // server inbox may contain private posts
});
server_tl.more(auth);
local_tl.more(auth);
if auth.token.get_untracked().is_some() { home_tl.more(auth) };
})
} else {
server_tl.more(auth);
local_tl.more(auth);
}
// refresh token every hour
set_interval(
move || spawn_local(async move { Auth::refresh(auth.token, set_token, set_userid).await; }),
std::time::Duration::from_secs(3600)
);
view! {
<nav class="w-100 mt-1 mb-1 pb-s">

View file

@ -1,13 +1,6 @@
use leptos::*;
use crate::URL_BASE;
pub trait AuthToken {
fn present(&self) -> bool;
fn token(&self) -> String;
fn user_id(&self) -> String;
fn username(&self) -> String;
fn outbox(&self) -> String;
}
use reqwest::Method;
use crate::{components::AuthResponse, URL_BASE};
#[derive(Debug, Clone, Copy)]
pub struct Auth {
@ -15,16 +8,16 @@ pub struct Auth {
pub userid: Signal<Option<String>>,
}
impl AuthToken for Auth {
fn token(&self) -> String {
impl Auth {
pub fn token(&self) -> String {
self.token.get().unwrap_or_default()
}
fn user_id(&self) -> String {
pub fn user_id(&self) -> String {
self.userid.get().unwrap_or_default()
}
fn username(&self) -> String {
pub fn username(&self) -> String {
// TODO maybe cache this?? how often do i need it?
self.userid.get()
.unwrap_or_default()
@ -34,11 +27,40 @@ impl AuthToken for Auth {
.to_string()
}
fn present(&self) -> bool {
pub fn present(&self) -> bool {
self.token.get().map_or(false, |x| !x.is_empty())
}
fn outbox(&self) -> String {
pub fn outbox(&self) -> String {
format!("{URL_BASE}/actors/{}/outbox", self.username())
}
pub async fn refresh(
token: Signal<Option<String>>,
set_token: WriteSignal<Option<String>>,
set_userid: WriteSignal<Option<String>>
) -> bool {
if let Some(tok) = token.get_untracked() {
match reqwest::Client::new()
.request(Method::PATCH, format!("{URL_BASE}/auth"))
.json(&serde_json::json!({"token": tok}))
.send()
.await
{
Err(e) => tracing::error!("could not refresh token: {e}"),
Ok(res) => match res.error_for_status() {
Err(e) => tracing::error!("server rejected refresh: {e}"),
Ok(doc) => match doc.json::<AuthResponse>().await {
Err(e) => tracing::error!("failed parsing auth response: {e}"),
Ok(auth) => {
set_token.set(Some(auth.token));
set_userid.set(Some(auth.user));
return true;
},
}
}
}
}
false
}
}