vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit 29a079521974027d12d6f504f37dcb42cc6a03d9
parent 63459c5f7267f41fbec9aaab4bca131bbc72f162
Author: Jeremy Lin <jeremy.lin@gmail.com>
Date:   Tue, 18 Feb 2020 21:27:00 -0800

Add backend support for alternate base dir (subdir/subpath) hosting

To use this, include a path in the `DOMAIN` URL, e.g.:

* `DOMAIN=https://example.com/custom-path`
* `DOMAIN=https://example.com/multiple/levels/are/ok`

Diffstat:
Msrc/api/admin.rs | 12++++++++----
Msrc/api/core/mod.rs | 2+-
Msrc/api/web.rs | 14++++++++++++--
Msrc/auth.rs | 10+++++-----
Msrc/config.rs | 21+++++++++++++++++++++
Msrc/main.rs | 18++++++++++--------
Msrc/static/templates/admin/base.hbs | 17++++++++---------
Msrc/static/templates/admin/page.hbs | 19+++++++++----------
Msrc/static/templates/email/invite_accepted.hbs | 2+-
Msrc/static/templates/email/invite_accepted.html.hbs | 2+-
Msrc/static/templates/email/invite_confirmed.hbs | 2+-
Msrc/static/templates/email/invite_confirmed.html.hbs | 2+-
Msrc/static/templates/email/new_device_logged_in.hbs | 2+-
Msrc/static/templates/email/new_device_logged_in.html.hbs | 2+-
Msrc/static/templates/email/pw_hint_some.hbs | 2+-
Msrc/static/templates/email/pw_hint_some.html.hbs | 2+-
Msrc/static/templates/email/welcome.hbs | 2+-
Msrc/static/templates/email/welcome.html.hbs | 2+-
Msrc/static/templates/email/welcome_must_verify.hbs | 2+-
Msrc/static/templates/email/welcome_must_verify.html.hbs | 2+-
Msrc/util.rs | 13+++++++++----
21 files changed, 95 insertions(+), 55 deletions(-)

diff --git a/src/api/admin.rs b/src/api/admin.rs @@ -52,6 +52,10 @@ const ADMIN_PATH: &str = "/admin"; const BASE_TEMPLATE: &str = "admin/base"; const VERSION: Option<&str> = option_env!("GIT_VERSION"); +fn admin_path() -> String { + format!("{}{}", CONFIG.domain_path(), ADMIN_PATH) +} + #[get("/", rank = 2)] fn admin_login(flash: Option<FlashMessage>) -> ApiResult<Html<String>> { // If there is an error, show it @@ -76,7 +80,7 @@ fn post_admin_login(data: Form<LoginForm>, mut cookies: Cookies, ip: ClientIp) - if !_validate_token(&data.token) { error!("Invalid admin token. IP: {}", ip.ip); Err(Flash::error( - Redirect::to(ADMIN_PATH), + Redirect::to(admin_path()), "Invalid admin token, please try again.", )) } else { @@ -85,14 +89,14 @@ fn post_admin_login(data: Form<LoginForm>, mut cookies: Cookies, ip: ClientIp) - let jwt = encode_jwt(&claims); let cookie = Cookie::build(COOKIE_NAME, jwt) - .path(ADMIN_PATH) + .path(admin_path()) .max_age(chrono::Duration::minutes(20)) .same_site(SameSite::Strict) .http_only(true) .finish(); cookies.add(cookie); - Ok(Redirect::to(ADMIN_PATH)) + Ok(Redirect::to(admin_path())) } } @@ -167,7 +171,7 @@ fn invite_user(data: Json<InviteData>, _token: AdminToken, conn: DbConn) -> Empt #[get("/logout")] fn logout(mut cookies: Cookies) -> Result<Redirect, ()> { cookies.remove(Cookie::named(COOKIE_NAME)); - Ok(Redirect::to(ADMIN_PATH)) + Ok(Redirect::to(admin_path())) } #[get("/users")] diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs @@ -172,7 +172,7 @@ fn hibp_breach(username: String) -> JsonResult { "BreachDate": "2019-08-18T00:00:00Z", "AddedDate": "2019-08-18T00:00:00Z", "Description": format!("Go to: <a href=\"https://haveibeenpwned.com/account/{account}\" target=\"_blank\" rel=\"noopener\">https://haveibeenpwned.com/account/{account}</a> for a manual check.<br/><br/>HaveIBeenPwned API key not set!<br/>Go to <a href=\"https://haveibeenpwned.com/API/Key\" target=\"_blank\" rel=\"noopener\">https://haveibeenpwned.com/API/Key</a> to purchase an API key from HaveIBeenPwned.<br/><br/>", account=username), - "LogoPath": "/bwrs_static/hibp.png", + "LogoPath": "bwrs_static/hibp.png", "PwnCount": 0, "DataClasses": [ "Error - No API key set!" diff --git a/src/api/web.rs b/src/api/web.rs @@ -37,7 +37,17 @@ fn app_id() -> Cached<Content<Json<Value>>> { { "version": { "major": 1, "minor": 0 }, "ids": [ - &CONFIG.domain(), + // Per <https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-appid-and-facets-v2.0-id-20180227.html#determining-the-facetid-of-a-calling-application>: + // + // "In the Web case, the FacetID MUST be the Web Origin [RFC6454] + // of the web page triggering the FIDO operation, written as + // a URI with an empty path. Default ports are omitted and any + // path component is ignored." + // + // This leaves it unclear as to whether the path must be empty, + // or whether it can be non-empty and will be ignored. To be on + // the safe side, use a proper web origin (with empty path). + &CONFIG.domain_origin(), "ios:bundle-id:com.8bit.bitwarden", "android:apk-key-hash:dUGFzUzf3lmHSLBDBIv+WaFyZMI" ] }] @@ -75,6 +85,6 @@ fn static_files(filename: String) -> Result<Content<&'static [u8]>, Error> { "bootstrap-native-v4.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native-v4.js"))), "md5.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/md5.js"))), "identicon.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))), - _ => err!("Image not found"), + _ => err!(format!("Static file not found: {}", filename)), } } diff --git a/src/auth.rs b/src/auth.rs @@ -16,11 +16,11 @@ const JWT_ALGORITHM: Algorithm = Algorithm::RS256; lazy_static! { pub static ref DEFAULT_VALIDITY: Duration = Duration::hours(2); static ref JWT_HEADER: Header = Header::new(JWT_ALGORITHM); - pub static ref JWT_LOGIN_ISSUER: String = format!("{}|login", CONFIG.domain()); - pub static ref JWT_INVITE_ISSUER: String = format!("{}|invite", CONFIG.domain()); - pub static ref JWT_DELETE_ISSUER: String = format!("{}|delete", CONFIG.domain()); - pub static ref JWT_VERIFYEMAIL_ISSUER: String = format!("{}|verifyemail", CONFIG.domain()); - pub static ref JWT_ADMIN_ISSUER: String = format!("{}|admin", CONFIG.domain()); + pub static ref JWT_LOGIN_ISSUER: String = format!("{}|login", CONFIG.domain_origin()); + pub static ref JWT_INVITE_ISSUER: String = format!("{}|invite", CONFIG.domain_origin()); + pub static ref JWT_DELETE_ISSUER: String = format!("{}|delete", CONFIG.domain_origin()); + pub static ref JWT_VERIFYEMAIL_ISSUER: String = format!("{}|verifyemail", CONFIG.domain_origin()); + pub static ref JWT_ADMIN_ISSUER: String = format!("{}|admin", CONFIG.domain_origin()); static ref PRIVATE_RSA_KEY: Vec<u8> = match read_file(&CONFIG.private_rsa_key()) { Ok(key) => key, Err(e) => panic!("Error loading private RSA Key.\n Error: {}", e), diff --git a/src/config.rs b/src/config.rs @@ -1,6 +1,8 @@ use std::process::exit; use std::sync::RwLock; +use reqwest::Url; + use crate::error::Error; use crate::util::{get_env, get_env_bool}; @@ -240,6 +242,10 @@ make_config! { domain: String, true, def, "http://localhost".to_string(); /// Domain Set |> Indicates if the domain is set by the admin. Otherwise the default will be used. domain_set: bool, false, def, false; + /// Domain origin |> Domain URL origin (in https://example.com:8443/path, https://example.com:8443 is the origin) + domain_origin: String, false, auto, |c| extract_url_origin(&c.domain); + /// Domain path |> Domain URL path (in https://example.com:8443/path, /path is the path) + domain_path: String, false, auto, |c| extract_url_path(&c.domain); /// Enable web vault web_vault_enabled: bool, false, def, true; @@ -457,6 +463,21 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { Ok(()) } +/// Extracts an RFC 6454 web origin from a URL. +fn extract_url_origin(url: &str) -> String { + let url = Url::parse(url).expect("valid URL"); + + url.origin().ascii_serialization() +} + +/// Extracts the path from a URL. +/// All trailing '/' chars are trimmed, even if the path is a lone '/'. +fn extract_url_path(url: &str) -> String { + let url = Url::parse(url).expect("valid URL"); + + url.path().trim_end_matches('/').to_string() +} + impl Config { pub fn load() -> Result<Self, Error> { // Loading from env and file diff --git a/src/main.rs b/src/main.rs @@ -255,18 +255,20 @@ mod migrations { } fn launch_rocket(extra_debug: bool) { - // Create Rocket object, this stores current log level and sets it's own + // Create Rocket object, this stores current log level and sets its own let rocket = rocket::ignite(); - // If addding more base paths here, consider also adding them to + let basepath = &CONFIG.domain_path(); + + // If adding more paths here, consider also adding them to // crate::utils::LOGGED_ROUTES to make sure they appear in the log let rocket = rocket - .mount("/", api::web_routes()) - .mount("/api", api::core_routes()) - .mount("/admin", api::admin_routes()) - .mount("/identity", api::identity_routes()) - .mount("/icons", api::icons_routes()) - .mount("/notifications", api::notifications_routes()) + .mount(&[basepath, "/"].concat(), api::web_routes()) + .mount(&[basepath, "/api"].concat(), api::core_routes()) + .mount(&[basepath, "/admin"].concat(), api::admin_routes()) + .mount(&[basepath, "/identity"].concat(), api::identity_routes()) + .mount(&[basepath, "/icons"].concat(), api::icons_routes()) + .mount(&[basepath, "/notifications"].concat(), api::notifications_routes()) .manage(db::init_pool()) .manage(api::start_notification_server()) .attach(util::AppHeaders()) diff --git a/src/static/templates/admin/base.hbs b/src/static/templates/admin/base.hbs @@ -6,10 +6,10 @@ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Bitwarden_rs Admin Panel</title> - <link rel="stylesheet" href="/bwrs_static/bootstrap.css" /> - <script src="/bwrs_static/bootstrap-native-v4.js"></script> - <script src="/bwrs_static/md5.js"></script> - <script src="/bwrs_static/identicon.js"></script> + <link rel="stylesheet" href="bwrs_static/bootstrap.css" /> + <script src="bwrs_static/bootstrap-native-v4.js"></script> + <script src="bwrs_static/md5.js"></script> + <script src="bwrs_static/identicon.js"></script> <style> body { padding-top: 70px; @@ -38,10 +38,10 @@ <div class="navbar-collapse"> <ul class="navbar-nav"> <li class="nav-item active"> - <a class="nav-link" href="/admin">Admin Panel</a> + <a class="nav-link" href="admin">Admin Panel</a> </li> <li class="nav-item"> - <a class="nav-link" href="/">Vault</a> + <a class="nav-link" href=".">Vault</a> </li> </ul> </div> @@ -55,7 +55,7 @@ {{#if logged_in}} <li class="nav-item"> - <a class="nav-link" href="/admin/logout">Log Out</a> + <a class="nav-link" href="admin/logout">Log Out</a> </li> {{/if}} </ul> @@ -64,4 +64,4 @@ {{> (page_content) }} </body> -</html> -\ No newline at end of file +</html> diff --git a/src/static/templates/admin/page.hbs b/src/static/templates/admin/page.hbs @@ -225,7 +225,7 @@ var input_mail = prompt("To delete user '" + mail + "', please type the email below") if (input_mail != null) { if (input_mail == mail) { - _post("/admin/users/" + id + "/delete", + _post("admin/users/" + id + "/delete", "User deleted correctly", "Error deleting user"); } else { @@ -235,19 +235,19 @@ return false; } function remove2fa(id) { - _post("/admin/users/" + id + "/remove-2fa", + _post("admin/users/" + id + "/remove-2fa", "2FA removed correctly", "Error removing 2FA"); return false; } function deauthUser(id) { - _post("/admin/users/" + id + "/deauth", + _post("admin/users/" + id + "/deauth", "Sessions deauthorized correctly", "Error deauthorizing sessions"); return false; } function updateRevisions() { - _post("/admin/users/update_revision", + _post("admin/users/update_revision", "Success, clients will sync next time they connect", "Error forcing clients to sync"); return false; @@ -256,7 +256,7 @@ inv = document.getElementById("email-invite"); data = JSON.stringify({ "email": inv.value }); inv.value = ""; - _post("/admin/invite/", "User invited correctly", + _post("admin/invite/", "User invited correctly", "Error inviting user", data); return false; } @@ -278,7 +278,7 @@ } function saveConfig() { data = JSON.stringify(getFormData()); - _post("/admin/config/", "Config saved correctly", + _post("admin/config/", "Config saved correctly", "Error saving config", data); return false; } @@ -286,7 +286,7 @@ var input = prompt("This will remove all user configurations, and restore the defaults and the " + "values set by the environment. This operation could be dangerous. Type 'DELETE' to proceed:"); if (input === "DELETE") { - _post("/admin/config/delete", + _post("admin/config/delete", "Config deleted correctly", "Error deleting config"); } else { @@ -296,7 +296,7 @@ return false; } function backupDatabase() { - _post("/admin/config/backup_db", + _post("admin/config/backup_db", "Backup created successfully", "Error creating backup"); return false; @@ -336,4 +336,4 @@ // {{#each config}} {{#if grouptoggle}} masterCheck("input_{{grouptoggle}}", "#g_{{group}} input"); // {{/if}} {{/each}} -</script> -\ No newline at end of file +</script> diff --git a/src/static/templates/email/invite_accepted.hbs b/src/static/templates/email/invite_accepted.hbs @@ -3,6 +3,6 @@ Invitation accepted <html> <p> Your invitation for <b>{{email}}</b> to join <b>{{org_name}}</b> was accepted. - Please <a href="{{url}}">log in</a> to the bitwarden_rs server and confirm them from the organization management page. + Please <a href="{{url}}/">log in</a> to the bitwarden_rs server and confirm them from the organization management page. </p> </html> diff --git a/src/static/templates/email/invite_accepted.html.hbs b/src/static/templates/email/invite_accepted.html.hbs @@ -101,7 +101,7 @@ Invitation accepted </tr> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top"> - Please <a href="{{url}}">log in</a> to the bitwarden_rs server and confirm them from the organization management page. + Please <a href="{{url}}/">log in</a> to the bitwarden_rs server and confirm them from the organization management page. </td> </tr> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> diff --git a/src/static/templates/email/invite_confirmed.hbs b/src/static/templates/email/invite_confirmed.hbs @@ -3,6 +3,6 @@ Invitation to {{org_name}} confirmed <html> <p> Your invitation to join <b>{{org_name}}</b> was confirmed. - It will now appear under the Organizations the next time you <a href="{{url}}">log in</a> to the web vault. + It will now appear under the Organizations the next time you <a href="{{url}}/">log in</a> to the web vault. </p> </html> diff --git a/src/static/templates/email/invite_confirmed.html.hbs b/src/static/templates/email/invite_confirmed.html.hbs @@ -102,7 +102,7 @@ Invitation to {{org_name}} confirmed <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top"> Any collections and logins being shared with you by this organization will now appear in your Bitwarden vault. <br> - <a href="{{url}}">Log in</a> + <a href="{{url}}/">Log in</a> </td> </tr> </table> diff --git a/src/static/templates/email/new_device_logged_in.hbs b/src/static/templates/email/new_device_logged_in.hbs @@ -9,6 +9,6 @@ New Device Logged In From {{device}} Device Type: {{device}} You can deauthorize all devices that have access to your account from the - <a href="{{url}}">web vault</a> under Settings > My Account > Deauthorize Sessions. + <a href="{{url}}/">web vault</a> under Settings > My Account > Deauthorize Sessions. </p> </html> diff --git a/src/static/templates/email/new_device_logged_in.html.hbs b/src/static/templates/email/new_device_logged_in.html.hbs @@ -116,7 +116,7 @@ New Device Logged In From {{device}} </tr> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top"> - You can deauthorize all devices that have access to your account from the <a href="{{url}}">web vault</a> under Settings > My Account > Deauthorize Sessions. + You can deauthorize all devices that have access to your account from the <a href="{{url}}/">web vault</a> under Settings > My Account > Deauthorize Sessions. </td> </tr> </table> diff --git a/src/static/templates/email/pw_hint_some.hbs b/src/static/templates/email/pw_hint_some.hbs @@ -3,7 +3,7 @@ Your master password hint You (or someone) recently requested your master password hint. Your hint is: "{{hint}}" -Log in: <a href="{{url}}">Web Vault</a> +Log in: <a href="{{url}}/">Web Vault</a> If you cannot remember your master password, there is no way to recover your data. The only option to gain access to your account again is to <a href="{{url}}/#/recover-delete">delete the account</a> so that you can register again and start over. All data associated with your account will be deleted. diff --git a/src/static/templates/email/pw_hint_some.html.hbs b/src/static/templates/email/pw_hint_some.html.hbs @@ -102,7 +102,7 @@ Your master password hint <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top"> Your hint is: "{{hint}}"<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" /> - Log in: <a href="{{url}}">Web Vault</a> + Log in: <a href="{{url}}/">Web Vault</a> </td> </tr> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> diff --git a/src/static/templates/email/welcome.hbs b/src/static/templates/email/welcome.hbs @@ -2,7 +2,7 @@ Welcome <!----------------> <html> <p> -Thank you for creating an account at <a href="{{url}}">{{url}}</a>. You may now log in with your new account. +Thank you for creating an account at <a href="{{url}}/">{{url}}</a>. You may now log in with your new account. </p> <p>If you did not request to create an account, you can safely ignore this email.</p> </html> diff --git a/src/static/templates/email/welcome.html.hbs b/src/static/templates/email/welcome.html.hbs @@ -96,7 +96,7 @@ Welcome <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center"> - Thank you for creating an account at <a href="{{url}}">{{url}}</a>. You may now log in with your new account. + Thank you for creating an account at <a href="{{url}}/">{{url}}</a>. You may now log in with your new account. </td> </tr> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> diff --git a/src/static/templates/email/welcome_must_verify.hbs b/src/static/templates/email/welcome_must_verify.hbs @@ -2,7 +2,7 @@ Welcome <!----------------> <html> <p> -Thank you for creating an account at <a href="{{url}}">{{url}}</a>. Before you can login with your new account, you must verify this email address by clicking the link below. +Thank you for creating an account at <a href="{{url}}/">{{url}}</a>. Before you can login with your new account, you must verify this email address by clicking the link below. <br> <br> <a href="{{url}}/#/verify-email/?userId={{user_id}}&token={{token}}"> diff --git a/src/static/templates/email/welcome_must_verify.html.hbs b/src/static/templates/email/welcome_must_verify.html.hbs @@ -96,7 +96,7 @@ Welcome <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center"> - Thank you for creating an account at <a href="{{url}}">{{url}}</a>. Before you can login with your new account, you must verify this email address by clicking the link below. + Thank you for creating an account at <a href="{{url}}/">{{url}}</a>. Before you can login with your new account, you must verify this email address by clicking the link below. </td> </tr> <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;"> diff --git a/src/util.rs b/src/util.rs @@ -109,7 +109,7 @@ impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> { } } -// Log all the routes from the main base paths list, and the attachments endoint +// Log all the routes from the main paths list, and the attachments endpoint // Effectively ignores, any static file route, and the alive endpoint const LOGGED_ROUTES: [&str; 6] = [ "/api", @@ -157,7 +157,10 @@ impl Fairing for BetterLogging { } let uri = request.uri(); let uri_path = uri.path(); - if self.0 || LOGGED_ROUTES.iter().any(|r| uri_path.starts_with(r)) { + // FIXME: trim_start_matches() could result in over-trimming in pathological cases; + // strip_prefix() would be a better option once it's stable. + let uri_subpath = uri_path.trim_start_matches(&CONFIG.domain_path()); + if self.0 || LOGGED_ROUTES.iter().any(|r| uri_subpath.starts_with(r)) { match uri.query() { Some(q) => info!(target: "request", "{} {}?{}", method, uri_path, &q[..q.len().min(30)]), None => info!(target: "request", "{} {}", method, uri_path), @@ -169,8 +172,10 @@ impl Fairing for BetterLogging { if !self.0 && request.method() == Method::Options { return; } - let uri_path = request.uri().path(); - if self.0 || LOGGED_ROUTES.iter().any(|r| uri_path.starts_with(r)) { + // FIXME: trim_start_matches() could result in over-trimming in pathological cases; + // strip_prefix() would be a better option once it's stable. + let uri_subpath = request.uri().path().trim_start_matches(&CONFIG.domain_path()); + if self.0 || LOGGED_ROUTES.iter().any(|r| uri_subpath.starts_with(r)) { let status = response.status(); if let Some(ref route) = request.route() { info!(target: "response", "{} => {} {}", route, status.code, status.reason)