Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/wastebin_server/src/handlers/delete/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub async fn delete(
async {
let id = id.parse()?;
db.delete_for(id, uid).await?;
Ok(Redirect::to("/"))
Ok(crate::redirect("/"))
}
.await
.map_err(|err| make_error(err, page.clone(), theme))
Expand Down
2 changes: 1 addition & 1 deletion crates/wastebin_server/src/handlers/insert/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub async fn post<E: std::fmt::Debug>(
.same_site(SameSite::Strict)
.build();

Ok((jar.add(cookie), Redirect::to(&url)))
Ok((jar.add(cookie), crate::redirect(&url)))
}
.await
.map_err(|err| make_error(err, page, theme))
Expand Down
2 changes: 1 addition & 1 deletion crates/wastebin_server/src/handlers/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub async fn get(headers: HeaderMap, Query(pref): Query<Preference>) -> impl Int
let response = headers
.get(REFERER)
.and_then(|referer| referer.to_str().ok())
.map_or_else(|| Redirect::to("/"), Redirect::to);
.map_or_else(|| crate::redirect("/"), Redirect::to);

([(SET_COOKIE, format!("pref={}", pref.pref))], response)
}
Expand Down
28 changes: 27 additions & 1 deletion crates/wastebin_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::time::Duration;
use axum::extract::{DefaultBodyLimit, FromRef, Request, State};
use axum::http::{HeaderName, HeaderValue, StatusCode};
use axum::middleware::{Next, from_fn, from_fn_with_state};
use axum::response::{IntoResponse, Response};
use axum::response::{IntoResponse, Redirect, Response};
use axum::routing::{Router, get, post};
use axum_extra::extract::cookie::Key;
use futures::future::TryFutureExt;
Expand All @@ -23,6 +23,7 @@ use http::header::{
X_XSS_PROTECTION,
};
use tokio::net::{TcpListener, UnixListener};
use tokio::task_local;
use tower::ServiceBuilder;
use tower_http::compression::CompressionLayer;
use tower_http::timeout::TimeoutLayer;
Expand All @@ -34,6 +35,10 @@ use crate::handlers::extract::Theme;
use crate::handlers::{delete, download, html, insert, raw, robots, theme};
use wastebin_core::db::Database;

task_local! {
static PATH_PREFIX: String;
}

/// Reference counted [`page::Page`] wrapper.
pub(crate) type Page = Arc<page::Page>;

Expand Down Expand Up @@ -79,6 +84,26 @@ impl FromRef<AppState> for Cache {
}
}

fn path_prefix() -> String {
PATH_PREFIX.with(|val| val.to_string())
}

fn redirect(uri: &str) -> Redirect {
let prefixed_uri = path_prefix() + uri;
Redirect::to(&prefixed_uri)
}

async fn path_prefix_layer(req: Request, next: Next) -> Response {
let prefix = req
.headers()
.get("x-forwarded-prefix")
.and_then(|val| val.to_str().ok())
.unwrap_or("")
.to_string();

PATH_PREFIX.scope(prefix, next.run(req)).await
}

async fn security_headers_layer(req: Request, next: Next) -> impl IntoResponse {
const SECURITY_HEADERS: [(HeaderName, HeaderValue); 7] = [
(SERVER, HeaderValue::from_static(env!("CARGO_PKG_NAME"))),
Expand Down Expand Up @@ -213,6 +238,7 @@ fn make_app(state: AppState, timeout: Duration, max_body_size: usize) -> Router
timeout,
))
.layer(from_fn_with_state(state.clone(), handle_service_errors))
.layer(from_fn(path_prefix_layer))
.layer(from_fn(security_headers_layer)),
)
.with_state(state)
Expand Down
27 changes: 14 additions & 13 deletions crates/wastebin_server/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{% let path_prefix = crate::path_prefix() %}
<!DOCTYPE html>
<html lang="en">
<head>
Expand All @@ -7,26 +8,26 @@
<title>{{ page.title }}{% block title_content %}{% endblock %}</title>
{% match theme %}
{% when Some with (Theme::Dark) %}
<link rel="stylesheet" href="{{ page.assets.css.dark.route() }}">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.dark.route() }}">
{% when Some with (Theme::Light) %}
<link rel="stylesheet" href="{{ page.assets.css.light.route() }}">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.light.route() }}">
{% when Some with (Theme::System) %}
<link rel="stylesheet" href="{{ page.assets.css.dark.route() }}" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="{{ page.assets.css.light.route() }}" media="(prefers-color-scheme: light)">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.dark.route() }}" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.light.route() }}" media="(prefers-color-scheme: light)">
{% when None %}
<link rel="stylesheet" href="{{ page.assets.css.dark.route() }}" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="{{ page.assets.css.light.route() }}" media="(prefers-color-scheme: light)">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.dark.route() }}" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.light.route() }}" media="(prefers-color-scheme: light)">
{% endmatch %}
<link rel="stylesheet" href="{{ page.assets.css.style.route() }}">
<link rel="icon" href="{{ page.assets.favicon.route() }}" type="image/png">
<link rel="stylesheet" href="{{ path_prefix }}{{ page.assets.css.style.route() }}">
<link rel="icon" href="{{ path_prefix }}{{ page.assets.favicon.route() }}" type="image/png">
{% block head %}{% endblock %}
</head>
<body>
<div id="main-container">
<header>
<div class="nav-group">
<div class="nav-item">
<a href="/" class="nav-button" title="home" aria-label="home">
<a href="{{ path_prefix }}/" class="nav-button" title="home" aria-label="home">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m4 12 8-8 8 8M6 10.5V19a1 1 0 0 0 1 1h3v-3a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3h3a1 1 0 0 0 1-1v-8.5"/>
</svg>
Expand All @@ -40,30 +41,30 @@
{% match theme %}
{% when None %}
<div class="nav-item" id="dark-switch">
<a href="/theme?pref=dark" class="nav-button" title="switch to dark" aria-label="switch to dark">
<a href="{{ path_prefix }}/theme?pref=dark" class="nav-button" title="switch to dark" aria-label="switch to dark">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21a9 9 0 0 1-.5-17.986V3c-.354.966-.5 1.911-.5 3a9 9 0 0 0 9 9c.239 0 .254.018.488 0A9.004 9.004 0 0 1 12 21Z"/>
</svg>
</a>
</div>
{% when Some with (Theme::System) %}
<div class="nav-item" id="dark-switch">
<a href="/theme?pref=dark" class="nav-button" title="switch to dark" aria-label="switch to dark">
<a href="{{ path_prefix }}/theme?pref=dark" class="nav-button" title="switch to dark" aria-label="switch to dark">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21a9 9 0 0 1-.5-17.986V3c-.354.966-.5 1.911-.5 3a9 9 0 0 0 9 9c.239 0 .254.018.488 0A9.004 9.004 0 0 1 12 21Z"/>
</svg>
</a>
</div>
{% when Some with (Theme::Dark) %}
<div class="nav-item" id="light-switch">
<a href="/theme?pref=light" class="nav-button" title="switch to light" aria-label="switch to light">
<a href="{{ path_prefix }}/theme?pref=light" class="nav-button" title="switch to light" aria-label="switch to light">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5V3m0 18v-2M7.05 7.05 5.636 5.636m12.728 12.728L16.95 16.95M5 12H3m18 0h-2M7.05 16.95l-1.414 1.414M18.364 5.636 16.95 7.05M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"/>
</svg>
</a>
</div>
{% when Some with (Theme::Light) %}
<div class="nav-item" id="system-switch"> <a href="/theme?pref=system" class="nav-button" title="switch to system" aria-label="switch to system">
<div class="nav-item" id="system-switch"> <a href="{{ path_prefix }}/theme?pref=system" class="nav-button" title="switch to system" aria-label="switch to system">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" d="M10 19H5a1 1 0 0 1-1-1v-1a3 3 0 0 1 3-3h2m10 1a3 3 0 0 1-3 3m3-3a3 3 0 0 0-3-3m3 3h1m-4 3a3 3 0 0 1-3-3m3 3v1m-3-4a3 3 0 0 1 3-3m-3 3h-1m4-3v-1m-2.121 1.879-.707-.707m5.656 5.656-.707-.707m-4.242 0-.707.707m5.656-5.656-.707.707M12 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
</svg>
Expand Down
2 changes: 1 addition & 1 deletion crates/wastebin_server/templates/burn.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% block content %}
<div class="flex-center">
<div>
Copy and send <a class="text-link" href="/{{ key }}">this link</a>. After opening it for the first time, it will be deleted.
Copy and send <a class="text-link" href="{{ path_prefix }}/{{ key }}">this link</a>. After opening it for the first time, it will be deleted.
</div>
<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 {{ code.size() + 4 }} {{ code.size() + 4 }}" stroke="none" width="16rem">
Expand Down
2 changes: 1 addition & 1 deletion crates/wastebin_server/templates/encrypted.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{% block content %}
<div class="flex-center">
<form action="/{{ id }}" method="post">
<form action="{{ path_prefix }}/{{ id }}" method="post">
<div class="controls">
<div class="controls-row">
<input type="password" id="password" name="password" placeholder="Password ..." autofocus>
Expand Down
2 changes: 1 addition & 1 deletion crates/wastebin_server/templates/error.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
{% block content %}
<div class="flex-center">
<p>😢 {{ description }}</p>
<p><a class="text-link" href="/">go back</a></p>
<p><a class="text-link" href="{{ path_prefix }}/">go back</a></p>
</div>
{% endblock %}
2 changes: 1 addition & 1 deletion crates/wastebin_server/templates/formatted.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@
</div>
{{ html|safe }}
{% if !is_available %}
<script defer src="{{ page.assets.burn_js.route()}}"></script>
<script defer src="{{ path_prefix }}{{ page.assets.burn_js.route()}}"></script>
{% endif %}
{% endblock %}
4 changes: 2 additions & 2 deletions crates/wastebin_server/templates/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends "base.html" %}

{% block head %}
<script defer src="{{ page.assets.index_js.route() }}"></script>
<script defer src="{{ path_prefix }}{{ page.assets.index_js.route() }}"></script>
{% endblock %}

{% block nav_specific %}
Expand All @@ -15,7 +15,7 @@
{% endblock %}

{%- block content -%}
<form id="form" action="/new" method="post">
<form id="form" action="{{ path_prefix }}/new" method="post">
<div class="container">
<div class="content">
<textarea id="text" name="text" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" placeholder="<paste text or drop file here>" autofocus required></textarea>
Expand Down
10 changes: 5 additions & 5 deletions crates/wastebin_server/templates/paste.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,29 @@
{% block title_content %}{% if let Some(title) = title %}: {{ title }}{% endif %}{% endblock %}

{% block head %}
<script defer src="{{ page.assets.paste_js.route() }}"></script>
<script defer src="{{ path_prefix }}{{ page.assets.paste_js.route() }}"></script>
{% endblock %}

{% block nav_common %}
{% if is_available %}
{% if can_delete %}
<div class="nav-item">
<a href="/delete/{{ key.id() }}" class="nav-button" title="delete paste" aria-label="delete paste">
<a href="{{ path_prefix }}/delete/{{ key.id() }}" class="nav-button" title="delete paste" aria-label="delete paste">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
</svg>
</a>
</div>
{% endif %}
<div class="nav-item">
<a href="/dl/{{ key }}" class="nav-button" title="download file" aria-label="download file">
<a href="{{ path_prefix }}/dl/{{ key }}" class="nav-button" title="download file" aria-label="download file">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 13V4M7 14H5a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-4a1 1 0 0 0-1-1h-2m-1-5-4 5-4-5m9 8h.01"/>
</svg>
</a>
</div>
<div class="nav-item">
<a href="/raw/{{ key }}" class="nav-button" title="display raw file" aria-label="display raw file">
<a href="{{ path_prefix }}/raw/{{ key }}" class="nav-button" title="display raw file" aria-label="display raw file">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 3v4a1 1 0 0 1-1 1H5m5 4-2 2 2 2m4-4 2 2-2 2m5-12v16a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7.914a1 1 0 0 1 .293-.707l3.914-3.914A1 1 0 0 1 9.914 3H18a1 1 0 0 1 1 1Z"/>
</svg>
Expand All @@ -52,7 +52,7 @@
{% block nav_specific %}
{% if is_available %}
<div class="nav-item">
<a href="/qr/{{ key }}" class="nav-button" title="qr code" aria-label="qr code">
<a href="{{ path_prefix }}/qr/{{ key }}" class="nav-button" title="qr code" aria-label="qr code">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linejoin="round" stroke-width="2" d="M4 4h6v6H4V4Zm10 10h6v6h-6v-6Zm0-10h6v6h-6V4Zm-4 10h.01v.01H10V14Zm0 4h.01v.01H10V18Zm-3 2h.01v.01H7V20Zm0-4h.01v.01H7V16Zm-3 2h.01v.01H4V18Zm0-4h.01v.01H4V14Z"/>
<path stroke="currentColor" stroke-linejoin="round" stroke-width="2" d="M7 7h.01v.01H7V7Zm10 10h.01v.01H17V17Z"/>
Expand Down
2 changes: 1 addition & 1 deletion crates/wastebin_server/templates/qr.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{% block nav_specific %}
<div class="nav-item">
<a href="../{{ key }}" class="nav-button" title="paste content" aria-label="paste content">
<a href="{{ path_prefix }}/{{ key }}" class="nav-button" title="paste content" aria-label="paste content">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 3v4a1 1 0 0 1-1 1H5m4 8h6m-6-4h6m4-8v16a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7.914a1 1 0 0 1 .293-.707l3.914-3.914A1 1 0 0 1 9.914 3H18a1 1 0 0 1 1 1Z"/>
</svg>
Expand Down