diff --git a/Cargo.lock b/Cargo.lock index 0381f9f..76f0474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -733,6 +733,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "html_parser" version = "0.6.3" @@ -1366,6 +1372,7 @@ dependencies = [ "futures-util", "getopts", "gettext", + "hex", "html_parser", "http", "http-content-range", diff --git a/Cargo.toml b/Cargo.toml index e5b6217..06ca3e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ flagset = { version = "0.4", optional = true } futures-util = "0.3" getopts = "0.2" gettext = "0.4" +hex = { version = "0.4", optional = true } html_parser = "0.6.3" http = "0.2" http-content-range = "0.1" @@ -55,7 +56,7 @@ db = ["anyhow", "async-trait", "bytes"] db_all = ["db", "db_sqlite"] db_sqlite = ["rusqlite"] exif = ["bindgen", "c_fixed_string", "cmake", "link-cplusplus", "utf16string"] -server = ["async-trait", "base64", "db", "hyper", "multipart", "openssl"] +server = ["async-trait", "base64", "db", "hex", "hyper", "multipart", "openssl"] ugoira = ["avdict", "bindgen", "cmake", "link-cplusplus"] [patch.crates-io] diff --git a/src/server/auth/user.rs b/src/server/auth/user.rs index d029500..683ab77 100644 --- a/src/server/auth/user.rs +++ b/src/server/auth/user.rs @@ -36,15 +36,24 @@ impl AuthUserContext { .get_params() .await .try_err3(-1002, gettext("Failed to get parameters:"))?; - if root_user.is_some() { - self.ctx - .verify_token(&req, ¶ms) - .await - .try_err3(-403, gettext("Failed to verify the token:"))?; - } + let user = if root_user.is_some() { + Some( + self.ctx + .verify_token(&req, ¶ms) + .await + .try_err3(-403, gettext("Failed to verify the token:"))?, + ) + } else { + None + }; match &self.action { Some(act) => match act { AuthUserAction::Add => { + if root_user.is_some() { + if !user.as_ref().expect("User not found:").is_admin { + return Err((9, gettext("Admin privileges required.")).into()); + } + } let name = params .get("name") .try_err((1, gettext("No user's name specified.")))?; diff --git a/src/server/context.rs b/src/server/context.rs index 4403351..7498165 100644 --- a/src/server/context.rs +++ b/src/server/context.rs @@ -1,12 +1,13 @@ use super::auth::RSAKey; use super::cors::CorsContext; use super::params::RequestParams; -use crate::db::{open_and_init_database, PixivDownloaderDb}; +use crate::db::{open_and_init_database, PixivDownloaderDb, User}; use crate::error::PixivDownloaderError; use crate::get_helper; use crate::gettext; use futures_util::lock::Mutex; use hyper::{Body, Request}; +use std::collections::BTreeMap; pub struct ServerContext { pub cors: CorsContext, @@ -30,7 +31,7 @@ impl ServerContext { &self, req: &Request, params: &RequestParams, - ) -> Result<(), PixivDownloaderError> { + ) -> Result { let mut token_id = None; match req.headers().get("X-TOKEN-ID") { Some(v) => { @@ -43,16 +44,55 @@ impl ServerContext { None => {} }, } + let mut sign = None; + match req.headers().get("X-SIGN") { + Some(v) => { + sign.replace(v.to_str()?.to_owned()); + } + None => match params.get("sign") { + Some(v) => { + sign.replace(v.to_owned()); + } + None => {} + }, + } let token_id = match token_id { Some(token_id) => token_id, None => return Err(PixivDownloaderError::from(gettext("Token id not found."))), } .parse::()?; + let sign = match sign { + Some(sign) => sign, + None => return Err(PixivDownloaderError::from(gettext("Sign not found."))), + }; let token = self .db .get_token(token_id) .await? .ok_or(gettext("Token not found."))?; - Ok(()) + let mut par = BTreeMap::new(); + for (k, v) in params.params.iter() { + if k == "sign" || k == "token_id" { + continue; + } + par.insert(k, v); + } + let mut sha = openssl::sha::Sha512::new(); + sha.update(token.token.as_bytes()); + for (k, v) in par { + for v in v { + sha.update(k.as_bytes()); + sha.update(v.as_bytes()); + } + } + let sha = hex::encode(sha.finish()); + if sign != sha { + return Err(PixivDownloaderError::from(gettext("Sign not match."))); + } + Ok(self + .db + .get_user(token.user_id) + .await? + .ok_or(gettext("No corresponding user was found."))?) } }