aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-25 17:20:58 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-25 17:20:58 +0100
commit7f7deec27e69ed110c52caddaa3a0c04430e71d9 (patch)
treeb0880d0407c09bc7fb0e83734c4d4683316fb429 /server
parent3b9ba348c8e77a47786bfcc1af6756e8d3bc7499 (diff)
downloadjellything-7f7deec27e69ed110c52caddaa3a0c04430e71d9.tar
jellything-7f7deec27e69ed110c52caddaa3a0c04430e71d9.tar.bz2
jellything-7f7deec27e69ed110c52caddaa3a0c04430e71d9.tar.zst
initial account setup
Diffstat (limited to 'server')
-rw-r--r--server/src/auth.rs20
-rw-r--r--server/src/ui/account/mod.rs62
-rw-r--r--server/src/ui/admin/import.rs2
3 files changed, 68 insertions, 16 deletions
diff --git a/server/src/auth.rs b/server/src/auth.rs
index 6463eb1..26da82b 100644
--- a/server/src/auth.rs
+++ b/server/src/auth.rs
@@ -8,8 +8,8 @@ use crate::State;
use anyhow::{Result, anyhow, bail};
use argon2::{Argon2, PasswordHasher, password_hash::Salt};
use jellycommon::{
- USER_LOGIN, USER_PASSWORD,
jellyobject::{ObjectBuffer, Path},
+ *,
};
use jellydb::{Filter, Query, Sort};
@@ -25,7 +25,12 @@ pub fn token_to_user(state: &State, token: &str) -> Result<ObjectBuffer> {
user.ok_or(anyhow!("user was deleted"))
}
-pub fn login(state: &State, username: &str, password: &str, expire: Option<i64>) -> Result<String> {
+pub fn login(
+ state: &State,
+ username: &str,
+ password: &str,
+ expire: Option<i64>,
+) -> Result<(String, bool)> {
let password = hash_password(username, password);
let mut user_row = None;
@@ -51,10 +56,13 @@ pub fn login(state: &State, username: &str, password: &str, expire: Option<i64>)
bail!("incorrect password")
}
- Ok(token::create(
- &state.session_key,
- user_row,
- expire.unwrap_or(60 * 60 * 24 * 30),
+ Ok((
+ token::create(
+ &state.session_key,
+ user_row,
+ expire.unwrap_or(60 * 60 * 24 * 30),
+ ),
+ user.as_object().has(USER_PASSWORD_REQUIRE_CHANGE.0),
))
}
diff --git a/server/src/ui/account/mod.rs b/server/src/ui/account/mod.rs
index 1c44914..837d49a 100644
--- a/server/src/ui/account/mod.rs
+++ b/server/src/ui/account/mod.rs
@@ -9,16 +9,20 @@ pub mod settings;
use super::error::MyError;
use crate::{
- auth::login, request_info::RequestInfo, ui::error::MyResult, ui_responder::UiResponse,
+ auth::{hash_password, login},
+ request_info::RequestInfo,
+ ui::error::MyResult,
+ ui_responder::UiResponse,
};
use anyhow::anyhow;
use jellycommon::{
- VIEW_ACCOUNT_LOGIN, VIEW_ACCOUNT_LOGOUT,
- jellyobject::OBB,
+ jellyobject::{OBB, Path},
routes::{u_account_login, u_home},
+ *,
};
+use jellydb::{Filter, Query, Sort};
use rocket::{
- FromForm,
+ Either, FromForm,
form::{Contextual, Form},
get,
http::{Cookie, CookieJar},
@@ -39,10 +43,14 @@ pub fn r_account_logout(ri: RequestInfo<'_>) -> UiResponse {
#[derive(FromForm, Serialize, Deserialize)]
pub struct LoginForm {
- #[field(validate = len(4..32))]
+ #[field(validate = len(..32))]
pub username: String,
#[field(validate = len(..64))]
pub password: String,
+ #[field(validate = len(..64))]
+ pub new_password: Option<String>,
+ #[field(validate = len(..64))]
+ pub display_name: Option<String>,
#[field(default = 604800)] // one week
pub expire: u64,
}
@@ -52,15 +60,51 @@ pub fn r_account_login_post(
ri: RequestInfo<'_>,
jar: &CookieJar,
form: Form<Contextual<LoginForm>>,
-) -> MyResult<Redirect> {
+) -> MyResult<Either<Redirect, UiResponse>> {
let form = match &form.value {
Some(v) => v,
None => return Err(MyError(anyhow!(format_form_error(form)))),
};
- let session = login(&ri.state, &form.username, &form.password, None)?;
- jar.add(Cookie::build(("session", session)).permanent().build());
- Ok(Redirect::found(u_home()))
+ let (session, need_pw_change) = login(&ri.state, &form.username, &form.password, None)?;
+
+ if need_pw_change {
+ if let Some(new_password) = &form.new_password {
+ let password_hash = hash_password(&form.username, &new_password);
+ ri.state.database.transaction(&mut |txn| {
+ let user_row = txn.query_single(Query {
+ filter: Filter::Match(Path(vec![USER_LOGIN.0]), form.username.clone().into()),
+ sort: Sort::None,
+ })?;
+ if let Some(ur) = user_row {
+ let mut user = txn.get(ur)?.unwrap();
+ user = user.as_object().remove(USER_PASSWORD_REQUIRE_CHANGE);
+ user = user.as_object().insert(USER_PASSWORD, &password_hash);
+ if let Some(name) = &form.display_name {
+ user = user.as_object().insert(USER_NAME, &name);
+ }
+ txn.update(ur, user)?;
+ }
+ Ok(())
+ })?;
+ } else {
+ return Ok(Either::Right(
+ ri.respond_ui(
+ OBB::new().with(
+ VIEW_ACCOUNT_SET_PASSWORD,
+ OBB::new()
+ .with(SETPW_USERNAME, &form.username)
+ .with(SETPW_PASSWORD, &form.password)
+ .finish()
+ .as_object(),
+ ),
+ ),
+ ));
+ }
+ }
+
+ jar.add(Cookie::build(("session", session)).permanent().build());
+ Ok(Either::Left(Redirect::found(u_home())))
}
#[post("/account/logout")]
diff --git a/server/src/ui/admin/import.rs b/server/src/ui/admin/import.rs
index eba2a3b..78db4a4 100644
--- a/server/src/ui/admin/import.rs
+++ b/server/src/ui/admin/import.rs
@@ -32,8 +32,8 @@ pub async fn r_admin_import(ri: RequestInfo<'_>) -> MyResult<UiResponse> {
.iter()
.map(|e| e.as_str())
.collect::<Vec<_>>();
- let mut data = ObjectBuffer::empty();
+ let mut data = ObjectBuffer::empty();
if is_importing() {
data = data.as_object().insert(ADMIN_IMPORT_BUSY, ());
}