Browse Source

use a custom 404 page

to customize the 404 page you can copy the handlebar template
`src/static/templates/404.hbs` to the TEMPLATES_FOLDER (defaults to
`data/templates/`)
Stefan Melmuk 2 years ago
parent
commit
d209df9e10
5 changed files with 167 additions and 5 deletions
  1. 93 0
      resources/404.svg
  2. 10 5
      src/api/web.rs
  3. 2 0
      src/config.rs
  4. BIN
      src/static/images/404.png
  5. 62 0
      src/static/templates/404.hbs

+ 93 - 0
resources/404.svg

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="500"
+   height="222"
+   viewBox="0 0 500 222"
+   version="1.1"
+   id="svg5"
+   xml:space="preserve"
+   inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
+   sodipodi:docname="404.svg"
+   inkscape:export-filename="404.png"
+   inkscape:export-xdpi="96"
+   inkscape:export-ydpi="96"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
+     id="namedview7"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     inkscape:document-units="px"
+     showgrid="false"
+     inkscape:zoom="1.3791767"
+     inkscape:cx="284.59007"
+     inkscape:cy="214.25826"
+     inkscape:window-width="1916"
+     inkscape:window-height="1038"
+     inkscape:window-x="0"
+     inkscape:window-y="18"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1"
+     showguides="false" /><defs
+     id="defs2"><mask
+       id="holes"><rect
+         x="-60"
+         y="-60"
+         width="120"
+         height="120"
+         fill="#ffffff"
+         id="rect3296" /><circle
+         id="hole"
+         cy="-40"
+         r="3"
+         cx="0" /><use
+         transform="rotate(72)"
+         xlink:href="#hole"
+         id="use3299" /><use
+         transform="rotate(144)"
+         xlink:href="#hole"
+         id="use3301" /><use
+         transform="rotate(-144)"
+         xlink:href="#hole"
+         id="use3303" /><use
+         transform="rotate(-72)"
+         xlink:href="#hole"
+         id="use3305" /></mask></defs><g
+     inkscape:label="Ebene 1"
+     inkscape:groupmode="layer"
+     id="layer1"><rect
+       style="fill:none;fill-opacity:0.5;stroke:none;stroke-width:0.74;stroke-opacity:1"
+       id="rect681"
+       width="666"
+       height="222"
+       x="0"
+       y="0" /><text
+       xml:space="preserve"
+       style="font-size:128px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:0.7;stroke-width:1"
+       x="249.9375"
+       y="134.8125"
+       id="text3425"><tspan
+         id="tspan3423"
+         x="249.9375"
+         y="134.8125"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:128px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:0.7;stroke-width:1"
+         sodipodi:role="line">404</tspan></text><text
+       xml:space="preserve"
+       style="font-size:26.6667px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';text-align:center;text-anchor:middle"
+       x="249.04297"
+       y="194.68582"
+       id="text4067"><tspan
+         sodipodi:role="line"
+         id="tspan4065"
+         x="249.04295"
+         y="194.68582"
+         style="font-size:26.6667px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:0.7">Return to the web vault?</tspan></text></g></svg>

+ 10 - 5
src/api/web.rs

@@ -1,11 +1,10 @@
 use std::path::{Path, PathBuf};
 
-use rocket::serde::json::Json;
-use rocket::{fs::NamedFile, http::ContentType, Catcher, Route};
+use rocket::{fs::NamedFile, http::ContentType, response::content::RawHtml as Html, serde::json::Json, Catcher, Route};
 use serde_json::Value;
 
 use crate::{
-    api::core::now,
+    api::{core::now, ApiResult},
     error::Error,
     util::{Cached, SafeString},
     CONFIG,
@@ -30,8 +29,13 @@ pub fn catchers() -> Vec<Catcher> {
 }
 
 #[catch(404)]
-async fn not_found() -> Cached<Option<NamedFile>> {
-    Cached::short(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join("404.html")).await.ok(), false)
+fn not_found() -> ApiResult<Html<String>> {
+    // Return the page
+    let json = json!({
+        "urlpath": CONFIG.domain_path()
+    });
+    let text = CONFIG.render_template("404", &json)?;
+    Ok(Html(text))
 }
 
 #[get("/")]
@@ -91,6 +95,7 @@ fn alive(_conn: DbConn) -> Json<String> {
 #[get("/vw_static/<filename>")]
 pub fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Error> {
     match filename.as_ref() {
+        "404.png" => Ok((ContentType::PNG, include_bytes!("../static/images/404.png"))),
         "mail-github.png" => Ok((ContentType::PNG, include_bytes!("../static/images/mail-github.png"))),
         "logo-gray.png" => Ok((ContentType::PNG, include_bytes!("../static/images/logo-gray.png"))),
         "error-x.svg" => Ok((ContentType::SVG, include_bytes!("../static/images/error-x.svg"))),

+ 2 - 0
src/config.rs

@@ -1123,6 +1123,8 @@ where
     reg!("admin/organizations");
     reg!("admin/diagnostics");
 
+    reg!("404");
+
     // And then load user templates to overwrite the defaults
     // Use .hbs extension for the files
     // Templates get registered with their relative name

BIN
src/static/images/404.png


+ 62 - 0
src/static/templates/404.hbs

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
+    <meta name="robots" content="noindex,nofollow" />
+    <link rel="icon" type="image/png" href="{{urlpath}}/vw_static/vaultwarden-icon.png">
+    <title>Page not found!</title>
+    <link rel="stylesheet" href="{{urlpath}}/vw_static/bootstrap.css" />
+    <style>
+        body {
+            padding-top: 75px;
+        }
+        .vaultwarden-icon {
+            width: 48px;
+            height: 48px;
+            height: 32px;
+            width: auto;
+            margin: -5px 0 0 0;
+        }
+        .footer {
+            padding: 40px 0 40px 0;
+            border-top: 1px solid #dee2e6;
+        }
+        .container {
+            max-width: 980px;
+        }
+        .content {
+            padding-top: 20px;
+            padding-bottom: 20px;
+            padding-left: 15px;
+            padding-right: 15px;
+        }
+    </style>
+</head>
+
+<body class="bg-light">
+
+    <nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top">
+        <div class="container">
+            <a class="navbar-brand" href="{{urlpath}}/"><img class="vaultwarden-icon" src="{{urlpath}}/vw_static/vaultwarden-icon.png" alt="V">aultwarden</a>
+            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
+                    aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="navbarCollapse">
+                <ul class="navbar-nav me-auto">
+            </div>
+        </div>
+    </nav>
+
+    <main class="container inner content text-center">
+        <h2>Page not found!</h2>
+        <p class="lead">Sorry, but the page you were looking for could not be found.</p>
+        <p class="display-6">
+            <a href="{{urlpath}}/"><img style="max-width: 500px; width: 100%;" src="{{urlpath}}/vw_static/404.png" alt="Return to the web vault?"></a></p>
+        <p>You can <a href="{{urlpath}}/">return to the web-vault</a>, or <a href="https://github.com/dani-garcia/vaultwarden">contact us</a>.</p>
+    </main>
+
+    <div class="container footer text-muted content">Vaultwarden (unofficial Bitwarden&reg; server)</div>
+</body>
+</html>