mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-07-08 01:32:41 +08:00
Impl /auth/user/change/password
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user