Add login

This commit is contained in:
2020-11-13 00:30:39 +01:00
parent fdab612863
commit 9b9cc4e0bd
8 changed files with 333 additions and 24 deletions

203
Cargo.lock generated
View File

@ -15,6 +15,60 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "aead"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "aes"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd2bc6d3f370b5666245ff421e231cba4353df936e26986d2918e61a8fd6aef6"
dependencies = [
"aes-soft",
"aesni",
"block-cipher",
]
[[package]]
name = "aes-gcm"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0301c9e9c443494d970a07885e8cf3e587bae8356a1d5abd0999068413f7205f"
dependencies = [
"aead",
"aes",
"block-cipher",
"ghash",
"subtle",
]
[[package]]
name = "aes-soft"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63dd91889c49327ad7ef3b500fd1109dbd3c509a03db0d4a9ce413b79f575cb6"
dependencies = [
"block-cipher",
"byteorder",
"opaque-debug 0.3.0",
]
[[package]]
name = "aesni"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6fe808308bb07d393e2ea47780043ec47683fcf19cf5efc8ca51c50cc8c68a"
dependencies = [
"block-cipher",
"opaque-debug 0.3.0",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.14" version = "0.7.14"
@ -87,6 +141,12 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]] [[package]]
name = "binascii" name = "binascii"
version = "0.1.4" version = "0.1.4"
@ -118,7 +178,25 @@ dependencies = [
"block-padding", "block-padding",
"byte-tools", "byte-tools",
"byteorder", "byteorder",
"generic-array", "generic-array 0.12.3",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-cipher"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80"
dependencies = [
"generic-array 0.14.4",
] ]
[[package]] [[package]]
@ -215,11 +293,23 @@ name = "cookie"
version = "0.15.0-dev" version = "0.15.0-dev"
source = "git+https://github.com/SergioBenitez/cookie-rs.git?rev=1c3ca83#1c3ca838543b60a4448d279dc4b903cc7a2bc22a" source = "git+https://github.com/SergioBenitez/cookie-rs.git?rev=1c3ca83#1c3ca838543b60a4448d279dc4b903cc7a2bc22a"
dependencies = [ dependencies = [
"aes-gcm",
"base64",
"hkdf",
"percent-encoding", "percent-encoding",
"rand 0.7.3",
"sha2",
"subtle",
"time 0.2.22", "time 0.2.22",
"version_check", "version_check",
] ]
[[package]]
name = "cpuid-bool"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.2.1" version = "1.2.1"
@ -255,6 +345,16 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "crypto-mac"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
dependencies = [
"generic-array 0.14.4",
"subtle",
]
[[package]] [[package]]
name = "devise" name = "devise"
version = "0.3.0" version = "0.3.0"
@ -291,7 +391,16 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [ dependencies = [
"generic-array", "generic-array 0.12.3",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.4",
] ]
[[package]] [[package]]
@ -550,6 +659,16 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.15" version = "0.1.15"
@ -561,6 +680,15 @@ dependencies = [
"wasi 0.9.0+wasi-snapshot-preview1", "wasi 0.9.0+wasi-snapshot-preview1",
] ]
[[package]]
name = "ghash"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531"
dependencies = [
"polyval",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.22.0" version = "0.22.0"
@ -622,6 +750,26 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hkdf"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe1149865383e4526a43aee8495f9a325f0b806c63ce6427d06336a590abbbc9"
dependencies = [
"digest 0.9.0",
"hmac",
]
[[package]]
name = "hmac"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
dependencies = [
"crypto-mac",
"digest 0.9.0",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.1" version = "0.2.1"
@ -958,6 +1106,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.0" version = "0.11.0"
@ -1108,6 +1262,16 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "polyval"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5884790f1ce3553ad55fec37b5aaac5882e0e845a2612df744d6c85c9bf046c"
dependencies = [
"cfg-if 0.1.10",
"universal-hash",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.9" version = "0.2.9"
@ -1575,10 +1739,10 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [ dependencies = [
"block-buffer", "block-buffer 0.7.3",
"digest", "digest 0.8.1",
"fake-simd", "fake-simd",
"opaque-debug", "opaque-debug 0.2.3",
] ]
[[package]] [[package]]
@ -1587,6 +1751,19 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]]
name = "sha2"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
"cpuid-bool",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.2.2" version = "1.2.2"
@ -1721,6 +1898,12 @@ dependencies = [
"uuid", "uuid",
] ]
[[package]]
name = "subtle"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.48" version = "1.0.48"
@ -1938,6 +2121,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "universal-hash"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402"
dependencies = [
"generic-array 0.14.4",
"subtle",
]
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.7.4" version = "0.7.4"

View File

@ -25,6 +25,7 @@ handlebars = "3"
#version = "0.4" #version = "0.4"
git = "https://github.com/SergioBenitez/Rocket" git = "https://github.com/SergioBenitez/Rocket"
branch = "master" branch = "master"
features = ["secrets"]
[dependencies.rocket_contrib] [dependencies.rocket_contrib]
#version = "0.4" #version = "0.4"

View File

@ -24,6 +24,7 @@ FROM scratch
ENV ROCKET_ENV="staging" ENV ROCKET_ENV="staging"
ENV ROCKET_TEMPLATE_DIR="/templates" ENV ROCKET_TEMPLATE_DIR="/templates"
ENV DB_PATH="/database" ENV DB_PATH="/database"
VOLUME "/database" VOLUME "/database"

62
src/auth.rs Normal file
View 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))
}

View File

@ -1,8 +1,10 @@
mod auth;
mod database; mod database;
mod handlebars_util; mod handlebars_util;
mod routes; mod routes;
mod status_json; mod status_json;
use crate::auth::MasterPassword;
use crate::database::migrations::migrate; use crate::database::migrations::migrate;
use crate::database::unversioned::global::schema_version; use crate::database::unversioned::global::schema_version;
use crate::database::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 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)?; let mut sled = sled::open(db_path)?;
match sled.insert( match sled.insert(
serialize(schema_version::K).unwrap(), serialize(schema_version::K).unwrap(),
@ -42,6 +51,7 @@ async fn main() -> io::Result<()> {
handlebars_util::register_helpers(engines) handlebars_util::register_helpers(engines)
})) }))
.manage(sled) .manage(sled)
.manage(master_pass)
.mount("/static", StaticFiles::from("static")) .mount("/static", StaticFiles::from("static"))
.mount( .mount(
"/", "/",
@ -56,8 +66,10 @@ async fn main() -> io::Result<()> {
routes::api::end_session, routes::api::end_session,
routes::api::bump_session, routes::api::bump_session,
routes::api::delete_session, routes::api::delete_session,
auth::login,
], ],
); )
.register(rocket::catchers![auth::login_page,]);
rocket.launch().await.expect("rocket failed to launch"); rocket.launch().await.expect("rocket failed to launch");

View File

@ -1,3 +1,4 @@
use crate::auth::Authorized;
use crate::database::latest::trees::{categories, sessions}; use crate::database::latest::trees::{categories, sessions};
use crate::routes::pages; use crate::routes::pages;
use crate::status_json::StatusJson; use crate::status_json::StatusJson;
@ -18,6 +19,7 @@ pub struct NewCategory {
#[post("/create_category", data = "<category>")] #[post("/create_category", data = "<category>")]
pub fn create_category( pub fn create_category(
_auth: Authorized,
category: Form<NewCategory>, category: Form<NewCategory>,
db: State<'_, sled::Db>, db: State<'_, sled::Db>,
) -> Result<StatusJson, StatusJson> { ) -> Result<StatusJson, StatusJson> {
@ -39,21 +41,9 @@ pub fn create_category(
Ok(Status::Ok.into()) 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>")] #[post("/category/<category_uuid>/bump_session/minutes/<minutes>")]
pub fn bump_session( pub fn bump_session(
_auth: Authorized,
category_uuid: Uuid, category_uuid: Uuid,
minutes: i64, minutes: i64,
db: State<'_, sled::Db>, 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( pub fn toggle_category_session(
category_uuid: Uuid, category_uuid: Uuid,
set_active: bool, set_active: bool,
@ -156,6 +164,7 @@ pub struct EditSession {
#[post("/session/<session_uuid>/edit", data = "<session>")] #[post("/session/<session_uuid>/edit", data = "<session>")]
pub fn edit_session( pub fn edit_session(
_auth: Authorized,
session_uuid: Uuid, session_uuid: Uuid,
session: Form<EditSession>, session: Form<EditSession>,
db: State<'_, sled::Db>, db: State<'_, sled::Db>,
@ -195,7 +204,11 @@ pub fn edit_session(
} }
#[post("/session/<session_uuid>/delete")] #[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 session_uuid_s = sled::IVec::from(serialize(&session_uuid.into_inner())?);
let sessions_tree = db.open_tree(sessions::NAME)?; let sessions_tree = db.open_tree(sessions::NAME)?;

View File

@ -1,3 +1,4 @@
use crate::auth::Authorized;
use crate::database::latest::trees::{categories, sessions}; use crate::database::latest::trees::{categories, sessions};
use crate::status_json::StatusJson; use crate::status_json::StatusJson;
use bincode::deserialize; use bincode::deserialize;
@ -12,7 +13,7 @@ use std::collections::{BTreeMap, HashMap};
use std::time::Duration; use std::time::Duration;
#[get("/")] #[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)] #[derive(Debug, Serialize, Deserialize)]
struct TemplateContext { struct TemplateContext {
categories: Vec<(uuid::Uuid, categories::V)>, 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")] #[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)] #[derive(Debug, Serialize, Deserialize)]
struct SessionPageContext { struct SessionPageContext {
session: sessions::V, session: sessions::V,
@ -57,7 +62,7 @@ pub fn session_edit(session_uuid: Uuid, db: State<'_, sled::Db>) -> Result<Templ
} }
#[get("/history")] #[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)] #[derive(Debug, Serialize, Deserialize)]
struct HistoryEntryContext { struct HistoryEntryContext {
category: categories::V, category: categories::V,
@ -108,7 +113,7 @@ pub fn history(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
} }
#[get("/stats")] #[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)] #[derive(Debug, Serialize, Deserialize)]
struct StatsContext { struct StatsContext {
categories_stats: Vec<CategoryStatsContext>, categories_stats: Vec<CategoryStatsContext>,

22
templates/login.hbs Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<link rel="icon" type="image/png" href="/static/icon.png">
<link rel="stylesheet" href="/static/styles.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu|Ubuntu+Mono&display=swap">
<title>stl</title>
</head>
<body>
<h1 class="title">stl</h1>
<h2>Logga in</h2>
<form action="/login" method="post">
<input type="password" id="password" name="password"></input>
</form>
</body>
</html>