diff --git a/evennia/server/portal/ssl.py b/evennia/server/portal/ssl.py index e3c18465d2..3d23d0436c 100644 --- a/evennia/server/portal/ssl.py +++ b/evennia/server/portal/ssl.py @@ -7,22 +7,70 @@ from __future__ import print_function import os import sys -from twisted.internet import ssl as twisted_ssl try: import OpenSSL -except ImportError: - print(" SSL_ENABLED requires PyOpenSSL.") - sys.exit(5) + from twisted.internet import ssl as twisted_ssl +except ImportError as err: + raise ImportError("SSL_ENABLED requires PyOpenSSL.") +from django.conf import settings from evennia.server.portal.telnet import TelnetProtocol +_GAME_DIR = settings.GAME_DIR + +# messages + +NO_AUTOGEN = """ + +{err} +Evennia could not auto-generate the SSL private key. If this error +persists, create {keyfile} yourself using third-party tools. +""" + +NO_AUTOCERT = """ + +{err} +Evennia's SSL context factory could not automatically, create an SSL +certificate {certfile}. + +A private key {keyfile} was already created. Please create {certfile} +manually using the commands valid for your operating system, for +example (linux, using the openssl program): + {exestring} +""" + class SSLProtocol(TelnetProtocol): """ Communication is the same as telnet, except data transfer is done with encryption. """ - pass + def __init__(self, *args, **kwargs): + super(TelnetProtocol, self).__init__(*args, **kwargs) + self.protocol_name = "ssl" + + def connectionMade(self): + print ("SSL connectionMade") + #self.iaw_mode = False + #self.no_lb_mode = False + #client_address = self.transport.client + #client_address = client_address[0] if client_address else None + #self.init_session(self.protocol_name, client_address, self.factory.sessionhandler) + #self.sessionhandler.connect(self) + + super(SSLProtocol, self).connectionMade() + + def connectionLost(self, reason): + print ("SSL connectionLost") + super(SSLProtocol, self).connectionLost(reason) + + def dataReceived(self, data): + print("SSL dataReceived:", data) + super(SSLProtocol, self).dataReceived(data) + + def send_text(self, *args, **kwargs): + print("SSL send_text:", args, kwargs) + super(SSLProtocol, self).send_text(*args, **kwargs) def verify_SSL_key_and_cert(keyfile, certfile): @@ -46,9 +94,8 @@ def verify_SSL_key_and_cert(keyfile, certfile): rsaKey = Key(RSA.generate(KEY_LENGTH)) keyString = rsaKey.toString(type="OPENSSH") file(keyfile, 'w+b').write(keyString) - except Exception as e: - print("rsaKey error: %(e)s\n WARNING: Evennia could not auto-generate SSL private key." % {'e': e}) - print("If this error persists, create game/%(keyfile)s yourself using third-party tools." % {'keyfile': keyfile}) + except Exception as err: + print(NO_AUTOGEN.format(err=err, keyfile=keyfile)) sys.exit(5) # try to create the certificate @@ -57,29 +104,24 @@ def verify_SSL_key_and_cert(keyfile, certfile): #openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300 exestring = "openssl req -new -x509 -key %s -out %s -days %s" % (keyfile, certfile, CERT_EXPIRE) try: - #, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) subprocess.call(exestring) - except OSError as e: - string = "\n".join([ - " %s\n" % e, - " Evennia's SSL context factory could not automatically", - " create an SSL certificate game/%(cert)s." % {'cert': certfile}, - " A private key 'ssl.key' was already created. Please", - " create %(cert)s manually using the commands valid" % {'cert': certfile}, - " for your operating system.", - " Example (linux, using the openssl program): ", - " %s" % exestring]) - print(string) - sys.exit(5) + except OSError as err: + raise OSError(NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring)) print("done.") def getSSLContext(): """ - Returns an SSL context (key and certificate). This function - verifies that key/cert exists before obtaining the context, and if - not, creates them. + This is called by the portal when creating the SSL context + server-side. + + Returns: + ssl_context (tuple): A key and certificate that is either + existing previously or or created on the fly. + """ - keyfile, certfile = "ssl.key", "ssl.cert" + keyfile = os.path.join(_GAME_DIR, "server", "ssl.key") + certfile = os.path.join(_GAME_DIR, "server", "ssl.cert") + verify_SSL_key_and_cert(keyfile, certfile) return twisted_ssl.DefaultOpenSSLContextFactory(keyfile, certfile) diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index 637a81e19e..0cad7558e7 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -31,6 +31,10 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): clients) gets a telnet protocol instance assigned to them. All communication between game and player goes through here. """ + def __init__(self, *args, **kwargs): + self.protocol_name = "telnet" + super(TelnetProtocol, self).__init__(*args, **kwargs) + def connectionMade(self): """ This is called when the connection is first established. @@ -44,7 +48,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): # this number is counted down for every handshake that completes. # when it reaches 0 the portal/server syncs their data self.handshakes = 7 # naws, ttype, mccp, mssp, msdp, gmcp, mxp - self.init_session("telnet", client_address, self.factory.sessionhandler) + self.init_session(self.protocol_name, client_address, self.factory.sessionhandler) # negotiate client size self.naws = naws.Naws(self)