Browse Source

Config option for client IP header

Daniel García 6 years ago
parent
commit
88c56de97b
3 changed files with 29 additions and 6 deletions
  1. 4 0
      .env.template
  2. 13 4
      src/auth.rs
  3. 12 2
      src/config.rs

+ 4 - 0
.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")

+ 13 - 4
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 })
     }
 }

+ 12 - 2
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.