sydent.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014 OpenMarket Ltd
  3. # Copyright 2018 New Vector Ltd
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. import ConfigParser
  17. import logging
  18. import logging.handlers
  19. import os
  20. import twisted.internet.reactor
  21. from twisted.python import log
  22. from db.sqlitedb import SqliteDatabase
  23. from http.httpcommon import SslComponents
  24. from http.httpserver import ClientApiHttpServer, ReplicationHttpsServer
  25. from http.httpsclient import ReplicationHttpsClient
  26. from http.servlets.blindlysignstuffservlet import BlindlySignStuffServlet
  27. from http.servlets.pubkeyservlets import EphemeralPubkeyIsValidServlet, PubkeyIsValidServlet
  28. from validators.emailvalidator import EmailValidator
  29. from validators.msisdnvalidator import MsisdnValidator
  30. from hs_federation.verifier import Verifier
  31. from sign.ed25519 import SydentEd25519
  32. from http.servlets.emailservlet import EmailRequestCodeServlet, EmailValidateCodeServlet
  33. from http.servlets.msisdnservlet import MsisdnRequestCodeServlet, MsisdnValidateCodeServlet
  34. from http.servlets.lookupservlet import LookupServlet
  35. from http.servlets.bulklookupservlet import BulkLookupServlet
  36. from http.servlets.pubkeyservlets import Ed25519Servlet
  37. from http.servlets.threepidbindservlet import ThreePidBindServlet
  38. from http.servlets.threepidunbindservlet import ThreePidUnbindServlet
  39. from http.servlets.replication import ReplicationPushServlet
  40. from http.servlets.getvalidated3pidservlet import GetValidated3pidServlet
  41. from http.servlets.store_invite_servlet import StoreInviteServlet
  42. from threepid.bind import ThreepidBinder
  43. from replication.pusher import Pusher
  44. logger = logging.getLogger(__name__)
  45. class Sydent:
  46. CONFIG_SECTIONS = ['general', 'db', 'http', 'email', 'crypto', 'sms']
  47. CONFIG_DEFAULTS = {
  48. # general
  49. 'server.name': '',
  50. 'log.path': '',
  51. 'pidfile.path': 'sydent.pid',
  52. # db
  53. 'db.file': 'sydent.db',
  54. # http
  55. 'clientapi.http.port': '8090',
  56. 'replication.https.certfile': '',
  57. 'replication.https.cacert': '', # This should only be used for testing
  58. 'replication.https.port': '4434',
  59. 'obey_x_forwarded_for': False,
  60. # email
  61. 'email.template': 'res/email.template',
  62. 'email.from': 'Sydent Validation <noreply@{hostname}>',
  63. 'email.subject': 'Your Validation Token',
  64. 'email.invite.subject': '%(sender_display_name)s has invited you to chat',
  65. 'email.smtphost': 'localhost',
  66. 'email.smtpport': '25',
  67. 'email.smtpusername': '',
  68. 'email.smtppassword': '',
  69. 'email.hostname': '',
  70. 'email.tlsmode': '0',
  71. # sms
  72. 'bodyTemplate': 'Your code is {token}',
  73. # crypto
  74. 'ed25519.signingkey': '',
  75. }
  76. def __init__(self):
  77. self.parse_config()
  78. log_format = (
  79. "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s"
  80. " - %(message)s"
  81. )
  82. formatter = logging.Formatter(log_format)
  83. logPath = self.cfg.get('general', "log.path")
  84. if logPath != '':
  85. handler = logging.handlers.RotatingFileHandler(
  86. logPath, maxBytes=(1000 * 1000 * 100), backupCount=3
  87. )
  88. handler.setFormatter(formatter)
  89. def sighup(signum, stack):
  90. logger.info("Closing log file due to SIGHUP")
  91. handler.doRollover()
  92. logger.info("Opened new log file due to SIGHUP")
  93. else:
  94. handler = logging.StreamHandler()
  95. handler.setFormatter(formatter)
  96. rootLogger = logging.getLogger('')
  97. rootLogger.setLevel(logging.INFO)
  98. rootLogger.addHandler(handler)
  99. logger.info("Starting Sydent server")
  100. self.pidfile = self.cfg.get('general', "pidfile.path");
  101. observer = log.PythonLoggingObserver()
  102. observer.start()
  103. self.db = SqliteDatabase(self).db
  104. self.server_name = self.cfg.get('general', 'server.name')
  105. if self.server_name == '':
  106. self.server_name = os.uname()[1]
  107. logger.warn(("You had not specified a server name. I have guessed that this server is called '%s' "
  108. + " and saved this in the config file. If this is incorrect, you should edit server.name in "
  109. + "the config file.") % (self.server_name,))
  110. self.cfg.set('general', 'server.name', self.server_name)
  111. self.save_config()
  112. self.validators = Validators()
  113. self.validators.email = EmailValidator(self)
  114. self.validators.msisdn = MsisdnValidator(self)
  115. self.keyring = Keyring()
  116. self.keyring.ed25519 = SydentEd25519(self).signing_key
  117. self.keyring.ed25519.alg = 'ed25519'
  118. self.sig_verifier = Verifier(self)
  119. self.servlets = Servlets()
  120. self.servlets.emailRequestCode = EmailRequestCodeServlet(self)
  121. self.servlets.emailValidate = EmailValidateCodeServlet(self)
  122. self.servlets.msisdnRequestCode = MsisdnRequestCodeServlet(self)
  123. self.servlets.msisdnValidate = MsisdnValidateCodeServlet(self)
  124. self.servlets.lookup = LookupServlet(self)
  125. self.servlets.bulk_lookup = BulkLookupServlet(self)
  126. self.servlets.pubkey_ed25519 = Ed25519Servlet(self)
  127. self.servlets.pubkeyIsValid = PubkeyIsValidServlet(self)
  128. self.servlets.ephemeralPubkeyIsValid = EphemeralPubkeyIsValidServlet(self)
  129. self.servlets.threepidBind = ThreePidBindServlet(self)
  130. self.servlets.threepidUnbind = ThreePidUnbindServlet(self)
  131. self.servlets.replicationPush = ReplicationPushServlet(self)
  132. self.servlets.getValidated3pid = GetValidated3pidServlet(self)
  133. self.servlets.storeInviteServlet = StoreInviteServlet(self)
  134. self.servlets.blindlySignStuffServlet = BlindlySignStuffServlet(self)
  135. self.threepidBinder = ThreepidBinder(self)
  136. self.sslComponents = SslComponents(self)
  137. self.clientApiHttpServer = ClientApiHttpServer(self)
  138. self.replicationHttpsServer = ReplicationHttpsServer(self)
  139. self.replicationHttpsClient = ReplicationHttpsClient(self)
  140. self.pusher = Pusher(self)
  141. def parse_config(self):
  142. self.cfg = ConfigParser.SafeConfigParser(Sydent.CONFIG_DEFAULTS)
  143. for sect in Sydent.CONFIG_SECTIONS:
  144. try:
  145. self.cfg.add_section(sect)
  146. except ConfigParser.DuplicateSectionError:
  147. pass
  148. self.cfg.read(os.environ.get('SYDENT_CONF', "sydent.conf"))
  149. def save_config(self):
  150. fp = open("sydent.conf", 'w')
  151. self.cfg.write(fp)
  152. fp.close()
  153. def run(self):
  154. self.clientApiHttpServer.setup()
  155. self.replicationHttpsServer.setup()
  156. self.pusher.setup()
  157. if self.pidfile:
  158. with open(self.pidfile, 'w') as pidfile:
  159. pidfile.write(str(os.getpid()) + "\n")
  160. twisted.internet.reactor.run()
  161. def ip_from_request(self, request):
  162. if (self.cfg.get('http', 'obey_x_forwarded_for') and
  163. request.requestHeaders.hasHeader("X-Forwarded-For")):
  164. return request.requestHeaders.getRawHeaders("X-Forwarded-For")[0]
  165. return request.getClientIP()
  166. class Validators:
  167. pass
  168. class Servlets:
  169. pass
  170. class Keyring:
  171. pass
  172. if __name__ == '__main__':
  173. syd = Sydent()
  174. syd.run()