mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-01 07:58:23 +00:00
session info handler
This commit is contained in:
1 parent
57e3fc4ebe
commit
03b4e92d3a
4 files changed
+188
-8
No files matched your search
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import requests
|
||||
import re
|
||||
|
||||
login_url = 'http://localhost:12345/login'
|
||||
session_info_url = 'http://localhost:12345/session'
|
||||
|
||||
|
||||
r = requests.get(session_info_url)
|
||||
|
||||
print("===== Session Info (logged out) =====")
|
||||
print(r.content)
|
||||
|
||||
payload = {
|
||||
'username_or_email': 'echelon',
|
||||
'password': 'testing',
|
||||
}
|
||||
|
||||
r = requests.post(login_url, json=payload)
|
||||
|
||||
print("===== Login =====")
|
||||
print('Status: {}'.format(r.status_code))
|
||||
print(r.content)
|
||||
for k, v in r.headers.items():
|
||||
print(' {}: {}'.format(k, v))
|
||||
|
||||
# NB: May not be set due to cookie domain:
|
||||
#r.cookies['session']
|
||||
|
||||
raw_set_cookie_header = r.headers['set-cookie']
|
||||
m = re.match(r'session=([^;\s]+);', raw_set_cookie_header)
|
||||
session_cookie = m.group(1)
|
||||
|
||||
cookies = { 'session': session_cookie }
|
||||
|
||||
r = requests.get(session_info_url, cookies=cookies)
|
||||
|
||||
print("===== Session Info (logged in) =====")
|
||||
print(r.content)
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
use actix_http::Error;
|
||||
use actix_http::http::header;
|
||||
use actix_web::dev::HttpResponseBuilder;
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{Responder, web, HttpResponse, error, HttpRequest, HttpMessage};
|
||||
use crate::endpoints::users::create_account::CreateAccountError::{BadInput, ServerError, UsernameTaken, EmailTaken};
|
||||
use crate::server_state::ServerState;
|
||||
use crate::util::ip_address::get_request_ip;
|
||||
use crate::util::tokens::random_token;
|
||||
use derive_more::{Display, Error};
|
||||
use log::{info, warn, log};
|
||||
use regex::Regex;
|
||||
use sqlx::error::DatabaseError;
|
||||
use sqlx::error::Error::Database;
|
||||
use sqlx::mysql::MySqlDatabaseError;
|
||||
use std::sync::Arc;
|
||||
use crate::validations::username::validate_username;
|
||||
use crate::validations::passwords::validate_passwords;
|
||||
use actix_web::cookie::Cookie;
|
||||
use sqlx::MySqlPool;
|
||||
use crate::AnyhowResult;
|
||||
use crate::common_queries::sessions::create_session_for_user;
|
||||
use crate::endpoints::users::login::LoginSuccessResponse;
|
||||
use crate::util::session_checker::SessionRecord;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct UserInfo {
|
||||
pub user_token: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SessionInfoSuccessResponse {
|
||||
pub success: bool,
|
||||
pub logged_in: bool,
|
||||
pub user: Option<UserInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ErrorResponse {
|
||||
pub success: bool,
|
||||
pub error_reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Display)]
|
||||
pub enum SessionInfoError {
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for SessionInfoError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
SessionInfoError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
SessionInfoError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
let response = ErrorResponse {
|
||||
success: false,
|
||||
error_reason,
|
||||
};
|
||||
|
||||
let body = match serde_json::to_string(&response) {
|
||||
Ok(json) => json,
|
||||
Err(_) => "{}".to_string(),
|
||||
};
|
||||
|
||||
HttpResponseBuilder::new(self.status_code())
|
||||
.set_header(header::CONTENT_TYPE, "application/json")
|
||||
.body(body)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn session_info_handler(
|
||||
http_request: HttpRequest,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SessionInfoError>
|
||||
{
|
||||
let maybe_session = server_state.session_checker.maybe_get_session(&http_request, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
SessionInfoError::ServerError
|
||||
})?;
|
||||
|
||||
let mut logged_in = false;
|
||||
let mut user_info = None;
|
||||
|
||||
match maybe_session {
|
||||
None => {}
|
||||
Some(session_data) => {
|
||||
logged_in = true;
|
||||
user_info = Some(UserInfo {
|
||||
user_token: session_data.user_token.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let response = SessionInfoSuccessResponse {
|
||||
success: true,
|
||||
logged_in,
|
||||
user: user_info,
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|e| SessionInfoError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(body))
|
||||
}
|
||||
@@ -27,6 +27,7 @@ use crate::endpoints::users::login::login_handler;
|
||||
use crate::util::cookies::CookieManager;
|
||||
use crate::endpoints::users::logout::logout_handler;
|
||||
use crate::util::session_checker::SessionChecker;
|
||||
use crate::endpoints::users::session_info::session_info_handler;
|
||||
|
||||
const DEFAULT_BIND_ADDRESS : &'static str = "0.0.0.0:12345";
|
||||
const DEFAULT_RUST_LOG: &'static str = "debug,actix_web=info";
|
||||
@@ -136,6 +137,11 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
|
||||
.route(web::post().to(logout_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(
|
||||
web::resource("/session")
|
||||
.route(web::get().to(session_info_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(
|
||||
web::scope("/foo")
|
||||
.service(
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use crate::util::cookies::CookieManager;
|
||||
use sqlx::MySqlPool;
|
||||
use crate::AnyhowResult;
|
||||
use actix_web::HttpRequest;
|
||||
use anyhow::anyhow;
|
||||
use crate::AnyhowResult;
|
||||
use crate::util::cookies::CookieManager;
|
||||
use log::{info, warn};
|
||||
use sqlx::MySqlPool;
|
||||
use sqlx::error::Error::RowNotFound;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionChecker {
|
||||
@@ -9,8 +12,8 @@ pub struct SessionChecker {
|
||||
}
|
||||
|
||||
pub struct SessionRecord {
|
||||
session_token: String,
|
||||
user_token: String,
|
||||
pub session_token: String,
|
||||
pub user_token: String,
|
||||
}
|
||||
|
||||
pub struct SessionUserRecord {
|
||||
@@ -38,7 +41,7 @@ impl SessionChecker {
|
||||
};
|
||||
|
||||
// NB: Lookup failure is Err(RowNotFound).
|
||||
let session_record = sqlx::query_as!(
|
||||
let maybe_session_record = sqlx::query_as!(
|
||||
SessionRecord,
|
||||
r#"
|
||||
SELECT
|
||||
@@ -51,9 +54,25 @@ AND deleted_at IS NULL
|
||||
session_token.to_string(),
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?; // TODO: This will return error if it doesn't exist
|
||||
.await; // TODO: This will return error if it doesn't exist
|
||||
|
||||
Ok(Some(session_record))
|
||||
match maybe_session_record {
|
||||
Ok(session_record) => {
|
||||
Ok(Some(session_record))
|
||||
},
|
||||
Err(err) => {
|
||||
match err {
|
||||
RowNotFound => {
|
||||
warn!("Valid cookie; invalid session: {}", session_token);
|
||||
Ok(None)
|
||||
},
|
||||
_ => {
|
||||
warn!("Session query error: {:?}", err);
|
||||
Err(anyhow!("session query error: {:?}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*pub async fn maybe_get_user(request: &HttpRequest, pool: &MySqlPool)
|
||||
|
||||
Reference in new issue
Block a user