static serve refactor
This commit is contained in:
parent
028026bfdc
commit
2026a8f457
16 changed files with 192 additions and 173 deletions
|
@ -80,7 +80,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.icons {
|
.icons {
|
||||||
background-image: url('/images/icons.png');
|
background-image: url('/image/icons.png');
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
|
@ -33,11 +33,11 @@ function remove(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function pfp(id) {
|
function pfp(id) {
|
||||||
return `<img src="/cdn/avatar?user_id=${id}">`
|
return `<img src="/image/avatar?user_id=${id}">`
|
||||||
}
|
}
|
||||||
|
|
||||||
function banner(id) {
|
function banner(id) {
|
||||||
return `<img src="/cdn/banner?user_id=${id}" onerror="this.remove()" >`
|
return `<img src="/image/banner?user_id=${id}" onerror="this.remove()" >`
|
||||||
}
|
}
|
||||||
|
|
||||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||||
|
|
|
@ -5,7 +5,8 @@ use serde::Deserialize;
|
||||||
use tower_cookies::{Cookie, Cookies};
|
use tower_cookies::{Cookie, Cookies};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
admin, database,
|
database,
|
||||||
|
public::admin,
|
||||||
types::{
|
types::{
|
||||||
extract::{AdminUser, Check, CheckResult, Json},
|
extract::{AdminUser, Check, CheckResult, Json},
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
use axum::{extract::Query, response::Response, routing::get, Router, http::StatusCode};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::types::http::ResponseCode;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct AvatarRequest {
|
|
||||||
user_id: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn avatar(params: Option<Query<AvatarRequest>>) -> Response {
|
|
||||||
|
|
||||||
let Some(params) = params else {
|
|
||||||
return ResponseCode::BadRequest.text("Missing query paramaters");
|
|
||||||
};
|
|
||||||
|
|
||||||
let custom = format!("/image/custom/avatar/{}.png", params.user_id);
|
|
||||||
let default = format!("/image/default/{}.png", params.user_id % 25);
|
|
||||||
|
|
||||||
let file = ResponseCode::Success.file(&custom).await;
|
|
||||||
if file.status() != StatusCode::OK {
|
|
||||||
return ResponseCode::Success.file(&default).await
|
|
||||||
}
|
|
||||||
file
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct BannerRequest {
|
|
||||||
user_id: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn banner(params: Option<Query<BannerRequest>>) -> Response {
|
|
||||||
|
|
||||||
let Some(params) = params else {
|
|
||||||
return ResponseCode::BadRequest.text("Missing query paramaters");
|
|
||||||
};
|
|
||||||
|
|
||||||
let custom = format!("/image/custom/banner/{}.png", params.user_id);
|
|
||||||
|
|
||||||
let file = ResponseCode::Success.file(&custom).await;
|
|
||||||
if file.status() != StatusCode::OK {
|
|
||||||
return ResponseCode::NotFound.text("User does not have a custom banner")
|
|
||||||
}
|
|
||||||
file
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn router() -> Router {
|
|
||||||
Router::new()
|
|
||||||
.route("/avatar", get(avatar))
|
|
||||||
.route("/banner", get(banner))
|
|
||||||
}
|
|
|
@ -1,14 +1,17 @@
|
||||||
use crate::types::extract::RouterURI;
|
use crate::types::extract::RouterURI;
|
||||||
use axum::{Extension, Router, BoxError, error_handling::HandleErrorLayer};
|
use axum::{error_handling::HandleErrorLayer, BoxError, Extension, Router};
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_governor::{governor::GovernorConfigBuilder, GovernorLayer, errors::display_error, key_extractor::SmartIpKeyExtractor};
|
use tower_governor::{
|
||||||
|
errors::display_error, governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor,
|
||||||
|
GovernorLayer,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod admin;
|
mod admin;
|
||||||
pub mod auth;
|
mod auth;
|
||||||
pub mod pages;
|
mod posts;
|
||||||
pub mod posts;
|
mod users;
|
||||||
pub mod users;
|
|
||||||
pub mod image;
|
pub use auth::RegistrationRequet;
|
||||||
|
|
||||||
pub fn router() -> Router {
|
pub fn router() -> Router {
|
||||||
let governor_conf = Box::new(
|
let governor_conf = Box::new(
|
||||||
|
|
|
@ -3,7 +3,11 @@ use crate::types::{
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
use axum::{response::Response, routing::{post, put}, Router};
|
use axum::{
|
||||||
|
response::Response,
|
||||||
|
routing::{post, put},
|
||||||
|
Router,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -64,7 +68,6 @@ async fn load_self(AuthorizedUser(user): AuthorizedUser) -> Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn avatar(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
async fn avatar(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
||||||
|
|
||||||
let path = format!("./public/image/custom/avatar/{}.png", user.user_id);
|
let path = format!("./public/image/custom/avatar/{}.png", user.user_id);
|
||||||
|
|
||||||
if img.save(path).is_err() {
|
if img.save(path).is_err() {
|
||||||
|
@ -75,7 +78,6 @@ async fn avatar(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn banner(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
async fn banner(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
||||||
|
|
||||||
let path = format!("./public/image/custom/banner/{}.png", user.user_id);
|
let path = format!("./public/image/custom/banner/{}.png", user.user_id);
|
||||||
|
|
||||||
if img.save(path).is_err() {
|
if img.save(path).is_err() {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use rusqlite::{OptionalExtension, Row};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::{api::auth::RegistrationRequet, database, types::user::User};
|
use crate::{api::RegistrationRequet, database, types::user::User};
|
||||||
|
|
||||||
pub fn init() -> Result<(), rusqlite::Error> {
|
pub fn init() -> Result<(), rusqlite::Error> {
|
||||||
let sql = "
|
let sql = "
|
||||||
|
|
39
src/main.rs
39
src/main.rs
|
@ -1,38 +1,25 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
body::HttpBody,
|
body::HttpBody,
|
||||||
http::{Request, StatusCode},
|
extract::DefaultBodyLimit,
|
||||||
|
http::Request,
|
||||||
middleware::{self, Next},
|
middleware::{self, Next},
|
||||||
response::Response,
|
response::Response,
|
||||||
RequestExt, Router, extract::DefaultBodyLimit,
|
RequestExt, Router,
|
||||||
};
|
};
|
||||||
use std::{net::SocketAddr, process::exit, fs};
|
use public::console;
|
||||||
|
use std::{fs, net::SocketAddr, process::exit};
|
||||||
use tower_cookies::CookieManagerLayer;
|
use tower_cookies::CookieManagerLayer;
|
||||||
use tracing::{error, info, metadata::LevelFilter};
|
use tracing::{error, info, metadata::LevelFilter};
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
filter::filter_fn, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer,
|
filter::filter_fn, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer,
|
||||||
};
|
};
|
||||||
use types::{http::ResponseCode, extract::RequestIp};
|
use types::extract::RequestIp;
|
||||||
|
|
||||||
use crate::api::{pages, image};
|
|
||||||
|
|
||||||
mod admin;
|
|
||||||
mod api;
|
mod api;
|
||||||
mod console;
|
|
||||||
mod database;
|
mod database;
|
||||||
|
mod public;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
async fn serve<B>(req: Request<B>, next: Next<B>) -> Response
|
|
||||||
where
|
|
||||||
B: Send + Sync + 'static + HttpBody,
|
|
||||||
{
|
|
||||||
let uri = req.uri();
|
|
||||||
let file = ResponseCode::Success.file(&uri.to_string()).await;
|
|
||||||
if file.status() != StatusCode::OK {
|
|
||||||
return next.run(req).await;
|
|
||||||
}
|
|
||||||
file
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn log<B>(mut req: Request<B>, next: Next<B>) -> Response
|
async fn log<B>(mut req: Request<B>, next: Next<B>) -> Response
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static + HttpBody,
|
B: Send + Sync + 'static + HttpBody,
|
||||||
|
@ -47,7 +34,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn not_found() -> Response {
|
async fn not_found() -> Response {
|
||||||
ResponseCode::NotFound.file("/404.html").await
|
public::serve("/404.html").await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -69,16 +56,16 @@ async fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::create_dir_all("./public/image/custom").expect("Coudn't make custom data directory");
|
fs::create_dir_all("./public/image/custom").expect("Coudn't make custom data directory");
|
||||||
fs::create_dir_all("./public/image/custom/avatar").expect("Coudn't make custom avatar directory");
|
fs::create_dir_all("./public/image/custom/avatar")
|
||||||
fs::create_dir_all("./public/image/custom/banner").expect("Coudn't make custom banner directory");
|
.expect("Coudn't make custom avatar directory");
|
||||||
|
fs::create_dir_all("./public/image/custom/banner")
|
||||||
|
.expect("Coudn't make custom banner directory");
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.fallback(not_found)
|
.fallback(not_found)
|
||||||
.layer(middleware::from_fn(log))
|
.layer(middleware::from_fn(log))
|
||||||
.layer(middleware::from_fn(serve))
|
.nest("/", public::router())
|
||||||
.nest("/", pages::router())
|
|
||||||
.nest("/api", api::router())
|
.nest("/api", api::router())
|
||||||
.nest("/cdn", image::router())
|
|
||||||
.layer(CookieManagerLayer::new())
|
.layer(CookieManagerLayer::new())
|
||||||
.layer(DefaultBodyLimit::max(512_000));
|
.layer(DefaultBodyLimit::max(512_000));
|
||||||
|
|
||||||
|
|
69
src/public/file.rs
Normal file
69
src/public/file.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use axum::{
|
||||||
|
extract::{Path, Query},
|
||||||
|
http::StatusCode,
|
||||||
|
response::Response,
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::types::http::ResponseCode;
|
||||||
|
|
||||||
|
use super::console;
|
||||||
|
|
||||||
|
pub async fn js(Path(path): Path<String>) -> Response {
|
||||||
|
let path = format!("/js/{}", path);
|
||||||
|
super::serve(&path).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn css(Path(path): Path<String>) -> Response {
|
||||||
|
let path = format!("/css/{}", path);
|
||||||
|
super::serve(&path).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn fonts(Path(path): Path<String>) -> Response {
|
||||||
|
let path = format!("/fonts/{}", path);
|
||||||
|
super::serve(&path).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn image(Path(path): Path<String>) -> Response {
|
||||||
|
let path = format!("/image/{}", path);
|
||||||
|
super::serve(&path).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct AvatarRequest {
|
||||||
|
user_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn avatar(params: Option<Query<AvatarRequest>>) -> Response {
|
||||||
|
let Some(params) = params else {
|
||||||
|
return ResponseCode::BadRequest.text("Missing query paramaters");
|
||||||
|
};
|
||||||
|
|
||||||
|
let custom = format!("/image/custom/avatar/{}.png", params.user_id);
|
||||||
|
let default = format!("/image/default/{}.png", params.user_id % 25);
|
||||||
|
|
||||||
|
let file = super::serve(&custom).await;
|
||||||
|
if file.status() != StatusCode::OK {
|
||||||
|
return super::serve(&default).await;
|
||||||
|
}
|
||||||
|
file
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct BannerRequest {
|
||||||
|
user_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn banner(params: Option<Query<BannerRequest>>) -> Response {
|
||||||
|
let Some(params) = params else {
|
||||||
|
return ResponseCode::BadRequest.text("Missing query paramaters");
|
||||||
|
};
|
||||||
|
|
||||||
|
let custom = format!("/image/custom/banner/{}.png", params.user_id);
|
||||||
|
|
||||||
|
let file = super::serve(&custom).await;
|
||||||
|
if file.status() != StatusCode::OK {
|
||||||
|
return ResponseCode::NotFound.text("User does not have a custom banner");
|
||||||
|
}
|
||||||
|
file
|
||||||
|
}
|
47
src/public/mod.rs
Normal file
47
src/public/mod.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
use axum::{
|
||||||
|
body::Body,
|
||||||
|
http::{Request, StatusCode},
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
routing::get,
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
use tower::ServiceExt;
|
||||||
|
use tower_http::services::ServeFile;
|
||||||
|
|
||||||
|
use crate::types::http::ResponseCode;
|
||||||
|
|
||||||
|
pub mod admin;
|
||||||
|
pub mod console;
|
||||||
|
pub mod file;
|
||||||
|
pub mod pages;
|
||||||
|
|
||||||
|
pub fn router() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.nest("/", pages::router())
|
||||||
|
.route("/js/*path", get(file::js))
|
||||||
|
.route("/css/*path", get(file::css))
|
||||||
|
.route("/fonts/*path", get(file::fonts))
|
||||||
|
.route("/image/*path", get(file::image))
|
||||||
|
.route("/image/avatar", get(file::avatar))
|
||||||
|
.route("/image/banner", get(file::banner))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn serve(path: &str) -> Response {
|
||||||
|
if !path.chars().any(|c| c == '.') {
|
||||||
|
return ResponseCode::BadRequest.text("Invalid file path");
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = format!("public{path}");
|
||||||
|
let file = ServeFile::new(path);
|
||||||
|
|
||||||
|
let Ok(res) = file.oneshot(Request::new(Body::empty())).await else {
|
||||||
|
tracing::error!("Error while fetching file");
|
||||||
|
return ResponseCode::InternalServerError.text("Error while fetching file");
|
||||||
|
};
|
||||||
|
|
||||||
|
if res.status() != StatusCode::OK {
|
||||||
|
return ResponseCode::NotFound.text("File not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
res.into_response()
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
console,
|
public::console,
|
||||||
types::{
|
types::{
|
||||||
extract::{AuthorizedUser, Log},
|
extract::{AuthorizedUser, Log},
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
|
@ -24,32 +24,20 @@ async fn login(user: Option<AuthorizedUser>, _: Log) -> Response {
|
||||||
if user.is_some() {
|
if user.is_some() {
|
||||||
Redirect::to("/home").into_response()
|
Redirect::to("/home").into_response()
|
||||||
} else {
|
} else {
|
||||||
ResponseCode::Success.file("/login.html").await
|
super::serve("/login.html").await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn home(user: Option<AuthorizedUser>, _: Log) -> Response {
|
async fn home(_: Log) -> Response {
|
||||||
if user.is_none() {
|
super::serve("/home.html").await
|
||||||
Redirect::to("/login").into_response()
|
|
||||||
} else {
|
|
||||||
ResponseCode::Success.file("/home.html").await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn people(user: Option<AuthorizedUser>, _: Log) -> Response {
|
async fn people(_: Log) -> Response {
|
||||||
if user.is_none() {
|
super::serve("/people.html").await
|
||||||
Redirect::to("/login").into_response()
|
|
||||||
} else {
|
|
||||||
ResponseCode::Success.file("/people.html").await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn profile(user: Option<AuthorizedUser>, _: Log) -> Response {
|
async fn profile(_: Log) -> Response {
|
||||||
if user.is_none() {
|
super::serve("/profile.html").await
|
||||||
Redirect::to("/login").into_response()
|
|
||||||
} else {
|
|
||||||
ResponseCode::Success.file("/profile.html").await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn console() -> Response {
|
async fn console() -> Response {
|
||||||
|
@ -57,7 +45,7 @@ async fn console() -> Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn admin() -> Response {
|
async fn admin() -> Response {
|
||||||
ResponseCode::Success.file("/admin.html").await
|
super::serve("/admin.html").await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wordpress(_: Log) -> Response {
|
async fn wordpress(_: Log) -> Response {
|
|
@ -1,20 +1,24 @@
|
||||||
use std::{io::{Read, Cursor}, net::{IpAddr, SocketAddr}};
|
use std::{
|
||||||
|
io::{Cursor, Read},
|
||||||
|
net::{IpAddr, SocketAddr},
|
||||||
|
};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
async_trait,
|
async_trait,
|
||||||
body::HttpBody,
|
body::HttpBody,
|
||||||
extract::{FromRequest, FromRequestParts, ConnectInfo},
|
extract::{ConnectInfo, FromRequest, FromRequestParts},
|
||||||
http::{request::Parts, Request},
|
http::{request::Parts, Request},
|
||||||
response::Response,
|
response::Response,
|
||||||
BoxError, RequestExt,
|
BoxError, RequestExt,
|
||||||
};
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use image::{io::Reader, ImageFormat, DynamicImage};
|
use image::{io::Reader, DynamicImage, ImageFormat};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tower_cookies::Cookies;
|
use tower_cookies::Cookies;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
admin, console,
|
public::admin,
|
||||||
|
public::console,
|
||||||
types::{
|
types::{
|
||||||
http::{ResponseCode, Result},
|
http::{ResponseCode, Result},
|
||||||
session::Session,
|
session::Session,
|
||||||
|
@ -32,41 +36,43 @@ 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 headers = &parts.headers;
|
let headers = &parts.headers;
|
||||||
|
|
||||||
let forwardedfor = headers.get("x-forwarded-for")
|
let forwardedfor = headers
|
||||||
.and_then(|h| h.to_str().ok())
|
.get("x-forwarded-for")
|
||||||
.and_then(|h|
|
.and_then(|h| h.to_str().ok())
|
||||||
h.split(',')
|
.and_then(|h| {
|
||||||
.rev()
|
h.split(',')
|
||||||
.find_map(|s| s.trim().parse::<IpAddr>().ok())
|
.rev()
|
||||||
);
|
.find_map(|s| s.trim().parse::<IpAddr>().ok())
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(forwardedfor) = forwardedfor {
|
if let Some(forwardedfor) = forwardedfor {
|
||||||
return Ok(RequestIp(forwardedfor))
|
return Ok(RequestIp(forwardedfor));
|
||||||
}
|
}
|
||||||
|
|
||||||
let realip = headers.get("x-real-ip")
|
let realip = headers
|
||||||
.and_then(|hv| hv.to_str().ok())
|
.get("x-real-ip")
|
||||||
.and_then(|s| s.parse::<IpAddr>().ok());
|
.and_then(|hv| hv.to_str().ok())
|
||||||
|
.and_then(|s| s.parse::<IpAddr>().ok());
|
||||||
|
|
||||||
if let Some(realip) = realip {
|
if let Some(realip) = realip {
|
||||||
return Ok(RequestIp(realip))
|
return Ok(RequestIp(realip));
|
||||||
}
|
}
|
||||||
|
|
||||||
let realip = headers.get("x-real-ip")
|
let realip = headers
|
||||||
.and_then(|hv| hv.to_str().ok())
|
.get("x-real-ip")
|
||||||
.and_then(|s| s.parse::<IpAddr>().ok());
|
.and_then(|hv| hv.to_str().ok())
|
||||||
|
.and_then(|s| s.parse::<IpAddr>().ok());
|
||||||
|
|
||||||
if let Some(realip) = realip {
|
if let Some(realip) = realip {
|
||||||
return Ok(RequestIp(realip))
|
return Ok(RequestIp(realip));
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = parts.extensions.get::<ConnectInfo<SocketAddr>>();
|
let info = parts.extensions.get::<ConnectInfo<SocketAddr>>();
|
||||||
|
|
||||||
if let Some(info) = info {
|
if let Some(info) = info {
|
||||||
return Ok(RequestIp(info.0.ip()))
|
return Ok(RequestIp(info.0.ip()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ResponseCode::Forbidden.text("You have no ip"))
|
Err(ResponseCode::Forbidden.text("You have no ip"))
|
||||||
|
@ -163,7 +169,6 @@ where
|
||||||
type Rejection = Response;
|
type Rejection = Response;
|
||||||
|
|
||||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self> {
|
async fn from_request(req: Request<B>, state: &S) -> Result<Self> {
|
||||||
|
|
||||||
let bytes = match read_body(req, state).await {
|
let bytes = match read_body(req, state).await {
|
||||||
Ok(body) => body,
|
Ok(body) => body,
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
|
@ -238,7 +243,6 @@ where
|
||||||
B::Error: Into<BoxError>,
|
B::Error: Into<BoxError>,
|
||||||
S: Send + Sync,
|
S: Send + Sync,
|
||||||
{
|
{
|
||||||
|
|
||||||
let Ok(RequestIp(ip)) = req.extract_parts::<RequestIp>().await else {
|
let Ok(RequestIp(ip)) = req.extract_parts::<RequestIp>().await else {
|
||||||
tracing::error!("Failed to read client ip");
|
tracing::error!("Failed to read client ip");
|
||||||
return Err(ResponseCode::InternalServerError.text("Failed to read client ip"));
|
return Err(ResponseCode::InternalServerError.text("Failed to read client ip"));
|
||||||
|
@ -255,14 +259,7 @@ where
|
||||||
return Err(ResponseCode::BadRequest.text("Request can be at most 512kb"));
|
return Err(ResponseCode::BadRequest.text("Request can be at most 512kb"));
|
||||||
};
|
};
|
||||||
|
|
||||||
console::log(
|
console::log(ip, method, uri, Some(path.to_string()), None).await;
|
||||||
ip,
|
|
||||||
method,
|
|
||||||
uri,
|
|
||||||
Some(path.to_string()),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(bytes.bytes().flatten().collect())
|
Ok(bytes.bytes().flatten().collect())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
|
||||||
headers::HeaderName,
|
headers::HeaderName,
|
||||||
http::{HeaderValue, Request, StatusCode},
|
http::{HeaderValue, StatusCode},
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
};
|
};
|
||||||
use tower::ServiceExt;
|
|
||||||
use tower_http::services::ServeFile;
|
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -58,24 +55,6 @@ impl ResponseCode {
|
||||||
);
|
);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument()]
|
|
||||||
pub async fn file(self, path: &str) -> Response {
|
|
||||||
if !path.chars().any(|c| c == '.') {
|
|
||||||
return Self::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 {
|
|
||||||
tracing::error!("Error while fetching file");
|
|
||||||
return Self::InternalServerError.text("Error while fetching file");
|
|
||||||
};
|
|
||||||
if res.status() != StatusCode::OK {
|
|
||||||
return Self::NotFound.text("File not found");
|
|
||||||
}
|
|
||||||
*res.status_mut() = self.code();
|
|
||||||
res.into_response()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Response>;
|
pub type Result<T> = std::result::Result<T, Response>;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::api::auth::RegistrationRequet;
|
use crate::api::RegistrationRequet;
|
||||||
use crate::database;
|
use crate::database;
|
||||||
use crate::types::http::{ResponseCode, Result};
|
use crate::types::http::{ResponseCode, Result};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue