css changes, secure/http only admin session
This commit is contained in:
parent
1d98d94385
commit
0c021ef938
9 changed files with 35 additions and 27 deletions
|
@ -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>
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
10
src/admin.rs
10
src/admin.rs
|
@ -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
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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('&', "&")
|
.replace('&', "&")
|
||||||
.replace('<', "<")
|
.replace('<', "<")
|
||||||
.replace('>', ">")
|
.replace('>', ">")
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue