startTLS: added --tls [file] argument in server

This commit is contained in:
Alberto Sottile 2019-02-04 16:01:27 +01:00
parent 3eeaeed6dd
commit 7910ddec15
5 changed files with 25 additions and 19 deletions

View File

@ -718,7 +718,6 @@ class SyncplayClient(object):
trust_root = Certificate.loadPEM(cert_file.read()) trust_root = Certificate.loadPEM(cert_file.read())
self._endpoint = HostnameEndpoint(reactor, host, port) self._endpoint = HostnameEndpoint(reactor, host, port)
self.protocolFactory.options = optionsForClientTLS(hostname=host, trustRoot = trust_root) self.protocolFactory.options = optionsForClientTLS(hostname=host, trustRoot = trust_root)
def retry(retries): def retry(retries):
self._lastGlobalUpdate = None self._lastGlobalUpdate = None

View File

@ -444,7 +444,7 @@ en = {
"server-chat-maxchars-argument": "Maximum number of characters in a chat message (default is {})", # Default number of characters "server-chat-maxchars-argument": "Maximum number of characters in a chat message (default is {})", # Default number of characters
"server-maxusernamelength-argument": "Maximum number of characters in a username (default is {})", "server-maxusernamelength-argument": "Maximum number of characters in a username (default is {})",
"server-stats-db-file-argument": "Enable server stats using the SQLite db file provided", "server-stats-db-file-argument": "Enable server stats using the SQLite db file provided",
"server-startTLS-argument": "Enable TLS connections using the certificate files in the path provided", "server-tls-argument": "Enable TLS connections using the certificate file provided",
"server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).", "server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).",
"server-messed-up-motd-too-long": "Message of the Day is too long - maximum of {} chars, {} given.", "server-messed-up-motd-too-long": "Message of the Day is too long - maximum of {} chars, {} given.",

View File

@ -328,10 +328,12 @@ class SyncClientProtocol(JSONCommandProtocol):
def handleTLS(self, message): def handleTLS(self, message):
answer = message["startTLS"] if "startTLS" in message else None answer = message["startTLS"] if "startTLS" in message else None
if "true" in answer and not self.logged: if "true" in answer and not self.logged and self._client.protocolFactory.options is not None:
self.transport.startTLS(self._client.protocolFactory.options) self.transport.startTLS(self._client.protocolFactory.options)
self._client.ui.showMessage("Secure connection established") self._client.ui.showMessage("Secure connection established")
self.sendHello() elif "false" in answer:
self._client.ui.showErrorMessage("This server does not support TLS")
self.sendHello()
class SyncServerProtocol(JSONCommandProtocol): class SyncServerProtocol(JSONCommandProtocol):
def __init__(self, factory): def __init__(self, factory):
@ -638,9 +640,12 @@ class SyncServerProtocol(JSONCommandProtocol):
def handleTLS(self, message): def handleTLS(self, message):
inquiry = message["startTLS"] if "startTLS" in message else None inquiry = message["startTLS"] if "startTLS" in message else None
if "send" in inquiry and not self.isLogged(): if "send" in inquiry:
self.sendTLS({"startTLS": "true"}) if not self.isLogged() and self._factory.options is not None:
self.transport.startTLS(self._factory.options) self.sendTLS({"startTLS": "true"})
self.transport.startTLS(self._factory.options)
else:
self.sendTLS({"startTLS": "false"})
class PingService(object): class PingService(object):

View File

@ -27,7 +27,7 @@ from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomString
class SyncFactory(Factory): class SyncFactory(Factory):
def __init__(self, port='', password='', motdFilePath=None, isolateRooms=False, salt=None, def __init__(self, port='', password='', motdFilePath=None, isolateRooms=False, salt=None,
disableReady=False, disableChat=False, maxChatMessageLength=constants.MAX_CHAT_MESSAGE_LENGTH, disableReady=False, disableChat=False, maxChatMessageLength=constants.MAX_CHAT_MESSAGE_LENGTH,
maxUsernameLength=constants.MAX_USERNAME_LENGTH, statsDbFile=None, tlsCertPath=None): maxUsernameLength=constants.MAX_USERNAME_LENGTH, statsDbFile=None, tlsCert=None):
self.isolateRooms = isolateRooms self.isolateRooms = isolateRooms
print(getMessage("welcome-server-notification").format(syncplay.version)) print(getMessage("welcome-server-notification").format(syncplay.version))
self.port = port self.port = port
@ -56,8 +56,15 @@ class SyncFactory(Factory):
else: else:
self._statsDbHandle = None self._statsDbHandle = None
self.options = None self.options = None
if tlsCertPath is not None: if tlsCert is not None:
self._allowTLSconnections(tlsCertPath) try:
with open(tlsCert) as f:
certData = f.read()
cert = ssl.PrivateCertificate.loadPEM(certData).options()
self.options = cert
except Exception as e:
print(e)
print("Cannot import certificate. TLS support not enabled.")
def buildProtocol(self, addr): def buildProtocol(self, addr):
return SyncServerProtocol(self) return SyncServerProtocol(self)
@ -655,4 +662,4 @@ class ConfigurationGetter(object):
self._argparser.add_argument('--max-chat-message-length', metavar='maxChatMessageLength', type=int, nargs='?', help=getMessage("server-chat-maxchars-argument").format(constants.MAX_CHAT_MESSAGE_LENGTH)) self._argparser.add_argument('--max-chat-message-length', metavar='maxChatMessageLength', type=int, nargs='?', help=getMessage("server-chat-maxchars-argument").format(constants.MAX_CHAT_MESSAGE_LENGTH))
self._argparser.add_argument('--max-username-length', metavar='maxUsernameLength', type=int, nargs='?', help=getMessage("server-maxusernamelength-argument").format(constants.MAX_USERNAME_LENGTH)) self._argparser.add_argument('--max-username-length', metavar='maxUsernameLength', type=int, nargs='?', help=getMessage("server-maxusernamelength-argument").format(constants.MAX_USERNAME_LENGTH))
self._argparser.add_argument('--stats-db-file', metavar='file', type=str, nargs='?', help=getMessage("server-stats-db-file-argument")) self._argparser.add_argument('--stats-db-file', metavar='file', type=str, nargs='?', help=getMessage("server-stats-db-file-argument"))
self._argparser.add_argument('--tls', metavar='path', type=str, nargs='?', help=getMessage("server-startTLS-argument")) self._argparser.add_argument('--tls', metavar='file', type=str, nargs='?', help=getMessage("server-tls-argument"))

View File

@ -14,16 +14,11 @@ except AttributeError:
warnings.warn("You must run Syncplay with Python 3.4 or newer!") warnings.warn("You must run Syncplay with Python 3.4 or newer!")
from OpenSSL import crypto from OpenSSL import crypto
from twisted.internet import reactor, ssl from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint, TCP6ServerEndpoint from twisted.internet.endpoints import TCP4ServerEndpoint, TCP6ServerEndpoint
from syncplay.server import SyncFactory, ConfigurationGetter from syncplay.server import SyncFactory, ConfigurationGetter
with open('cert/server.pem') as f:
certData = f.read()
cert = ssl.PrivateCertificate.loadPEM(certData).options()
if __name__ == '__main__': if __name__ == '__main__':
argsGetter = ConfigurationGetter() argsGetter = ConfigurationGetter()
args = argsGetter.getConfiguration() args = argsGetter.getConfiguration()
@ -37,9 +32,9 @@ if __name__ == '__main__':
args.disable_chat, args.disable_chat,
args.max_chat_message_length, args.max_chat_message_length,
args.max_username_length, args.max_username_length,
args.stats_db_file args.stats_db_file,
args.tls
) )
factory.options = cert
endpoint4 = TCP4ServerEndpoint(reactor, int(args.port)) endpoint4 = TCP4ServerEndpoint(reactor, int(args.port))
endpoint4.listen(factory) endpoint4.listen(factory)
endpoint6 = TCP6ServerEndpoint(reactor, int(args.port)) endpoint6 = TCP6ServerEndpoint(reactor, int(args.port))