]> jfr.im git - irc/quakenet/qwebirc.git/blob - twisted/plugins/webirc.py
Merge.
[irc/quakenet/qwebirc.git] / twisted / plugins / webirc.py
1 from zope.interface import implements
2
3 from twisted.python import usage
4
5 from twisted.internet import task, protocol
6 from twisted.protocols import basic, policies
7 from twisted.plugin import IPlugin
8 from twisted.application.service import IServiceMaker
9 from twisted.application import internet, strports, service
10 from twisted.web import static, server
11 import urlparse
12 import urllib
13
14 from qwebirc.root import RootSite
15
16 class Options(usage.Options):
17 optParameters = [["port", "p", "9090","Port to start the server on."],
18 ["ip", "i", "0.0.0.0", "IP address to listen on."],
19 ["logfile", "l", None, "Path to web CLF (Combined Log Format) log file."],
20 ["https", None, None, "Port to listen on for Secure HTTP."],
21 ["certificate", "c", "server.pem", "SSL certificate to use for HTTPS. "],
22 ["privkey", "k", "server.pem", "SSL certificate to use for HTTPS."],
23 ["certificate-chain", "C", None, "Chain SSL certificate"],
24 ["staticpath", "s", "static", "Path to static content"],
25 ["flashPort", None, None, "Port to listen on for flash policy connections."],
26 ]
27
28 optFlags = [["notracebacks", "n", "Display tracebacks in broken web pages. " +
29 "Displaying tracebacks to users may be security risk!"],
30 ]
31
32 def postOptions(self):
33 if self['https']:
34 try:
35 get_ssl_factory_factory()
36 except ImportError:
37 raise usage.UsageError("SSL support not installed")
38
39 class FlashPolicyProtocol(protocol.Protocol, policies.TimeoutMixin):
40 def connectionMade(self):
41 self.setTimeout(5)
42
43 def dataReceived(self, data):
44 if data == '<policy-file-request/>\0':
45 self.transport.write(self.factory.response_body)
46 self.transport.loseConnection()
47 return
48 elif self.factory.childProtocol:
49 self.setTimeout(None)
50 p = self.factory.childProtocol.buildProtocol(self.transport.client)
51 p.transport = self.transport
52 self.transport.protocol = p
53 p.connectionMade()
54 p.dataReceived(data)
55 else:
56 self.transport.loseConnection()
57
58 class FlashPolicyFactory(protocol.ServerFactory):
59 protocol = FlashPolicyProtocol
60
61 def __init__(self, childProtocol=None):
62 import config
63 base_url = urlparse.urlparse(config.BASE_URL)
64 port = base_url.port
65 if port is None:
66 if base_url.scheme == "http":
67 port = 80
68 elif base_url.scheme == "https":
69 port = 443
70 else:
71 raise Exception("Unknown scheme: " + base_url.scheme)
72
73 self.childProtocol = childProtocol
74 self.response_body = """<cross-domain-policy>
75 <allow-access-from domain="%s" to-ports="%d" />
76 </cross-domain-policy>""" % (urllib.quote(base_url.hostname), port) + '\0'
77
78 class QWebIRCServiceMaker(object):
79 implements(IServiceMaker, IPlugin)
80 tapname = "qwebirc"
81 description = "QuakeNet web-based IRC client"
82 options = Options
83
84 def makeService(self, config):
85 if config['logfile']:
86 site = RootSite(config['staticpath'], logPath=config['logfile'])
87 else:
88 site = RootSite(config['staticpath'])
89
90 s = service.MultiService()
91 site.displayTracebacks = not config["notracebacks"]
92 if config['https']:
93 ssl_factory = get_ssl_factory_factory()
94 i = internet.SSLServer(int(config['https']), site, ssl_factory(config['privkey'], config['certificate'], certificateChainFile=config["certificate-chain"]), interface=config['ip'])
95 else:
96 i = internet.TCPServer(int(config['port']), FlashPolicyFactory(site), interface=config['ip'])
97
98 i.setServiceParent(s)
99 if config["flashPort"]:
100 f = internet.TCPServer(int(config['flashPort']), FlashPolicyFactory(), interface=config['ip'])
101 f.setServiceParent(s)
102
103 return s
104
105 def get_ssl_factory_factory():
106 from twisted.internet.ssl import DefaultOpenSSLContextFactory
107 class ChainingOpenSSLContextFactory(DefaultOpenSSLContextFactory):
108 def __init__(self, *args, **kwargs):
109 self.chain = None
110 if kwargs.has_key("certificateChainFile"):
111 self.chain = kwargs["certificateChainFile"]
112 del kwargs["certificateChainFile"]
113
114 DefaultOpenSSLContextFactory.__init__(self, *args, **kwargs)
115
116 def cacheContext(self):
117 DefaultOpenSSLContextFactory.cacheContext(self)
118 if self.chain:
119 self._context.use_certificate_chain_file(self.chain)
120 self._context.use_privatekey_file(self.privateKeyFileName)
121
122 return ChainingOpenSSLContextFactory
123
124 serviceMaker = QWebIRCServiceMaker()