2022-04-15 17:04:23 +02:00
|
|
|
mod api_v1;
|
|
|
|
|
2022-04-14 21:40:26 +02:00
|
|
|
use actix::Addr;
|
|
|
|
use actix_session::Session;
|
2022-04-15 17:04:23 +02:00
|
|
|
use actix_web::web::{scope, Data, Json, ServiceConfig};
|
2022-04-14 21:40:26 +02:00
|
|
|
use actix_web::{delete, get, post, HttpResponse};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-04-15 17:04:23 +02:00
|
|
|
use crate::database::{AccountByIdentity, Database};
|
|
|
|
use crate::logic::encrypt_password;
|
2022-04-14 21:40:26 +02:00
|
|
|
use crate::model::{Account, Email, Login, PassHash, Password, PasswordConfirmation, Role};
|
|
|
|
use crate::routes::{RequireLogin, Result};
|
2022-04-15 17:04:23 +02:00
|
|
|
use crate::{database, model, routes, Config};
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! admin_send_db {
|
|
|
|
($db: expr, $msg: expr) => {{
|
|
|
|
let db = $db;
|
|
|
|
return match db.send($msg).await {
|
|
|
|
Ok(Ok(res)) => Ok(HttpResponse::Ok().json(res)),
|
|
|
|
Ok(Err(e)) => {
|
|
|
|
log::error!("{}", e);
|
|
|
|
Err(crate::routes::Error::Admin(Error::Database(e)))
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
log::error!("{}", e);
|
|
|
|
Err(crate::routes::Error::Admin(Error::DatabaseConnection))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}};
|
|
|
|
}
|
2022-04-14 21:40:26 +02:00
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub enum Error {
|
|
|
|
#[error("Can't register new account")]
|
|
|
|
Register,
|
|
|
|
#[error("Can't hash password")]
|
|
|
|
HashPass,
|
|
|
|
#[error("Internal server error")]
|
|
|
|
DatabaseConnection,
|
|
|
|
#[error("{0}")]
|
|
|
|
Database(#[from] database::Error),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
pub struct LogoutResponse {}
|
|
|
|
|
2022-04-15 17:04:23 +02:00
|
|
|
#[delete("logout")]
|
2022-04-14 21:40:26 +02:00
|
|
|
async fn logout(session: Session) -> Result<HttpResponse> {
|
|
|
|
session.require_admin()?;
|
2022-04-15 17:04:23 +02:00
|
|
|
session.clear();
|
|
|
|
|
2022-04-14 21:40:26 +02:00
|
|
|
Ok(HttpResponse::NotImplemented().body(""))
|
|
|
|
}
|
|
|
|
|
2022-04-15 17:04:23 +02:00
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
pub struct SignInInput {
|
|
|
|
login: Option<Login>,
|
|
|
|
email: Option<Email>,
|
|
|
|
password: Password,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[post("sign-in")]
|
|
|
|
async fn sign_in(
|
|
|
|
session: Session,
|
|
|
|
db: Data<Addr<Database>>,
|
|
|
|
Json(payload): Json<SignInInput>,
|
|
|
|
) -> Result<HttpResponse> {
|
|
|
|
log::debug!("{:?}", payload);
|
|
|
|
let db = db.into_inner();
|
|
|
|
let user: model::FullAccount =
|
|
|
|
match db.send(AccountByIdentity { email: payload.email, login: payload.login }).await {
|
|
|
|
Ok(Ok(user)) => user,
|
|
|
|
Ok(Err(e)) => {
|
|
|
|
log::error!("{}", e);
|
|
|
|
return Err(routes::Error::Unauthorized);
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
log::error!("{}", e);
|
|
|
|
return Err(routes::Error::Unauthorized);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if let Err(e) = crate::logic::validate_password(&payload.password, &user.pass_hash) {
|
|
|
|
log::error!("Password validation failed. {}", e);
|
|
|
|
Err(routes::Error::Unauthorized)
|
|
|
|
} else {
|
|
|
|
if let Err(e) = session.insert("admin_id", *user.id) {
|
|
|
|
log::error!("{:?}", e);
|
|
|
|
}
|
|
|
|
Ok(HttpResponse::Ok().json(model::Account::from(user)))
|
|
|
|
}
|
2022-04-14 21:40:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct RegisterInput {
|
|
|
|
pub login: Login,
|
|
|
|
pub email: Email,
|
|
|
|
pub password: Password,
|
|
|
|
pub password_confirmation: PasswordConfirmation,
|
|
|
|
pub role: Role,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Default)]
|
|
|
|
pub struct RegisterResponse {
|
|
|
|
pub success: bool,
|
|
|
|
pub errors: Vec<RegisterError>,
|
|
|
|
pub account: Option<Account>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
pub enum RegisterError {
|
|
|
|
PasswordDiffer,
|
|
|
|
}
|
|
|
|
|
|
|
|
// login_required
|
2022-04-15 17:04:23 +02:00
|
|
|
#[post("register")]
|
2022-04-14 21:40:26 +02:00
|
|
|
async fn register(
|
|
|
|
session: Session,
|
|
|
|
Json(input): Json<RegisterInput>,
|
|
|
|
db: Data<Addr<Database>>,
|
|
|
|
config: Data<Arc<Config>>,
|
|
|
|
) -> Result<HttpResponse> {
|
|
|
|
let mut response = RegisterResponse::default();
|
|
|
|
session.require_admin()?;
|
|
|
|
|
|
|
|
if input.password != input.password_confirmation {
|
|
|
|
response.errors.push(RegisterError::PasswordDiffer);
|
|
|
|
}
|
|
|
|
|
2022-04-15 17:04:23 +02:00
|
|
|
let hash = match encrypt_password(&input.password, &config.pass_salt) {
|
2022-04-14 21:40:26 +02:00
|
|
|
Ok(s) => s,
|
|
|
|
Err(e) => {
|
|
|
|
log::error!("{e:?}");
|
|
|
|
return Err(routes::Error::Admin(Error::HashPass));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match db
|
|
|
|
.send(database::CreateAccount {
|
|
|
|
email: input.email,
|
|
|
|
login: input.login,
|
|
|
|
pass_hash: PassHash(hash),
|
|
|
|
role: input.role,
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
Ok(Ok(account)) => {
|
|
|
|
response.account = Some(account.into());
|
|
|
|
}
|
|
|
|
Ok(Err(e)) => {
|
|
|
|
log::error!("{}", e);
|
|
|
|
return Err(super::Error::Admin(Error::Register));
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
log::error!("{}", e);
|
|
|
|
return Err(super::Error::Admin(Error::Register));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
response.success = response.errors.is_empty();
|
|
|
|
Ok(if response.success {
|
2022-04-15 17:04:23 +02:00
|
|
|
HttpResponse::Ok().json(response)
|
2022-04-14 21:40:26 +02:00
|
|
|
} else {
|
|
|
|
HttpResponse::BadRequest().json(response)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/admin")]
|
|
|
|
async fn landing() -> Result<HttpResponse> {
|
2022-04-15 17:04:23 +02:00
|
|
|
Ok(HttpResponse::NotImplemented()
|
|
|
|
.append_header(("Content-Type", "text/html"))
|
|
|
|
.body(include_str!("../../../assets/index.html")))
|
2022-04-14 21:40:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn configure(config: &mut ServiceConfig) {
|
2022-04-15 17:04:23 +02:00
|
|
|
config
|
|
|
|
.service(
|
|
|
|
scope("/admin")
|
|
|
|
.service(sign_in)
|
|
|
|
.service(logout)
|
|
|
|
.service(register)
|
|
|
|
.service(actix_web::web::scope("/api/v1").configure(api_v1::configure)),
|
|
|
|
)
|
|
|
|
.service(landing);
|
2022-04-14 21:40:26 +02:00
|
|
|
}
|