fix crash on first startup due to making admin account, and allow creation of new users through a ui

This commit is contained in:
SadlyNotSappho 2024-02-06 14:41:29 -08:00
parent d6c418a899
commit 8e1d34595a
4 changed files with 94 additions and 66 deletions

View File

@ -1,4 +1,5 @@
use rocket::fairing::AdHoc;
use rocket::fs::FileServer;
use rocket::http::Status;
use rocket::response::content::{self, RawHtml};
use rocket::{Build, Request, Rocket};
@ -15,29 +16,18 @@ use rocket_db_pools::{
};
use rocket::serde::{json::Json, Deserialize};
use rocket::{
fs::FileServer,
http::CookieJar,
tokio::time::{sleep, Duration},
};
use rocket::http::CookieJar;
use fossil::tables::{Db, Post, User};
#[get("/")]
fn hello() -> RawHtml<String> {
content::RawHtml(fs::read_to_string("/srv/web/index.html").unwrap())
// format!("hi!!!")
#[get("/login")]
fn login_page() -> RawHtml<String> {
content::RawHtml(fs::read_to_string("/srv/web/login.html").unwrap())
}
#[get("/book/<card>/<isbn>")]
fn get_book(card: String, isbn: String) -> String {
format!("You're checking out the book {isbn}, with the account {card}.")
}
#[get("/delay/<time>")]
async fn delay(time: u64) -> String {
sleep(Duration::from_secs(time)).await;
format!("waited for {time} seconds")
#[get("/createuser")]
fn createuser_page() -> RawHtml<String> {
content::RawHtml(fs::read_to_string("/srv/web/createuser.html").unwrap())
}
#[derive(Deserialize)]
@ -49,9 +39,7 @@ struct LoginInfo {
#[post("/createuser", data = "<info>")]
async fn createuser(
// this is so fucking jank but it works !!!
db: Connection<Db>,
db2: Connection<Db>,
mut db: Connection<Db>,
info: Json<LoginInfo>,
cookies: &CookieJar<'_>,
) -> &'static str {
@ -59,22 +47,35 @@ async fn createuser(
match token.is_some() {
true => "You're already logged in. Log out before trying to create a new account.",
false => {
if User::get_by_username(db, &info.username).await.is_some() {
"Username already taken. Please try again."
} else {
User::create(db2, &info.username, &info.password).await;
"Account created."
match User::get_by_username(&mut db, &info.username).await {
Some(_) => "Username already taken. Please try again.",
None => {
User::create(&mut db, &info.username, &info.password).await;
match User::get_by_username(&mut db, &info.username).await {
Some(user) => match user.set_new_token(&mut db).await {
Ok(t) => {
cookies.add_private(("token", t));
"Your account has been created and you've been automatically logged in."
},
Err(why) => {
eprintln!("{why:?}");
"Couldn't log you in. Your account has been created, though."
},
},
None => "Something went really wrong. I don't know what."
}
}
}
}
}
}
#[get("/account")]
async fn account(db: Connection<Db>, cookies: &CookieJar<'_>) -> String {
async fn account(mut db: Connection<Db>, cookies: &CookieJar<'_>) -> String {
let token = cookies.get_private("token");
match token {
Some(t) => {
match User::get_by_token(db, t.to_string().split('=').collect::<Vec<&str>>()[1].to_string() /*GOD I LOVE RUST*/).await {
match User::get_by_token(&mut db, t.to_string().split('=').collect::<Vec<&str>>()[1].to_string() /*GOD I LOVE RUST*/).await {
Some(user) => format!("Username: {}\nAdmin: {}\nMake Posts: {}\nComment: {}", user.username, user.admin, user.make_posts, user.comment),
None => "User doesn't exist.".to_string()
}
@ -86,20 +87,20 @@ async fn account(db: Connection<Db>, cookies: &CookieJar<'_>) -> String {
}
#[post("/login", data = "<info>")]
async fn login(db: Connection<Db>, db2: Connection<Db>, info: Json<LoginInfo>, cookies: &CookieJar<'_>) -> String {
async fn login(mut db: Connection<Db>, info: Json<LoginInfo>, cookies: &CookieJar<'_>) -> String {
let token = cookies.get_private("token");
match token {
Some(_) => {
"already logged in".to_string()
}
None => {
match User::get_by_username(db, &info.username).await {
match User::get_by_username(&mut db, &info.username).await {
Some(user) => {
if user.password == sha256::digest(&info.password) {
match user.token {
Some(t) => {cookies.add_private(("token", t)); "Logged in".to_string()},
None => {
match user.set_new_token(db2).await {
match user.set_new_token(&mut db).await {
Ok(t) => {
cookies.add_private(("token", t));
"logged in".to_string()
@ -129,26 +130,6 @@ async fn logout(cookies: &CookieJar<'_>) -> &'static str {
}
}
#[get("/dbtest/<id>")]
async fn dbtest(db: Connection<Db>, id: i32) -> Option<String> {
let post = Post::get(db, id).await;
Some(format!(
"ID: {}\nTitle: {}\nBody: {}\nPublished: {}",
post.id, post.title, post.body, post.published
))
}
#[get("/dbcreate/<title>/<body>/<published>")]
async fn dbcreate(
db: Connection<Db>,
title: String,
body: String,
published: bool,
) -> &'static str {
Post::create(db, title, body, published).await;
"created!"
}
#[catch(default)]
fn default_catcher(status: Status, _: &Request) -> RawHtml<String> {
content::RawHtml(
@ -199,9 +180,7 @@ async fn migrate(rocket: Rocket<Build>) -> Rocket<Build> {
let username = std::env::var("ADMIN_USERNAME").expect("make ADMIN_USERNAME env var");
let password = sha256::digest(std::env::var("ADMIN_PASSWORD").expect("make ADMIN_PASSWORD env var"));
eprintln!("{username}\n{password}");
conn.fetch_one(sqlx::query(
conn.execute(sqlx::query(
r#"
INSERT INTO users (username, password, admin)
VALUES ($1, $2, true);
@ -226,10 +205,10 @@ async fn main() {
.attach(AdHoc::on_ignite("DB Migrations", migrate))
.mount(
"/",
routes![hello, get_book, delay, login, logout, dbtest, dbcreate, createuser, account],
routes![login_page, login, logout, createuser, createuser_page, account],
)
.mount("/css", FileServer::from("/srv/web/css"))
.register("/", catchers![default_catcher])
.mount("/login", FileServer::from("/srv/web"))
.launch()
.await
.unwrap();

View File

@ -70,9 +70,9 @@ pub enum UserRole {
Comment,
}
impl User {
pub async fn create(mut db: Connection<Db>, username: &String, password: &String) {
pub async fn create(db: &mut Connection<Db>, username: &String, password: &String) {
match db
.fetch_all(
.execute(
sqlx::query(
r#"
INSERT INTO users (username, password)
@ -90,7 +90,7 @@ impl User {
}
}
}
pub async fn get_by_id(mut db: Connection<Db>, id: i32) -> Option<User> {
pub async fn get_by_id(db: &mut Connection<Db>, id: i32) -> Option<User> {
match db
.fetch_one(sqlx::query("SELECT * FROM users WHERE id = $1;").bind(id))
.await
@ -107,7 +107,7 @@ impl User {
Err(_) => None,
}
}
pub async fn get_by_token(mut db: Connection<Db>, token: String) -> Option<User> {
pub async fn get_by_token(db: &mut Connection<Db>, token: String) -> Option<User> {
match db
.fetch_one(sqlx::query("SELECT * FROM users WHERE token = $1;").bind(token))
.await
@ -124,7 +124,7 @@ impl User {
Err(_) => None,
}
}
pub async fn get_by_username(mut db: Connection<Db>, username: &String) -> Option<User> {
pub async fn get_by_username(db: &mut Connection<Db>, username: &String) -> Option<User> {
match db
.fetch_one(sqlx::query("SELECT * FROM users WHERE username = $1;").bind(username))
.await
@ -141,14 +141,14 @@ impl User {
Err(_) => None,
}
}
pub async fn set_new_token(&self, mut db: Connection<Db>) -> Result<String, String> {
pub async fn set_new_token(&self, db: &mut Connection<Db>) -> Result<String, String> {
let token_end = rand_hc::Hc128Rng::from_entropy().next_u64();
let token_start = sha256::digest(&self.username);
let token = sha256::digest(format!("{token_start}-{token_end}"));
match db
.fetch_one(
.execute(
sqlx::query("UPDATE users SET token = $1 WHERE id = $2")
.bind(&token)
.bind(self.id),

50
web/createuser.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>create user</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/createuser/css/style.css" rel="stylesheet">
</head>
<body>
create user
<form action="/createuser" method="post" class="login-form" id="login-form">
<div class="form-test">
<label for="name">Username: </label>
<input type="text" name="username" id="name" required />
</div>
<div class="form-test">
<label for="pass">Password: </label>
<input type="text" name="password" id="password" required />
</div>
<div class="form-test">
<input type="submit" value="Create user" />
</div>
</form>
<button id="logout-button">Log Out</button>
</body>
<script defer>
document.getElementById("login-form").addEventListener("submit", async (event) => {
event.preventDefault();
const username = event.target.username.value;
const password = event.target.password.value;
const token = await fetch("/createuser", {
method: "POST",
header: {"Content-Type": "application/json"},
body: JSON.stringify({username, password})
})
alert(await token.text());
});
document.getElementById("logout-button").addEventListener("click", async (event) => {
event.preventDefault();
const loggedout = await fetch("/logout", {
method: "POST"
});
alert(await loggedout.text());
});
</script>
</html>

View File

@ -26,7 +26,6 @@
<button id="logout-button">Log Out</button>
</body>
<script defer>
console.log("FUCK YEAH JAVASCRIPT TIME BABYYYYYYY");
document.getElementById("login-form").addEventListener("submit", async (event) => {
event.preventDefault();
const username = event.target.username.value;
@ -37,14 +36,14 @@
header: {"Content-Type": "application/json"},
body: JSON.stringify({username, password})
})
console.log(await token.text());
alert(await token.text());
});
document.getElementById("logout-button").addEventListener("click", async (event) => {
event.preventDefault();
const loggedout = await fetch("/logout", {
method: "POST"
});
console.log(await loggedout.text());
alert(await loggedout.text());
});
</script>