]> jfr.im git - irc/quakenet/qwebirc.git/blobdiff - qwebirc/root.py
add dynamic configuration support
[irc/quakenet/qwebirc.git] / qwebirc / root.py
index 99464c1fb93d91edf97fcc92e81a66f6f6f80038..6afaa0fdc81cfae4f66641a06d9e09f4b22699f8 100644 (file)
@@ -1,9 +1,11 @@
+from twisted.protocols.policies import TimeoutMixin
 from twisted.web import resource, server, static, http
 from twisted.internet import error, reactor
 import engines
 import mimetypes
 import config
 import sigdebug
 from twisted.web import resource, server, static, http
 from twisted.internet import error, reactor
 import engines
 import mimetypes
 import config
 import sigdebug
+import re
 
 class RootResource(resource.Resource):
   def getChild(self, name, request):
 
 class RootResource(resource.Resource):
   def getChild(self, name, request):
@@ -11,38 +13,65 @@ class RootResource(resource.Resource):
       name = "qui.html"
     return self.primaryChild.getChild(name, request)
 
       name = "qui.html"
     return self.primaryChild.getChild(name, request)
 
-# we do NOT use the built-in timeOut mixin as it's very very buggy!
-class TimeoutHTTPChannel(http.HTTPChannel):
-  timeout = config.HTTP_REQUEST_TIMEOUT
-
-  def connectionMade(self):
-    self.customTimeout = reactor.callLater(self.timeout, self.timeoutOccured)
-    http.HTTPChannel.connectionMade(self)
-    
-  def timeoutOccured(self):
-    self.customTimeout = None
-    self.transport.loseConnection()
+class WrappedRequest(server.Request):
+  ip_re = re.compile(r"^((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})|(::|(([a-fA-F0-9]{1,4}):){7}(([a-fA-F0-9]{1,4}))|(:(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){1,6}:)|((([a-fA-F0-9]{1,4}):)(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){2}(:([a-fA-F0-9]{1,4})){1,5})|((([a-fA-F0-9]{1,4}):){3}(:([a-fA-F0-9]{1,4})){1,4})|((([a-fA-F0-9]{1,4}):){4}(:([a-fA-F0-9]{1,4})){1,3})|((([a-fA-F0-9]{1,4}):){5}(:([a-fA-F0-9]{1,4})){1,2})))$", re.IGNORECASE)
+  def validIP(self, ip):
+    m = self.ip_re.match(ip)
+    if m is None:
+      return False
+    return True
     
     
-  def cancelTimeout(self):
-    if self.customTimeout is not None:
-      try:
-        self.customTimeout.cancel()
-        self.customTimeout = None
-      except error.AlreadyCalled:
-        pass
-
-  def connectionLost(self, reason):
-    self.cancelTimeout()
-    http.HTTPChannel.connectionLost(self, reason)
+  def _getClientIP(self):
+    # twisted.web.http.Request.getClientIP returns None if not IPv4;
+    # client.host has the real address
+
+    if not hasattr(self, "client") or not hasattr(self.client, "host"):
+        return None
+
+    real_ip = self.client.host
+
+    if real_ip[:7] == "::ffff:":
+      real_ip = real_ip[7:]
+
+    if not hasattr(config, "FORWARDED_FOR_HEADER"):
+      return real_ip
+
+    if real_ip not in config.FORWARDED_FOR_IPS:
+      return real_ip
+      
+    fake_ips = self.getHeader(config.FORWARDED_FOR_HEADER)
+    if fake_ips is None:
+      return real_ip
+      
+    fake_ip = fake_ips.split(",")[-1].strip()
+    if not self.validIP(fake_ip):
+      return real_ip
+      
+    return fake_ip
+
+  def getClientIP(self):
+    ip = self._getClientIP()
+
+    if ip is None:
+      return None
+
+    # make absolutely sure that the address doesn't start with : before we
+    # try to use it as a string to the IRC server!
+    return ip.lstrip(":")
+
+class HTTPChannel(http.HTTPChannel):
+  def timeoutConnection(self):
+    self.transport.abortConnection()
 
 class RootSite(server.Site):
 
 class RootSite(server.Site):
-  # we do this ourselves as the built in timeout stuff is really really buggy
-  protocol = TimeoutHTTPChannel
-  
+  protocol = HTTPChannel
+
+  requestFactory = WrappedRequest
+
   def __init__(self, path, *args, **kwargs):
     root = RootResource()
   def __init__(self, path, *args, **kwargs):
     root = RootResource()
+    kwargs["timeout"] = config.HTTP_REQUEST_TIMEOUT
     server.Site.__init__(self, root, *args, **kwargs)
     server.Site.__init__(self, root, *args, **kwargs)
-
     services = {}
     services["StaticEngine"] = root.primaryChild = engines.StaticEngine(path)
 
     services = {}
     services["StaticEngine"] = root.primaryChild = engines.StaticEngine(path)
 
@@ -52,7 +81,10 @@ class RootSite(server.Site):
       root.putChild(path, sobj)
       
     register(engines.AJAXEngine, "e")
       root.putChild(path, sobj)
       
     register(engines.AJAXEngine, "e")
-    register(engines.FeedbackEngine, "feedback")
+    try:
+      register(engines.WebSocketEngine, "w")
+    except AttributeError:
+      pass
     register(engines.AuthgateEngine, "auth")
     register(engines.AdminEngine, "adminengine", services)
     
     register(engines.AuthgateEngine, "auth")
     register(engines.AdminEngine, "adminengine", services)