add(ui): ability to log out
This commit is contained in:
parent
d2ca9e23d3
commit
b3cac5f97a
29 changed files with 499 additions and 124 deletions
|
@ -11,6 +11,7 @@ use axum::{
|
|||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::extract::CookieJar;
|
||||
use tetratto_shared::hash::hash;
|
||||
|
||||
/// `/api/v1/auth/register`
|
||||
pub async fn register_request(
|
||||
|
@ -20,7 +21,7 @@ pub async fn register_request(
|
|||
Json(props): Json<AuthProps>,
|
||||
) -> impl IntoResponse {
|
||||
let data = &(data.read().await).0;
|
||||
let user = get_user_from_token!((jar, data) <optional>);
|
||||
let user = get_user_from_token!(jar, data);
|
||||
|
||||
if user.is_some() {
|
||||
return (
|
||||
|
@ -75,7 +76,7 @@ pub async fn login_request(
|
|||
Json(props): Json<AuthProps>,
|
||||
) -> impl IntoResponse {
|
||||
let data = &(data.read().await).0;
|
||||
let user = get_user_from_token!((jar, data) <optional>);
|
||||
let user = get_user_from_token!(jar, data);
|
||||
|
||||
if user.is_some() {
|
||||
return (None, Json(Error::AlreadyAuthenticated.into()));
|
||||
|
@ -125,3 +126,50 @@ pub async fn login_request(
|
|||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// `/api/v1/auth/logout`
|
||||
pub async fn logout_request(
|
||||
jar: CookieJar,
|
||||
Extension(data): Extension<State>,
|
||||
) -> impl IntoResponse {
|
||||
let data = &(data.read().await).0;
|
||||
let user = match get_user_from_token!(jar, data) {
|
||||
Some(ua) => ua,
|
||||
None => return (None, Json(Error::NotAllowed.into())),
|
||||
};
|
||||
|
||||
// update tokens
|
||||
let token = jar
|
||||
.get("__Secure-atto-token")
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.replace("__Secure-atto-token=", "");
|
||||
|
||||
let mut new_tokens = user.tokens.clone();
|
||||
new_tokens.remove(
|
||||
new_tokens
|
||||
.iter()
|
||||
.position(|t| t.1 == hash(token.to_string()))
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
if let Err(e) = data.update_user_tokens(user.id, new_tokens).await {
|
||||
return (None, Json(e.into()));
|
||||
}
|
||||
|
||||
// ...
|
||||
(
|
||||
Some([(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"__Secure-atto-token={}; SameSite=Lax; Secure; Path=/; HostOnly=true; HttpOnly=true; Max-Age=0",
|
||||
"refresh",
|
||||
),
|
||||
)]),
|
||||
Json(ApiReturn {
|
||||
ok: true,
|
||||
message: "Goodbye!".to_string(),
|
||||
payload: (),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@ use serde::Deserialize;
|
|||
|
||||
pub fn routes() -> Router {
|
||||
Router::new()
|
||||
// auth
|
||||
// global
|
||||
.route("/auth/register", post(auth::register_request))
|
||||
.route("/auth/login", post(auth::login_request))
|
||||
.route("/auth/logout", post(auth::logout_request))
|
||||
// profile
|
||||
.route(
|
||||
"/auth/profile/{id}/avatar",
|
||||
|
|
|
@ -1,27 +1,16 @@
|
|||
use axum::response::IntoResponse;
|
||||
|
||||
/// `/public/favicon.svg`
|
||||
pub async fn favicon_request() -> impl IntoResponse {
|
||||
([("Content-Type", "image/svg+xml")], crate::assets::FAVICON)
|
||||
macro_rules! serve_asset {
|
||||
($fn_name:ident: $name:ident($type:literal)) => {
|
||||
pub async fn $fn_name() -> impl IntoResponse {
|
||||
([("Content-Type", $type)], crate::assets::$name)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// `/css/style.css`
|
||||
pub async fn style_css_request() -> impl IntoResponse {
|
||||
([("Content-Type", "text/css")], crate::assets::STYLE_CSS)
|
||||
}
|
||||
serve_asset!(favicon_request: FAVICON("image/svg+xml"));
|
||||
serve_asset!(style_css_request: STYLE_CSS("text/css"));
|
||||
|
||||
/// `/js/atto.js`
|
||||
pub async fn atto_js_request() -> impl IntoResponse {
|
||||
(
|
||||
[("Content-Type", "text/javascript")],
|
||||
crate::assets::ATTO_JS,
|
||||
)
|
||||
}
|
||||
|
||||
/// `/js/atto.js`
|
||||
pub async fn loader_js_request() -> impl IntoResponse {
|
||||
(
|
||||
[("Content-Type", "text/javascript")],
|
||||
crate::assets::LOADER_JS,
|
||||
)
|
||||
}
|
||||
serve_asset!(loader_js_request: LOADER_JS("text/javascript"));
|
||||
serve_asset!(atto_js_request: ATTO_JS("text/javascript"));
|
||||
serve_asset!(me_js_request: ME_JS("text/javascript"));
|
||||
|
|
|
@ -12,8 +12,9 @@ pub fn routes(config: &Config) -> Router {
|
|||
Router::new()
|
||||
// assets
|
||||
.route("/css/style.css", get(assets::style_css_request))
|
||||
.route("/js/atto.js", get(assets::atto_js_request))
|
||||
.route("/js/loader.js", get(assets::loader_js_request))
|
||||
.route("/js/atto.js", get(assets::atto_js_request))
|
||||
.route("/js/me.js", get(assets::me_js_request))
|
||||
.nest_service(
|
||||
"/public",
|
||||
get_service(tower_http::services::ServeDir::new(&config.dirs.assets)),
|
||||
|
|
|
@ -8,7 +8,7 @@ use axum_extra::extract::CookieJar;
|
|||
/// `/auth/login`
|
||||
pub async fn login_request(jar: CookieJar, Extension(data): Extension<State>) -> impl IntoResponse {
|
||||
let data = data.read().await;
|
||||
let user = get_user_from_token!((jar, data.0) <optional>);
|
||||
let user = get_user_from_token!(jar, data.0);
|
||||
|
||||
if user.is_some() {
|
||||
return Err(Redirect::to("/"));
|
||||
|
@ -28,7 +28,7 @@ pub async fn register_request(
|
|||
Extension(data): Extension<State>,
|
||||
) -> impl IntoResponse {
|
||||
let data = data.read().await;
|
||||
let user = get_user_from_token!((jar, data.0) <optional>);
|
||||
let user = get_user_from_token!(jar, data.0);
|
||||
|
||||
if user.is_some() {
|
||||
return Err(Redirect::to("/"));
|
||||
|
|
|
@ -8,7 +8,7 @@ use axum_extra::extract::CookieJar;
|
|||
/// `/`
|
||||
pub async fn index_request(jar: CookieJar, Extension(data): Extension<State>) -> impl IntoResponse {
|
||||
let data = data.read().await;
|
||||
let user = get_user_from_token!((jar, data.0) <optional>);
|
||||
let user = get_user_from_token!(jar, data.0);
|
||||
|
||||
let lang = get_lang!(jar, data.0);
|
||||
let mut context = initial_context(&data.0.0, lang, &user);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue