1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
use crate::{CONF, DATABASE, session::create};
use anyhow::{Result, anyhow};
use argon2::{Argon2, PasswordHasher, password_hash::Salt};
use jellycommon::user::UserPermission;
use log::info;
use std::{collections::HashSet, time::Duration};
pub fn create_admin_account() -> Result<()> {
if let Some(username) = &CONF.admin_username
&& let Some(password) = &CONF.admin_password
{
DATABASE
.create_admin_user(username, hash_password(username, password))
.unwrap();
} else {
info!("admin account disabled")
}
Ok(())
}
pub fn login_logic(
username: &str,
password: &str,
expire: Option<i64>,
drop_permissions: Option<HashSet<UserPermission>>,
) -> Result<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(create(
user.name,
user.permissions,
Duration::from_days(
CONF.login_expire
.min(expire.unwrap_or(i64::MAX))
.try_into()
.unwrap(),
),
))
}
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()
}
|