fix rerendering logout button, console page
This commit is contained in:
parent
8536e41c64
commit
c01b8b8c90
21 changed files with 373 additions and 95 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -381,6 +381,12 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
|
@ -1051,6 +1057,7 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"axum",
|
||||
"bytes",
|
||||
"lazy_static",
|
||||
"rand",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
|
|
|
@ -11,7 +11,8 @@ tower-cookies = "0.8.0"
|
|||
tower = "0.4.13"
|
||||
bytes = "1.3.0"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_json = { version = "1.0", features = ["std"] }
|
||||
rusqlite = { version = "0.28.0", features = ["bundled"] }
|
||||
rand = "0.8.5"
|
||||
time = "0.3.17"
|
||||
time = "0.3.17"
|
||||
lazy_static = "1.4.0"
|
|
@ -2,8 +2,6 @@ body {
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #181818;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -30,20 +28,20 @@ span {
|
|||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.body span {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.json span {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.key {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.boolean {
|
||||
.bool {
|
||||
color: aqua;
|
||||
}
|
||||
|
||||
|
@ -57,4 +55,8 @@ span {
|
|||
|
||||
.string {
|
||||
color: #4ae04a
|
||||
}
|
||||
|
||||
.key .string {
|
||||
color: white;
|
||||
}
|
|
@ -62,6 +62,7 @@ body {
|
|||
height: 3em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.profilebuttons button {
|
||||
|
@ -74,6 +75,7 @@ body {
|
|||
justify-content: center;
|
||||
color: #606770;
|
||||
cursor: pointer;
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.profilebuttons button:hover {
|
||||
|
@ -118,4 +120,9 @@ body {
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logout {
|
||||
flex: 1;
|
||||
/* align-self: flex-end !important; */
|
||||
}
|
|
@ -30,6 +30,10 @@ const register = async (firstname, lastname, email, password, gender, day, month
|
|||
return await request('/auth/register', {firstname, lastname, email, password, gender, day, month, year})
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
return await request('/auth/logout', {})
|
||||
}
|
||||
|
||||
const loadpostspage = async (page) => {
|
||||
return await request('/posts/page', {page})
|
||||
}
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
|
||||
function parseDate(date) {
|
||||
return months[date.getUTCMonth()] + ' ' + date.getUTCDate() + ', ' + date.getUTCFullYear() + ' ' + date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
function parseComment(comment) {
|
||||
const author = data.users[comment[0]]
|
||||
let author = data.users[comment[0]]
|
||||
if (author === undefined) {
|
||||
author = {}
|
||||
}
|
||||
|
@ -25,14 +18,14 @@ function parseComment(comment) {
|
|||
}
|
||||
|
||||
function parsePost(post) {
|
||||
const author = data.users[post.user_id]
|
||||
let author = data.users[post.user_id]
|
||||
if (author === undefined) {
|
||||
author = {}
|
||||
}
|
||||
const html = `
|
||||
<div class="post" postid=${post.post_id}>
|
||||
<div class="postheader">
|
||||
<a class="pfp">
|
||||
<a class="pfp" href=/profile?id=${author.user_id}>
|
||||
|
||||
</a>
|
||||
<div class="postname">
|
||||
|
@ -217,8 +210,8 @@ async function load() {
|
|||
batch.push(post.user_id)
|
||||
}
|
||||
const users = (await loadusers(batch)).json
|
||||
for (const id in users) {
|
||||
data.users[id] = users[id]
|
||||
for (const user of users) {
|
||||
data.users[user.user_id] = user
|
||||
}
|
||||
render()
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ async function onregister() {
|
|||
const year = document.getElementById('year').value
|
||||
const gender = document.querySelector('input[name="gender"]:checked').value
|
||||
const response = await register(first, last, email, pass, gender, parseInt(day), parseInt(month), parseInt(year))
|
||||
if (response.status !== 200) {
|
||||
if (response.status !== 201) {
|
||||
const error = document.getElementsByClassName('error')[1]
|
||||
error.innerHTML = response.msg
|
||||
} else {
|
||||
|
|
|
@ -19,4 +19,25 @@ function remove(id) {
|
|||
if (old !== null) {
|
||||
old.remove()
|
||||
}
|
||||
}
|
||||
|
||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
|
||||
const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||
|
||||
function parseMonth(month) {
|
||||
if (month > -1 && month < 26) {
|
||||
return months[month]
|
||||
} else {
|
||||
let first = letters[month%26].toUpperCase()
|
||||
let middle = letters[month*13%26]
|
||||
let last = letters[month*50%26]
|
||||
return first + middle + last
|
||||
}
|
||||
}
|
||||
|
||||
function parseDate(date) {
|
||||
return parseMonth(date.getUTCMonth()) + ' ' + date.getUTCDate() + ', ' + date.getUTCFullYear() + ' ' + date.toLocaleTimeString();
|
||||
}
|
|
@ -1,10 +1,3 @@
|
|||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
|
||||
function parseDate(date) {
|
||||
return months[date.getUTCMonth()] + ' ' + date.getUTCDate() + ', ' + date.getUTCFullYear() + ' ' + date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
function parseUser(user) {
|
||||
const html = `
|
||||
<a class="person" href="/profile?id=${user.id}">
|
||||
|
@ -15,7 +8,7 @@ function parseUser(user) {
|
|||
<span class="bold ltext">${user.firstname + ' ' + user.lastname}</span>
|
||||
<span class="gtext">Joined ${parseDate(new Date(user.date))}</span>
|
||||
<span class="gtext">Gender: ${user.gender}</span>
|
||||
<span class="gtext">Birthday: ${months[user.month] + ' ' + user.day + ', ' + user.year}</span>
|
||||
<span class="gtext">Birthday: ${parseMonth(user.month) + ' ' + user.day + ', ' + user.year}</span>
|
||||
<span class="gtext" style="margin-bottom: -100px;">User ID: ${user.user_id}</span>
|
||||
</div>
|
||||
</a>
|
||||
|
|
|
@ -23,6 +23,8 @@ function render() {
|
|||
<button class="${posts ? '' : 'selected'}" onclick="posts = false; render()">
|
||||
About
|
||||
</button>
|
||||
<div style="flex: 20"></div>
|
||||
${ isself ? `<button class="logout" onclick="logout_button()">Logout</button>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
@ -44,7 +46,7 @@ function render() {
|
|||
<span class="gtext bold">Name: ${data.user.firstname + ' ' + data.user.lastname}</span>
|
||||
<span class="gtext bold">Email: ${data.user.email}</span>
|
||||
<span class="gtext bold">Gender: ${data.user.gender}</span>
|
||||
<span class="gtext bold">Birthday: ${months[data.user.month] + ' ' + data.user.day + ', ' + data.user.year}</span>
|
||||
<span class="gtext bold">Birthday: ${parseMonth(data.user.month) + ' ' + data.user.day + ', ' + data.user.year}</span>
|
||||
<span class="gtext bold">User ID: ${data.user.user_id}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -53,7 +55,14 @@ function render() {
|
|||
add(about, 'about')
|
||||
}
|
||||
|
||||
async function logout_button() {
|
||||
const response = await logout()
|
||||
if (response.status != 200) return;
|
||||
location.href = '/login'
|
||||
}
|
||||
|
||||
var posts = true
|
||||
var isself = false
|
||||
|
||||
async function load() {
|
||||
header(false, false)
|
||||
|
@ -63,7 +72,18 @@ async function load() {
|
|||
params[key] = value
|
||||
}
|
||||
|
||||
const id = params.id !== undefined && !isNaN(params.id) ? parseInt(params.id) : (await loadself()).json.user_id
|
||||
let self = (await loadself()).json;
|
||||
let id;
|
||||
|
||||
if (params.id !== undefined && !isNaN(params.id)) {
|
||||
|
||||
id = parseInt(params.id);
|
||||
} else {
|
||||
id = self.user_id
|
||||
}
|
||||
|
||||
isself = id === self.user_id
|
||||
|
||||
const posts = (await loadusersposts(id)).json
|
||||
data.posts.push(... posts)
|
||||
const batch = [id]
|
||||
|
|
|
@ -3,7 +3,7 @@ use serde::Deserialize;
|
|||
use time::{OffsetDateTime, Duration};
|
||||
use tower_cookies::{Cookies, Cookie};
|
||||
|
||||
use crate::types::{user::User, response::ResponseCode, session::Session, extract::{Json, AuthorizedUser, Check, CheckResult}};
|
||||
use crate::types::{user::User, response::ResponseCode, session::Session, extract::{Json, AuthorizedUser, Check, CheckResult, Log}};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RegistrationRequet {
|
||||
|
@ -55,7 +55,7 @@ async fn register(cookies: Cookies, Json(body): Json<RegistrationRequet>) -> Res
|
|||
|
||||
cookies.add(cookie);
|
||||
|
||||
ResponseCode::Created.msg("Successfully created new user")
|
||||
ResponseCode::Created.text("Successfully created new user")
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -73,11 +73,11 @@ impl Check for LoginRequest {
|
|||
async fn login(cookies: Cookies, Json(body): Json<LoginRequest>) -> Response {
|
||||
|
||||
let Ok(user) = User::from_email(&body.email) else {
|
||||
return ResponseCode::BadRequest.msg("Email is not registered")
|
||||
return ResponseCode::BadRequest.text("Email is not registered")
|
||||
};
|
||||
|
||||
if user.password != body.password {
|
||||
return ResponseCode::BadRequest.msg("Password is not correct")
|
||||
return ResponseCode::BadRequest.text("Password is not correct")
|
||||
}
|
||||
|
||||
let session = match Session::new(user.user_id) {
|
||||
|
@ -96,10 +96,10 @@ async fn login(cookies: Cookies, Json(body): Json<LoginRequest>) -> Response {
|
|||
|
||||
cookies.add(cookie);
|
||||
|
||||
ResponseCode::Success.msg("Successfully logged in")
|
||||
ResponseCode::Success.text("Successfully logged in")
|
||||
}
|
||||
|
||||
async fn logout(cookies: Cookies, AuthorizedUser(user): AuthorizedUser) -> Response {
|
||||
async fn logout(cookies: Cookies, AuthorizedUser(user): AuthorizedUser, _: Log) -> Response {
|
||||
|
||||
cookies.remove(Cookie::new("auth", ""));
|
||||
|
||||
|
@ -107,7 +107,7 @@ async fn logout(cookies: Cookies, AuthorizedUser(user): AuthorizedUser) -> Respo
|
|||
return err
|
||||
}
|
||||
|
||||
ResponseCode::Success.msg("Successfully logged out")
|
||||
ResponseCode::Success.text("Successfully logged out")
|
||||
}
|
||||
|
||||
pub fn router() -> Router {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use axum::{Router, response::{Response, Redirect, IntoResponse}, routing::get};
|
||||
|
||||
use crate::types::{extract::AuthorizedUser, response::ResponseCode};
|
||||
use crate::{types::{extract::AuthorizedUser, response::ResponseCode}, console};
|
||||
|
||||
async fn root(user: Option<AuthorizedUser>) -> Response {
|
||||
if user.is_some() {
|
||||
|
@ -42,8 +42,12 @@ async fn profile(user: Option<AuthorizedUser>) -> Response {
|
|||
}
|
||||
}
|
||||
|
||||
async fn console() -> Response {
|
||||
console::generate().await
|
||||
}
|
||||
|
||||
async fn wordpress() -> Response {
|
||||
ResponseCode::ImATeapot.msg("Hello i am a teapot owo")
|
||||
ResponseCode::ImATeapot.text("Hello i am a teapot owo")
|
||||
}
|
||||
|
||||
pub fn router() -> Router {
|
||||
|
@ -53,5 +57,6 @@ pub fn router() -> Router {
|
|||
.route("/home", get(home))
|
||||
.route("/people", get(people))
|
||||
.route("/profile", get(profile))
|
||||
.route("/console", get(console))
|
||||
.route("/wp-admin", get(wordpress))
|
||||
}
|
|
@ -19,11 +19,11 @@ impl Check for PostCreateRequest {
|
|||
async fn create(AuthorizedUser(user): AuthorizedUser, Json(body): Json<PostCreateRequest>) -> Response {
|
||||
|
||||
let Ok(post) = Post::new(user.user_id, body.content) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to create post")
|
||||
return ResponseCode::InternalServerError.text("Failed to create post")
|
||||
};
|
||||
|
||||
let Ok(json) = serde_json::to_string(&post) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to create post")
|
||||
return ResponseCode::InternalServerError.text("Failed to create post")
|
||||
};
|
||||
|
||||
ResponseCode::Created.json(&json)
|
||||
|
@ -43,11 +43,11 @@ impl Check for PostPageRequest {
|
|||
async fn page(AuthorizedUser(_user): AuthorizedUser, Json(body): Json<PostPageRequest>) -> Response {
|
||||
|
||||
let Ok(posts) = Post::from_post_page(body.page) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch posts")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch posts")
|
||||
};
|
||||
|
||||
let Ok(json) = serde_json::to_string(&posts) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch posts")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch posts")
|
||||
};
|
||||
|
||||
ResponseCode::Success.json(&json)
|
||||
|
@ -67,11 +67,11 @@ impl Check for UsersPostsRequest {
|
|||
async fn user(AuthorizedUser(_user): AuthorizedUser, Json(body): Json<UsersPostsRequest>) -> Response {
|
||||
|
||||
let Ok(posts) = Post::from_user_id(body.user_id) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch posts")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch posts")
|
||||
};
|
||||
|
||||
let Ok(json) = serde_json::to_string(&posts) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch posts")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch posts")
|
||||
};
|
||||
|
||||
ResponseCode::Success.json(&json)
|
||||
|
@ -93,14 +93,14 @@ impl Check for PostCommentRequest {
|
|||
async fn comment(AuthorizedUser(user): AuthorizedUser, Json(body): Json<PostCommentRequest>) -> Response {
|
||||
|
||||
let Ok(mut post) = Post::from_post_id(body.post_id) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch posts")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch posts")
|
||||
};
|
||||
|
||||
if let Err(err) = post.comment(user.user_id, body.content) {
|
||||
return err;
|
||||
}
|
||||
|
||||
ResponseCode::Success.msg("Successfully commented on post")
|
||||
ResponseCode::Success.text("Successfully commented on post")
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -118,14 +118,14 @@ impl Check for PostLikeRequest {
|
|||
async fn like(AuthorizedUser(user): AuthorizedUser, Json(body): Json<PostLikeRequest>) -> Response {
|
||||
|
||||
let Ok(mut post) = Post::from_post_id(body.post_id) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch posts")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch posts")
|
||||
};
|
||||
|
||||
if let Err(err) = post.like(user.user_id, body.state) {
|
||||
return err;
|
||||
}
|
||||
|
||||
ResponseCode::Success.msg("Successfully changed like status on post")
|
||||
ResponseCode::Success.text("Successfully changed like status on post")
|
||||
}
|
||||
|
||||
pub fn router() -> Router {
|
||||
|
|
|
@ -17,7 +17,7 @@ async fn load_batch(AuthorizedUser(_user): AuthorizedUser, Json(body): Json<User
|
|||
|
||||
let users = User::from_user_ids(body.ids);
|
||||
let Ok(json) = serde_json::to_string(&users) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch users")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch users")
|
||||
};
|
||||
|
||||
ResponseCode::Success.json(&json)
|
||||
|
@ -37,11 +37,11 @@ impl Check for UserPageReqiest {
|
|||
async fn load_page(AuthorizedUser(_user): AuthorizedUser, Json(body): Json<UserPageReqiest>) -> Response {
|
||||
|
||||
let Ok(users) = User::from_user_page(body.page) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch users")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch users")
|
||||
};
|
||||
|
||||
let Ok(json) = serde_json::to_string(&users) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch users")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch users")
|
||||
};
|
||||
|
||||
ResponseCode::Success.json(&json)
|
||||
|
@ -50,7 +50,7 @@ async fn load_page(AuthorizedUser(_user): AuthorizedUser, Json(body): Json<UserP
|
|||
async fn load_self(AuthorizedUser(user): AuthorizedUser) -> Response {
|
||||
|
||||
let Ok(json) = serde_json::to_string(&user) else {
|
||||
return ResponseCode::InternalServerError.msg("Failed to fetch user")
|
||||
return ResponseCode::InternalServerError.text("Failed to fetch user")
|
||||
};
|
||||
|
||||
ResponseCode::Success.json(&json)
|
||||
|
|
200
src/console.rs
200
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)
|
||||
}
|
|
@ -25,7 +25,7 @@ async fn log<B>(mut req: Request<B>, next: Next<B>) -> Response where
|
|||
return next.run(req).await
|
||||
};
|
||||
|
||||
console::log(&info.ip(), req.method(), req.uri(), None, None).await;
|
||||
console::log(info.ip().clone(), req.method().clone(), req.uri().clone(), None, None).await;
|
||||
|
||||
return next.run(req).await
|
||||
}
|
||||
|
|
|
@ -15,25 +15,60 @@ impl<S> FromRequestParts<S> for AuthorizedUser where S: Send + Sync {
|
|||
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 {
|
||||
return Err(ResponseCode::Forbidden.msg("No cookies provided"))
|
||||
return Err(ResponseCode::Forbidden.text("No cookies provided"))
|
||||
};
|
||||
|
||||
let Some(token) = cookies.get("auth") else {
|
||||
return Err(ResponseCode::Forbidden.msg("No auth token provided"))
|
||||
return Err(ResponseCode::Forbidden.text("No auth token provided"))
|
||||
};
|
||||
|
||||
let Ok(session) = Session::from_token(&token) else {
|
||||
return Err(ResponseCode::Unauthorized.msg("Auth token invalid"))
|
||||
return Err(ResponseCode::Unauthorized.text("Auth token invalid"))
|
||||
};
|
||||
|
||||
let Ok(user) = User::from_user_id(session.user_id, true) else {
|
||||
return Err(ResponseCode::InternalServerError.msg("Valid token but no valid user"))
|
||||
return Err(ResponseCode::InternalServerError.text("Valid token but no valid user"))
|
||||
};
|
||||
|
||||
Ok(AuthorizedUser(user))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Log;
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Log where
|
||||
B: HttpBody + Sync + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(mut req: Request<B>, state: &S) -> Result<Self> {
|
||||
|
||||
let Ok(ConnectInfo(info)) = req.extract_parts::<ConnectInfo<SocketAddr>>().await else {
|
||||
return Ok(Log)
|
||||
};
|
||||
let method = req.method().clone();
|
||||
let path = req.extensions().get::<RouterURI>().unwrap().0;
|
||||
let uri = req.uri().clone();
|
||||
|
||||
let Ok(bytes) = Bytes::from_request(req, state).await else {
|
||||
console::log(info.ip().clone(), method.clone(), uri.clone(), Some(path.to_string()), None).await;
|
||||
return Ok(Log)
|
||||
};
|
||||
|
||||
let Ok(body) = String::from_utf8(bytes.bytes().flatten().collect()) else {
|
||||
console::log(info.ip().clone(), method.clone(), uri.clone(), Some(path.to_string()), None).await;
|
||||
return Ok(Log)
|
||||
};
|
||||
|
||||
console::log(info.ip().clone(), method.clone(), uri.clone(), Some(path.to_string()), Some(body.to_string())).await;
|
||||
|
||||
Ok(Log)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Json<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
|
@ -49,28 +84,28 @@ impl<T, S, B> FromRequest<S, B> for Json<T> where
|
|||
async fn from_request(mut req: Request<B>, state: &S) -> Result<Self> {
|
||||
|
||||
let Ok(ConnectInfo(info)) = req.extract_parts::<ConnectInfo<SocketAddr>>().await else {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to read connection info"));
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to read connection info"));
|
||||
};
|
||||
let method = req.method().clone();
|
||||
let path = req.extensions().get::<RouterURI>().unwrap().0;
|
||||
let uri = req.uri().clone();
|
||||
|
||||
let Ok(bytes) = Bytes::from_request(req, state).await else {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to read request body"));
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to read request body"));
|
||||
};
|
||||
|
||||
let Ok(body) = String::from_utf8(bytes.bytes().flatten().collect()) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Invalid utf8 body"))
|
||||
return Err(ResponseCode::BadRequest.text("Invalid utf8 body"))
|
||||
};
|
||||
|
||||
console::log(&info.ip(), &method, &uri, Some(path), Some(&body)).await;
|
||||
console::log(info.ip().clone(), method.clone(), uri.clone(), Some(path.to_string()), Some(body.to_string())).await;
|
||||
|
||||
let Ok(value) = serde_json::from_str::<T>(&body) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Invalid request body"))
|
||||
return Err(ResponseCode::BadRequest.text("Invalid request body"))
|
||||
};
|
||||
|
||||
if let Err(msg) = value.check() {
|
||||
return Err(ResponseCode::BadRequest.msg(&msg));
|
||||
return Err(ResponseCode::BadRequest.text(&msg));
|
||||
}
|
||||
|
||||
Ok(Json(value))
|
||||
|
|
|
@ -18,7 +18,7 @@ impl Post {
|
|||
|
||||
pub fn from_post_id(post_id: u64) -> Result<Self> {
|
||||
let Ok(Some(post)) = database::posts::get_post(post_id) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Post does not exist"))
|
||||
return Err(ResponseCode::BadRequest.text("Post does not exist"))
|
||||
};
|
||||
|
||||
Ok(post)
|
||||
|
@ -35,21 +35,21 @@ impl Post {
|
|||
|
||||
pub fn from_post_page(page: u64) -> Result<Vec<Self>> {
|
||||
let Ok(posts) = database::posts::get_post_page(page) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Failed to fetch posts"))
|
||||
return Err(ResponseCode::BadRequest.text("Failed to fetch posts"))
|
||||
};
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub fn from_user_id(user_id: u64) -> Result<Vec<Self>> {
|
||||
let Ok(posts) = database::posts::get_users_posts(user_id) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Failed to fetch posts"))
|
||||
return Err(ResponseCode::BadRequest.text("Failed to fetch posts"))
|
||||
};
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub fn new(user_id: u64, content: String) -> Result<Self> {
|
||||
let Ok(post) = database::posts::add_post(user_id, &content) else {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to create post"))
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to create post"))
|
||||
};
|
||||
|
||||
Ok(post)
|
||||
|
@ -59,7 +59,7 @@ impl Post {
|
|||
self.comments.push((user_id, content));
|
||||
|
||||
if database::posts::update_post(self.post_id, &self.likes, &self.comments).is_err() {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to comment on post"))
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to comment on post"))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -74,7 +74,7 @@ impl Post {
|
|||
}
|
||||
|
||||
if database::posts::update_post(self.post_id, &self.likes, &self.comments).is_err() {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to comment on post"))
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to comment on post"))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -28,7 +28,7 @@ impl ResponseCode {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn msg(self, msg: &str) -> Response {
|
||||
pub fn text(self, msg: &str) -> Response {
|
||||
(self.code(), msg.to_owned()).into_response()
|
||||
}
|
||||
|
||||
|
@ -40,17 +40,25 @@ impl ResponseCode {
|
|||
res
|
||||
}
|
||||
|
||||
pub fn html(self, json: &str) -> Response {
|
||||
let mut res = (self.code(), json.to_owned()).into_response();
|
||||
res.headers_mut().insert(
|
||||
HeaderName::from_static("content-type"), HeaderValue::from_static("text/html"),
|
||||
);
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn file(self, path: &str) -> Result<Response> {
|
||||
if path.chars().position(|c| c == '.' ).is_none() {
|
||||
return Err(ResponseCode::BadRequest.msg("Folders cannot be served"));
|
||||
return Err(ResponseCode::BadRequest.text("Folders cannot be served"));
|
||||
}
|
||||
let path = format!("public{}", path);
|
||||
let svc = ServeFile::new(path);
|
||||
let Ok(mut res) = svc.oneshot(Request::new(Body::empty())).await else {
|
||||
return Err(ResponseCode::InternalServerError.msg("Error wile fetching file"));
|
||||
return Err(ResponseCode::InternalServerError.text("Error wile fetching file"));
|
||||
};
|
||||
if res.status() != StatusCode::OK {
|
||||
return Err(ResponseCode::NotFound.msg("File not found"));
|
||||
return Err(ResponseCode::NotFound.text("File not found"));
|
||||
}
|
||||
*res.status_mut() = self.code();
|
||||
Ok(res.into_response())
|
||||
|
|
|
@ -14,7 +14,7 @@ impl Session {
|
|||
|
||||
pub fn from_token(token: &str) -> Result<Self> {
|
||||
let Ok(Some(session)) = database::sessions::get_session(token) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Invalid auth token"));
|
||||
return Err(ResponseCode::BadRequest.text("Invalid auth token"));
|
||||
};
|
||||
|
||||
Ok(session)
|
||||
|
@ -23,14 +23,14 @@ impl Session {
|
|||
pub fn new(user_id: u64) -> Result<Self> {
|
||||
let token: String = rand::thread_rng().sample_iter(&Alphanumeric).take(32).map(char::from).collect();
|
||||
match database::sessions::set_session(user_id, &token) {
|
||||
Err(_) => return Err(ResponseCode::BadRequest.msg("Failed to create session")),
|
||||
Err(_) => return Err(ResponseCode::BadRequest.text("Failed to create session")),
|
||||
Ok(_) => return Ok(Session {user_id, token})
|
||||
};
|
||||
}
|
||||
|
||||
pub fn delete(user_id: u64) -> Result<()> {
|
||||
if let Err(_) = database::sessions::delete_session(user_id) {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to logout"));
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to logout"));
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ impl User {
|
|||
|
||||
pub fn from_user_id(user_id: u64, hide_password: bool) -> Result<Self> {
|
||||
let Ok(Some(user)) = database::users::get_user_by_id(user_id, hide_password) else {
|
||||
return Err(ResponseCode::BadRequest.msg("User does not exist"))
|
||||
return Err(ResponseCode::BadRequest.text("User does not exist"))
|
||||
};
|
||||
|
||||
Ok(user)
|
||||
|
@ -39,14 +39,14 @@ impl User {
|
|||
|
||||
pub fn from_user_page(page: u64) -> Result<Vec<Self>> {
|
||||
let Ok(users) = database::users::get_user_page(page, true) else {
|
||||
return Err(ResponseCode::BadRequest.msg("Failed to fetch users"))
|
||||
return Err(ResponseCode::BadRequest.text("Failed to fetch users"))
|
||||
};
|
||||
Ok(users)
|
||||
}
|
||||
|
||||
pub fn from_email(email: &str) -> Result<Self> {
|
||||
let Ok(Some(user)) = database::users::get_user_by_email(email, false) else {
|
||||
return Err(ResponseCode::BadRequest.msg("User does not exist"))
|
||||
return Err(ResponseCode::BadRequest.text("User does not exist"))
|
||||
};
|
||||
|
||||
Ok(user)
|
||||
|
@ -54,7 +54,7 @@ impl User {
|
|||
|
||||
pub fn from_password(password: &str) -> Result<Self> {
|
||||
let Ok(Some(user)) = database::users::get_user_by_password(password, true) else {
|
||||
return Err(ResponseCode::BadRequest.msg("User does not exist"))
|
||||
return Err(ResponseCode::BadRequest.text("User does not exist"))
|
||||
};
|
||||
|
||||
Ok(user)
|
||||
|
@ -62,15 +62,15 @@ impl User {
|
|||
|
||||
pub fn new(firstname: String, lastname: String, email: String, password: String, gender: String, day: u8, month: u8, year: u32) -> Result<Self> {
|
||||
if let Ok(_) = User::from_email(&email) {
|
||||
return Err(ResponseCode::BadRequest.msg(&format!("Email is already in use by {}", &email)))
|
||||
return Err(ResponseCode::BadRequest.text(&format!("Email is already in use by {}", &email)))
|
||||
}
|
||||
|
||||
if let Ok(user) = User::from_password(&password) {
|
||||
return Err(ResponseCode::BadRequest.msg(&format!("Password is already in use by {}", user.email)))
|
||||
return Err(ResponseCode::BadRequest.text(&format!("Password is already in use by {}", user.email)))
|
||||
}
|
||||
|
||||
let Ok(user) = database::users::add_user(&firstname, &lastname, &email, &password, &gender, day, month, year) else {
|
||||
return Err(ResponseCode::InternalServerError.msg("Failed to create new uesr"))
|
||||
return Err(ResponseCode::InternalServerError.text("Failed to create new uesr"))
|
||||
};
|
||||
|
||||
Ok(user)
|
||||
|
|
Loading…
Reference in a new issue