mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
INSECURE HACK TO BYPASS CORS UGH
This commit is contained in:
1 parent
b7091b8b07
commit
748e8a6d3e
4 files changed
+131
-9
No files matched your search
@@ -6,3 +6,4 @@ pub mod logout_handler;
|
||||
pub mod password_reset_redeem_handler;
|
||||
pub mod password_reset_request_handler;
|
||||
pub mod session_info_handler;
|
||||
pub mod session_token_info_handler;
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::Json;
|
||||
use log::warn;
|
||||
use sqlx::MySqlPool;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::users::user_feature_flag::UserFeatureFlag;
|
||||
use http_server_common::response::response_error_helpers::to_simple_json_error;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
|
||||
use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager;
|
||||
use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags;
|
||||
use crate::http_server::session::session_checker::SessionChecker;
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct SessionTokenInfoSuccessResponse {
|
||||
/// A signed session that can be sent as a header, bypassing cookies.
|
||||
/// This is useful for API clients that don't support cookies or Google
|
||||
/// browsers killing cross-domain cookies.
|
||||
pub maybe_signed_session: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum SessionTokenInfoError {
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for SessionTokenInfoError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
SessionTokenInfoError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
SessionTokenInfoError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
SessionTokenInfoError::ServerError => "server error".to_string(),
|
||||
SessionTokenInfoError::NotAuthorized => "not authorized".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for SessionTokenInfoError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
tag = "Users",
|
||||
path = "/v1/session_token",
|
||||
responses(
|
||||
(status = 200, description = "Success response", body = SessionTokenInfoSuccessResponse),
|
||||
(status = 500, description = "Server error", body = SessionTokenInfoError),
|
||||
),
|
||||
)]
|
||||
pub async fn session_token_info_handler(
|
||||
http_request: HttpRequest,
|
||||
session_checker: web::Data<SessionChecker>,
|
||||
server_state: web::Data<Arc<ServerState>>,
|
||||
) -> Result<Json<SessionTokenInfoSuccessResponse>, SessionTokenInfoError>
|
||||
{
|
||||
let maybe_session_payload = server_state
|
||||
.session_cookie_manager
|
||||
.check_and_return_session_token_decodes(&http_request)
|
||||
.map_err(|e| {
|
||||
warn!("Session cookie decode error: {:?}", e);
|
||||
SessionTokenInfoError::ServerError
|
||||
})?;
|
||||
|
||||
Ok(Json(SessionTokenInfoSuccessResponse {
|
||||
maybe_signed_session: maybe_session_payload,
|
||||
}))
|
||||
}
|
||||
@@ -14,6 +14,7 @@ use crate::http_server::endpoints::users::logout_handler::logout_handler;
|
||||
use crate::http_server::endpoints::users::password_reset_redeem_handler::password_reset_redeem_handler;
|
||||
use crate::http_server::endpoints::users::password_reset_request_handler::password_reset_request_handler;
|
||||
use crate::http_server::endpoints::users::session_info_handler::session_info_handler;
|
||||
use crate::http_server::endpoints::users::session_token_info_handler::session_token_info_handler;
|
||||
use crate::http_server::endpoints::w2l::list_user_w2l_inference_results::list_user_w2l_inference_results_handler;
|
||||
use crate::http_server::endpoints::w2l::list_user_w2l_templates::list_user_w2l_templates_handler;
|
||||
|
||||
@@ -73,6 +74,11 @@ pub fn add_user_routes<T, B> (app: App<T>) -> App<T>
|
||||
.route(web::get().to(session_info_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(
|
||||
web::resource("/v1/session_token")
|
||||
.route(web::get().to(session_token_info_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(
|
||||
web::resource("/v1/password_reset/request")
|
||||
.route(web::post().to(password_reset_request_handler))
|
||||
|
||||
+36
-9
@@ -80,15 +80,7 @@ impl HttpUserSessionManager {
|
||||
request: &HttpRequest
|
||||
) -> AnyhowResult<Option<HttpUserSessionPayload>>
|
||||
{
|
||||
let mut signed_session_payload= request.cookie(SESSION_COOKIE_NAME)
|
||||
.map(|cookie| cookie.value().to_string());
|
||||
|
||||
if signed_session_payload.is_none() {
|
||||
signed_session_payload = request.headers().get(SESSION_HEADER_NAME)
|
||||
.map(|header| header.to_str())
|
||||
.transpose()?
|
||||
.map(|payload| payload.to_string());
|
||||
}
|
||||
let signed_session_payload = self.session_payload_from_request(request)?;
|
||||
|
||||
let signed_session_payload = match signed_session_payload {
|
||||
Some(payload) => payload,
|
||||
@@ -103,6 +95,41 @@ impl HttpUserSessionManager {
|
||||
Ok(payload) => Ok(Some(payload)),
|
||||
}
|
||||
}
|
||||
|
||||
// NB: THIS IS ONLY FOR A QUICK HACK FOR FREAKING CORS UGH
|
||||
// THIS IS A HUGE STUPID SECURITY VULN. DAMNIT GOOGLE DAMNIT CORS.
|
||||
pub fn check_and_return_session_token_decodes(&self, request: &HttpRequest) -> AnyhowResult<Option<String>> {
|
||||
let signed_session_payload = self.session_payload_from_request(request)?;
|
||||
|
||||
let signed_session_payload = match signed_session_payload {
|
||||
Some(payload) => payload,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
match self.payload_signer.decode(&signed_session_payload) {
|
||||
Err(e) => {
|
||||
warn!("Session cookie decode error: {:?}", e);
|
||||
return Err(anyhow!("Could not decode session cookie: {:?}", e));
|
||||
},
|
||||
Ok(_payload) => {}, // Good! We'll just discard this.
|
||||
}
|
||||
|
||||
Ok(Some(signed_session_payload))
|
||||
}
|
||||
|
||||
fn session_payload_from_request(&self, request: &HttpRequest) -> AnyhowResult<Option<String>> {
|
||||
let mut signed_session_payload= request.cookie(SESSION_COOKIE_NAME)
|
||||
.map(|cookie| cookie.value().to_string());
|
||||
|
||||
if signed_session_payload.is_none() {
|
||||
signed_session_payload = request.headers().get(SESSION_HEADER_NAME)
|
||||
.map(|header| header.to_str())
|
||||
.transpose()?
|
||||
.map(|payload| payload.to_string());
|
||||
}
|
||||
|
||||
Ok(signed_session_payload)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in new issue
Block a user