1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
use actix::prelude::*;
use actix_web::middleware::{errhandlers::ErrorHandlers, Logger};
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{http, web, App, HttpServer};
use argonautica::{Hasher, Verifier};
use chrono::Duration;
use diesel::mysql::MysqlConnection;
use dotenv::dotenv;
use r2d2_diesel::ConnectionManager;
mod admin;
mod error;
mod error_handlers;
mod model;
mod schema;
mod user;
mod util;
use crate::admin::user_creation::PassHashExecutor;
use crate::model::DbExecutor;
use crate::user::login::HashVerifyExecutor;
embed_migrations!();
pub struct Secret(String);
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
std::env::set_var(
"RUST_LOG",
"joklerpoint=debug,actix_web=trace,actix_server=debug",
);
env_logger::init();
let bind_host: String =
std::env::var("BIND_HOST").unwrap_or_else(|_| "127.0.0.1:8000".to_string());
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let manager = ConnectionManager::<MysqlConnection>::new(database_url);
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Can to build connection pool");
embedded_migrations::run(&*pool.get().expect("Can connect to mysql"))
.expect("Can run migrations");
let db_addr: Addr<DbExecutor> = SyncArbiter::start(4, move || DbExecutor(pool.clone()));
let verifier_addr: Addr<HashVerifyExecutor> =
SyncArbiter::start(4, move || HashVerifyExecutor(Verifier::default()));
let hasher_addr: Addr<PassHashExecutor> =
SyncArbiter::start(4, move || PassHashExecutor(Hasher::default()));
HttpServer::new(move || {
let secret: String = std::env::var("SECRET_KEY").expect("SECRET_KEY env var should be set");
let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string());
let secure_cookies = &domain != "localhost";
let error_handlers = ErrorHandlers::new()
.handler(
http::StatusCode::INTERNAL_SERVER_ERROR,
error_handlers::internal_server_error,
)
.handler(http::StatusCode::BAD_REQUEST, error_handlers::bad_request)
.handler(http::StatusCode::NOT_FOUND, error_handlers::not_found);
App::new()
.data(db_addr.clone())
.data(verifier_addr.clone())
.data(hasher_addr.clone())
.data(Secret(secret.clone()))
.wrap(error_handlers)
.wrap(IdentityService::new(
CookieIdentityPolicy::new(secret.as_bytes())
.name("jkp-session")
.domain(domain.as_str())
.max_age_time(Duration::days(30))
.secure(secure_cookies), // this has to reflect the usage of https
))
.wrap(Logger::default())
.route("/", web::get().to(user::index))
.service(
web::resource("/login")
.route(web::get().to(user::login))
.route(web::post().to(user::confirm_login)),
)
.route("/transactions", web::get().to(user::transactions))
.service(
web::resource("/transfer")
.route(web::get().to(user::transfer))
.route(web::post().to(user::confirm_transfer)),
)
.route("/settings", web::get().to(user::settings))
.route("/reset-password", web::post().to(user::reset_password))
.route("/logout", web::get().to(user::logout))
.service(
web::resource("/admin")
.route(web::get().to(admin::index))
.route(web::post().to(admin::create_user)),
)
.service(actix_files::Files::new("/static", "static/"))
})
.bind(&bind_host)?
.run()
.await?;
Ok(())
}
|