/test/server.py

https://bitbucket.org/kewegmey/zmessage · Python · 134 lines · 76 code · 19 blank · 39 comment · 16 complexity · 1aebf14e09f009922a07c68cc699f8ad MD5 · raw file

  1. import zmq.auth
  2. from zmq.auth.thread import ThreadAuthenticator
  3. import os
  4. import logging
  5. import rsa
  6. import binascii
  7. import json
  8. import uuid
  9. def process_incoming(msg):
  10. # message should be a dict representing the json sent
  11. # the type field specifies what kind of message this is
  12. if msg['type'] == 'regular_msg':
  13. # This is a chat message destined for a user
  14. # Call reg_message handler
  15. return regular_msg(msg)
  16. elif msg['type'] == 'msg_recv':
  17. # This is a client asking for message delivery
  18. # Don't call anything. For now user will just poll for new messages.
  19. print "Not ready"
  20. elif msg['type'] == 'usr_reg':
  21. # User is trying to register their username and public key combo
  22. # Call usr_reg handler
  23. return usr_reg(msg)
  24. elif msg['type'] == 'key_lookup':
  25. # User wants to lookup another user's pubkey
  26. # Call key_lookup handler
  27. return key_lookup(msg)
  28. elif msg['type'] == 'msg_query':
  29. # User is asking if they have any messages
  30. # Call msg_query
  31. print "Not ready"
  32. def regular_msg(msg):
  33. # Process chat message destined for user
  34. # Double check that message is reg_msg
  35. if msg['type'] == 'regular_msg':
  36. # Accept message and save in queue
  37. # queue will be a dict msgs[destpubkey][messageid][actualmessageobj]
  38. return {"status": "Message sent."}
  39. def msg_recv(msg):
  40. # Process client request for message in queue.
  41. # Double check that message is msg_recv
  42. if msg['type'] == 'msg_recv':
  43. # Notification of waiting message will have been recvd by dest. Dest client will have sent REQ with signed message including the id for the requested message.
  44. # First verify the msg_recv came from the same key as the reg_msg's dest. (ensure the requesting client is the proper recipient)
  45. # reply to client with message if signature checks out.
  46. print "Not ready"
  47. def usr_reg(msg):
  48. #global pubkeys
  49. # user is trying to register username/pubkey
  50. if msg['type'] == 'usr_reg':
  51. # Grab the user's public key from from user_kvp and verify that user_kvp came from the associated privkey
  52. pubkeyo = rsa.PublicKey(5,3)
  53. srcpubkey = pubkeyo.load_pkcs1(msg['message']['pubkey'], format='PEM')
  54. try:
  55. print "Verifying Message"
  56. ser_msg = json.dumps(msg['message'])
  57. if rsa.verify(ser_msg, binascii.unhexlify(msg['signature']), srcpubkey):
  58. print "Message authentic!"
  59. username = msg['message']['username']
  60. pubkeys[username] = srcpubkey
  61. return {"status": "Successfully registered."}
  62. except:
  63. print "Verification Failed"
  64. return {"status": "Failed to register. Unable to verify signature"}
  65. # if it does then add key-value pair to key registry
  66. def key_lookup(msg):
  67. #global pubkeys
  68. # User is looking up another users Key
  69. if msg['type'] == 'key_lookup':
  70. # No need to verify signatures on the recv side since these are public however we should sign the message back to the user so that they can sort of trust the key is correct.abs
  71. # Lookup pubkey for specified user and then sign a message with that key back to requester.
  72. username = msg['message']
  73. if username in pubkeys:
  74. pubkey = pubkeys[username]
  75. pubkey = pubkey.save_pkcs1('PEM')
  76. return {username: pubkey}
  77. else:
  78. return {"status": "User not found"}
  79. def msg_query(msg):
  80. if msg['type'] == 'msg_query':
  81. # Verify user and then look for any messages for that key
  82. # reply with any messages
  83. print "Not ready"
  84. def main():
  85. # Main function sets up ZMQ server and waits for messages
  86. auth_keys = "keys/authkeys"
  87. # Start child threads
  88. public_keys_dir = os.path.abspath(auth_keys)
  89. ctx = zmq.Context.instance()
  90. # Start an authenticator for this context.
  91. auth = ThreadAuthenticator(ctx, log=logging)
  92. auth.start()
  93. # Tell authenticator to use the certificate in a directory
  94. auth.configure_curve(domain='*', location=public_keys_dir)
  95. server = ctx.socket(zmq.REP)
  96. server_secret_file = os.path.abspath("keys/server.key_secret")
  97. server_public, server_secret = zmq.auth.load_certificate(server_secret_file)
  98. server.curve_secretkey = server_secret
  99. server.curve_publickey = server_public
  100. server.curve_server = True # must come before bind
  101. server.bind("tcp://*:5555")
  102. print "Starting Server"
  103. # Message loop
  104. while True:
  105. # Block for message.
  106. message = server.recv_json()
  107. print "Received request: ", message
  108. # Call processor
  109. reply = process_incoming(message)
  110. server.send_json(reply)
  111. # Create pubkeys dict that will map usernames to public keys
  112. pubkeys = {}
  113. msg_queue = {}
  114. if __name__ == "__main__":
  115. main()