You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

226 lines
5.8 KiB

  1. # Copyright 2015, 2016 OpenMarket Ltd
  2. # Copyright 2018 New Vector
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import argparse
  16. import getpass
  17. import hashlib
  18. import hmac
  19. import logging
  20. import sys
  21. import requests as _requests
  22. import yaml
  23. def request_registration(
  24. user,
  25. password,
  26. server_location,
  27. shared_secret,
  28. admin=False,
  29. user_type=None,
  30. requests=_requests,
  31. _print=print,
  32. exit=sys.exit,
  33. ):
  34. url = "%s/_synapse/admin/v1/register" % (server_location.rstrip("/"),)
  35. # Get the nonce
  36. r = requests.get(url, verify=False)
  37. if r.status_code != 200:
  38. _print("ERROR! Received %d %s" % (r.status_code, r.reason))
  39. if 400 <= r.status_code < 500:
  40. try:
  41. _print(r.json()["error"])
  42. except Exception:
  43. pass
  44. return exit(1)
  45. nonce = r.json()["nonce"]
  46. mac = hmac.new(key=shared_secret.encode("utf8"), digestmod=hashlib.sha1)
  47. mac.update(nonce.encode("utf8"))
  48. mac.update(b"\x00")
  49. mac.update(user.encode("utf8"))
  50. mac.update(b"\x00")
  51. mac.update(password.encode("utf8"))
  52. mac.update(b"\x00")
  53. mac.update(b"admin" if admin else b"notadmin")
  54. if user_type:
  55. mac.update(b"\x00")
  56. mac.update(user_type.encode("utf8"))
  57. mac = mac.hexdigest()
  58. data = {
  59. "nonce": nonce,
  60. "username": user,
  61. "password": password,
  62. "mac": mac,
  63. "admin": admin,
  64. "user_type": user_type,
  65. }
  66. _print("Sending registration request...")
  67. r = requests.post(url, json=data, verify=False)
  68. if r.status_code != 200:
  69. _print("ERROR! Received %d %s" % (r.status_code, r.reason))
  70. if 400 <= r.status_code < 500:
  71. try:
  72. _print(r.json()["error"])
  73. except Exception:
  74. pass
  75. return exit(1)
  76. _print("Success!")
  77. def register_new_user(user, password, server_location, shared_secret, admin, user_type):
  78. if not user:
  79. try:
  80. default_user = getpass.getuser()
  81. except Exception:
  82. default_user = None
  83. if default_user:
  84. user = input("New user localpart [%s]: " % (default_user,))
  85. if not user:
  86. user = default_user
  87. else:
  88. user = input("New user localpart: ")
  89. if not user:
  90. print("Invalid user name")
  91. sys.exit(1)
  92. if not password:
  93. password = getpass.getpass("Password: ")
  94. if not password:
  95. print("Password cannot be blank.")
  96. sys.exit(1)
  97. confirm_password = getpass.getpass("Confirm password: ")
  98. if password != confirm_password:
  99. print("Passwords do not match")
  100. sys.exit(1)
  101. if admin is None:
  102. admin = input("Make admin [no]: ")
  103. if admin in ("y", "yes", "true"):
  104. admin = True
  105. else:
  106. admin = False
  107. request_registration(
  108. user, password, server_location, shared_secret, bool(admin), user_type
  109. )
  110. def main():
  111. logging.captureWarnings(True)
  112. parser = argparse.ArgumentParser(
  113. description="Used to register new users with a given homeserver when"
  114. " registration has been disabled. The homeserver must be"
  115. " configured with the 'registration_shared_secret' option"
  116. " set."
  117. )
  118. parser.add_argument(
  119. "-u",
  120. "--user",
  121. default=None,
  122. help="Local part of the new user. Will prompt if omitted.",
  123. )
  124. parser.add_argument(
  125. "-p",
  126. "--password",
  127. default=None,
  128. help="New password for user. Will prompt if omitted.",
  129. )
  130. parser.add_argument(
  131. "-t",
  132. "--user_type",
  133. default=None,
  134. help="User type as specified in synapse.api.constants.UserTypes",
  135. )
  136. admin_group = parser.add_mutually_exclusive_group()
  137. admin_group.add_argument(
  138. "-a",
  139. "--admin",
  140. action="store_true",
  141. help=(
  142. "Register new user as an admin. "
  143. "Will prompt if --no-admin is not set either."
  144. ),
  145. )
  146. admin_group.add_argument(
  147. "--no-admin",
  148. action="store_true",
  149. help=(
  150. "Register new user as a regular user. "
  151. "Will prompt if --admin is not set either."
  152. ),
  153. )
  154. group = parser.add_mutually_exclusive_group(required=True)
  155. group.add_argument(
  156. "-c",
  157. "--config",
  158. type=argparse.FileType("r"),
  159. help="Path to server config file. Used to read in shared secret.",
  160. )
  161. group.add_argument(
  162. "-k", "--shared-secret", help="Shared secret as defined in server config file."
  163. )
  164. parser.add_argument(
  165. "server_url",
  166. default="https://localhost:8448",
  167. nargs="?",
  168. help="URL to use to talk to the homeserver. Defaults to "
  169. " 'https://localhost:8448'.",
  170. )
  171. args = parser.parse_args()
  172. if "config" in args and args.config:
  173. config = yaml.safe_load(args.config)
  174. secret = config.get("registration_shared_secret", None)
  175. if not secret:
  176. print("No 'registration_shared_secret' defined in config.")
  177. sys.exit(1)
  178. else:
  179. secret = args.shared_secret
  180. admin = None
  181. if args.admin or args.no_admin:
  182. admin = args.admin
  183. register_new_user(
  184. args.user, args.password, args.server_url, secret, admin, args.user_type
  185. )
  186. if __name__ == "__main__":
  187. main()