aboutsummaryrefslogtreecommitdiff
path: root/server/src/ui/account
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/ui/account')
-rw-r--r--server/src/ui/account/mod.rs171
-rw-r--r--server/src/ui/account/settings.rs47
2 files changed, 90 insertions, 128 deletions
diff --git a/server/src/ui/account/mod.rs b/server/src/ui/account/mod.rs
index 54fa4d0..a9c28ea 100644
--- a/server/src/ui/account/mod.rs
+++ b/server/src/ui/account/mod.rs
@@ -8,22 +8,31 @@ pub mod settings;
use super::error::MyError;
use crate::{
database::Database,
+ helper::A,
locale::AcceptLanguage,
ui::{error::MyResult, home::rocket_uri_macro_r_home},
};
use anyhow::anyhow;
-use chrono::Duration;
-use jellycommon::user::{User, UserPermission};
+use jellycommon::user::User;
+use jellyimport::is_importing;
+use jellylogic::{
+ login::{hash_password, login_logic},
+ session::Session,
+};
+use jellyui::{
+ account::{AccountLogin, AccountLogout, AccountRegister, AccountRegisterSuccess},
+ render_page,
+ scaffold::{RenderInfo, SessionInfo},
+};
use rocket::{
form::{Contextual, Form},
get,
http::{Cookie, CookieJar},
post,
- response::Redirect,
+ response::{content::RawHtml, Redirect},
FromForm, State,
};
use serde::{Deserialize, Serialize};
-use std::collections::HashSet;
#[derive(FromForm)]
pub struct RegisterForm {
@@ -36,15 +45,16 @@ pub struct RegisterForm {
}
#[get("/account/register")]
-pub async fn r_account_register(lang: AcceptLanguage) -> DynLayoutPage<'static> {
+pub async fn r_account_register(lang: AcceptLanguage) -> RawHtml<String> {
let AcceptLanguage(lang) = lang;
- LayoutPage {
- title: tr(lang, "account.register").to_string(),
- content: markup::new! {
-
+ RawHtml(render_page(
+ &AccountRegister { lang: &lang },
+ RenderInfo {
+ importing: false,
+ session: None,
},
- ..Default::default()
- }
+ lang,
+ ))
}
#[derive(FromForm, Serialize, Deserialize)]
@@ -58,69 +68,47 @@ pub struct LoginForm {
}
#[get("/account/login")]
-pub fn r_account_login(sess: Option<Session>, lang: AcceptLanguage) -> DynLayoutPage<'static> {
+pub fn r_account_login(session: Option<A<Session>>, lang: AcceptLanguage) -> RawHtml<String> {
let AcceptLanguage(lang) = lang;
- let logged_in = sess.is_some();
- let title = tr(
- lang,
- if logged_in {
- "account.login.switch"
- } else {
- "account.login"
+ let logged_in = session.is_some();
+ RawHtml(render_page(
+ &AccountLogin {
+ lang: &lang,
+ logged_in,
},
- );
- LayoutPage {
- title: title.to_string(),
- content: markup::new! {
- form.account[method="POST", action=""] {
- h1 { @title.to_string() }
-
- label[for="inp-username"] { @trs(&lang, "account.username") }
- input[type="text", id="inp-username", name="username"]; br;
- label[for="inp-password"] { @trs(&lang, "account.password") }
- input[type="password", id="inp-password", name="password"]; br;
-
- input[type="submit", value=&*tr(lang, if logged_in { "account.login.submit.switch" } else { "account.login.submit" })];
-
- @if logged_in {
- p { @trs(&lang, "account.login.register.switch") " " a[href=uri!(r_account_register())] { @trs(&lang, "account.login.register_here") } }
- } else {
- p { @trs(&lang, "account.login.cookie_note") }
- p { @trs(&lang, "account.login.register") " " a[href=uri!(r_account_register())] { @trs(&lang, "account.login.register_here") } }
- }
- }
+ RenderInfo {
+ session: session.map(|s| SessionInfo { user: s.0.user }),
+ importing: is_importing(),
},
- ..Default::default()
- }
+ lang,
+ ))
}
#[get("/account/logout")]
-pub fn r_account_logout(lang: AcceptLanguage) -> DynLayoutPage<'static> {
+pub fn r_account_logout(session: Option<A<Session>>, lang: AcceptLanguage) -> RawHtml<String> {
let AcceptLanguage(lang) = lang;
- LayoutPage {
- title: tr(lang, "account.logout").to_string(),
- content: markup::new! {
- form.account[method="POST", action=""] {
- h1 { @trs(&lang, "account.logout") }
- input[type="submit", value=&*tr(lang, "account.logout.submit")];
- }
+ RawHtml(render_page(
+ &AccountLogout { lang: &lang },
+ RenderInfo {
+ session: session.map(|s| SessionInfo { user: s.0.user }),
+ importing: is_importing(),
},
- ..Default::default()
- }
+ lang,
+ ))
}
#[post("/account/register", data = "<form>")]
pub fn r_account_register_post<'a>(
database: &'a State<Database>,
- _sess: Option<Session>,
+ session: Option<A<Session>>,
form: Form<Contextual<'a, RegisterForm>>,
lang: AcceptLanguage,
-) -> MyResult<DynLayoutPage<'a>> {
+) -> MyResult<RawHtml<String>> {
let AcceptLanguage(lang) = lang;
- let logged_in = _sess.is_some();
+ let logged_in = session.is_some();
let form = match &form.value {
Some(v) => v,
- None => return Err(format_form_error(form)),
+ None => return Err(MyError(anyhow!(format_form_error(form)))),
};
database.register_user(
@@ -134,17 +122,17 @@ pub fn r_account_register_post<'a>(
},
)?;
- Ok(LayoutPage {
- title: tr(lang, "account.register.success.title").to_string(),
- content: markup::new! {
- h1 { @trs(&lang, if logged_in {
- "account.register.success.switch"
- } else {
- "account.register.success"
- })}
+ Ok(RawHtml(render_page(
+ &AccountRegisterSuccess {
+ lang: &lang,
+ logged_in,
+ },
+ RenderInfo {
+ session: session.map(|s| SessionInfo { user: s.0.user }),
+ importing: is_importing(),
},
- ..Default::default()
- })
+ lang,
+ )))
}
#[post("/account/login", data = "<form>")]
@@ -155,7 +143,7 @@ pub fn r_account_login_post(
) -> MyResult<Redirect> {
let form = match &form.value {
Some(v) => v,
- None => return Err(format_form_error(form)),
+ None => return Err(MyError(anyhow!(format_form_error(form)))),
};
jar.add(
Cookie::build((
@@ -175,39 +163,7 @@ pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Redirect> {
Ok(Redirect::found(rocket::uri!(r_home())))
}
-pub fn login_logic(
- database: &Database,
- username: &str,
- password: &str,
- expire: Option<i64>,
- drop_permissions: Option<HashSet<UserPermission>>,
-) -> MyResult<String> {
- // hashing the password regardless if the accounts exists to better resist timing attacks
- let password = hash_password(username, password);
-
- let mut user = database
- .get_user(username)?
- .ok_or(anyhow!("invalid password"))?;
-
- if user.password != password {
- Err(anyhow!("invalid password"))?
- }
-
- if let Some(ep) = drop_permissions {
- // remove all grant perms that are in `ep`
- user.permissions
- .0
- .retain(|p, val| if *val { !ep.contains(p) } else { true })
- }
-
- Ok(session::create(
- user.name,
- user.permissions,
- Duration::days(CONF.login_expire.min(expire.unwrap_or(i64::MAX))),
- ))
-}
-
-pub fn format_form_error<T>(form: Form<Contextual<T>>) -> MyError {
+pub fn format_form_error<T>(form: Form<Contextual<T>>) -> String {
let mut k = String::from("form validation failed:");
for e in form.context.errors() {
k += &format!(
@@ -218,18 +174,5 @@ pub fn format_form_error<T>(form: Form<Contextual<T>>) -> MyError {
.unwrap_or("<unknown>".to_string())
)
}
- MyError(anyhow!(k))
-}
-
-pub fn hash_password(username: &str, password: &str) -> Vec<u8> {
- Argon2::default()
- .hash_password(
- format!("{username}\0{password}").as_bytes(),
- <&str as TryInto<Salt>>::try_into("IYMa13osbNeLJKnQ1T8LlA").unwrap(),
- )
- .unwrap()
- .hash
- .unwrap()
- .as_bytes()
- .to_vec()
+ k
}
diff --git a/server/src/ui/account/settings.rs b/server/src/ui/account/settings.rs
index e6d096f..5355321 100644
--- a/server/src/ui/account/settings.rs
+++ b/server/src/ui/account/settings.rs
@@ -4,16 +4,20 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
use super::{format_form_error, hash_password};
-use crate::{database::Database, locale::AcceptLanguage, ui::error::MyResult};
+use crate::{database::Database, helper::A, locale::AcceptLanguage, ui::error::MyResult};
use jellybase::permission::PermissionSetExt;
use jellycommon::user::{PlayerKind, Theme, UserPermission};
+use jellyimport::is_importing;
use jellylogic::session::Session;
-use jellyui::locale::Language;
+use jellyui::{
+ account::settings::SettingsPage,
+ locale::{tr, Language},
+ render_page,
+ scaffold::{RenderInfo, SessionInfo},
+};
use rocket::{
form::{self, validate::len, Contextual, Form},
- get,
- http::uri::fmt::{Query, UriDisplay},
- post,
+ get, post,
response::content::RawHtml,
FromForm, State,
};
@@ -25,8 +29,8 @@ pub struct SettingsForm {
password: Option<String>,
#[field(validate = option_len(4..32))]
display_name: Option<String>,
- theme: Option<Theme>,
- player_preference: Option<PlayerKind>,
+ theme: Option<A<Theme>>,
+ player_preference: Option<A<PlayerKind>>,
native_secret: Option<String>,
}
@@ -36,25 +40,40 @@ fn option_len<'v>(value: &Option<String>, range: Range<usize>) -> form::Result<'
fn settings_page(
session: Session,
- flash: Option<MyResult<String>>,
+ flash: Option<Result<String, String>>,
lang: Language,
) -> RawHtml<String> {
+ RawHtml(render_page(
+ &SettingsPage {
+ flash,
+ session: &SessionInfo {
+ user: session.user.clone(),
+ },
+ lang: &lang,
+ },
+ RenderInfo {
+ importing: is_importing(),
+ session: Some(SessionInfo { user: session.user }),
+ },
+ lang,
+ ))
}
#[get("/account/settings")]
-pub fn r_account_settings(session: Session, lang: AcceptLanguage) -> RawHtml<String> {
+pub fn r_account_settings(session: A<Session>, lang: AcceptLanguage) -> RawHtml<String> {
let AcceptLanguage(lang) = lang;
- settings_page(session, None, lang)
+ settings_page(session.0, None, lang)
}
#[post("/account/settings", data = "<form>")]
pub fn r_account_settings_post(
- session: Session,
+ session: A<Session>,
database: &State<Database>,
form: Form<Contextual<SettingsForm>>,
lang: AcceptLanguage,
) -> MyResult<RawHtml<String>> {
let AcceptLanguage(lang) = lang;
+ let A(session) = session;
session
.user
.permissions
@@ -65,7 +84,7 @@ pub fn r_account_settings_post(
None => {
return Ok(settings_page(
session,
- Some(Err(format_form_error(form))),
+ Some(Err(format_form_error(form).to_string())),
lang,
))
}
@@ -85,12 +104,12 @@ pub fn r_account_settings_post(
out += "\n";
}
if let Some(theme) = form.theme {
- user.theme = theme;
+ user.theme = theme.0;
out += &*tr(lang, "settings.account.theme.changed");
out += "\n";
}
if let Some(player_preference) = form.player_preference {
- user.player_preference = player_preference;
+ user.player_preference = player_preference.0;
out += &*tr(lang, "settings.player_preference.changed");
out += "\n";
}