Ejemplo n.º 1
0
    async def recieve_invite(self, msg):
        '''
        Recieve invitation from user to create a pending connection.
        :param msg: code generated from user
        '''
        invite_msg = Serializer.unpack(
            base64.urlsafe_b64decode(msg).decode('utf-8'))

        print("\nMESSAGE RECEIVED: ", invite_msg)

        pending_connection = Message({
            '@type':
            "INVITE_RECEIVED",
            'label':
            invite_msg['label'],
            'connection_key':
            invite_msg['recipientKeys'][0],
            'history': [{
                'date': str(datetime.datetime.now()),
                'msg': invite_msg.to_dict()
            }],
            'status':
            "Invite Received"
        })
        print("\nPENDING CONNECTION", pending_connection)
        # Store invitation in the wallet
        await non_secrets.add_wallet_record(
            self.agent.wallet_handle,
            'invitations', invite_msg['recipientKeys'][0],
            Serializer.pack(pending_connection), '{}')
        return True
Ejemplo n.º 2
0
async def ui_event_process(agent):
    ui_router = agent['ui_router']
    ui_event_queue = agent['ui_event_queue']

    await ui_router.register(UI.SEND_OFFER, connection.send_offer)
    await ui_router.register(UI.STATE_REQUEST, ui.ui_connect)
    await ui_router.register(UI.INITIALIZE, init.initialize_agent)
    await ui_router.register(UI.SEND_OFFER_ACCEPTED, connection.send_offer_accepted)
    await ui_router.register(UI.SENDER_SEND_OFFER_REJECTED, connection.sender_send_offer_rejected)
    await ui_router.register(UI.RECEIVER_SEND_OFFER_REJECTED, connection.receiver_send_offer_rejected)
    await ui_router.register(UI.SEND_CONN_REJECTED, connection.send_conn_rejected)

    while True:
        msg_bytes = await ui_event_queue.recv()
        try:
            msg = Serializer.unpack(msg_bytes)
        except Exception as e:
            print('Failed to unpack message: {}\n\nError: {}'.format(msg_bytes, e))
            continue

        if msg.id != UI_TOKEN:
            print('Invalid token received, rejecting message: {}'.format(msg_bytes))
            continue

        res = await ui_router.route(msg, agent['agent'])
        if res is not None:
            await ui_event_queue.send(Serializer.pack(res))
Ejemplo n.º 3
0
    async def unpack_agent_message(self, wire_msg_bytes):

        unpacked = json.loads(await
                              crypto.unpack_message(self.wallet_handle,
                                                    wire_msg_bytes))

        from_key = None
        if 'sender_verkey' in unpacked:
            from_key = unpacked['sender_verkey']
            from_did = await utils.did_for_key(self.wallet_handle,
                                               unpacked['sender_verkey'])

        to_key = unpacked['recipient_verkey']
        to_did = await utils.did_for_key(self.wallet_handle,
                                         unpacked['recipient_verkey'])

        msg = Serializer.unpack(unpacked['message'])

        msg.context = {
            'from_did': from_did,  # Could be None
            'to_did': to_did,  # Could be None
            'from_key': from_key,  # Could be None
            'to_key': to_key
        }
        return msg
Ejemplo n.º 4
0
async def ui_event_process(agent):
    ui_router = agent['ui_router']
    ui_event_queue = agent['ui_event_queue']
    connection = agent['modules']['connection']
    ui = agent['modules']['ui']

    ui_router.register(CONN_UI.FAMILY, connection)
    ui_router.register(UI.FAMILY, ui)
    ui_router.register(ADMIN_WALLETCONNECTION.FAMILY,
                       agent['modules']['admin_walletconnection'])

    while True:
        msg = await ui_event_queue.recv()

        if not isinstance(msg, Message):
            try:
                msg = Serializer.unpack(msg)
            except Exception as e:
                print('Failed to unpack message: {}\n\nError: {}'.format(
                    msg, e))
                continue

        if msg['ui_token'] != UI_TOKEN:
            print('Invalid token received, rejecting message: {}'.format(msg))
            continue

        res = await ui_router.route(msg)
        if res is not None:
            await ui_event_queue.send(Serializer.pack(res))
Ejemplo n.º 5
0
    async def start(self):
        """ Message processing loop task.
        """
        while True:
            try:
                wire_msg_bytes = await self.message_queue.get()

                # Try to unpack message assuming it's not encrypted
                try:
                    msg = Serializer.unpack(wire_msg_bytes)
                except Exception as e:
                    print("Message encrypted, attempting to unpack...")

                # TODO: More graceful checking here
                # (This is an artifact of the provisional wire format and connection protocol)
                if not isinstance(msg, Message) or "@type" not in msg:
                    # Message IS encrypted so unpack it
                    try:
                        msg = await self.unpack_agent_message(wire_msg_bytes)
                    except Exception as e:
                        print(
                            'Failed to unpack message: {}\n\nError: {}'.format(
                                wire_msg_bytes, e))
                        continue  # handle next message in loop

                await self.route_message_to_module(msg)
            except Exception as e:
                print("\n\n--- Message Processing failed --- \n\n")
                traceback.print_exc()
Ejemplo n.º 6
0
async def message_process(agent):
    """ Message processing loop task.
        Message routes are also defined here through the message router.
    """
    msg_router = agent['msg_router']
    msg_receiver = agent['msg_receiver']
    ui_event_queue = agent['ui_event_queue']

    await msg_router.register(CONN.REQUEST, connection.handle_request)
    await msg_router.register(CONN.RESPONSE, connection.handle_response)

    while True:
        encrypted_msg_bytes = await msg_receiver.recv()
        # TODO: make this logic work
        try:
            decrypted_msg_bytes = await crypto.anon_decrypt(
                    agent.wallet_handle,
                    agent.endpoint_vk,
                    encrypted_msg_bytes
                    )
        except Exception as e:
            print('Could not decrypt message: {}\nError: {}'.format(msg_bytes, e))
            continue

        try:
            msg = Serializer.unpack(encrypted_msg_bytes)
        except Exception as e:
            print('Failed to unpack message: {}\n\nError: {}'.format(msg_bytes, e))
            continue

        res = await msg_router.route(msg, agent['agent'])
        if res is not None:
            await ui_event_queue.send(Serializer.pack(res))
Ejemplo n.º 7
0
    async def unpack_agent_message(self, wire_msg_bytes):
        '''
        Message passed is unpacked as bytes and returned
        '''
        print("\nUnpack agent message")
        if isinstance(wire_msg_bytes, str):
            wire_msg_bytes = bytes(wire_msg_bytes, 'utf-8')
        unpacked = json.loads(await
                              crypto.unpack_message(self.wallet_handle,
                                                    bytes(wire_msg_bytes)))
        print("UNPACKED: ", unpacked)

        from_key = None
        from_did = None
        if 'sender_verkey' in unpacked:
            from_key = unpacked['sender_verkey']
            from_did = await utils.did_for_key(self.wallet_handle,
                                               unpacked['sender_verkey'])

        to_key = unpacked['recipient_verkey']
        to_did = await utils.did_for_key(self.wallet_handle,
                                         unpacked['recipient_verkey'])

        msg = Serializer.unpack(unpacked['message'])
        print(msg)

        msg.context = {
            'from_did': from_did,  # Could be None
            'to_did': to_did,  # Could be None
            'from_key': from_key,  # Could be None
            'to_key': to_key
        }
        print("Message context: ", msg.context)
        return msg
Ejemplo n.º 8
0
    async def receive_invite(self, msg: Message) -> Message:
        """ Receive and save invite.

            This interaction represents an out-of-band communication channel. In the future and in
            practice, these sort of invitations will be received over any number of channels such as
            SMS, Email, QR Code, NFC, etc.

            In this iteration, invite messages are received from the admin interface as a URL
            after being copied and pasted from another agent instance.

            The URL is formatted as follows:

                https://<domain>/<path>?c_i=<invitationstring>

            The invitation string is a base64 url encoded json string.

            Structure of an invite message:

                {
                    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
                    "label": "Alice",
                    "did": "did:sov:QmWbsNYhMrjHiqZDTUTEJs"
                }

            Or, in the case of a peer DID:

                {
                    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
                    "label": "Alice",
                    "key": "8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K",
                    "endpoint": "https://example.com/endpoint"
                }

            Currently, only peer DID format is supported.
        """

        # Parse invite string
        matches = re.match("(.+)?c_i=(.+)", msg['invite'])
        if not matches:
            raise BadInviteException("Invite string is improperly formatted")

        invite_msg = Serializer.unpack(
            base64.urlsafe_b64decode(matches.group(2)).decode('utf-8'))

        record = uuid.uuid4().hex

        await self.agent.send_admin_message(
            Message({
                '@type': AdminConnection.INVITE_RECEIVED,
                'label': invite_msg['label'],
                'key': invite_msg['key'],
                'endpoint': invite_msg['endpoint']
            }))

        await non_secrets.add_wallet_record(self.agent.wallet_handle,
                                            'invitation', invite_msg['key'],
                                            Serializer.pack(invite_msg), '{}')
Ejemplo n.º 9
0
async def message_process(agent):
    """ Message processing loop task.
        Message routes are also defined here through the message router.
    """
    msg_router = agent['msg_router']
    msg_receiver = agent['msg_receiver']

    await msg_router.register("CONN_REQ", connection.handle_request_received)
    await msg_router.register("CONN_RES", connection.handle_response)

    while True:
        msg_bytes = await msg_receiver.recv()
        msg = Serializer.unpack(msg_bytes)
        await msg_router.route(msg, agent['agent'])
Ejemplo n.º 10
0
    async def read_msg(self, wire_msg):
        '''
        Message is unpacked depending on how its encrypted and returned unpacked
        '''
        print("read wire msg: ", wire_msg)
        msg = ""
        try:
            msg = Serializer.unpack(wire_msg)
        except Exception as e:
            print("Message encrypted, trying to unpack", e)

        if not isinstance(msg, Message) or "@type" not in msg:
            try:
                msg = await self.unpack_agent_message(wire_msg)
                print("msg unpack: ", msg)
                return msg
            except Exception as e:
                print("Failed to unpack messgae", e)
Ejemplo n.º 11
0
async def conn_process(agent):
    conn_router = agent['conn_router']
    conn_receiver = agent['conn_receiver']
    ui_event_queue = agent['ui_event_queue']
    connection = agent['modules']['connection']

    conn_router.register(CONN.FAMILY, connection)

    while True:
        msg_bytes = await conn_receiver.recv()
        try:
            msg = Serializer.unpack(msg_bytes)
        except Exception as e:
            print('Failed to unpack message: {}\n\nError: {}'.format(msg_bytes, e))
            continue

        res = await conn_router.route(msg)
        if res is not None:
            await ui_event_queue.send(Serializer.pack(res))
Ejemplo n.º 12
0
    async def unpack_wire_msg(self, wire_msg) -> Optional:
        # Try to unpack message assuming it's not encrypted
        msg = ""
        try:
            msg = Serializer.unpack(wire_msg)
        except Exception as e:
            print("Message encrypted, attempting to unpack...")

        # TODO: More graceful checking here
        # (This is an artifact of the provisional wire format and connection protocol)
        if not isinstance(msg, Message) or "@type" not in msg:
            # Message IS encrypted so unpack it
            try:
                msg = await self.unpack_agent_message(wire_msg)
            except Exception as e:
                print('Failed to unpack message: {}\n\nError: {}'.format(
                    wire_msg, e))
                traceback.print_exc()
                return None

        return msg
Ejemplo n.º 13
0
async def conn_process(agent):
    conn_router = agent['conn_router']
    conn_receiver = agent['conn_receiver']
    ui_event_queue = agent['ui_event_queue']

    await conn_router.register(CONN.OFFER, connection.offer_recv)
    await conn_router.register(CONN.ACKNOWLEDGE, connection.offer_accepted)
    await conn_router.register(CONN.SENDER_REJECTION, connection.receiver_offer_rejected)
    await conn_router.register(CONN.RECEIVER_REJECTION, connection.sender_offer_rejected)
    await conn_router.register(CONN.REJECTION, connection.conn_rejected)

    while True:
        msg_bytes = await conn_receiver.recv()
        try:
            msg = Serializer.unpack(msg_bytes)
        except Exception as e:
            print('Failed to unpack message: {}\n\nError: {}'.format(msg_bytes, e))
            continue

        res = await conn_router.route(msg, agent['agent'])
        if res is not None:
            await ui_event_queue.send(Serializer.pack(res))
Ejemplo n.º 14
0
async def handle_request_accepted(request):
    """ Handle reception of accept connection request message.
    """
    accept_did = request.match_info['did']
    agent = request.app['agent']
    wallet_handle = agent.wallet_handle

    if accept_did not in agent.received_requests:
        raise web.HTTPNotFound()

    msg = Serializer.unpack(agent.received_requests[accept_did])

    #TODO: validate correct format for incoming data
    data = msg.data
    endpoint = data['endpoint']
    verkey = data['verkey']
    owner = data['owner']

    ident_json = json.dumps({"did": accept_did, "verkey": verkey})

    meta_json = json.dumps({"owner": owner, "endpoint": endpoint})

    (my_did, _) = await did.create_and_store_my_did(wallet_handle, "{}")

    await did.store_their_did(wallet_handle, ident_json)

    await did.set_endpoint_for_did(wallet_handle, accept_did, endpoint, verkey)

    await did.set_did_metadata(wallet_handle, accept_did, meta_json)

    await pairwise.create_pairwise(wallet_handle, accept_did, my_did,
                                   json.dumps({"hello": "world"}))

    await send_response(accept_did, agent)

    raise web.HTTPFound('/')
Ejemplo n.º 15
0
    async def send_response(self, msg):
        '''
        When clicking on send response button, response message is send to other user to create pairwise connection
        '''
        print("\nSEND RESPONSE")
        their_did = msg['did']
        # pairwise connection info
        pairwise_info = json.loads(await pairwise.get_pairwise(
            self.agent.wallet_handle, their_did))
        pairwise_meta = json.loads(pairwise_info['metadata'])
        my_did = pairwise_info['my_did']
        label = pairwise_meta['label']
        my_vk = await did.key_for_local_did(self.agent.wallet_handle, my_did)

        # response message generated
        response_msg = Message({
            '@type': "SEND_RESPONSE",
            '@sendTo': label,
            '~thread': {
                'thid': pairwise_meta['req_id']
            },
            'connection': {
                'DID': my_did,
                'DIDDoc': {
                    "@context":
                    "https://w3id.org/did/v1",
                    "id":
                    my_did,
                    "publicKey": [{
                        "id": my_did + "#keys-1",
                        "type": "Ed25519VerificationKey2018",
                        "controller": my_did,
                        "publicKeyBase58": my_vk
                    }],
                    "service": [{
                        "id": my_did + ";indy",
                        "type": "IndyAgent",
                        "recipientKeys": [my_vk],
                    }],
                }
            }
        })
        print("SEND RESPONSE: ", response_msg)

        # apply signature to connection field, sign with key used in invitation and request
        response_msg[
            'connection~sig'] = await self.agent.sign_agent_message_field(
                response_msg['connection'], pairwise_meta['connection_key'])
        del response_msg['connection']

        pending_connection = Serializer.unpack(
            json.loads(await non_secrets.get_wallet_record(
                self.agent.wallet_handle, 'invitations',
                pairwise_meta['connection_key'], '{}'))['value'])
        pending_connection['status'] = "Response Sent"
        pending_connection['@type'] = "RESPONSE SENT"
        pending_connection['history'].append({
            'date':
            str(datetime.datetime.now()),
            'msg':
            Message(msg).to_dict()
        })

        # send message to agent
        await self.agent.send_message_to_agent(their_did, response_msg)
        # delete invitation from records
        await non_secrets.delete_wallet_record(self.agent.wallet_handle,
                                               'invitations',
                                               pairwise_meta['connection_key'])
Ejemplo n.º 16
0
    async def send_request(self, msg: Message):
        """ Recall invite message from wallet and prepare and send request to the inviter.

            send_request message format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/admin_connections/1.0/send_request",
                  "key": <key sent in invite>
                }

            Request format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/request",
                  "label": "Bob",
                  "DID": "B.did@B:A",
                  "DIDDoc": {
                      // did Doc here.
                  }
                }
        """
        invite = Serializer.unpack(
            json.loads(await
                       non_secrets.get_wallet_record(self.agent.wallet_handle,
                                                     'invitation', msg['key'],
                                                     '{}'))['value'])

        my_label = self.agent.owner
        label = invite['label']
        their_connection_key = invite['key']
        their_endpoint = invite['endpoint']

        # Create my information for connection
        (my_did,
         my_vk) = await utils.create_and_store_my_did(self.agent.wallet_handle)

        await did.set_did_metadata(
            self.agent.wallet_handle, my_did,
            json.dumps({
                'label': label,
                'their_endpoint': their_endpoint
            }))

        # Send Connection Request to inviter
        request = Message({
            '@type': Connection.REQUEST,
            'label': my_label,
            'DID': my_did,
            'DIDDoc': {
                'key': my_vk,
                'endpoint': self.agent.endpoint,
            }
        })

        await self.agent.send_message_to_endpoint_and_key(
            my_vk, their_connection_key, their_endpoint, request)

        await self.agent.send_admin_message(
            Message({
                '@type': AdminConnection.REQUEST_SENT,
                'label': label
            }))
Ejemplo n.º 17
0
    async def send_response(self, msg: Message) -> Message:
        """ Send response to request.

            send_response message format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/admin_connections/1.0/send_response",
                  "did": <did of request sender>
                }

            Response format:
                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/response",
                  "did":"A.did@A:B",
                  "did_doc": {
                      //did doc
                  }
                }
        """
        their_did = msg['did']

        pairwise_info = json.loads(await pairwise.get_pairwise(self.agent.wallet_handle, their_did))
        pairwise_meta = json.loads(pairwise_info['metadata'])

        my_did = pairwise_info['my_did']
        label = pairwise_meta['label']
        my_vk = await did.key_for_local_did(self.agent.wallet_handle, my_did)

        response_msg = Message({
            '@type': Connection.RESPONSE,
            '~thread': { 'thid': pairwise_meta['req_id'] },
            'connection': {
                'did': my_did,
                'did_doc': {
                    "@context": "https://w3id.org/did/v1",
                    "id": my_did,
                    "publicKey": [{
                        "id": my_did + "#keys-1",
                        "type": "Ed25519VerificationKey2018",
                        "controller": my_did,
                        "publicKeyBase58": my_vk
                    }],
                    "service": [{
                        "id": my_did + ";indy",
                        "type": "IndyAgent",
                        "recipientKeys": [my_vk],
                        #"routingKeys": ["<example-agency-verkey>"],
                        "serviceEndpoint": self.agent.endpoint,
                    }],
                }
            }
        })

        # Apply signature to connection field, sign it with the key used in the invitation and request
        response_msg['connection~sig'] = await self.agent.sign_agent_message_field(response_msg['connection'], pairwise_meta["connection_key"])
        del response_msg['connection']

        pending_connection = Serializer.unpack(
            json.loads(
                await non_secrets.get_wallet_record(self.agent.wallet_handle,
                                                    'invitations',
                                                    pairwise_meta['connection_key'],
                                                    '{}')
            )['value']
        )
        pending_connection['status'] = "Response Sent"
        pending_connection['@type'] = AdminConnection.RESPONSE_SENT
        pending_connection['history'].append({
            'date': str(datetime.datetime.now()),
            'msg': msg.to_dict()})

        await self.agent.send_message_to_agent(their_did, response_msg)

        await self.agent.send_admin_message(pending_connection)

        await non_secrets.delete_wallet_record(self.agent.wallet_handle,
                                               'invitations',
                                               pairwise_meta['connection_key'])
Ejemplo n.º 18
0
    async def response_received(self, msg: Message) -> Message:
        """ Process response

            Response format:
                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/response",
                  "did":"A.did@A:B",
                  "did_doc": {
                      //did doc
                  }
                }
        """
        my_did = msg.context['to_did']
        my_vk = await did.key_for_local_did(self.agent.wallet_handle, my_did)

        #process signed field
        msg['connection'], sig_verified = await self.agent.unpack_and_verify_signed_agent_message_field(msg['connection~sig'])
        # connection~sig remains for metadata


        their_did = msg['connection']['did']
        their_vk = msg['connection']['did_doc']['publicKey'][0]['publicKeyBase58']
        their_endpoint = msg['connection']['did_doc']['service'][0]['serviceEndpoint']

        msg_vk = msg.context['from_key']
        # TODO: verify their_vk (from did doc) matches msg_vk

        # Retrieve connection information from DID metadata
        my_did_meta = json.loads(
            await did.get_did_metadata(self.agent.wallet_handle, my_did)
        )
        label = my_did_meta['label']

        # Clear DID metadata. This info will be stored in pairwise meta.
        await did.set_did_metadata(self.agent.wallet_handle, my_did, '')

        # In the final implementation, a signature will be provided to verify changes to
        # the keys and DIDs to be used long term in the relationship.
        # Both the signature and signature check are omitted for now until specifics of the
        # signature are decided.

        # Store their information from response
        await utils.store_their_did(self.agent.wallet_handle, their_did, their_vk)

        await did.set_did_metadata(
            self.agent.wallet_handle,
            their_did,
            json.dumps({
                'label': label,
                'endpoint': their_endpoint
            })
        )

        # Create pairwise relationship between my did and their did
        await pairwise.create_pairwise(
            self.agent.wallet_handle,
            their_did,
            my_did,
            json.dumps({
                'label': label,
                'their_endpoint': their_endpoint,
                'their_vk': their_vk,
                'my_vk': my_vk
            })
        )

        pending_connection = Serializer.unpack(
            json.loads(
                await non_secrets.get_wallet_record(self.agent.wallet_handle,
                                                    'invitations',
                                                    msg.data['connection~sig']['signer'],
                                                    '{}')
            )['value']
        )
        pending_connection['status'] = "Response Received"
        pending_connection['@type'] = AdminConnection.RESPONSE_RECEIVED
        pending_connection['history'].append({
            'date': str(datetime.datetime.now()),
            'msg': msg.to_dict()})

        # Pairwise connection between agents is established at this point
        await self.agent.send_admin_message(pending_connection)

        # Delete invitation
        await non_secrets.delete_wallet_record(self.agent.wallet_handle,
                                               'invitations',
                                               msg.data['connection~sig']['signer'])
Ejemplo n.º 19
0
    async def send_request(self, msg: Message):
        """ Recall invite message from wallet and prepare and send request to the inviter.

            send_request message format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/admin_connections/1.0/send_request",
                  "key": <key sent in invite>
                }

            Request format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/request",
                  "label": "Bob",
                  "did": "B.did@B:A",
                  "did_doc": {
                      // did Doc here.
                  }
                }
        """
        pending_connection = Serializer.unpack(
            json.loads(
                await non_secrets.get_wallet_record(
                    self.agent.wallet_handle,
                    'invitations',
                    msg['connection_key'],
                    '{}'
                )
            )['value']
        )

        my_label = self.agent.owner
        label = pending_connection['label']
        their_connection_key = pending_connection['connection_key']
        their_endpoint = pending_connection['endpoint']

        # Create my information for connection
        (my_did, my_vk) = await utils.create_and_store_my_did(self.agent.wallet_handle)

        await did.set_did_metadata(
            self.agent.wallet_handle,
            my_did,
            json.dumps({
                'label': label,
                'their_endpoint': their_endpoint
            })
        )

        # Send Connection Request to inviter
        request = Message({
            '@type': Connection.REQUEST,
            'label': my_label,
            'connection': {
                'did': my_did,
                'did_doc': {
                    "@context": "https://w3id.org/did/v1",
                    "id": my_did,
                    "publicKey": [{
                        "id": my_did + "#keys-1",
                        "type": "Ed25519VerificationKey2018",
                        "controller": my_did,
                        "publicKeyBase58": my_vk
                    }],
                    "service": [{
                        "id": my_did + ";indy",
                        "type": "IndyAgent",
                        "recipientKeys": [my_vk],
                        #"routingKeys": ["<example-agency-verkey>"],
                        "serviceEndpoint": self.agent.endpoint,
                    }],
                }
            }
        })

        await self.agent.send_message_to_endpoint_and_key(
            my_vk,
            their_connection_key,
            their_endpoint,
            request
        )

        pending_connection['@type'] = AdminConnection.REQUEST_SENT
        pending_connection['status'] = "Request Sent"
        pending_connection['history'].append({
            'date': str(datetime.datetime.now()),
            'msg': msg.to_dict()})
        await non_secrets.update_wallet_record_value(self.agent.wallet_handle,
                                                     'invitations',
                                                     pending_connection['connection_key'],
                                                     Serializer.pack(pending_connection))

        await self.agent.send_admin_message(pending_connection)
Ejemplo n.º 20
0
    async def response_received(self, msg: Message) -> Message:
        """ Process response

            Response format:
                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/response",
                  "did":"A.did@A:B",
                  "did_doc": {
                      //did doc
                  }
                }
        """
        r = await self.validate_common_message_blocks(msg, Connection.FAMILY)
        if not r:
            return r

        my_did = msg.context['to_did']
        if my_did is None:
            msg[ConnectionMessage.CONNECTION], sig_verified = await self.agent.unpack_and_verify_signed_agent_message_field(
                msg['connection~sig'])
            if not sig_verified:
                print('Encountered error parsing connection response. Connection request not found.')
            else:
                vk, endpoint = ConnectionMessage.extract_verkey_endpoint(msg)
                if None in (vk, endpoint):
                    # Cannot extract verkey and endpoint hence won't send any message back.
                    print('Encountered error parsing connection response. Connection request not found.')
                else:
                    # Sending an error message back to the sender
                    err_msg = self.build_problem_report_for_connections(Connection.FAMILY,
                                                                        ConnectionMessage.RESPONSE_FOR_UNKNOWN_REQUEST,
                                                                        "No corresponding connection request found")
                    await self.agent.send_message_to_endpoint_and_key(vk, endpoint, err_msg)
            return
        # Following should return an error if key not found for given DID
        my_vk = await did.key_for_local_did(self.agent.wallet_handle, my_did)

        #process signed field
        msg[ConnectionMessage.CONNECTION], sig_verified = await self.agent.unpack_and_verify_signed_agent_message_field(msg['connection~sig'])
        # connection~sig remains for metadata

        their_did, their_vk, their_endpoint = ConnectionMessage.extract_their_info(msg)

        msg_vk = msg.context['from_key']
        # TODO: verify their_vk (from did doc) matches msg_vk

        # Retrieve connection information from DID metadata
        my_did_meta = json.loads(
            await did.get_did_metadata(self.agent.wallet_handle, my_did)
        )
        label = my_did_meta['label']

        # Clear DID metadata. This info will be stored in pairwise meta.
        await did.set_did_metadata(self.agent.wallet_handle, my_did, '')

        # In the final implementation, a signature will be provided to verify changes to
        # the keys and DIDs to be used long term in the relationship.
        # Both the signature and signature check are omitted for now until specifics of the
        # signature are decided.

        # Store their information from response
        await utils.store_their_did(self.agent.wallet_handle, their_did, their_vk)

        await did.set_did_metadata(
            self.agent.wallet_handle,
            their_did,
            json.dumps({
                'label': label,
                'endpoint': their_endpoint
            })
        )

        # Create pairwise relationship between my did and their did
        await pairwise.create_pairwise(
            self.agent.wallet_handle,
            their_did,
            my_did,
            json.dumps({
                'label': label,
                'their_endpoint': their_endpoint,
                'their_vk': their_vk,
                'my_vk': my_vk,
                'connection_key': msg.data['connection~sig']['signer']
            })
        )

        pending_connection = Serializer.unpack(
            json.loads(
                await non_secrets.get_wallet_record(self.agent.wallet_handle,
                                                    'invitations',
                                                    msg.data['connection~sig']['signer'],
                                                    '{}')
            )['value']
        )
        pending_connection['status'] = "Response Received"
        pending_connection['@type'] = AdminConnection.RESPONSE_RECEIVED
        pending_connection['history'].append({
            'date': str(datetime.datetime.now()),
            'msg': msg.to_dict()})

        # Pairwise connection between agents is established at this point
        await self.agent.send_admin_message(pending_connection)

        # Delete invitation
        await non_secrets.delete_wallet_record(self.agent.wallet_handle,
                                               'invitations',
                                               msg.data['connection~sig']['signer'])
Ejemplo n.º 21
0
    async def response_recieved(self, msg: Message) -> Message:
        '''
        Response is received from user and connection is set into place.
        '''
        print("\nresponse received")
        my_did = msg.context['to_did']
        my_vk = await did.key_for_local_did(self.agent.wallet_handle, my_did)

        # process signed field
        msg['connection'], sig_verified = await self.agent.unpack_and_verify_signed_agent_message_field(
            msg['connection~sig'])
        # connection~sig remains for metadata
        their_did = msg['connection']['DID']
        their_vk = msg['connection']['DIDDoc']['publicKey'][0][
            'publicKeyBase58']

        msg_vk = msg.context['from_key']

        # Retrieve connection information from DID metadata
        my_did_meta = json.loads(await
                                 did.get_did_metadata(self.agent.wallet_handle,
                                                      my_did))
        label = my_did_meta['label']

        # Clear DID metadata. This info will be stored in pairwise meta.
        await did.set_did_metadata(self.agent.wallet_handle, my_did, '')

        # In the final implementation, a signature will be provided to verify changes to
        # the keys and DIDs to be used long term in the relationship.
        # Both the signature and signature check are omitted for now until specifics of the
        # signature are decided.

        # Store their information from response
        await utils.store_their_did(self.agent.wallet_handle, their_did,
                                    their_vk)

        await did.set_did_metadata(self.agent.wallet_handle, their_did,
                                   json.dumps({'label': label}))

        # Create pairwise relationship between my did and their did
        await pairwise.create_pairwise(
            self.agent.wallet_handle, their_did, my_did,
            json.dumps({
                'label': label,
                'their_vk': their_vk,
                'my_vk': my_vk,
                'connection_key': msg.data['connection~sig']['signer']
            }))
        # Retrieve pending connection from records
        pending_connection = Serializer.unpack(
            json.loads(await non_secrets.get_wallet_record(
                self.agent.wallet_handle, 'invitations',
                msg.data['connection~sig']['signer'], '{}'))['value'])
        pending_connection['status'] = "Response Received"
        pending_connection['@type'] = "RESPONSE_RECIEVED"
        pending_connection['history'].append({
            'date':
            str(datetime.datetime.now()),
            'msg':
            msg.to_dict()
        })
        print("CONNECTION RESPONSE_RECEIVED: PENDING CONN: ",
              pending_connection)

        # Pairwise connection between agents is established at this point
        # Delete invitation
        await non_secrets.delete_wallet_record(
            self.agent.wallet_handle, 'invitations',
            msg.data['connection~sig']['signer'])
Ejemplo n.º 22
0
async def message_process(agent):
    """ Message processing loop task.
        Message routes are also defined here through the message router.
    """
    msg_router = agent['msg_router']
    msg_receiver = agent['msg_receiver']
    ui_event_queue = agent['ui_event_queue']
    connection = agent['modules']['connection']

    msg_router.register(CONN.FAMILY, connection)

    while True:
        encrypted_msg_bytes = await msg_receiver.recv()
        try:
            encrypted_msg_str = Serializer.unpack(encrypted_msg_bytes)
        except Exception as e:
            print('Failed to unpack message: {}\n\nError: {}'.format(
                encrypted_msg_bytes, e))
            continue

        encrypted_msg_bytes = base64.b64decode(
            encrypted_msg_str['content'].encode('utf-8'))

        agent_dids_str = await did.list_my_dids_with_meta(
            WEBAPP['agent'].wallet_handle)

        agent_dids_json = json.loads(agent_dids_str)

        this_did = ""

        #  trying to find verkey for encryption
        for agent_did_data in agent_dids_json:
            try:
                decrypted_msg = await crypto.anon_decrypt(
                    WEBAPP['agent'].wallet_handle, agent_did_data['verkey'],
                    encrypted_msg_bytes)
                this_did = agent_did_data['did']
                #  decrypted -> found key, stop loop
                break

            except IndyError as e:
                #  key did not work
                if e.error_code == error.ErrorCode.CommonInvalidStructure:
                    print('Key did not work')
                    continue
                else:
                    #  something else happened
                    print('Could not decrypt message: {}\nError: {}'.format(
                        encrypted_msg_bytes, e))
                    continue

        if not decrypted_msg:
            "Agent doesn't have needed verkey for anon_decrypt"
            continue

        try:
            msg = Serializer.unpack(decrypted_msg)
        except Exception as e:
            print('Failed to unpack message: {}\n\nError: {}'.format(
                decrypted_msg, e))
            continue

        #  pass this connections did with the message
        msg['content']['did'] = this_did
        msg = Serializer.unpack_dict(msg['content'])

        res = await msg_router.route(msg)

        if res is not None:
            await ui_event_queue.send(Serializer.pack(res))
Ejemplo n.º 23
0
    async def send_request(self, invitation):
        '''
        When button pressed, connection request is send to the other user.
        :param invitation: invitation from wallet record
        '''
        pending_connection = Serializer.unpack(  # recover invitation from wallet record
            json.loads(await non_secrets.get_wallet_record(
                self.agent.wallet_handle, 'invitations',
                invitation.get('connection_key'), '{}'))['value'])
        print("PENDING CONNECTION", pending_connection)

        my_label = self.agent.owner  # agent name
        label = pending_connection['label']  # name of other agent
        their_connection_key = pending_connection['connection_key']

        # create info for connection
        (my_did,
         my_vk) = await create_and_store_my_did(self.agent.wallet_handle)
        await did.set_did_metadata(self.agent.wallet_handle, my_did,
                                   json.dumps({'label': label}))

        # Send Connection Request to inviter
        request = Message({
            '@type': "SEND_REQUEST",
            '@sendTo': label,
            'label': my_label,
            'connection': {
                'DID': my_did,
                'DIDDoc': {
                    "@context":
                    "https://w3id.org/did/v1",
                    "id":
                    my_did,
                    "publicKey": [{
                        "id": my_did + "#keys-1",
                        "type": "Ed25519VerificationKey2018",
                        "controller": my_did,
                        "publicKeyBase58": my_vk
                    }],
                    "service": [{
                        "id": my_did + ";indy",
                        "type": "IndyAgent",
                        "recipientKeys": [my_vk],
                    }],
                }
            }
        })
        print("REQUEST", request)

        print("SEND MESSAGE TO END AND KEY")
        await self.agent.send_message_to_endpoint_and_key(  # Send request to other user
            my_vk, their_connection_key, request)

        # update pending request record
        pending_connection['@type'] = "REQUEST_SENT"
        pending_connection['status'] = "Request Sent"
        pending_connection['history'].append({
            'date':
            str(datetime.datetime.now()),
            'msg':
            Message(invitation).to_dict()
        })
        await non_secrets.update_wallet_record_value(
            self.agent.wallet_handle, 'invitations',
            pending_connection['connection_key'],
            Serializer.pack(pending_connection))