|
|
|
@ -1,79 +1,184 @@
|
|
|
|
|
use std::{any::Any, io};
|
|
|
|
|
use std::{io, sync::Arc};
|
|
|
|
|
|
|
|
|
|
use actix_session::{storage::CookieSessionStore, Session, SessionMiddleware};
|
|
|
|
|
use actix_identity::{Identity, IdentityMiddleware};
|
|
|
|
|
use actix_session::{
|
|
|
|
|
config::PersistentSession, storage::CookieSessionStore, Session, SessionMiddleware,
|
|
|
|
|
};
|
|
|
|
|
use actix_web::{
|
|
|
|
|
get,
|
|
|
|
|
cookie::{time::Duration, Key},
|
|
|
|
|
delete, get,
|
|
|
|
|
http::{header::ContentType, Method},
|
|
|
|
|
middleware,
|
|
|
|
|
middleware, post, put,
|
|
|
|
|
web::{self},
|
|
|
|
|
App, HttpRequest, HttpResponse, HttpServer,
|
|
|
|
|
App, HttpMessage, HttpRequest, HttpResponse, HttpServer, Responder,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Define our model module and use our models
|
|
|
|
|
// Define our model module
|
|
|
|
|
mod model;
|
|
|
|
|
use model::todo::{Priority, Status, Todo};
|
|
|
|
|
use model::user::User;
|
|
|
|
|
use model::todo::{Todo, Priority, Status};
|
|
|
|
|
// Define our repo module
|
|
|
|
|
mod repo;
|
|
|
|
|
// use repo::todo_repository::TodoRepository;
|
|
|
|
|
use repo::user_repository::UserRepository;
|
|
|
|
|
|
|
|
|
|
async fn index(method: Method) -> HttpResponse {
|
|
|
|
|
async fn index(id: Option<Identity>, method: Method) -> impl Responder {
|
|
|
|
|
match method {
|
|
|
|
|
Method::GET => HttpResponse::Ok()
|
|
|
|
|
.content_type(ContentType::plaintext())
|
|
|
|
|
.body(format!("Welcome")),
|
|
|
|
|
Method::GET => match id {
|
|
|
|
|
Some(id) => HttpResponse::Ok()
|
|
|
|
|
.content_type(ContentType::plaintext())
|
|
|
|
|
.body(format!(
|
|
|
|
|
"You are logged in. Welcome! ({:?})",
|
|
|
|
|
id.id().unwrap()
|
|
|
|
|
)),
|
|
|
|
|
None => HttpResponse::Unauthorized().finish(),
|
|
|
|
|
},
|
|
|
|
|
_ => HttpResponse::Forbidden().finish(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[get("/counter")]
|
|
|
|
|
async fn get_counter(req: HttpRequest, session: Session) -> actix_web::Result<HttpResponse> {
|
|
|
|
|
// log::info!("Request: {req:?}");
|
|
|
|
|
#[get("/user")]
|
|
|
|
|
async fn get_user(id: Identity, repo: web::Data<UserRepository>) -> impl Responder {
|
|
|
|
|
match repo.read_all() {
|
|
|
|
|
Ok(users) => {
|
|
|
|
|
log::info!("{users:?}");
|
|
|
|
|
HttpResponse::Ok().body(format!("{users:?}"))
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
log::error!("Could not read from user repo: {err}");
|
|
|
|
|
HttpResponse::InternalServerError()
|
|
|
|
|
.body(format!("Could not read from user repo: {err}"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut counter = 1;
|
|
|
|
|
if let Some(count) = session.get::<i32>("counter")? {
|
|
|
|
|
log::info!("Session counter: {count}");
|
|
|
|
|
counter = count + 1;
|
|
|
|
|
// TODO: Guard for login
|
|
|
|
|
#[put("/user")]
|
|
|
|
|
async fn put_user(
|
|
|
|
|
id: Identity,
|
|
|
|
|
payload: web::Json<User>,
|
|
|
|
|
session: Session,
|
|
|
|
|
repo: web::Data<UserRepository>,
|
|
|
|
|
) -> impl Responder {
|
|
|
|
|
log::debug!("Received {payload:?}");
|
|
|
|
|
match repo.update(&payload.0) {
|
|
|
|
|
Ok(_) => HttpResponse::Ok().finish(),
|
|
|
|
|
Err(_) => {
|
|
|
|
|
let msg = format!("No user with that id: {payload:?}");
|
|
|
|
|
log::debug!("{}", msg);
|
|
|
|
|
HttpResponse::InternalServerError().body(msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: For a real app, impl smth like a registration-secret or email verification
|
|
|
|
|
#[post("/user")]
|
|
|
|
|
async fn post_user(payload: web::Json<User>, repo: web::Data<UserRepository>) -> impl Responder {
|
|
|
|
|
log::debug!("Received {payload:?}");
|
|
|
|
|
let user = User::new(payload.login(), payload.hash(), payload.salt());
|
|
|
|
|
match repo.create(&user) {
|
|
|
|
|
Ok(_) => {
|
|
|
|
|
log::debug!("Successfully created {user:?}");
|
|
|
|
|
HttpResponse::Created().finish()
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
log::debug!("{err}");
|
|
|
|
|
HttpResponse::BadRequest().body(format!("{user:?}"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
session.insert("counter", counter)?;
|
|
|
|
|
#[post("/login")]
|
|
|
|
|
async fn post_login(
|
|
|
|
|
req: HttpRequest,
|
|
|
|
|
payload: web::Json<User>,
|
|
|
|
|
repo: web::Data<UserRepository>,
|
|
|
|
|
session: Session,
|
|
|
|
|
) -> impl Responder {
|
|
|
|
|
log::debug!("Received {payload:?}");
|
|
|
|
|
match repo.read(&payload.id()) {
|
|
|
|
|
Ok(Some(user)) => {
|
|
|
|
|
if payload.salt() == "" {
|
|
|
|
|
log::debug!("Initial login request with empty salt: {payload:?}");
|
|
|
|
|
HttpResponse::Ok().json(format!("{{ 'salt': '{}' }}", user.salt()))
|
|
|
|
|
} else if payload.hash() == user.hash() {
|
|
|
|
|
log::debug!("User successfully logged in: {payload:?} == {user:?}");
|
|
|
|
|
// TODO: Mayb handle more gracefully
|
|
|
|
|
Identity::login(&req.extensions(), format!("{}", payload.id()))
|
|
|
|
|
.expect("Log the user in");
|
|
|
|
|
|
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
|
// TODO: Mayb handle more gracefully
|
|
|
|
|
session
|
|
|
|
|
.insert("user", payload.0)
|
|
|
|
|
.expect("Insert user into session");
|
|
|
|
|
HttpResponse::Ok().finish()
|
|
|
|
|
} else {
|
|
|
|
|
log::debug!("Wrong password hash for user: {payload:?} != {user:?}");
|
|
|
|
|
HttpResponse::Unauthorized().finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(None) => {
|
|
|
|
|
log::debug!("User not found: {payload:?}");
|
|
|
|
|
HttpResponse::Unauthorized().finish()
|
|
|
|
|
}
|
|
|
|
|
Err(_) => {
|
|
|
|
|
let msg = format!("Could not create user: {payload:?}");
|
|
|
|
|
log::debug!("{}", msg);
|
|
|
|
|
HttpResponse::InternalServerError().body(msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[delete("/logout")]
|
|
|
|
|
async fn delete_logout(id: Identity) -> impl Responder {
|
|
|
|
|
id.logout();
|
|
|
|
|
HttpResponse::Ok()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[actix_web::main]
|
|
|
|
|
async fn main() -> io::Result<()> {
|
|
|
|
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
|
|
|
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("debug"));
|
|
|
|
|
|
|
|
|
|
let user = User::new(
|
|
|
|
|
"phga".to_string(),
|
|
|
|
|
"onetuhoneuth".to_string(),
|
|
|
|
|
"salt".to_string(),
|
|
|
|
|
);
|
|
|
|
|
let user = User::new("admin", "init_pw_hash", "init_salt");
|
|
|
|
|
log::info!("{user:#?}");
|
|
|
|
|
let todo = Todo::new(
|
|
|
|
|
user.id().clone(),
|
|
|
|
|
"Mein todo".to_string(),
|
|
|
|
|
"Es hat viele Aufgaben".to_string(),
|
|
|
|
|
"Mein todo",
|
|
|
|
|
"Es hat viele Aufgaben",
|
|
|
|
|
Priority::Normal,
|
|
|
|
|
Status::Todo,
|
|
|
|
|
);
|
|
|
|
|
log::info!("{todo:#?}");
|
|
|
|
|
// Create a better session key for production
|
|
|
|
|
// This one is only 0's -> 64 byte "random" string
|
|
|
|
|
let key: &[u8] = &[0; 64];
|
|
|
|
|
let key = actix_web::cookie::Key::from(key);
|
|
|
|
|
|
|
|
|
|
let cassandra_session = Arc::new(repo::init());
|
|
|
|
|
|
|
|
|
|
let user_repo = web::Data::new(UserRepository::new(Arc::clone(&cassandra_session)));
|
|
|
|
|
if let Err(err) = user_repo.create(&user) {
|
|
|
|
|
log::debug!("Default user already exists: {err}");
|
|
|
|
|
}
|
|
|
|
|
let key = Key::generate();
|
|
|
|
|
|
|
|
|
|
log::info!("Starting HTTP server: http://127.0.0.1:6969");
|
|
|
|
|
|
|
|
|
|
HttpServer::new(move || {
|
|
|
|
|
App::new()
|
|
|
|
|
.wrap(middleware::Compress::default())
|
|
|
|
|
.wrap(IdentityMiddleware::default())
|
|
|
|
|
.wrap(
|
|
|
|
|
SessionMiddleware::builder(CookieSessionStore::default(), key.clone())
|
|
|
|
|
.cookie_secure(false)
|
|
|
|
|
// Session lifetime
|
|
|
|
|
.session_lifecycle(PersistentSession::default().session_ttl(Duration::days(7)))
|
|
|
|
|
.build(),
|
|
|
|
|
)
|
|
|
|
|
.wrap(middleware::Logger::default())
|
|
|
|
|
.service(get_counter)
|
|
|
|
|
.app_data(user_repo.clone())
|
|
|
|
|
// .service(get_counter)
|
|
|
|
|
.service(get_user)
|
|
|
|
|
.service(put_user)
|
|
|
|
|
.service(post_user)
|
|
|
|
|
.service(post_login)
|
|
|
|
|
.service(delete_logout)
|
|
|
|
|
.default_service(web::to(index))
|
|
|
|
|
})
|
|
|
|
|
.bind(("127.0.0.1", 6969))?
|
|
|
|
|