diff --git a/doc/api/auth.zh_CN.md b/doc/api/auth.zh_CN.md index a76b8ee..3cb733c 100644 --- a/doc/api/auth.zh_CN.md +++ b/doc/api/auth.zh_CN.md @@ -12,3 +12,8 @@ * 方法: `GET` 或 `POST` * RESTful: `PUT /api/auth/user` 或 `PUT /auth/user` * 鉴权: 一般需要(如服务器状态内的`has_root_user`为`false`则无需鉴权) +## 获取Token +* 路径: `/api/auth/token/add`、 `/auth/token/add` +* 方法: `GET` 或 `POST` +* RESTful: `PUT /api/auth/token` 或 `PUT /auth/token` +* 鉴权:不需要 diff --git a/src/server/auth/mod.rs b/src/server/auth/mod.rs index 7ff187a..cc26ca8 100644 --- a/src/server/auth/mod.rs +++ b/src/server/auth/mod.rs @@ -1,9 +1,11 @@ pub mod pubkey; pub mod status; +pub mod token; pub mod user; pub use pubkey::{AuthPubkeyContext, AuthPubkeyRoute, RSAKey}; pub use status::{AuthStatusContext, AuthStatusRoute}; +pub use token::{AuthTokenContext, AuthTokenRoute}; pub use user::{AuthUserContext, AuthUserRoute}; const PASSWORD_SALT: [u8; 64] = [ diff --git a/src/server/auth/token.rs b/src/server/auth/token.rs new file mode 100644 index 0000000..469f74b --- /dev/null +++ b/src/server/auth/token.rs @@ -0,0 +1,135 @@ +use super::super::preclude::*; +use crate::ext::json::ToJson2; + +/// Action to perform about token +pub enum AuthTokenAction { + /// Add a new token + Add, +} + +pub struct AuthTokenContext { + ctx: Arc, + action: Option, + is_restful: bool, +} + +impl AuthTokenContext { + pub fn new(ctx: Arc, action: Option, is_restful: bool) -> Self { + Self { + ctx, + action, + is_restful, + } + } + + async fn handle(&self, mut req: Request) -> JSONResult { + Ok(json::object! {}) + } +} + +#[async_trait] +impl ResponseJsonFor for AuthTokenContext { + async fn response_json( + &self, + req: Request, + ) -> Result, PixivDownloaderError> { + let builder = if self.is_restful { + filter_http_methods!( + req, + json::object! {}, + true, + self.ctx, + allow_headers = [CONTENT_TYPE, X_SIGN, X_TOKEN_ID], + OPTIONS, + PUT, + ); + builder + } else { + filter_http_methods!( + req, + json::object! {}, + true, + self.ctx, + allow_headers = [CONTENT_TYPE, X_SIGN, X_TOKEN_ID], + GET, + OPTIONS, + POST, + ); + builder + }; + let re = self.handle(req).await; + let builder = match &re { + Ok(_) => builder, + Err(err) => { + if err.code <= -400 && err.code >= -600 { + builder.status((-err.code) as u16) + } else if err.code < 0 { + builder.status(500) + } else if err.code > 0 { + builder.status(400) + } else { + builder + } + } + }; + Ok(builder.body(re.to_json2())?) + } +} + +pub struct AuthTokenRoute { + regex: Regex, +} + +impl AuthTokenRoute { + pub fn new() -> Self { + Self { + regex: Regex::new(r"^(/+api)?/+auth/+token(/+add)?$").unwrap(), + } + } +} + +impl MatchRoute for AuthTokenRoute { + fn match_route( + &self, + ctx: &Arc, + req: &http::Request, + ) -> Option> { + let path = req.uri().path(); + let pat = self.regex.captures(path); + match pat { + Some(cap) => { + if req.method() == Method::OPTIONS { + return Some(Box::new(AuthTokenContext::new( + Arc::clone(ctx), + None, + cap.get(2).is_none(), + ))); + } + let cap2 = cap.get(2); + let is_restful = cap2.is_none(); + let action = match cap2 { + Some(m) => { + let m = m.as_str().trim_start_matches("/"); + match m { + "add" => Some(AuthTokenAction::Add), + _ => return None, + } + } + None => { + if req.method() == Method::PUT { + Some(AuthTokenAction::Add) + } else { + None + } + } + }; + Some(Box::new(AuthTokenContext::new( + Arc::clone(ctx), + action, + is_restful, + ))) + } + None => None, + } + } +} diff --git a/src/server/route.rs b/src/server/route.rs index 8ecc088..897ab7d 100644 --- a/src/server/route.rs +++ b/src/server/route.rs @@ -21,6 +21,7 @@ impl ServerRoutes { routes.push(Box::new(AuthStatusRoute::new())); routes.push(Box::new(AuthUserRoute::new())); routes.push(Box::new(AuthPubkeyRoute::new())); + routes.push(Box::new(AuthTokenRoute::new())); Self { routes } }