Add the ability to delete a session
This commit is contained in:
parent
4a0dc5b87a
commit
87b187c8f1
@ -1,7 +1,7 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use async_std::sync::RwLock;
|
use async_std::sync::RwLock;
|
||||||
use chrono::{DateTime, TimeDelta, Utc};
|
use chrono::{DateTime, Duration, TimeDelta, Utc};
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use result_extended::{error, fatal, ok, result_as_fatal, return_error, ResultExt};
|
use result_extended::{error, fatal, ok, result_as_fatal, return_error, ResultExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -165,7 +165,7 @@ impl Core {
|
|||||||
Some(_) => error(AppError::UsernameUnavailable),
|
Some(_) => error(AppError::UsernameUnavailable),
|
||||||
None => match state
|
None => match state
|
||||||
.db
|
.db
|
||||||
.create_user(username, "", false, AccountState::PasswordReset(Utc::now()))
|
.create_user(username, "", false, AccountState::PasswordReset(Utc::now() + Duration::minutes(60)))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(user_id) => ok(user_id),
|
Ok(user_id) => ok(user_id),
|
||||||
@ -341,6 +341,7 @@ impl Core {
|
|||||||
) -> ResultExt<AuthResponse, AppError, FatalError> {
|
) -> ResultExt<AuthResponse, AppError, FatalError> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let state = self.0.read().await;
|
let state = self.0.read().await;
|
||||||
|
let user = state.db.user_by_username(username).await.unwrap().unwrap();
|
||||||
let user_info = return_error!(match state.db.user_by_username(username).await {
|
let user_info = return_error!(match state.db.user_by_username(username).await {
|
||||||
Ok(Some(row)) if row.password == password => ok(row),
|
Ok(Some(row)) if row.password == password => ok(row),
|
||||||
Ok(_) => error(AppError::AuthFailed),
|
Ok(_) => error(AppError::AuthFailed),
|
||||||
@ -375,6 +376,14 @@ impl Core {
|
|||||||
Err(fatal_error) => fatal(fatal_error),
|
Err(fatal_error) => fatal(fatal_error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_session(&self, session_id: &SessionId) -> ResultExt<(), AppError, FatalError> {
|
||||||
|
let state = self.0.read().await;
|
||||||
|
match state.db.delete_session(session_id).await {
|
||||||
|
Ok(_) => ok(()),
|
||||||
|
Err(err) => fatal(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_expiration_date() -> DateTime<Utc> {
|
fn create_expiration_date() -> DateTime<Utc> {
|
||||||
|
@ -237,6 +237,21 @@ impl DiskDb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_session(&self, session_id: &SessionId) -> Result<(), FatalError> {
|
||||||
|
match self.session(session_id) {
|
||||||
|
Ok(Some(_)) => {
|
||||||
|
let mut stmt = self.conn.prepare("DELETE FROM sessions WHERE id = ?")
|
||||||
|
.map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?;
|
||||||
|
|
||||||
|
let session_id = SessionId::new();
|
||||||
|
stmt.execute((session_id.as_str(),)).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ok(None) => Err(FatalError::DatabaseKeyMissing),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn character(&self, id: CharacterId) -> Result<Option<CharsheetRow>, FatalError> {
|
pub fn character(&self, id: CharacterId) -> Result<Option<CharsheetRow>, FatalError> {
|
||||||
let mut stmt = self
|
let mut stmt = self
|
||||||
.conn
|
.conn
|
||||||
@ -316,6 +331,10 @@ pub async fn db_handler(db: DiskDb, requestor: Receiver<DatabaseRequest>) {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
Request::DeleteSession(id) => {
|
||||||
|
db.delete_session(&id).unwrap();
|
||||||
|
tx.send(DatabaseResponse::DeleteSession).await.unwrap();
|
||||||
|
}
|
||||||
Request::Games => match db.games() {
|
Request::Games => match db.games() {
|
||||||
Ok(games) => tx.send(DatabaseResponse::Games(games)).await.unwrap(),
|
Ok(games) => tx.send(DatabaseResponse::Games(games)).await.unwrap(),
|
||||||
_ => unimplemented!("errors for Request::Games"),
|
_ => unimplemented!("errors for Request::Games"),
|
||||||
|
@ -16,6 +16,7 @@ enum Request {
|
|||||||
CreateGame(UserId, String, String),
|
CreateGame(UserId, String, String),
|
||||||
CreateSession(UserId),
|
CreateSession(UserId),
|
||||||
CreateUser(String, String, bool, AccountState),
|
CreateUser(String, String, bool, AccountState),
|
||||||
|
DeleteSession(SessionId),
|
||||||
Game(GameId),
|
Game(GameId),
|
||||||
Games,
|
Games,
|
||||||
SaveGame(Game),
|
SaveGame(Game),
|
||||||
@ -36,6 +37,7 @@ struct DatabaseRequest {
|
|||||||
enum DatabaseResponse {
|
enum DatabaseResponse {
|
||||||
Charsheet(Option<CharsheetRow>),
|
Charsheet(Option<CharsheetRow>),
|
||||||
CreateSession(SessionId),
|
CreateSession(SessionId),
|
||||||
|
DeleteSession,
|
||||||
Games(Vec<Game>),
|
Games(Vec<Game>),
|
||||||
Game(Option<Game>),
|
Game(Option<Game>),
|
||||||
SaveGame(GameId),
|
SaveGame(GameId),
|
||||||
@ -49,6 +51,7 @@ enum DatabaseResponse {
|
|||||||
pub trait Database: Send + Sync {
|
pub trait Database: Send + Sync {
|
||||||
async fn create_session(&self, id: &UserId) -> Result<SessionId, FatalError>;
|
async fn create_session(&self, id: &UserId) -> Result<SessionId, FatalError>;
|
||||||
async fn session(&self, id: &SessionId) -> Result<Option<User>, FatalError>;
|
async fn session(&self, id: &SessionId) -> Result<Option<User>, FatalError>;
|
||||||
|
async fn delete_session(&self, id: &SessionId) -> Result<(), FatalError>;
|
||||||
|
|
||||||
async fn character(&self, id: &CharacterId) -> Result<Option<CharsheetRow>, FatalError>;
|
async fn character(&self, id: &CharacterId) -> Result<Option<CharsheetRow>, FatalError>;
|
||||||
|
|
||||||
@ -125,6 +128,9 @@ impl Database for DbConn {
|
|||||||
async fn session(&self, id: &SessionId) -> Result<Option<User>, FatalError> {
|
async fn session(&self, id: &SessionId) -> Result<Option<User>, FatalError> {
|
||||||
send_request!(self, Request::Session(id.to_owned()), DatabaseResponse::Session(row) => Ok(row))
|
send_request!(self, Request::Session(id.to_owned()), DatabaseResponse::Session(row) => Ok(row))
|
||||||
}
|
}
|
||||||
|
async fn delete_session(&self, id: &SessionId) -> Result<(), FatalError> {
|
||||||
|
send_request!(self, Request::DeleteSession(id.to_owned()), DatabaseResponse::DeleteSession => Ok(()))
|
||||||
|
}
|
||||||
async fn character(&self, id: &CharacterId) -> Result<Option<CharsheetRow>, FatalError> {
|
async fn character(&self, id: &CharacterId) -> Result<Option<CharsheetRow>, FatalError> {
|
||||||
send_request!(self, Request::Charsheet(id.to_owned()), DatabaseResponse::Charsheet(row) => Ok(row))
|
send_request!(self, Request::Charsheet(id.to_owned()), DatabaseResponse::Charsheet(row) => Ok(row))
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,7 @@ pub struct SetAdminPasswordRequest {
|
|||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_session(
|
fn parse_session_header(headers: HeaderMap) -> ResultExt<Option<SessionId>, AppError, FatalError> {
|
||||||
core: &Core,
|
|
||||||
headers: HeaderMap,
|
|
||||||
) -> ResultExt<Option<User>, AppError, FatalError> {
|
|
||||||
match headers.get("Authorization") {
|
match headers.get("Authorization") {
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
println!("check_session: {:?}", token);
|
println!("check_session: {:?}", token);
|
||||||
@ -52,7 +49,7 @@ async fn check_session(
|
|||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
{
|
{
|
||||||
[_schema, token] => core.session(&SessionId::from(token.to_owned())).await,
|
[_schema, token] => ok(Some(SessionId::from(*token))),
|
||||||
_ => error(AppError::BadRequest),
|
_ => error(AppError::BadRequest),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,6 +57,16 @@ async fn check_session(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_session(
|
||||||
|
core: &Core,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> ResultExt<Option<User>, AppError, FatalError> {
|
||||||
|
match return_error!(parse_session_header(headers)) {
|
||||||
|
Some(session_id) => core.session(&session_id).await,
|
||||||
|
None => ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn auth_required<F, A, Fut>(
|
pub async fn auth_required<F, A, Fut>(
|
||||||
core: Core,
|
core: Core,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
@ -101,7 +108,27 @@ pub async fn check_password(
|
|||||||
req: Json<AuthRequest>,
|
req: Json<AuthRequest>,
|
||||||
) -> ResultExt<AuthResponse, AppError, FatalError> {
|
) -> ResultExt<AuthResponse, AppError, FatalError> {
|
||||||
let Json(AuthRequest { username, password }) = req;
|
let Json(AuthRequest { username, password }) = req;
|
||||||
core.auth(&username, &password).await
|
println!("check_password: {} {}", username, password);
|
||||||
|
let result = core.auth(&username, &password).await;
|
||||||
|
println!("auth result: {:?}", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_session(core: Core, headers: HeaderMap,) -> ResultExt<(), AppError, FatalError> {
|
||||||
|
/*
|
||||||
|
auth_required(core.clone(), headers, |user| async move {
|
||||||
|
match user_id {
|
||||||
|
Some(user_id) => core.delete_session
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}).await
|
||||||
|
*/
|
||||||
|
|
||||||
|
match return_error!(parse_session_header(headers)) {
|
||||||
|
Some(session_id) => core.delete_session(&session_id).await,
|
||||||
|
None => error(AppError::AuthFailed),
|
||||||
|
}
|
||||||
|
// await core.delete_session(session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user(
|
pub async fn get_user(
|
||||||
|
@ -13,8 +13,7 @@ use crate::{
|
|||||||
core::Core,
|
core::Core,
|
||||||
database::UserId,
|
database::UserId,
|
||||||
handlers::{
|
handlers::{
|
||||||
check_password, create_game, create_user, get_user, get_users, healthcheck, set_password,
|
check_password, create_game, create_user, delete_session, get_user, get_users, healthcheck, set_password, wrap_handler, AuthRequest, CreateGameRequest, CreateUserRequest, SetPasswordRequest
|
||||||
wrap_handler, AuthRequest, CreateGameRequest, CreateUserRequest, SetPasswordRequest,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,10 +37,14 @@ pub fn routes(core: Core) -> Router {
|
|||||||
let core = core.clone();
|
let core = core.clone();
|
||||||
move |req: Json<AuthRequest>| wrap_handler(|| check_password(core, req))
|
move |req: Json<AuthRequest>| wrap_handler(|| check_password(core, req))
|
||||||
})
|
})
|
||||||
|
.delete({
|
||||||
|
let core = core.clone();
|
||||||
|
move |headers: HeaderMap| wrap_handler(|| delete_session(core, headers))
|
||||||
|
})
|
||||||
.layer(
|
.layer(
|
||||||
CorsLayer::new()
|
CorsLayer::new()
|
||||||
.allow_methods([Method::POST])
|
.allow_methods([Method::DELETE, Method::POST])
|
||||||
.allow_headers([CONTENT_TYPE])
|
.allow_headers([AUTHORIZATION, CONTENT_TYPE])
|
||||||
.allow_origin(Any),
|
.allow_origin(Any),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -93,7 +96,13 @@ pub fn routes(core: Core) -> Router {
|
|||||||
let Json(req) = req;
|
let Json(req) = req;
|
||||||
wrap_handler(|| set_password(core, headers, req))
|
wrap_handler(|| set_password(core, headers, req))
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
|
.layer(
|
||||||
|
CorsLayer::new()
|
||||||
|
.allow_methods([Method::PUT])
|
||||||
|
.allow_headers([AUTHORIZATION, CONTENT_TYPE])
|
||||||
|
.allow_origin(Any),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/v1/user/:user_id",
|
"/api/v1/user/:user_id",
|
||||||
|
Loading…
Reference in New Issue
Block a user