2020-12-16 02:40:41 +00:00
|
|
|
use actix_session::CookieSession;
|
|
|
|
use actix_web::{http::header::LOCATION, HttpResponse};
|
|
|
|
use sled::Db;
|
|
|
|
use std::sync::Arc;
|
2021-01-14 04:41:20 +00:00
|
|
|
use uuid::Uuid;
|
2020-12-16 02:40:41 +00:00
|
|
|
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
|
|
|
|
|
|
|
mod extractors;
|
|
|
|
mod forms;
|
|
|
|
mod store;
|
|
|
|
|
|
|
|
pub use {
|
2020-12-16 04:14:01 +00:00
|
|
|
extractors::{AcceptedCookies, Auth, Authenticated},
|
2020-12-16 02:40:41 +00:00
|
|
|
forms::{
|
|
|
|
cookies::{cookies, cookies_page, CookiesArgs, CookiesPageArgs, CookiesState},
|
|
|
|
delete_user::{
|
|
|
|
delete_user, delete_user_page, DeleteUserArgs, DeleteUserPageArgs, DeleteUserState,
|
|
|
|
},
|
|
|
|
login::{login, login_page, LoginArgs, LoginPageArgs, LoginState},
|
|
|
|
logout::{logout, logout_page, LogoutArgs, LogoutPageArgs, LogoutState},
|
|
|
|
register::{register, register_page, RegisterArgs, RegisterPageArgs, RegisterState},
|
|
|
|
update_password::{
|
|
|
|
update_password, update_password_page, UpdatePasswordArgs, UpdatePasswordPageArgs,
|
|
|
|
UpdatePasswordState,
|
|
|
|
},
|
|
|
|
update_username::{
|
|
|
|
update_username, update_username_page, UpdateUsernameArgs, UpdateUsernamePageArgs,
|
|
|
|
UpdateUsernameState,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
store::User,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub trait Pages {
|
|
|
|
fn home_path(&self) -> String;
|
|
|
|
|
|
|
|
fn not_found_path(&self) -> String;
|
|
|
|
|
|
|
|
fn internal_server_error_path(&self) -> String;
|
|
|
|
|
|
|
|
fn cookies_path(&self) -> String;
|
|
|
|
|
|
|
|
fn login_path(&self) -> String;
|
|
|
|
|
|
|
|
fn register_path(&self) -> String;
|
|
|
|
|
|
|
|
fn logout_path(&self) -> String;
|
|
|
|
|
|
|
|
fn accounts_path(&self) -> String;
|
|
|
|
|
|
|
|
fn update_username_path(&self) -> String;
|
|
|
|
|
|
|
|
fn update_password_path(&self) -> String;
|
|
|
|
|
|
|
|
fn delete_user_path(&self) -> String;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Config {
|
|
|
|
pub toolkit_path: String,
|
|
|
|
pub key: Vec<u8>,
|
|
|
|
pub https: bool,
|
|
|
|
pub pages: Arc<dyn Pages + Send + Sync>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct State {
|
|
|
|
toolkit_path: String,
|
|
|
|
user_store: store::UserStore,
|
|
|
|
db: Db,
|
|
|
|
pages: Arc<dyn Pages + Send + Sync>,
|
|
|
|
}
|
|
|
|
|
2021-01-14 04:41:20 +00:00
|
|
|
impl State {
|
|
|
|
pub async fn by_username(&self, username: String) -> Result<Option<User>, Error> {
|
|
|
|
Ok(self.user_store.user_by_username(username).await?)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn suspend(&self, user_id: Uuid) -> Result<(), Error> {
|
|
|
|
Ok(self.user_store.suspend(user_id).await?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-16 02:40:41 +00:00
|
|
|
pub fn state(config: &Config, db: Db) -> Result<State, store::StoreError> {
|
|
|
|
Ok(State {
|
|
|
|
toolkit_path: config.toolkit_path.clone(),
|
|
|
|
user_store: store::UserStore::build(&db)?,
|
|
|
|
db,
|
|
|
|
pages: Arc::clone(&config.pages),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-11 03:59:39 +00:00
|
|
|
pub fn cookie_middleware(config: &Config) -> CookieSession {
|
2020-12-16 02:40:41 +00:00
|
|
|
CookieSession::private(&config.key)
|
|
|
|
.name("accounts_scope")
|
|
|
|
.secure(config.https)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub enum Error {
|
|
|
|
#[error("{0}")]
|
|
|
|
Session(#[from] extractors::SessionError),
|
|
|
|
|
|
|
|
#[error("{0}")]
|
|
|
|
Store(#[from] store::StoreError),
|
|
|
|
|
|
|
|
#[error("Panic in blocking operation")]
|
|
|
|
Blocking,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for Config {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
f.debug_struct("Config")
|
|
|
|
.field("toolkit_path", &self.toolkit_path)
|
|
|
|
.field("key", &"Key")
|
|
|
|
.field("https", &self.https)
|
|
|
|
.field("pages", &"Box<dyn Pages>")
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for State {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
f.debug_struct("State")
|
|
|
|
.field("toolkit_path", &self.toolkit_path)
|
|
|
|
.field("user_store", &"UserStore")
|
|
|
|
.field("db", &"Db")
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_cookie_page(state: &State) -> HttpResponse {
|
|
|
|
HttpResponse::SeeOther()
|
|
|
|
.header(LOCATION, state.pages.cookies_path())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_register(state: &State) -> HttpResponse {
|
|
|
|
HttpResponse::SeeOther()
|
|
|
|
.header(LOCATION, state.pages.register_path())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_account_page(state: &State) -> HttpResponse {
|
|
|
|
HttpResponse::SeeOther()
|
|
|
|
.header(LOCATION, state.pages.accounts_path())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_home(state: &State) -> HttpResponse {
|
|
|
|
HttpResponse::SeeOther()
|
|
|
|
.header(LOCATION, state.pages.home_path())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<E> From<actix_web::error::BlockingError<E>> for Error
|
|
|
|
where
|
|
|
|
Error: From<E>,
|
|
|
|
E: std::fmt::Debug,
|
|
|
|
{
|
|
|
|
fn from(e: actix_web::error::BlockingError<E>) -> Self {
|
|
|
|
match e {
|
|
|
|
actix_web::error::BlockingError::Error(e) => e.into(),
|
|
|
|
_ => Error::Blocking,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|