]> jfr.im git - irc/quakenet/qwebirc.git/blobdiff - qwebirc/ajaxengine.py
Add QTicket support!
[irc/quakenet/qwebirc.git] / qwebirc / ajaxengine.py
index 84b4a0982137cf6973f3f409ee2c517a71b1fb6f..336feb24cf56ef15abe871b69f97fdfebdb67b63 100644 (file)
@@ -1,26 +1,36 @@
 from twisted.web import resource, server, static
 from twisted.names import client
 from twisted.internet import reactor
-import traceback
-import simplejson, md5, sys, os, ircclient, time, config, weakref
+from authgateengine import login_optional, getSessionData
+import simplejson, md5, sys, os, ircclient, time, config, weakref, traceback
 
 Sessions = {}
 
 def get_session_id():
-  return md5.md5(os.urandom(16)).hexdigest()[:10]
+  return md5.md5(os.urandom(16)).hexdigest()
 
 class BufferOverflowException(Exception):
   pass
 
+class AJAXException(Exception):
+  pass
+  
 class IDGenerationException(Exception):
   pass
 
+NOT_DONE_YET = None
+
 def jsondump(fn):
   def decorator(*args, **kwargs):
-    x = fn(*args, **kwargs)
-    if isinstance(x, list):
-      return simplejson.dumps(x)
-    return x
+    try:
+      x = fn(*args, **kwargs)
+      if x is None:
+        return server.NOT_DONE_YET
+      x = (True, x)
+    except AJAXException, e:
+      x = (False, e[0])
+      
+    return simplejson.dumps(x)
   return decorator
 
 def cleanupSession(id):
@@ -41,7 +51,7 @@ class IRCSession:
 
   def subscribe(self, channel):
     if len(self.subscriptions) >= config.MAXSUBSCRIPTIONS:
-      self.subscriptions.pop(0)
+      self.subscriptions.pop(0).close()
 
     self.subscriptions.append(channel)
     self.flush()
@@ -111,6 +121,9 @@ class SingleUseChannel(Channel):
     self.request.finish()
     return False
     
+  def close(self):
+    self.request.finish()
+    
 class MultipleUseChannel(Channel):
   def write(self, data):
     self.request.write(data)
@@ -125,72 +138,95 @@ class AJAXEngine(resource.Resource):
   @jsondump
   def render_POST(self, request):
     path = request.path[len(self.prefix):]
-    if path == "/n":
-      ip = request.transport.getPeer()
-      ip = ip[1]
-
-      nick, ident = request.args.get("nick"), "webchat"
-      if not nick:
-        return [False, "Nickname not supplied"]
-        
-      nick = nick[0]
-
-      for i in xrange(10):
-        id = get_session_id()
-        if not Sessions.get(id):
-          break
-      else:
-        raise IDGenerationException()
-
-      session = IRCSession(id)
+    if path[0] == "/":
+      handler = self.COMMANDS.get(path[1:])
+      if handler is not None:
+        return handler(self, request)
+    raise AJAXException("404")
+
+#  def render_GET(self, request):
+#    return self.render_POST(request)
+  
+  def newConnection(self, request):
+    ticket = login_optional(request)
+    
+    _, ip, port = request.transport.getPeer()
 
-      client = ircclient.createIRC(session, nick=nick, ident=ident, ip=ip, realname=config.REALNAME)
-      session.client = client
+    nick, ident, realname = request.args.get("nick"), "webchat", config.REALNAME
+    
+    if not ticket is None:
+      realname = "%s (%s:%d:%s)" % (realname, ticket.username, ticket.id, ticket.authflags)
       
-      Sessions[id] = session
+    if not nick:
+      raise AJAXException("Nickname not supplied")
       
-      return [True, id]    
-    return [False, "404"]
+    nick = nick[0]
 
-  @jsondump
-  def render_GET(self, request):
-    path = request.path[len(self.prefix):]
-    if path.startswith("/s/"):
-      sessionid = path[3:]
-      session = Sessions.get(sessionid)
-      
-      if not session:
-        return [False, "Bad session ID"]
+    for i in xrange(10):
+      id = get_session_id()
+      if not Sessions.get(id):
+        break
+    else:
+      raise IDGenerationException()
 
-      session.subscribe(SingleUseChannel(request))
-      return server.NOT_DONE_YET
-    if path.startswith("/p/"):
-      command = request.args.get("c")
-      if not command:
-        return [False, "No command specified"]
+    session = IRCSession(id)
 
-      command = command[0]
+    qticket = getSessionData(request).get("qticket")
+    if qticket is None:
+      perform = None
+    else:
+      perform = ["PRIVMSG %s :TICKETAUTH %s" % (config.QBOT, qticket)]
+
+    client = ircclient.createIRC(session, nick=nick, ident=ident, ip=ip, realname=realname, perform=perform)
+    session.client = client
+    
+    Sessions[id] = session
+    
+    return id
+  
+  def getSession(self, request):
+    sessionid = request.args.get("s")
+    if sessionid is None:
+      raise AJAXException("Bad session ID")
       
-      sessionid = path[3:]
-      session = Sessions.get(sessionid)
-      if not session:
-        return [False, "Bad session ID"]
-
-      try:
-        decoded = command.decode("utf-8")
-      except UnicodeDecodeError:
-        decoded = command.decode("iso-8859-1", "ignore")
-
-      try:
-        session.push(decoded)
-      except AttributeError: # occurs when we haven't noticed an error
-        session.disconnect()
-        return [False, "Connection closed by server."]
-      except Exception, e: # catch all
-        session.disconnect()        
-        traceback.print_exc(file=sys.stderr)
-        return [False, "Unknown error."]
+    session = Sessions.get(sessionid[0])
+    if not session:
+      raise AJAXException("Bad session ID")
+    return session
     
-      return [True]
+  def subscribe(self, request):
+    self.getSession(request).subscribe(SingleUseChannel(request))
+    return NOT_DONE_YET
+
+  def push(self, request):
+    command = request.args.get("c")
+    if command is None:
+      raise AJAXException("No command specified")
 
-    return [False, "404"]
+    command = command[0]
+    
+    session = self.getSession(request)
+
+    try:
+      decoded = command.decode("utf-8")
+    except UnicodeDecodeError:
+      decoded = command.decode("iso-8859-1", "ignore")
+
+    if len(decoded) > config.MAXLINELEN:
+      session.disconnect()
+      raise AJAXException("Line too long")
+
+    try:
+      session.push(decoded)
+    except AttributeError: # occurs when we haven't noticed an error
+      session.disconnect()
+      raise AJAXException("Connection closed by server.")
+    except Exception, e: # catch all
+      session.disconnect()        
+      traceback.print_exc(file=sys.stderr)
+      raise AJAXException("Unknown error.")
+  
+    return True
+  
+  COMMANDS = dict(p=push, n=newConnection, s=subscribe)
+  
\ No newline at end of file