Add login
This commit is contained in:
62
src/auth.rs
Normal file
62
src/auth.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use crate::routes::pages;
|
||||
use rocket::{
|
||||
catch,
|
||||
http::{Cookie, CookieJar, Status},
|
||||
post,
|
||||
request::{Form, FromForm, FromRequest, Outcome, Request},
|
||||
response::Redirect,
|
||||
uri, State,
|
||||
};
|
||||
use rocket_contrib::templates::Template;
|
||||
|
||||
pub struct MasterPassword(String);
|
||||
impl From<String> for MasterPassword {
|
||||
fn from(pass: String) -> Self {
|
||||
Self(pass)
|
||||
}
|
||||
}
|
||||
|
||||
const AUTH_COOKIE_KEY: &str = "authorized";
|
||||
const AUTH_COOKIE_VAL: &str = "true";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Authorized;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Unauthorized;
|
||||
|
||||
#[rocket::async_trait]
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for Authorized {
|
||||
type Error = Unauthorized;
|
||||
|
||||
async fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
let cookies = request.cookies();
|
||||
|
||||
match cookies.get_private(AUTH_COOKIE_KEY) {
|
||||
Some(cookie) if cookie.value() == AUTH_COOKIE_VAL => Outcome::Success(Authorized),
|
||||
_ => Outcome::Failure((Status::Unauthorized, Unauthorized)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[catch(401)]
|
||||
pub fn login_page(_req: &Request) -> Template {
|
||||
Template::render("login", &())
|
||||
}
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct Login {
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[post("/login", data = "<login>")]
|
||||
pub fn login(
|
||||
cookies: &CookieJar,
|
||||
login: Form<Login>,
|
||||
master_pass: State<MasterPassword>,
|
||||
) -> Redirect {
|
||||
if login.password == master_pass.0 {
|
||||
cookies.add_private(Cookie::new(AUTH_COOKIE_KEY, AUTH_COOKIE_VAL));
|
||||
}
|
||||
Redirect::to(uri!(pages::index))
|
||||
}
|
||||
14
src/main.rs
14
src/main.rs
@ -1,8 +1,10 @@
|
||||
mod auth;
|
||||
mod database;
|
||||
mod handlebars_util;
|
||||
mod routes;
|
||||
mod status_json;
|
||||
|
||||
use crate::auth::MasterPassword;
|
||||
use crate::database::migrations::migrate;
|
||||
use crate::database::unversioned::global::schema_version;
|
||||
use crate::database::SCHEMA_VERSION;
|
||||
@ -18,6 +20,13 @@ async fn main() -> io::Result<()> {
|
||||
|
||||
let db_path = env::var("DB_PATH").expect("DB_PATH not set");
|
||||
|
||||
let master_pass: MasterPassword = env::var("STL_PASSWORD")
|
||||
.unwrap_or_else(|_| {
|
||||
eprintln!(r#"STL_PASSWORD not set, defaulting to "password""#);
|
||||
"password".into()
|
||||
})
|
||||
.into();
|
||||
|
||||
let mut sled = sled::open(db_path)?;
|
||||
match sled.insert(
|
||||
serialize(schema_version::K).unwrap(),
|
||||
@ -42,6 +51,7 @@ async fn main() -> io::Result<()> {
|
||||
handlebars_util::register_helpers(engines)
|
||||
}))
|
||||
.manage(sled)
|
||||
.manage(master_pass)
|
||||
.mount("/static", StaticFiles::from("static"))
|
||||
.mount(
|
||||
"/",
|
||||
@ -56,8 +66,10 @@ async fn main() -> io::Result<()> {
|
||||
routes::api::end_session,
|
||||
routes::api::bump_session,
|
||||
routes::api::delete_session,
|
||||
auth::login,
|
||||
],
|
||||
);
|
||||
)
|
||||
.register(rocket::catchers![auth::login_page,]);
|
||||
|
||||
rocket.launch().await.expect("rocket failed to launch");
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::auth::Authorized;
|
||||
use crate::database::latest::trees::{categories, sessions};
|
||||
use crate::routes::pages;
|
||||
use crate::status_json::StatusJson;
|
||||
@ -18,6 +19,7 @@ pub struct NewCategory {
|
||||
|
||||
#[post("/create_category", data = "<category>")]
|
||||
pub fn create_category(
|
||||
_auth: Authorized,
|
||||
category: Form<NewCategory>,
|
||||
db: State<'_, sled::Db>,
|
||||
) -> Result<StatusJson, StatusJson> {
|
||||
@ -39,21 +41,9 @@ pub fn create_category(
|
||||
Ok(Status::Ok.into())
|
||||
}
|
||||
|
||||
#[post("/category/<category_uuid>/start_session")]
|
||||
pub fn start_session(
|
||||
category_uuid: Uuid,
|
||||
db: State<'_, sled::Db>,
|
||||
) -> Result<StatusJson, StatusJson> {
|
||||
toggle_category_session(category_uuid, true, db)
|
||||
}
|
||||
|
||||
#[post("/category/<category_uuid>/end_session")]
|
||||
pub fn end_session(category_uuid: Uuid, db: State<'_, sled::Db>) -> Result<StatusJson, StatusJson> {
|
||||
toggle_category_session(category_uuid, false, db)
|
||||
}
|
||||
|
||||
#[post("/category/<category_uuid>/bump_session/minutes/<minutes>")]
|
||||
pub fn bump_session(
|
||||
_auth: Authorized,
|
||||
category_uuid: Uuid,
|
||||
minutes: i64,
|
||||
db: State<'_, sled::Db>,
|
||||
@ -95,6 +85,24 @@ pub fn bump_session(
|
||||
})??)
|
||||
}
|
||||
|
||||
#[post("/category/<category_uuid>/start_session")]
|
||||
pub fn start_session(
|
||||
_auth: Authorized,
|
||||
category_uuid: Uuid,
|
||||
db: State<'_, sled::Db>,
|
||||
) -> Result<StatusJson, StatusJson> {
|
||||
toggle_category_session(category_uuid, true, db)
|
||||
}
|
||||
|
||||
#[post("/category/<category_uuid>/end_session")]
|
||||
pub fn end_session(
|
||||
_auth: Authorized,
|
||||
category_uuid: Uuid,
|
||||
db: State<'_, sled::Db>,
|
||||
) -> Result<StatusJson, StatusJson> {
|
||||
toggle_category_session(category_uuid, false, db)
|
||||
}
|
||||
|
||||
pub fn toggle_category_session(
|
||||
category_uuid: Uuid,
|
||||
set_active: bool,
|
||||
@ -156,6 +164,7 @@ pub struct EditSession {
|
||||
|
||||
#[post("/session/<session_uuid>/edit", data = "<session>")]
|
||||
pub fn edit_session(
|
||||
_auth: Authorized,
|
||||
session_uuid: Uuid,
|
||||
session: Form<EditSession>,
|
||||
db: State<'_, sled::Db>,
|
||||
@ -195,7 +204,11 @@ pub fn edit_session(
|
||||
}
|
||||
|
||||
#[post("/session/<session_uuid>/delete")]
|
||||
pub fn delete_session(session_uuid: Uuid, db: State<'_, sled::Db>) -> Result<Redirect, StatusJson> {
|
||||
pub fn delete_session(
|
||||
_auth: Authorized,
|
||||
session_uuid: Uuid,
|
||||
db: State<'_, sled::Db>,
|
||||
) -> Result<Redirect, StatusJson> {
|
||||
let session_uuid_s = sled::IVec::from(serialize(&session_uuid.into_inner())?);
|
||||
|
||||
let sessions_tree = db.open_tree(sessions::NAME)?;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::auth::Authorized;
|
||||
use crate::database::latest::trees::{categories, sessions};
|
||||
use crate::status_json::StatusJson;
|
||||
use bincode::deserialize;
|
||||
@ -12,7 +13,7 @@ use std::collections::{BTreeMap, HashMap};
|
||||
use std::time::Duration;
|
||||
|
||||
#[get("/")]
|
||||
pub fn index(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
pub fn index(_auth: Authorized, db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct TemplateContext {
|
||||
categories: Vec<(uuid::Uuid, categories::V)>,
|
||||
@ -33,7 +34,11 @@ pub fn index(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
}
|
||||
|
||||
#[get("/session/<session_uuid>/edit")]
|
||||
pub fn session_edit(session_uuid: Uuid, db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
pub fn session_edit(
|
||||
_auth: Authorized,
|
||||
session_uuid: Uuid,
|
||||
db: State<'_, sled::Db>,
|
||||
) -> Result<Template, StatusJson> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SessionPageContext {
|
||||
session: sessions::V,
|
||||
@ -57,7 +62,7 @@ pub fn session_edit(session_uuid: Uuid, db: State<'_, sled::Db>) -> Result<Templ
|
||||
}
|
||||
|
||||
#[get("/history")]
|
||||
pub fn history(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
pub fn history(_auth: Authorized, db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct HistoryEntryContext {
|
||||
category: categories::V,
|
||||
@ -108,7 +113,7 @@ pub fn history(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
}
|
||||
|
||||
#[get("/stats")]
|
||||
pub fn stats(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
pub fn stats(_auth: Authorized, db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct StatsContext {
|
||||
categories_stats: Vec<CategoryStatsContext>,
|
||||
|
||||
Reference in New Issue
Block a user