2019-12-07 23:59:24 +06:00
|
|
|
use std::pin::Pin;
|
|
|
|
|
2019-06-17 12:48:03 +06:00
|
|
|
use actix_identity::Identity;
|
2019-07-18 12:55:14 +01:00
|
|
|
use actix_web::{
|
2019-07-18 18:03:19 +06:00
|
|
|
dev::Payload, error::BlockingError, web, Error, FromRequest, HttpRequest,
|
|
|
|
HttpResponse,
|
2019-07-18 12:55:14 +01:00
|
|
|
};
|
2018-12-09 15:55:36 +00:00
|
|
|
use diesel::prelude::*;
|
2019-07-18 12:55:14 +01:00
|
|
|
use diesel::PgConnection;
|
2019-12-07 23:59:24 +06:00
|
|
|
use futures::future::Future;
|
2019-03-29 13:43:03 -07:00
|
|
|
|
|
|
|
use crate::errors::ServiceError;
|
2019-07-18 12:55:14 +01:00
|
|
|
use crate::models::{Pool, SlimUser, User};
|
|
|
|
use crate::utils::verify;
|
2018-12-09 15:55:36 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
pub struct AuthData {
|
|
|
|
pub email: String,
|
|
|
|
pub password: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
// we need the same data
|
|
|
|
// simple aliasing makes the intentions clear and its more readable
|
|
|
|
pub type LoggedUser = SlimUser;
|
|
|
|
|
2019-04-14 10:34:41 -07:00
|
|
|
impl FromRequest for LoggedUser {
|
|
|
|
type Config = ();
|
2019-03-29 13:43:03 -07:00
|
|
|
type Error = Error;
|
2019-12-07 23:59:24 +06:00
|
|
|
type Future = Pin<Box<dyn Future<Output = Result<LoggedUser, Error>>>>;
|
2019-03-29 13:43:03 -07:00
|
|
|
|
2019-04-14 10:34:41 -07:00
|
|
|
fn from_request(req: &HttpRequest, pl: &mut Payload) -> Self::Future {
|
2019-12-07 23:59:24 +06:00
|
|
|
let fut = Identity::from_request(req, pl);
|
|
|
|
|
|
|
|
Box::pin(async move {
|
|
|
|
if let Some(identity) = fut.await?.identity() {
|
|
|
|
let user: LoggedUser = serde_json::from_str(&identity)?;
|
|
|
|
return Ok(user);
|
|
|
|
};
|
|
|
|
Err(ServiceError::Unauthorized.into())
|
|
|
|
})
|
2018-12-09 15:55:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-18 12:55:14 +01:00
|
|
|
|
2019-12-07 23:59:24 +06:00
|
|
|
pub async fn logout(id: Identity) -> HttpResponse {
|
2019-07-18 12:55:14 +01:00
|
|
|
id.forget();
|
|
|
|
HttpResponse::Ok().finish()
|
|
|
|
}
|
|
|
|
|
2019-12-07 23:59:24 +06:00
|
|
|
pub async fn login(
|
2019-07-18 12:55:14 +01:00
|
|
|
auth_data: web::Json<AuthData>,
|
|
|
|
id: Identity,
|
|
|
|
pool: web::Data<Pool>,
|
2019-12-07 23:59:24 +06:00
|
|
|
) -> Result<HttpResponse, ServiceError> {
|
|
|
|
let res = web::block(move || query(auth_data.into_inner(), pool)).await;
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(user) => {
|
|
|
|
let user_string = serde_json::to_string(&user).unwrap();
|
|
|
|
id.remember(user_string);
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
}
|
|
|
|
Err(err) => match err {
|
|
|
|
BlockingError::Error(service_error) => Err(service_error),
|
|
|
|
BlockingError::Canceled => Err(ServiceError::InternalServerError),
|
2019-07-18 12:55:14 +01:00
|
|
|
},
|
2019-12-07 23:59:24 +06:00
|
|
|
}
|
2019-07-18 12:55:14 +01:00
|
|
|
}
|
|
|
|
|
2019-12-07 23:59:24 +06:00
|
|
|
pub async fn get_me(logged_user: LoggedUser) -> HttpResponse {
|
2019-07-18 12:55:14 +01:00
|
|
|
HttpResponse::Ok().json(logged_user)
|
|
|
|
}
|
|
|
|
/// Diesel query
|
|
|
|
fn query(auth_data: AuthData, pool: web::Data<Pool>) -> Result<SlimUser, ServiceError> {
|
|
|
|
use crate::schema::users::dsl::{email, users};
|
|
|
|
let conn: &PgConnection = &pool.get().unwrap();
|
|
|
|
let mut items = users
|
|
|
|
.filter(email.eq(&auth_data.email))
|
|
|
|
.load::<User>(conn)?;
|
|
|
|
|
|
|
|
if let Some(user) = items.pop() {
|
|
|
|
if let Ok(matching) = verify(&user.hash, &auth_data.password) {
|
|
|
|
if matching {
|
|
|
|
return Ok(user.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(ServiceError::Unauthorized)
|
|
|
|
}
|