Example #1
0
    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
Example #2
0
    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}
Example #3
0
    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
Example #4
0
    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