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 88c56de97b48bb5b9b8af350d0d0e0d5f080ff0e
parent e274af6e3db0572bcd6acb8a89485e2fc4d9111b
Author: Daniel GarcĂ­a <dani-garcia@users.noreply.github.com>
Date:   Fri, 27 Dec 2019 18:42:39 +0100

Config option for client IP header

Diffstat:
M.env.template | 4++++
Msrc/auth.rs | 17+++++++++++++----
Msrc/config.rs | 14++++++++++++--
3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/.env.template b/.env.template @@ -21,6 +21,10 @@ ## Automatically reload the templates for every request, slow, use only for development # RELOAD_TEMPLATES=false +## Client IP Header, used to identify the IP of the client, defaults to "X-Client-IP" +## Set to the string "none" (without quotes), to disable any headers and just use the remote IP +# IP_HEADER=X-Client-IP + ## Cache time-to-live for successfully obtained icons, in seconds (0 is "forever") # ICON_CACHE_TTL=2592000 ## Cache time-to-live for icons which weren't available, in seconds (0 is "forever") diff --git a/src/auth.rs b/src/auth.rs @@ -426,12 +426,21 @@ pub struct ClientIp { impl<'a, 'r> FromRequest<'a, 'r> for ClientIp { type Error = (); - fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { - let ip = match request.client_ip() { - Some(addr) => addr, - None => "0.0.0.0".parse().unwrap(), + fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { + let ip = if CONFIG._ip_header_enabled() { + req.headers().get_one(&CONFIG.ip_header()).and_then(|ip| { + ip.parse() + .map_err(|_| warn_!("'{}' header is malformed: {}", CONFIG.ip_header(), ip)) + .ok() + }) + } else { + None }; + let ip = ip + .or_else(|| req.remote().map(|r| r.ip())) + .unwrap_or_else(|| "0.0.0.0".parse().unwrap()); + Outcome::Success(ClientIp { ip }) } } diff --git a/src/config.rs b/src/config.rs @@ -185,19 +185,24 @@ macro_rules! make_config { } } }}; + ( @build $value:expr, $config:expr, gen, $default_fn:expr ) => {{ + let f: &dyn Fn(&ConfigItems) -> _ = &$default_fn; + f($config) + }}; } //STRUCTURE: // /// Short description (without this they won't appear on the list) // group { // /// Friendly Name |> Description (Optional) -// name: type, is_editable, none_action, <default_value (Optional)> +// name: type, is_editable, action, <default_value (Optional)> // } // -// Where none_action applied when the value wasn't provided and can be: +// Where action applied when the value wasn't provided and can be: // def: Use a default value // auto: Value is auto generated based on other values // option: Value is optional +// gen: Value is always autogenerated and it's original value ignored make_config! { folders { /// Data folder |> Main data folder @@ -266,6 +271,11 @@ make_config! { /// Advanced settings advanced { + /// Client IP header |> If not present, the remote IP is used. + /// Set to the string "none" (without quotes), to disable any headers and just use the remote IP + ip_header: String, true, def, "X-Real-IP".to_string(); + /// Internal IP header property, used to avoid recomputing each time + _ip_header_enabled: bool, false, gen, |c| &c.ip_header.trim().to_lowercase() != "none"; /// Positive icon cache expiry |> Number of seconds to consider that an already cached icon is fresh. After this period, the icon will be redownloaded icon_cache_ttl: u64, true, def, 2_592_000; /// Negative icon cache expiry |> Number of seconds before trying to download an icon that failed again.