some type of authentication for the site

This commit is contained in:
Reid 2023-09-21 18:43:41 -07:00
parent b3451a641e
commit cdaf5febb7
Signed by: reidlab
GPG key ID: 6C9EAA3364F962C8
13 changed files with 318 additions and 7 deletions

126
Cargo.lock generated
View file

@ -8,6 +8,41 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "aes"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aes-gcm"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]]
name = "aho-corasick"
version = "1.0.4"
@ -161,13 +196,29 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "cookie"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
dependencies = [
"aes-gcm",
"base64",
"hkdf",
"percent-encoding",
"rand",
"sha2",
"subtle",
"time",
"version_check",
]
@ -232,9 +283,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"rand_core",
"typenum",
]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]]
name = "deranged"
version = "0.3.8"
@ -571,6 +632,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "ghash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]]
name = "glob"
version = "0.3.1"
@ -628,6 +699,24 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "hkdf"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
dependencies = [
"hmac",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "http"
version = "0.2.9"
@ -756,6 +845,15 @@ dependencies = [
"libc",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]]
name = "ipnet"
version = "2.8.0"
@ -996,6 +1094,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.57"
@ -1184,6 +1288,18 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "polyval"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -2023,6 +2139,16 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]]
name = "url"
version = "2.4.1"

View file

@ -12,8 +12,8 @@ maplit = "1.0.2"
password-auth = "0.3.0"
rand = "0.8.5"
regex = "1.9.4"
reqwest = { version = "0.11.20", features = ["blocking"] }
rocket = "=0.5.0-rc.3"
reqwest = "0.11.20"
rocket = { version = "=0.5.0-rc.3", features = ["secrets"]}
rocket_dyn_templates = { version = "0.1.0-rc.3", features = ["handlebars"] }
roxmltree = "0.18.0"
serde = { version = "1.0.188", features = ["derive"] }

View file

@ -44,4 +44,27 @@ pre {
a {
color: #89b4fa;
}
.error {
color: #f38ba8;
}
.success {
color: #a6e3a1;
}
.fancy-button {
outline: 0;
border: none;
background-color: #89b4fa;
color: #11111b;
font-size: 1.2rem;
padding: 0.4em 0.8em;
margin: 0.5em;
border-radius: 16px;
cursor: pointer;
transition: 0.1s background-color;
}

View file

@ -38,4 +38,5 @@ i've run out of ideas.
- ip actions
- better song support
- authentication caching (ip? redis?)
- use log instead of println
- use log instead of println
- store everything in 1 cookie?

View file

@ -45,7 +45,7 @@ pub fn login_account(input: Form<FromLoginAccount>) -> status::Custom<&'static s
let query_result = accounts
.select(id)
.filter(username.eq(input.userName.clone()))
.get_result::<i32>(connection);
.get_result::<i32, >(connection);
match query_result {
Ok(account_id_val) => {

View file

@ -4,4 +4,5 @@ pub mod difficulty;
pub mod encryption;
pub mod format;
pub mod levels;
pub mod reupload;
pub mod reupload;
pub mod templates;

19
src/helpers/templates.rs Normal file
View file

@ -0,0 +1,19 @@
macro_rules! auth {
($cookies: expr) => {
match $cookies.get_private("blackmail_data") {
Some(cookie_val) => {
let parts = cookie_val.value().split(":").collect::<Vec<&str>>();
let username = parts[0].to_string();
let account_id = parts[1].parse::<i32>().expect("account id is not an integer! this should NOT happen!");
let user_id = parts[2].parse::<i32>().expect("user id is not an integer! this should NOT happen!");
(true, Some(username), Some(account_id), Some(user_id))
}
None => {
(false, None, None, None)
}
}
}
}
pub(crate) use auth;

View file

@ -53,7 +53,12 @@ fn rocket() -> _ {
template_endpoints::index::index,
template_endpoints::reupload::post_reupload,
template_endpoints::reupload::get_reupload
template_endpoints::reupload::get_reupload,
template_endpoints::login::post_login,
template_endpoints::login::get_login,
template_endpoints::logout::logout,
])
// assets
.mount("/", routes![

View file

@ -1,2 +1,4 @@
pub mod index;
pub mod login;
pub mod logout;
pub mod reupload;

View file

@ -0,0 +1,68 @@
use rocket::response::Redirect;
use rocket_dyn_templates::{Template, context};
use rocket::form::Form;
use rocket::http::{Cookie, CookieJar};
use diesel::prelude::*;
use crate::db;
use crate::helpers;
#[derive(FromForm)]
pub struct FormLogin {
username: String,
password: String
}
#[post("/login", data = "<input>")]
pub fn post_login(jar: &CookieJar<'_>, input: Form<FormLogin>) -> Template {
let connection = &mut db::establish_connection_pg();
use crate::schema::accounts::dsl::*;
let result = accounts
.select((id, username))
.filter(username.eq(input.username.clone()))
.get_result::<(i32, String), >(connection);
match result {
Ok(account_id_username_val) => {
match helpers::accounts::auth(account_id_username_val.0, Some(input.password.clone()), None, None) {
Ok(account_id_user_id_val) => {
jar.add_private(Cookie::build(
"blackmail_data",
format!("{}:{}:{}", account_id_username_val.1, account_id_user_id_val.0, account_id_user_id_val.1))
.finish());
return Template::render("login", context! {
success: "Successfully logged in"
})
},
Err(_) => {
return Template::render("login", context! {
error: "Invalid password"
})
}
}
}
Err(_) => {
return Template::render("login", context! {
error: "Invalid username or password"
})
}
}
}
#[get("/login")]
pub fn get_login(cookies: &CookieJar<'_>) -> Result<Redirect, Template> {
let (logged_in, _username, _account_id, _user_id) = crate::helpers::templates::auth!(cookies);
if logged_in {
Ok(Redirect::to("/"))
} else {
Err(Template::render("login", context! { }))
}
}

View file

@ -0,0 +1,11 @@
use rocket::http::{Cookie, CookieJar};
use rocket::response::Redirect;
#[post("/accounts/logout")]
pub fn logout(jar: &CookieJar<'_>) -> Redirect {
jar.remove_private(Cookie::named("username"));
jar.remove_private(Cookie::named("account_id"));
jar.remove_private(Cookie::named("user_id"));
Redirect::to("/")
}

55
templates/login.html.hbs Normal file
View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
<title>Login</title>
<style>
body {
min-height: 100vh;
text-align: center;
width: 100%;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
form {
display: flex;
flex-direction: column;
gap: 0.5em;
align-items: center;
justify-content: center;
max-width: 800px;
height: 100%;
padding: 1em;
}
</style>
</head>
<body>
<form method="post">
<img src="/favicon.png" width="64" height="auto">
<br>
<label for="username">Username</label>
<input type="text" id="username" name="username" minlength="3" maxlength="20" required />
<label for="password">Password</label>
<input type="password" id="password" name="password" minlength="6" required />
{{#if error}}
<div class="error">{{error}}</div>
{{/if}}
{{#if success}}
<div class="success">{{success}}</div>
{{/if}}
<input type="submit" value="Login" class="fancy-button" />
</form>
</body>
</html>

View file

@ -13,7 +13,7 @@
<h1>Level Reupload</h1>
{{#if error}}
<div>Error while uploading: {{ error }}</div><br />
<div class="error">Error while uploading: {{ error }}</div><br />
{{/if}}
{{#if level_id}}
<div>Uploaded successfully! Level ID: <b>{{ level_id }}</b></div><br />