fix crash on first startup due to making admin account, and allow creation of new users through a ui
This commit is contained in:
parent
d6c418a899
commit
8e1d34595a
91
src/main.rs
91
src/main.rs
|
@ -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();
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
Loading…
Reference in New Issue