136 lines
3.9 KiB
Rust
136 lines
3.9 KiB
Rust
#[cfg(feature = "server")]
|
|
use crate::util::surrealdb::{thing_to_string, DB};
|
|
use dioxus::prelude::*;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::user::User;
|
|
|
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
|
pub struct Session {
|
|
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
|
|
id: String,
|
|
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
|
|
user_id: String,
|
|
expires: i64,
|
|
token: String,
|
|
}
|
|
|
|
#[cfg(feature = "server")]
|
|
impl Session {
|
|
pub async fn new(user_id: String) -> Result<Self, crate::Error> {
|
|
let mut res = DB
|
|
.query("CREATE ONLY session SET user = type::thing('user', $user_id) RETURN id, user as user_id, time::unix(expires) as expires, token;")
|
|
.bind(("user_id", user_id))
|
|
.await?;
|
|
|
|
res = res.check()?;
|
|
|
|
let session: Option<Self> = res.take(0)?;
|
|
|
|
match session {
|
|
Some(s) => Ok(s),
|
|
None => Err(crate::Error::NoDocument),
|
|
}
|
|
}
|
|
|
|
pub fn set_cookie(&self) -> Result<(), crate::Error> {
|
|
use axum::http::{header, HeaderValue};
|
|
use axum_extra::extract::cookie::{Cookie, Expiration, SameSite};
|
|
use dioxus::prelude::server_context;
|
|
use time::OffsetDateTime;
|
|
|
|
let timestamp = OffsetDateTime::from_unix_timestamp(self.expires)?;
|
|
let expiration = Expiration::from(timestamp);
|
|
|
|
let mut cookie = Cookie::build(("session_token", &self.token))
|
|
.expires(expiration)
|
|
.build();
|
|
|
|
cookie.set_same_site(SameSite::Strict);
|
|
|
|
server_context()
|
|
.response_parts_mut()
|
|
.unwrap()
|
|
.headers
|
|
.insert(
|
|
header::SET_COOKIE,
|
|
HeaderValue::from_str(&cookie.to_string())?,
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn fetch_user_from_token(session_token: String) -> Result<User, crate::Error> {
|
|
let mut res = DB
|
|
.query(
|
|
"SELECT user as id, user.email as email, user.admin as admin FROM session WHERE token = $session_token",
|
|
)
|
|
.bind(("session_token", session_token))
|
|
.await?;
|
|
|
|
res = res.check()?;
|
|
|
|
let user: Option<User> = res.take(0)?;
|
|
|
|
match user {
|
|
Some(u) => Ok(u),
|
|
None => Err(crate::Error::NoDocument),
|
|
}
|
|
}
|
|
|
|
pub async fn get_token_from_cookie() -> Result<String, crate::Error> {
|
|
use axum_extra::extract::CookieJar;
|
|
|
|
let jar: CookieJar = extract().await.unwrap_or_default();
|
|
|
|
match jar.get("session_token") {
|
|
Some(s) => Ok(s.value().to_string()),
|
|
None => Err(crate::Error::NoSessionCookie),
|
|
}
|
|
}
|
|
|
|
pub async fn delete_cookie() -> Result<(), crate::Error> {
|
|
use axum::http::{header, HeaderValue};
|
|
use axum_extra::extract::cookie::{Cookie, SameSite};
|
|
use dioxus::prelude::server_context;
|
|
use time::Duration;
|
|
|
|
let mut cookie = Cookie::build(("session_token", ""))
|
|
.max_age(Duration::seconds(1))
|
|
.build();
|
|
|
|
cookie.set_same_site(SameSite::Strict);
|
|
|
|
server_context()
|
|
.response_parts_mut()
|
|
.unwrap()
|
|
.headers
|
|
.insert(
|
|
header::SET_COOKIE,
|
|
HeaderValue::from_str(&cookie.to_string())?,
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn delete_session(user_id: String) -> Result<(), crate::Error> {
|
|
let res = DB
|
|
.query("DELETE ONLY session WHERE user = type::thing('user', $user_id)")
|
|
.bind(("user_id", user_id))
|
|
.await?;
|
|
|
|
res.check()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Fetches the current user from cookie headers
|
|
pub async fn fetch_current_user() -> Result<User, crate::Error> {
|
|
let session_token = Self::get_token_from_cookie().await?;
|
|
let user = Self::fetch_user_from_token(session_token).await?;
|
|
|
|
Ok(user)
|
|
}
|
|
}
|