### # Copyright (c) 2005, Ali Afshar # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions, and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the author of this software nor the name of # contributors to this software may be used to endorse or promote products # derived from this software without specific prior written consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ### import time from twisted.internet import reactor from twisted.web import server, resource from gwbase import BasePlugin class WebUser(object): def __init__(self, user): self.user = user self.hostmask = user.gwhm self.rbuf = [] def sendReply(self, reply, inreply): news = """
[%s] %s
""" self.rbuf.append(news % (inreply.strip(), reply.strip())) def close(self): self.user.clearAuth() self.cb._connections.remove(self) class WebGW(BasePlugin): PROTOCOL = 'http' USERCLASS = WebUser DEFAULT_PORT = 9080 CONFIG_EXTRA = [('refreshRate', 'Integer', 15, """Web interface will refresh every X seconds."""), ('sessionTimeout', 'Integer', 300, """Timeout for inactivity."""), ('@html',None, None, """HTML Options"""), ('html.replyFontSize', 'String', 'Small', """Default font size for replies."""), ('html.replyFontColor', 'String', 'Black', """Default font color for replies."""), ('html.inReplyFontColor', 'String', 'Blue', """Default font color for the command calling a reply."""), ('html.contentBackgroundColor', 'String', 'white', """Default background color for the main content area."""), ('html.generalFontSize', 'String', 'small', """Default general font size."""), ('html.borderColor', 'String', '#999999', """Border color for content areas."""), ('html.buttonBackgroundColor', 'String', '#ededed', """Default background color for input buttons.""")] class FactoryClass(server.Site): def __init__(self): server.Site.__init__(self, MainPage()) def makeSession(self): """Generate a new Session instance, and store it for future reference. """ uid = self._mkuid() s = SBSession(self, uid) s.expiryTimeout = self.cb.personalRegistryValue('sessionTimeout') session = self.sessions[uid] = s reactor.callLater(s.expiryTimeout, s.checkExpired) return session class SBSession(server.Session): def checkExpired(self): # If I haven't been touched in 15 minutes: if time.time() - self.lastModified > self.expiryTimeout: if self.site.sessions.has_key(self.uid): self.expire() else: pass #log.msg("no session to expire: %s" % self.uid) else: #log.msg("session given the will to live for 30 more minutes") reactor.callLater(self.expiryTimeout, self.checkExpired) class MainPage(resource.Resource): def isAuthd(self, request): return hasattr(request.getSession(), 'authd') def getHostmask(self, request): return request.getSession().authd.hostmask def getRbuf(self, request): if len(request.getSession().authd.rbuf) > 10: request.getSession().authd.rbuf = request.getSession().authd.rbuf[-10:] return ''.join(request.getSession().authd.rbuf) def render_GET(self, request): refreshTime = False if len(request.args): if 'refresh' in request.args: refreshTime = int(request.args['refresh'].pop()) if refreshTime < 10: refreshTime = 10 return self.render_ALL(request, self.isAuthd(request), refreshTime) def render_POST(self, request): isAuthd = self.isAuthd(request) if isAuthd: cmd = request.args['command'].pop() if len(cmd): if cmd == 'logout': request.redirect('/logout') return 'logging out' else: request.getSession().site.cb.cb.receivedCommand(cmd, request.getSession().authd) return self.render_ALL(request, isAuthd) def render_ALL(self, request, isAuthd, refresh=10): rs = '' if refresh: rs = """""" % (refresh, refresh) content = '' loginLine = '' if isAuthd: loginLine = 'You are logged in as %s.' % self.getHostmask(request) content = self.getRbuf(request) else: loginLine = 'You are not Logged in.' content = TLOGIN htmlopt = lambda v: \ request.getSession().site.cb.personalRegistryValue('html.%s' % v) page = TALL % {'content':content, 'postForm': TPOST, 'controlBar': TCONTROL, 'loginLine': loginLine, 'fontSize':htmlopt('generalFontSize'), 'replySize': htmlopt('replyFontSize'), 'replyColor': htmlopt('replyFontColor'), 'inReplyColor': htmlopt('inReplyFontColor'), 'contentBackground': htmlopt('contentBackgroundColor'), 'controlBackground': htmlopt('buttonBackgroundColor'), 'borderColor': htmlopt('borderColor')} return page def getChild(self, name, request): if name == 'login': return LoginPage() elif name == 'logout': return LogoutPage() else: return self class LogoutPage(resource.Resource): isLeaf = True def render_GET(self, request): if hasattr(request.getSession(), 'authd'): #authd = request.getSession().authd #authd.close() #del request.getSession().authd request.getSession().expire() request.redirect('/') return 'logout' class LoginPage(resource.Resource): isLeaf = True def render_GET(self, request): request.redirect('/') return 'no GET' def render_POST(self, request): #request.isSecure() #request.getClientIP() un = request.args['name'].pop() pw = request.args['pass'].pop() sess = request.getSession() a = sess.site.cb.cb.getUser(username=un, password=pw, protocol=request.getSession().site.cb.PROTOCOL, peer=request.getClientIP()) if a: sess.authd = request.getSession().site.cb.USERCLASS(a) sess.authd.cb = sess.site.cb sess.notifyOnExpire(sess.authd.close) sess.site.cb.authorised(sess.authd) request.redirect('/') return 'authd' else: sess.expire() request.redirect('/') return 'failed' THEAD = """ """ TCONTROL = """
refresh log out
""" TPOST = """
""" TBODY = """
%(controlBar)s
%(loginLine)s %(content)s
%(postForm)s
""" TALL = """ %(head)s %(body)s """ % {'head':THEAD, 'body':TBODY} TLOGIN = """
Log in here.
Username
Password
""" # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: