don't use param for passing the redirect info

revert some changes and also rename catcher to `admin_login` to make its
function clearer

Co-authored-by: BlackDex <black.dex@gmail.com>
This commit is contained in:
Stefan Melmuk 2022-11-28 17:35:36 +01:00
parent fa7dbedd5d
commit 0aa33a2cb4
No known key found for this signature in database
GPG key ID: 817020C608FE9C09
2 changed files with 36 additions and 32 deletions

View file

@ -31,7 +31,6 @@ pub fn routes() -> Vec<Route> {
} }
routes![ routes![
admin_login,
get_users_json, get_users_json,
get_user_json, get_user_json,
post_admin_login, post_admin_login,
@ -61,19 +60,10 @@ pub fn catchers() -> Vec<Catcher> {
if !CONFIG.disable_admin_token() && !CONFIG.is_admin_token_set() { if !CONFIG.disable_admin_token() && !CONFIG.is_admin_token_set() {
catchers![] catchers![]
} else { } else {
catchers![unauthorized] catchers![admin_login]
} }
} }
#[catch(401)]
fn unauthorized(request: &Request<'_>) -> Result<Redirect, Error> {
if request.format() == Some(&MediaType::JSON) {
err_code!("Authorization failed.", Status::Unauthorized.code);
}
let redirect = request.segments::<std::path::PathBuf>(0..).unwrap_or_default().display().to_string();
Ok(Redirect::to(admin_redirect_url(&redirect)))
}
static DB_TYPE: Lazy<&str> = Lazy::new(|| { static DB_TYPE: Lazy<&str> = Lazy::new(|| {
DbConnType::from_url(&CONFIG.database_url()) DbConnType::from_url(&CONFIG.database_url())
.map(|t| match t { .map(|t| match t {
@ -102,10 +92,6 @@ fn admin_path() -> String {
format!("{}{}", CONFIG.domain_path(), ADMIN_PATH) format!("{}{}", CONFIG.domain_path(), ADMIN_PATH)
} }
fn admin_redirect_url(redirect: &str) -> String {
format!("{}/?redirect=/{}", admin_path(), redirect)
}
#[derive(Debug)] #[derive(Debug)]
struct IpHeader(Option<String>); struct IpHeader(Option<String>);
@ -134,24 +120,31 @@ fn admin_url() -> String {
#[derive(Responder)] #[derive(Responder)]
enum AdminResponse { enum AdminResponse {
#[response(status = 200)]
Ok(ApiResult<Html<String>>),
#[response(status = 401)] #[response(status = 401)]
Unauthorized(ApiResult<Html<String>>), Unauthorized(ApiResult<Html<String>>),
#[response(status = 429)] #[response(status = 429)]
TooManyRequests(ApiResult<Html<String>>), TooManyRequests(ApiResult<Html<String>>),
} }
#[get("/?<_redirect..>")] #[catch(401)]
fn admin_login(_redirect: &str) -> ApiResult<Html<String>> { fn admin_login(request: &Request<'_>) -> ApiResult<Html<String>> {
render_admin_login(None) if request.format() == Some(&MediaType::JSON) {
err_code!("Authorization failed.", Status::Unauthorized.code);
}
let redirect = request.segments::<std::path::PathBuf>(0..).unwrap_or_default().display().to_string();
render_admin_login(None, Some(redirect))
} }
fn render_admin_login(msg: Option<&str>) -> ApiResult<Html<String>> { fn render_admin_login(msg: Option<&str>, redirect: Option<String>) -> ApiResult<Html<String>> {
// If there is an error, show it // If there is an error, show it
let msg = msg.map(|msg| format!("Error: {msg}")); let msg = msg.map(|msg| format!("Error: {msg}"));
let json = json!({ let json = json!({
"page_content": "admin/login", "page_content": "admin/login",
"version": VERSION, "version": VERSION,
"error": msg, "error": msg,
"redirect": redirect,
"urlpath": CONFIG.domain_path() "urlpath": CONFIG.domain_path()
}); });
@ -163,25 +156,25 @@ fn render_admin_login(msg: Option<&str>) -> ApiResult<Html<String>> {
#[derive(FromForm)] #[derive(FromForm)]
struct LoginForm { struct LoginForm {
token: String, token: String,
redirect: Option<String>,
} }
#[post("/?<redirect>", data = "<data>")] #[post("/", data = "<data>")]
fn post_admin_login( fn post_admin_login(data: Form<LoginForm>, cookies: &CookieJar<'_>, ip: ClientIp) -> Result<Redirect, AdminResponse> {
data: Form<LoginForm>,
redirect: &str,
cookies: &CookieJar<'_>,
ip: ClientIp,
) -> Result<Redirect, AdminResponse> {
let data = data.into_inner(); let data = data.into_inner();
let redirect = data.redirect;
if crate::ratelimit::check_limit_admin(&ip.ip).is_err() { if crate::ratelimit::check_limit_admin(&ip.ip).is_err() {
return Err(AdminResponse::TooManyRequests(render_admin_login(Some("Too many requests, try again later.")))); return Err(AdminResponse::TooManyRequests(render_admin_login(
Some("Too many requests, try again later."),
redirect,
)));
} }
// If the token is invalid, redirect to login page // If the token is invalid, redirect to login page
if !_validate_token(&data.token) { if !_validate_token(&data.token) {
error!("Invalid admin token. IP: {}", ip.ip); error!("Invalid admin token. IP: {}", ip.ip);
Err(AdminResponse::Unauthorized(render_admin_login(Some("Invalid admin token, please try again.")))) Err(AdminResponse::Unauthorized(render_admin_login(Some("Invalid admin token, please try again."), redirect)))
} else { } else {
// If the token received is valid, generate JWT and save it as a cookie // If the token received is valid, generate JWT and save it as a cookie
let claims = generate_admin_claims(); let claims = generate_admin_claims();
@ -195,7 +188,11 @@ fn post_admin_login(
.finish(); .finish();
cookies.add(cookie); cookies.add(cookie);
if let Some(redirect) = redirect {
Ok(Redirect::to(format!("{}{}", admin_path(), redirect))) Ok(Redirect::to(format!("{}{}", admin_path(), redirect)))
} else {
Err(AdminResponse::Ok(render_admin_page()))
}
} }
} }
@ -247,12 +244,16 @@ impl AdminTemplateData {
} }
} }
#[get("/")] fn render_admin_page() -> ApiResult<Html<String>> {
fn admin_page(_token: AdminToken) -> ApiResult<Html<String>> {
let text = AdminTemplateData::new().render()?; let text = AdminTemplateData::new().render()?;
Ok(Html(text)) Ok(Html(text))
} }
#[get("/")]
fn admin_page(_token: AdminToken) -> ApiResult<Html<String>> {
render_admin_page()
}
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
struct InviteData { struct InviteData {

View file

@ -12,8 +12,11 @@
<h6 class="mb-0 text-white">Authentication key needed to continue</h6> <h6 class="mb-0 text-white">Authentication key needed to continue</h6>
<small>Please provide it below:</small> <small>Please provide it below:</small>
<form class="form-inline" method="post"> <form class="form-inline" method="post" action="{{urlpath}}/admin">
<input type="password" class="form-control w-50 mr-2" name="token" placeholder="Enter admin token" autofocus="autofocus"> <input type="password" class="form-control w-50 mr-2" name="token" placeholder="Enter admin token" autofocus="autofocus">
{{#if redirect}}
<input type="hidden" id="redirect" name="redirect" value="/{{redirect}}">
{{/if}}
<button type="submit" class="btn btn-primary">Enter</button> <button type="submit" class="btn btn-primary">Enter</button>
</form> </form>
</div> </div>