summaryrefslogtreecommitdiff
path: root/src/console.rs
diff options
context:
space:
mode:
authorTyler Murphy <tylermurphy534@gmail.com>2023-01-28 02:51:34 -0500
committerTyler Murphy <tylermurphy534@gmail.com>2023-01-28 02:51:34 -0500
commitc01b8b8c90fa762f25bf52437611643e3ca16e5a (patch)
treec93293c5c074a03808cdd4b85cdf6001f2f17dd6 /src/console.rs
parentrusty boio finished (diff)
downloadxssbook-c01b8b8c90fa762f25bf52437611643e3ca16e5a.tar.gz
xssbook-c01b8b8c90fa762f25bf52437611643e3ca16e5a.tar.bz2
xssbook-c01b8b8c90fa762f25bf52437611643e3ca16e5a.zip
fix rerendering logout button, console page
Diffstat (limited to 'src/console.rs')
-rw-r--r--src/console.rs198
1 files changed, 190 insertions, 8 deletions
diff --git a/src/console.rs b/src/console.rs
index 5a3c60b..660fb25 100644
--- a/src/console.rs
+++ b/src/console.rs
@@ -1,13 +1,195 @@
-use std::net::IpAddr;
-use axum::http::{Method, Uri};
+use std::{net::IpAddr, collections::VecDeque, io, };
+use axum::{http::{Method, Uri}, response::Response};
+use lazy_static::lazy_static;
+use serde::Serialize;
+use serde_json::{ser::Formatter, Value};
+use tokio::sync::Mutex;
-pub async fn log(ip: &IpAddr, method: &Method, uri: &Uri, path: Option<&str>, body: Option<&str>) {
-
- if path.is_some() && body.is_some() {
- println!("{} {} {}{} {}", ip, method, path.unwrap(), uri, body.unwrap());
- } else {
- println!("{} {} {}", ip, method, uri);
+use crate::types::response::ResponseCode;
+
+struct LogMessage {
+ ip: IpAddr,
+ method: Method,
+ uri: Uri,
+ path: String,
+ body: String
+}
+
+impl ToString for LogMessage {
+ fn to_string(&self) -> String {
+ let mut ip = self.ip.to_string();
+ if ip.contains("::ffff:") {
+ ip = ip.as_str()[7..].to_string()
+ }
+ let color = match self.method {
+ Method::GET => "#3fe04f",
+ Method::POST => "#853fe0",
+ Method::PATCH => "#e0773f",
+ Method::PUT => "#e0cb3f",
+ Method::HEAD => "#3f75e0",
+ Method::DELETE => "#e04c3f",
+ Method::CONNECT => "#3fe0ad",
+ Method::TRACE => "#e03fc5",
+ Method::OPTIONS => "#423fe0",
+ _ => "white"
+ };
+ format!("<div><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, self.uri, self.body)
}
+}
+
+lazy_static! {
+ static ref LOG: Mutex<VecDeque<LogMessage>> = Mutex::new(VecDeque::with_capacity(200));
+}
+
+pub async fn log(ip: IpAddr, method: Method, uri: Uri, path: Option<String>, body: Option<String>) {
+
+ if uri.to_string().starts_with("/console") { return; }
+
+ let path = path.unwrap_or_default();
+ let body = body.unwrap_or_default();
+
+ println!("{} {} {}{} {}", &ip, &method, &path, &uri, &body);
+
+ let message = LogMessage {
+ ip: ip,
+ method: method,
+ uri: uri,
+ path: path,
+ body: beautify(body)
+ };
+ let mut lock = LOG.lock().await;
+ if lock.len() > 200 {
+ lock.pop_back();
+ }
+ lock.push_front(message);
+}
+
+struct HtmlFormatter;
+impl Formatter for HtmlFormatter {
+ fn write_null<W>(&mut self, writer: &mut W) -> io::Result<()> where W: ?Sized + io::Write {
+ writer.write_all(b"<span class='null'>null</span>")
+ }
+
+ fn write_bool<W>(&mut self, writer: &mut W, value: bool) -> io::Result<()> where W: ?Sized + io::Write {
+ let s = if value {
+ b"<span class='bool'>true</span>" as &[u8]
+ } else {
+ b"<span class='bool'>false</span>" as &[u8]
+ };
+ writer.write_all(s)
+ }
+
+ fn write_i8<W>(&mut self, writer: &mut W, value: i8) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_i16<W>(&mut self, writer: &mut W, value: i16) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_i32<W>(&mut self, writer: &mut W, value: i32) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_i64<W>(&mut self, writer: &mut W, value: i64) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_u8<W>(&mut self, writer: &mut W, value: u8) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_u16<W>(&mut self, writer: &mut W, value: u16) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_u32<W>(&mut self, writer: &mut W, value: u32) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_u64<W>(&mut self, writer: &mut W, value: u64) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_f32<W>(&mut self, writer: &mut W, value: f32) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn write_f64<W>(&mut self, writer: &mut W, value: f64) -> io::Result<()> where W: ?Sized + io::Write {
+ let buff = format!("<span class='number'>{}</span>", value);
+ writer.write_all(buff.as_bytes())
+ }
+
+ fn begin_string<W>(&mut self, writer: &mut W) -> io::Result<()> where W: ?Sized + io::Write {
+ writer.write_all(b"<span class='string'>\"")
+ }
+
+ fn end_string<W>(&mut self, writer: &mut W) -> io::Result<()> where W: ?Sized + io::Write {
+ writer.write_all(b"\"</span>")
+ }
+
+ fn begin_object_key<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()> where W: ?Sized + io::Write {
+ if first {
+ writer.write_all(b"<span class='key'>")
+ } else {
+ writer.write_all(b"<span class='key'>,")
+ }
+ }
+
+ fn end_object_key<W>(&mut self, writer: &mut W) -> io::Result<()> where W: ?Sized + io::Write {
+ writer.write_all(b"</span>")
+ }
+
+}
+
+fn beautify(body: String) -> String {
+ if body.len() < 1 {
+ return "".to_string()
+ }
+ let Ok(mut json) = serde_json::from_str::<Value>(&body) else {
+ return body
+ };
+ if json["password"].is_string() {
+ json["password"] = Value::String("********".to_owned());
+ }
+ let mut writer: Vec<u8> = Vec::with_capacity(128);
+ let mut serializer = serde_json::Serializer::with_formatter(&mut writer, HtmlFormatter);
+ if let Err(_) = json.serialize(&mut serializer) {
+ return body
+ }
+ String::from_utf8_lossy(&writer).to_string()
+}
+
+pub async fn generate() -> Response {
+
+ let lock = LOG.lock().await;
+
+ let mut html = r#"<!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <meta http-equiv="refresh" content="5">
+ <link rel="stylesheet" href="css/console.css">
+ <title>XSSBook - Console</title>
+ </head>
+ <body>
+ "#.to_string();
+
+ for message in lock.iter() {
+ html.push_str(&message.to_string());
+ }
+
+ html.push_str("</body></html>");
+ ResponseCode::Success.html(&html)
} \ No newline at end of file