Merge pull request #868 from jjlin/alt-base
Add backend support for alternate base dir (subdir/subpath) hosting
This commit is contained in:
commit
8a5450e830
|
@ -31,7 +31,7 @@
|
|||
{% endif %}
|
||||
FROM {{ vault_stage_base_image }} as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
|
@ -42,8 +42,7 @@ RUN apk add --no-cache --upgrade curl tar
|
|||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
{% endif %}
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
{% if "alpine" in vault_stage_base_image %}
|
||||
SHELL ["/bin/ash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM alpine:3.11 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
RUN apk add --no-cache --upgrade curl tar
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/ash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM alpine:3.11 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
RUN apk add --no-cache --upgrade curl tar
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/ash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM alpine:3.11 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
RUN apk add --no-cache --upgrade curl tar
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/ash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
####################### VAULT BUILD IMAGE #######################
|
||||
FROM rust:1.40 as vault
|
||||
|
||||
ENV VAULT_VERSION "v2.12.0c"
|
||||
ENV VAULT_VERSION "v2.12.0d"
|
||||
|
||||
ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz"
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
||||
RUN mkdir /web-vault
|
||||
WORKDIR /web-vault
|
||||
WORKDIR /
|
||||
|
||||
SHELL ["/bin/bash", "-o", "nounset", "-o", "pipefail", "-o", "errexit", "-c"]
|
||||
|
||||
|
|
|
@ -52,11 +52,15 @@ 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
|
||||
let msg = flash.map(|msg| format!("{}: {}", msg.name(), msg.msg()));
|
||||
let json = json!({"page_content": "admin/login", "version": VERSION, "error": msg});
|
||||
let json = json!({"page_content": "admin/login", "version": VERSION, "error": msg, "urlpath": CONFIG.domain_path()});
|
||||
|
||||
// Return the page
|
||||
let text = CONFIG.render_template(BASE_TEMPLATE, &json)?;
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,6 +115,7 @@ struct AdminTemplateData {
|
|||
config: Value,
|
||||
can_backup: bool,
|
||||
logged_in: bool,
|
||||
urlpath: String,
|
||||
}
|
||||
|
||||
impl AdminTemplateData {
|
||||
|
@ -122,6 +127,7 @@ impl AdminTemplateData {
|
|||
config: CONFIG.prepare_json(),
|
||||
can_backup: *CAN_BACKUP,
|
||||
logged_in: true,
|
||||
urlpath: CONFIG.domain_path(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +173,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")]
|
||||
|
|
|
@ -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!"
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
10
src/auth.rs
10
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),
|
||||
|
|
|
@ -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
|
||||
|
|
18
src/main.rs
18
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())
|
||||
|
|
|
@ -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="{{urlpath}}/bwrs_static/bootstrap.css" />
|
||||
<script src="{{urlpath}}/bwrs_static/bootstrap-native-v4.js"></script>
|
||||
<script src="{{urlpath}}/bwrs_static/md5.js"></script>
|
||||
<script src="{{urlpath}}/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="{{urlpath}}/admin">Admin Panel</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Vault</a>
|
||||
<a class="nav-link" href="{{urlpath}}/">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="{{urlpath}}/admin/logout">Log Out</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
@ -64,4 +64,4 @@
|
|||
{{> (page_content) }}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<span class="d-block">{{Email}}</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<strong> Organizations:</strong>
|
||||
<strong> Organizations: </strong>
|
||||
<span class="d-block">
|
||||
{{#each Organizations}}
|
||||
<span class="badge badge-primary" data-orgtype="{{Type}}">{{Name}}</span>
|
||||
|
@ -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("{{urlpath}}/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("{{urlpath}}/admin/users/" + id + "/remove-2fa",
|
||||
"2FA removed correctly",
|
||||
"Error removing 2FA");
|
||||
return false;
|
||||
}
|
||||
function deauthUser(id) {
|
||||
_post("/admin/users/" + id + "/deauth",
|
||||
_post("{{urlpath}}/admin/users/" + id + "/deauth",
|
||||
"Sessions deauthorized correctly",
|
||||
"Error deauthorizing sessions");
|
||||
return false;
|
||||
}
|
||||
function updateRevisions() {
|
||||
_post("/admin/users/update_revision",
|
||||
_post("{{urlpath}}/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("{{urlpath}}/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("{{urlpath}}/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("{{urlpath}}/admin/config/delete",
|
||||
"Config deleted correctly",
|
||||
"Error deleting config");
|
||||
} else {
|
||||
|
@ -296,7 +296,7 @@
|
|||
return false;
|
||||
}
|
||||
function backupDatabase() {
|
||||
_post("/admin/config/backup_db",
|
||||
_post("{{urlpath}}/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>
|
||||
</script>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;">
|
||||
|
|
|
@ -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}}">
|
||||
|
|
|
@ -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;">
|
||||
|
|
13
src/util.rs
13
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)
|
||||
|
|
Loading…
Reference in New Issue