Impl /auth/user/change/password

This commit is contained in:
2022-10-14 01:45:11 +00:00
committed by GitHub
parent d10e1b4571
commit 5034616ab8
5 changed files with 197 additions and 3 deletions

View File

@@ -13,6 +13,8 @@ pub enum AuthUserAction {
Add,
/// Change a user's name.
ChangeName,
/// Change a user's password.
ChangePassword,
/// Update a existed user.
Update,
}
@@ -53,6 +55,11 @@ impl AuthUserContext {
} else {
None
};
if let Some(act) = self.action.as_ref() {
if root_user.is_none() && !matches!(act, AuthUserAction::Add) {
return Err((19, gettext("No root user, you need add a user first.")).into());
}
}
match &self.action {
Some(act) => match act {
AuthUserAction::Add => {
@@ -165,6 +172,55 @@ impl AuthUserContext {
.try_err3(-1001, gettext("Failed to operate the database:"))?;
Ok(user.to_json2())
}
AuthUserAction::ChangePassword => {
let token_id = match req.headers().get("X-TOKEN-ID") {
Some(s) => s.to_str().unwrap().to_owned(),
None => params.get("token_id").unwrap().to_owned(),
}
.parse::<u64>()
.unwrap();
let password = params
.get("password")
.try_err3(3, "No password specified.")?;
let password = base64::decode(password)
.try_err3(4, gettext("Failed to decode password with base64:"))?;
let rsa_key = self.ctx.rsa_key.lock().await;
match *rsa_key {
Some(ref key) => {
if key.is_too_old() {
return Err((
6,
gettext("RSA key is too old. A new key should be generated."),
)
.into());
}
let password = key
.decrypt(&password)
.try_err3(7, gettext("Failed to decrypt password with RSA:"))?;
let mut hashed_password = [0; 64];
pbkdf2_hmac(
&password,
&PASSWORD_SALT,
PASSWORD_ITER,
MessageDigest::sha512(),
&mut hashed_password,
)
.try_err3(11, gettext("Failed to hash password:"))?;
let user = self
.ctx
.db
.update_user_password(
user.expect("User not found:").id,
&hashed_password,
token_id,
)
.await
.try_err3(8, gettext("Failed to update user in database:"))?;
Ok(user.to_json2())
}
None => Err((5, gettext("No RSA key found.")).into()),
}
}
AuthUserAction::Update => {
if root_user.is_some() {
if !user.as_ref().expect("User not found:").is_admin {
@@ -308,7 +364,8 @@ pub struct AuthUserRoute {
impl AuthUserRoute {
pub fn new() -> Self {
Self {
regex: Regex::new(r"^(/+api)?/+auth/+user(/+(add|update|change/+name))?$").unwrap(),
regex: Regex::new(r"^(/+api)?/+auth/+user(/+(add|update|change/+(name|password)))?$")
.unwrap(),
}
}
}
@@ -344,6 +401,7 @@ impl MatchRoute<Body, Body> for AuthUserRoute {
let m = m.trim_start_matches("/");
match m {
"name" => Some(AuthUserAction::ChangeName),
"password" => Some(AuthUserAction::ChangePassword),
_ => return None,
}
} else {

View File

@@ -9,6 +9,17 @@ use openssl::rsa::{Padding, Rsa};
/// Test authentification methods
/// Returns token
pub async fn test(ctx: &UnitTestContext) -> Result<[(u64, Vec<u8>); 2], PixivDownloaderError> {
let re = ctx
.request_json2(
"/auth/user/change/name",
&json::object! {
"name": "test",
},
)
.await?
.unwrap();
let result = JSONResult::from_json(&re)?.unwrap_err();
assert_eq!(result.code, 19);
let re = Request::builder().uri("/auth").body(Body::empty())?;
let res = ctx.request_json(re).await?.unwrap();
assert_eq!(res["has_root_user"].as_bool(), Some(false));
@@ -279,5 +290,78 @@ pub async fn test(ctx: &UnitTestContext) -> Result<[(u64, Vec<u8>); 2], PixivDow
"is_admin": false,
}
);
let re = ctx
.request_json2(
"/auth/token/add",
&json::object! {
"username": "test1",
"password": b64_password2.as_str(),
},
)
.await?
.unwrap();
let result = JSONResult::from_json(re)?.expect("Failed to add token:");
assert_eq!(Some(1), result["user_id"].as_u64());
let token3 = base64::decode(result["token"].as_str().unwrap()).unwrap();
assert_eq!(token2.len(), 64);
let token3_id = result["id"].as_u64().unwrap();
openssl::rand::rand_bytes(&mut password2)?;
key.public_encrypt(&password2, &mut encypted2, Padding::PKCS1)?;
let b64_password2 = base64::encode(&encypted2);
let re = ctx
.request_json2_sign(
"/auth/user/change/password",
&json::object! {
"password": b64_password2.as_str(),
},
&token2,
token2_id,
)
.await?
.unwrap();
let result = JSONResult::from_json(re)?.unwrap();
assert_eq!(
result,
json::object! {
"id": 1,
"name": "sdlkasdjklasjd",
"username": "test1",
"is_admin": false,
}
);
let re = ctx
.request_json2_sign(
"/auth/user/change/name",
&json::object! {
"name": "sadiuqwed",
},
&token3,
token3_id,
)
.await?
.unwrap();
let result = JSONResult::from_json(re)?.unwrap_err();
assert_eq!(result.code, -403);
let re = ctx
.request_json2_sign(
"/auth/user/change/name",
&json::object! {
"name": "sadiuqwed",
},
&token2,
token2_id,
)
.await?
.unwrap();
let result = JSONResult::from_json(re)?.unwrap();
assert_eq!(
result,
json::object! {
"id": 1,
"name": "sadiuqwed",
"username": "test1",
"is_admin": false,
}
);
Ok([(token_id, token), (token2_id, token2)])
}