css changes, secure/http only admin session

This commit is contained in:
Tyler Murphy 2023-01-30 11:42:45 -05:00
parent 1d98d94385
commit 0c021ef938
9 changed files with 35 additions and 27 deletions

View file

@ -12,9 +12,9 @@
<script src="/js/admin.js"></script> <script src="/js/admin.js"></script>
<div id="header"> <div id="header">
<span class="logo"><a href="/">xssbook</a></span> <span class="logo"><a href="/">xssbook</a></span>
<span class="gtext desc" style="margin-left: 6em; font-size: 2em">Admin Panel</span>
</div> </div>
<div id="login" class="hidden"> <div id="login" class="hidden">
<span class="gtext desc">Admin Login</span>
<form autocomplete="off" onsubmit="auth(event)"> <form autocomplete="off" onsubmit="auth(event)">
<input autocomplete="new-password" type="password" name="adminpassword" id="adminpassword" placeholder="Login Secret"> <input autocomplete="new-password" type="password" name="adminpassword" id="adminpassword" placeholder="Login Secret">
</form> </form>

View file

@ -93,6 +93,8 @@ table {
margin-top: 3em; margin-top: 3em;
border-collapse: separate; border-collapse: separate;
border-spacing: 15px; border-spacing: 15px;
table-layout: fixed;
width: 100%;
} }
th, td { th, td {
@ -102,6 +104,7 @@ th, td {
border-radius: 10px; border-radius: 10px;
background-color: #242424; background-color: #242424;
border-radius: 10px; border-radius: 10px;
word-wrap: break-word;
} }
th { th {

View file

@ -9,7 +9,7 @@ body {
src: url("../fonts/sfpro.otf") format("opentype"); src: url("../fonts/sfpro.otf") format("opentype");
} }
div { .msg {
background-color: #282828; background-color: #282828;
font-family: sfpro; font-family: sfpro;
margin: 15px; margin: 15px;
@ -19,7 +19,7 @@ div {
width: calc(100% - 50px) width: calc(100% - 50px)
} }
span { .msg span {
display: inline-block; display: inline-block;
padding: 0; padding: 0;
margin: 0; margin: 0;

View file

@ -59,8 +59,8 @@ pub fn generate_users() -> Response {
for user in users { for user in users {
html.push_str( html.push_str(
&format!("<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>", &format!("<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>",
user.user_id, sanatize(user.firstname), sanatize(user.lastname), sanatize(user.email), sanatize(user.password), user.user_id, sanatize(&user.firstname), sanatize(&user.lastname), sanatize(&user.email), sanatize(&user.password),
sanatize(user.gender), user.date, user.day, user.month, user.year sanatize(&user.gender), user.date, user.day, user.month, user.year
) )
); );
} }
@ -94,9 +94,9 @@ pub fn generate_posts() -> Response {
"<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>", "<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>",
post.post_id, post.post_id,
post.user_id, post.user_id,
sanatize(post.content), sanatize(&post.content),
console::beautify(likes), console::beautify(&likes),
console::beautify(comments), console::beautify(&comments),
post.date post.date
)); ));
} }

View file

@ -30,8 +30,8 @@ async fn auth(cookies: Cookies, Json(body): Json<AdminAuthRequest>) -> Response
} }
let mut cookie = Cookie::new("admin", admin::regen_secret().await); let mut cookie = Cookie::new("admin", admin::regen_secret().await);
cookie.set_secure(false); cookie.set_secure(true);
cookie.set_http_only(false); cookie.set_http_only(true);
cookie.set_path("/"); cookie.set_path("/");
cookies.add(cookie); cookies.add(cookie);

View file

@ -36,8 +36,8 @@ impl ToString for LogMessage {
Method::OPTIONS => "#423fe0", Method::OPTIONS => "#423fe0",
_ => "white", _ => "white",
}; };
format!("<div><span class='ip'>{}</span> <span class='method' style='color: {};'>{}</span> <span class='path'>{}{}</span> <span class='body'>{}</span></div>", format!("<div class='msg'><span class='ip'>{}</span> <span class='method' style='color: {};'>{}</span> <span class='path'>{}{}</span> <span class='body'>{}</span></div>",
ip, color, self.method, self.path, sanatize(self.uri.to_string()), self.body) ip, color, self.method, self.path, sanatize(&self.uri.to_string()), self.body)
} }
} }
@ -46,12 +46,11 @@ lazy_static! {
} }
pub async fn log(ip: IpAddr, method: Method, uri: Uri, path: Option<String>, body: Option<String>) { pub async fn log(ip: IpAddr, method: Method, uri: Uri, path: Option<String>, body: Option<String>) {
let path = path.unwrap_or_default(); let path = path.unwrap_or_default();
let body = body.unwrap_or_default(); let body = body.unwrap_or_default();
if path == "/api/admin" { if path == "/api/admin" {
return return;
} }
tracing::info!("{} {} {}{} {}", &ip, &method, &path, &uri, &body); tracing::info!("{} {} {}{} {}", &ip, &method, &path, &uri, &body);
@ -61,7 +60,7 @@ pub async fn log(ip: IpAddr, method: Method, uri: Uri, path: Option<String>, bod
method, method,
uri, uri,
path, path,
body: beautify(body), body: beautify(&body),
}; };
let mut lock = LOG.lock().await; let mut lock = LOG.lock().await;
@ -205,14 +204,14 @@ impl Formatter for HtmlFormatter {
} }
} }
pub fn sanatize(input: String) -> String { pub fn sanatize(input: &str) -> String {
input input
.replace('&', "&amp;") .replace('&', "&amp;")
.replace('<', "&lt;") .replace('<', "&lt;")
.replace('>', "&gt;") .replace('>', "&gt;")
} }
pub fn beautify(body: String) -> String { pub fn beautify(body: &str) -> String {
let body = sanatize(body); let body = sanatize(body);
if body.is_empty() { if body.is_empty() {
@ -240,10 +239,18 @@ pub async fn generate() -> Response {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="refresh" content="5"> <meta http-equiv="refresh" content="5">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="css/console.css"> <link rel="stylesheet" href="css/console.css">
<link rel="stylesheet" href="css/header.css">
<link rel="stylesheet" href="/css/admin.css">
<title>XSSBook - Console</title> <title>XSSBook - Console</title>
</head> </head>
<body> <body>
<div id="header">
<span class="logo"><a href="/">xssbook</a></span>
<span class="gtext desc" style="margin-left: 6em; font-size: 2em">Console</span>
</div>
<div style="margin-botton: 4.25em"></div>
"# "#
.to_string(); .to_string();

View file

@ -81,7 +81,7 @@ pub fn get_post_page(page: u64) -> Result<Vec<Post>, rusqlite::Error> {
pub fn get_all_posts() -> Result<Vec<Post>, rusqlite::Error> { pub fn get_all_posts() -> Result<Vec<Post>, rusqlite::Error> {
tracing::trace!("Retrieving posts page"); tracing::trace!("Retrieving posts page");
let conn = database::connect()?; let conn = database::connect()?;
let mut stmt = conn.prepare("SELECT * FROM posts ORDER BY post_id")?; let mut stmt = conn.prepare("SELECT * FROM posts ORDER BY post_id DESC")?;
let row = stmt.query_map([], |row| { let row = stmt.query_map([], |row| {
let row = post_from_row(row)?; let row = post_from_row(row)?;
Ok(row) Ok(row)

View file

@ -121,7 +121,7 @@ pub fn get_user_page(page: u64, hide_password: bool) -> Result<Vec<User>, rusqli
pub fn get_all_users() -> Result<Vec<User>, rusqlite::Error> { pub fn get_all_users() -> Result<Vec<User>, rusqlite::Error> {
tracing::trace!("Retrieving user page"); tracing::trace!("Retrieving user page");
let conn = database::connect()?; let conn = database::connect()?;
let mut stmt = conn.prepare("SELECT * FROM users ORDER BY user_id")?; let mut stmt = conn.prepare("SELECT * FROM users ORDER BY user_id DESC")?;
let row = stmt.query_map([], |row| { let row = stmt.query_map([], |row| {
let row = user_from_row(row, false)?; let row = user_from_row(row, false)?;
Ok(row) Ok(row)

View file

@ -4,14 +4,14 @@ use axum::{
async_trait, async_trait,
body::HttpBody, body::HttpBody,
extract::{FromRequest, FromRequestParts}, extract::{FromRequest, FromRequestParts},
headers::Cookie,
http::{request::Parts, Request}, http::{request::Parts, Request},
response::Response, response::Response,
BoxError, RequestExt, TypedHeader, BoxError, RequestExt,
}; };
use axum_client_ip::ClientIp; use axum_client_ip::ClientIp;
use bytes::Bytes; use bytes::Bytes;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tower_cookies::Cookies;
use crate::{ use crate::{
admin, console, admin, console,
@ -32,7 +32,7 @@ where
type Rejection = Response; type Rejection = Response;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self> { async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self> {
let Ok(Some(cookies)) = Option::<TypedHeader<Cookie>>::from_request_parts(parts, state).await else { let Ok(Some(cookies)) = Option::<Cookies>::from_request_parts(parts, state).await else {
return Err(ResponseCode::Forbidden.text("No cookies provided")) return Err(ResponseCode::Forbidden.text("No cookies provided"))
}; };
@ -40,7 +40,7 @@ where
return Err(ResponseCode::Forbidden.text("No auth token provided")) return Err(ResponseCode::Forbidden.text("No auth token provided"))
}; };
let Ok(session) = Session::from_token(token) else { let Ok(session) = Session::from_token(token.value()) else {
return Err(ResponseCode::Unauthorized.text("Auth token invalid")) return Err(ResponseCode::Unauthorized.text("Auth token invalid"))
}; };
@ -63,7 +63,7 @@ where
type Rejection = Response; type Rejection = Response;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self> { async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self> {
let Ok(Some(cookies)) = Option::<TypedHeader<Cookie>>::from_request_parts(parts, state).await else { let Ok(Some(cookies)) = Option::<Cookies>::from_request_parts(parts, state).await else {
return Err(ResponseCode::Forbidden.text("No cookies provided")) return Err(ResponseCode::Forbidden.text("No cookies provided"))
}; };
@ -71,11 +71,9 @@ where
return Err(ResponseCode::Forbidden.text("No admin secret provided")) return Err(ResponseCode::Forbidden.text("No admin secret provided"))
}; };
println!("{secret}");
let check = admin::get_secret().await; let check = admin::get_secret().await;
if check != secret { if check != secret.value() {
return Err(ResponseCode::Unauthorized.text("Auth token invalid")); return Err(ResponseCode::Unauthorized.text("Auth token invalid"));
} }