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:
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.