def post(self): """ user registration method. Args: username (str): Desired username to register with shsmd. master_verify_key (str): NaCl verification key for adding new devices. Returns: HTTP 422: If the desired username is already registered. HTTP 400: If the provided master_verify_key is not a valid NaCl verify key. username, HTTP 201: If the user registration was successful. """ parser = reqparse.RequestParser() parser.add_argument('username', type=str, required=True, help="username is either blank or incorrect type.") parser.add_argument('master_verify_key', type=str, required=True, help="master_verify_key is either blank or incorrect type.") args = parser.parse_args() #check if user exists already username = query_db(''' SELECT username FROM users WHERE username = ?;''', [args['username']], one=True) if username is not None: abort(422, message="username already registered.") #check if provided key is a valid key try: master_verify_key = VerifyKey( args['master_verify_key'], encoder=HexEncoder) except TypeError: abort(400, message="The provided master_verify_key is not valid.") #otherwise, add user query_db(''' INSERT INTO users VALUES(?, ?);''', [args['username'], args['master_verify_key']]) get_db().commit() return args['username'], 201
def post(self): """ message delivery method. Args: device_verify_key (str): NaCl verification for the device the user is sending the query as. signed_device_verify_key (str): base64 encoded, signed device_verify_key to ensure that the user is only fetching messages for devices which they posess the full device verification keypair for. Returns: HTTP 422: If the device_verify_key provided by the user does not exist. HTTP 400: If the provided signed_device_verify_key is not signed by the correct device_verify_key provided during device registration. messages (dict): A dictionary containing all messages to be delivered to the requested device. """ parser = reqparse.RequestParser() parser.add_argument('device_verify_key', type=str, required=True, help="device_verify_key is either blank or incorrect type.") parser.add_argument('signed_device_verify_key', type=str, required=True, help="signed_device_verify_key is either blank or incorrect type.") args = parser.parse_args() #check if user exists already stored_key = query_db(''' SELECT device_verify_key FROM devices WHERE device_verify_key = ?;''', [args['device_verify_key']], one=True) if stored_key is None: abort(422, message="Device does not exist.") signed_device_verify_key = reconstruct_signed_message(args['signed_device_verify_key']) device_verify_key = VerifyKey(stored_key['device_verify_key'], encoder=HexEncoder) try: device_verify_key.verify(signed_device_verify_key) except nacl.exceptions.BadSignatureError: abort(400, message="Signature for provided username is corrupt or invalid.") messages = {} for row in query_db(''' SELECT message_public_key, reply_to, message_contents FROM messages JOIN message_recipients ON messages.message_id = message_recipients.message_id WHERE device_verify_key=?;''', [signed_device_verify_key.message]): if row is not None: messages[row[0]] = json.dumps({'reply_to': row[1], 'message_manifest': row[2]}) query_db(''' DELETE FROM message_recipients WHERE device_verify_key=?;''', [signed_device_verify_key.message]) query_db(''' DELETE FROM messages WHERE message_id NOT IN ( SELECT message_id FROM message_recipients);''') get_db().commit() return {'messages': messages}
def post(self): """ message sending method. Args: device_verify_key (str): NaCl verification key for the device the user is sending the query as. destination_usernames (str): base64 encoded, signed, JSON encapsulated list of destination usernames. message_public_key (str): base64 encoded, signed, ephemeral public key that was used to encrypt the message. message_contents (str): base64 encoded, signed message contents. Returns: HTTP 422: If the device_verify_key provided by the user does not exist. HTTP 400: If the provided destination_usernames, message_public_key or message_contents is not signed by the correct device_verify_key provided during device registration, or if the provided message_public_key is not a valid NaCl public key. device_verify_key, HTTP 201: If the message was sent successfully. """ parser = reqparse.RequestParser() parser.add_argument('device_verify_key', type=str, required=True, help="device_verify_key is either blank or incorrect type.") parser.add_argument('destination_usernames', type=str, required=True, help="destination_usernames is either blank or incorrect type.") parser.add_argument('message_public_key', type=str, required=True, help="message_public_key is either blank or incorrect type.") parser.add_argument('message_contents', type=str, required=True, help="message_contents is either blank or incorrect type.") args = parser.parse_args() #check if user exists already device_record = query_db(''' SELECT username, device_verify_key FROM devices WHERE device_verify_key = ?;''', [args['device_verify_key']], one=True) if device_record is None: abort(422, message="Device does not exist.") else: stored_key = device_record['device_verify_key'] username = device_record['username'] destination_usernames = reconstruct_signed_message(args['destination_usernames']) message_contents = reconstruct_signed_message(args['message_contents']) message_public_key = reconstruct_signed_message(args['message_public_key']) try: PublicKey(message_public_key.message, encoder=HexEncoder) except TypeError: abort(400, message='Provided message_public_key is not a valid public key.') device_verify_key = VerifyKey(stored_key, encoder=HexEncoder) try: device_verify_key.verify(destination_usernames) except BadSignatureError: abort(400, message="Signature for provided username is corrupt or invalid.") try: device_verify_key.verify(message_contents) except BadSignatureError: abort(400, message="Signature for provided message_contents is corrupt or invalid.") try: device_verify_key.verify(message_public_key) except BadSignatureError: abort(400, message="Signature for provided message_public_key is corrupt or invalid.") message_id = b64encode(message_contents.signature) query_db(''' INSERT INTO messages VALUES(?, ?, ?, ?);''', [message_id, username, b64encode(message_contents.message), b64encode(message_public_key.message)]) get_db().commit() for dest_user in json.loads(destination_usernames.message)['destination_usernames']: for row in query_db(''' SELECT device_verify_key FROM devices WHERE username=?;''', [dest_user]): query_db(''' INSERT INTO message_recipients VALUES(?, ?);''', [row['device_verify_key'], message_id]) get_db().commit() return args['device_verify_key'], 201
def post(self): """ device registration method. Args: username (str): Username the device will be registered against. device_verify_key (str): NaCl verification key for the device. device_public_key (str): NaCl public key for the device. Returns: HTTP 422: If the username the user has requested to register the device under does not exist. HTTP 400: If either device_public_key or device_verify_key is not a valid NaCl key, or if any of the provided keys are not signed by the master verification key provided during user registration. device_verify_key, HTTP 201: If the device registration was successful. """ parser = reqparse.RequestParser() parser.add_argument('username', type=str, required=True, help="username is either blank or incorrect type.") parser.add_argument('device_verify_key', type=str, required=True, help="device_verify_key is either blank or incorrect type.") parser.add_argument('device_public_key', type=str, required=True, help="device_public_key is either blank or incorrect type.") args = parser.parse_args() #check if user exists already stored_key = query_db(''' SELECT master_verify_key FROM users WHERE username = ?;''', [args['username']], one=True) if stored_key is None: abort(422, message="Username does not exist.") #check if input is valid device_verify_key = reconstruct_signed_message(args['device_verify_key']) try: VerifyKey(device_verify_key.message, encoder=HexEncoder) except TypeError: abort(400, message="The provided device_verify_key is not valid.") device_public_key = reconstruct_signed_message(args['device_public_key']) try: PublicKey(device_public_key.message, encoder=HexEncoder) except TypeError: abort(400, message="The provided device_public_key is not valid.") #check to ensure keys are signed with master key master_verify_key = VerifyKey(stored_key['master_verify_key'], encoder=HexEncoder) try: master_verify_key.verify(device_verify_key) except BadSignatureError: abort(400, message="Signature for device_verify_key is corrupt or invalid.") try: master_verify_key.verify(device_public_key) except BadSignatureError: abort(400, message="Signature for device_public_key is corrupt or invalid.") #otherwise, add device query_db(''' INSERT INTO devices VALUES(?, ?, ?);''', [device_verify_key.message, args['username'], device_public_key.message]) get_db().commit() return device_verify_key.message, 201