1 from zope
.interface
import implements
3 from twisted
.python
import usage
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
14 from qwebirc
.root
import RootSite
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."],
28 optFlags
= [["notracebacks", "n", "Display tracebacks in broken web pages. " +
29 "Displaying tracebacks to users may be security risk!"],
32 def postOptions(self
):
35 get_ssl_factory_factory()
37 raise usage
.UsageError("SSL support not installed")
39 class FlashPolicyProtocol(protocol
.Protocol
, policies
.TimeoutMixin
):
40 def connectionMade(self
):
43 def dataReceived(self
, data
):
44 if data
== '<policy-file-request/>\0':
45 self
.transport
.write(self
.factory
.response_body
)
46 self
.transport
.loseConnection()
48 elif self
.factory
.childProtocol
:
50 p
= self
.factory
.childProtocol
.buildProtocol(self
.transport
.client
)
51 p
.transport
= self
.transport
52 self
.transport
.protocol
= p
56 self
.transport
.loseConnection()
58 class FlashPolicyFactory(protocol
.ServerFactory
):
59 protocol
= FlashPolicyProtocol
61 def __init__(self
, childProtocol
=None):
63 base_url
= urlparse
.urlparse(config
.BASE_URL
)
66 if base_url
.scheme
== "http":
68 elif base_url
.scheme
== "https":
71 raise Exception("Unknown scheme: " + base_url
.scheme
)
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'
78 class QWebIRCServiceMaker(object):
79 implements(IServiceMaker
, IPlugin
)
81 description
= "QuakeNet web-based IRC client"
84 def makeService(self
, config
):
86 site
= RootSite(config
['staticpath'], logPath
=config
['logfile'])
88 site
= RootSite(config
['staticpath'])
90 s
= service
.MultiService()
91 site
.displayTracebacks
= not config
["notracebacks"]
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'])
96 i
= internet
.TCPServer(int(config
['port']), FlashPolicyFactory(site
), interface
=config
['ip'])
99 if config
["flashPort"]:
100 f
= internet
.TCPServer(int(config
['flashPort']), FlashPolicyFactory(), interface
=config
['ip'])
101 f
.setServiceParent(s
)
105 def get_ssl_factory_factory():
106 from twisted
.internet
.ssl
import DefaultOpenSSLContextFactory
107 class ChainingOpenSSLContextFactory(DefaultOpenSSLContextFactory
):
108 def __init__(self
, *args
, **kwargs
):
110 if kwargs
.has_key("certificateChainFile"):
111 self
.chain
= kwargs
["certificateChainFile"]
112 del kwargs
["certificateChainFile"]
114 DefaultOpenSSLContextFactory
.__init
__(self
, *args
, **kwargs
)
116 def cacheContext(self
):
117 DefaultOpenSSLContextFactory
.cacheContext(self
)
119 self
._context
.use_certificate_chain_file(self
.chain
)
120 self
._context
.use_privatekey_file(self
.privateKeyFileName
)
122 return ChainingOpenSSLContextFactory
124 serviceMaker
= QWebIRCServiceMaker()