class AdminWalletConnection(Module):
    FAMILY_NAME = "admin_walletconnection"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    CONNECT = FAMILY + "/connect"
    DISCONNECT = FAMILY + "/disconnect"
    USER_ERROR = FAMILY + "/user_error"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(AdminWalletConnection.CONNECT, self.connect)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def connect(self, msg):
        """ Connect to existing wallet.
        """

        try:
            await self.agent.connect_wallet(msg['name'], msg['passphrase'])
        except WalletConnectionException:
            return Message({
                '@type': AdminWalletConnection.USER_ERROR,
                'error_code': "invalid_passphrase",
                'message': "Invalid Passphrase",
                'thread': {
                    'thid': msg.id
                }
            })

        # prompt a STATE message.
        return await self.agent.modules[Admin.FAMILY].state_request(None)
Exemple #2
0
class AdminWalletConnection(Module):
    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(ADMIN_WALLETCONNECTION.CONNECT, self.connect)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def connect(self, msg):
        """ Connect to existing wallet.
        """

        try:
            await self.agent.connect_wallet(msg['name'], msg['passphrase'])
        except WalletConnectionException:
            return Message({
                'type': ADMIN_WALLETCONNECTION.USER_ERROR,
                'error_code': "invalid_passphrase",
                'message': "Invalid Passphrase",
                'thread': {
                    'thid': msg.id
                }
            })

        # prompt a STATE message.
        return await self.agent.modules['ui'].ui_connect(None)
Exemple #3
0
    def __init__(self, agent):
        self.agent = agent

        self.router = SimpleRouter()
        self.router.register(AdminConnection.SEND_INVITE, self.send_invite)
        self.router.register(AdminConnection.SEND_REQUEST, self.send_request)
        self.router.register(AdminConnection.SEND_RESPONSE, self.send_response)
class AdminProtocolDiscovery(Module):
    FAMILY_NAME = "admin_protocol_discovery"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    SEND_QUERY = FAMILY + "/send_query"
    QUERY_SENT = FAMILY + "/query_sent"
    QUERY_RECEIVED = FAMILY + "/query_received"
    DISCLOSE_SENT = FAMILY + "/disclose_sent"
    DISCLOSE_RECEIVED = FAMILY + "/disclose_received"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(AdminProtocolDiscovery.SEND_QUERY,
                             self.send_query)

    async def route(self, msg: Message) -> None:
        return await self.router.route(msg)

    async def send_query(self, msg: Message) -> None:
        query_msg = Message({
            '@type': ProtocolDiscovery.QUERY,
            'query': msg['query']
        })

        await self.agent.send_message_to_agent(msg['did'], query_msg)

        await self.agent.send_admin_message(
            Message({
                '@type': AdminProtocolDiscovery.QUERY_SENT,
                'from': msg['did']
            }))
Exemple #5
0
class Ui(Module):
    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(UI.STATE_REQUEST, self.ui_connect)
        self.router.register(UI.INITIALIZE, self.initialize_agent)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def ui_connect(self, _) -> Message:

        return Message({
            'type': UI.STATE,
            'content': {
                'initialized': self.agent.initialized,
                'agent_name': self.agent.owner
            }
        })

    async def initialize_agent(self, msg):
        """ Initialize agent.
        """
        if self.agent.initialized is True:
            return
        data = msg['content']
        agent_name = data['name']
        passphrase = data['passphrase']
        await self.agent.connect_wallet(data['name'], data['passphrase'])

        return await self.ui_connect(None)
Exemple #6
0
    def __init__(self, agent):
        self.agent = agent

        self.router = SimpleRouter()
        self.router.register(AdminConnection.GENERATE_INVITE, self.generate_invite)
        self.router.register(AdminConnection.RECEIVE_INVITE, self.receive_invite)
        self.router.register(AdminConnection.SEND_REQUEST, self.send_request)
        self.router.register(AdminConnection.SEND_RESPONSE, self.send_response)
class BasicMessage(Module):

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(BASICMESSAGE.MESSAGE, self.receive_message)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def receive_message(self, msg: Message) -> Message:
        their_did_str = msg['from']

        pairwise_conn_info_str = await pairwise.get_pairwise(self.agent.wallet_handle, their_did_str)
        pairwise_conn_info_json = json.loads(pairwise_conn_info_str)

        my_did_str = pairwise_conn_info_json['my_did']
        metadata = json.loads(pairwise_conn_info_json['metadata'])

        my_did_info_str = await did.get_my_did_with_meta(self.agent.wallet_handle, my_did_str)

        my_did_info_json = json.loads(my_did_info_str)
        my_verkey = my_did_info_json['verkey']

        message_bytes = str_to_bytes(msg['message'])
        message_bytes = base64.b64decode(message_bytes)

        their_key_str, their_data_bytes = await crypto.auth_decrypt(
            self.agent.wallet_handle, my_verkey, message_bytes)

        their_data_json = json.loads(bytes_to_str(their_data_bytes))

        # store message in the wallet
        await non_secrets.add_wallet_record(
            self.agent.wallet_handle,
            "basicmessage",
            uuid.uuid4().hex,
            json.dumps({
                'from': their_did_str,
                'timestamp': their_data_json['timestamp'],
                'content': their_data_json['content']
            }),
            json.dumps({
                "their_did": their_did_str
            })
        )

        return Message({
            '@type': ADMIN_BASICMESSAGE.MESSAGE_RECEIVED,
            'id': self.agent.ui_token,
            'with': their_did_str,
            'message': {
                'from': their_did_str,
                'timestamp': their_data_json['timestamp'],
                'content': their_data_json['content']
            }
        })
Exemple #8
0
class BasicMessage(Module):
    """ Class handling messages received from another Indy agent.
    """
    FAMILY_NAME = "basicmessage"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    MESSAGE = FAMILY + "/message"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(BasicMessage.MESSAGE, self.receive_message)

    async def route(self, msg: Message) -> None:
        """ Route a message to its registered callback.
        """
        return await self.router.route(msg)

    async def receive_message(self, msg: Message) -> None:
        """ Process the reception of a basic message from another Indy agent.

        :param msg: Basic message is of the following format:
            {
                '@type': BasicMessage.MESSAGE,
                '~l10n': {'locale': 'en'},
                'sent_time': '2019-05-27 08:34:25.105373+00:00',
                'content': 'Hello'
            }
        :return: None
        """
        is_valid = await self.validate_common_message_blocks(
            msg, BasicMessage.FAMILY)
        if not is_valid:
            return

        # Store message in the wallet
        await non_secrets.add_wallet_record(
            self.agent.wallet_handle, 'basicmessage',
            uuid.uuid4().hex,
            json.dumps({
                'from': msg.context['from_did'],
                'sent_time': msg['sent_time'],
                'content': msg['content']
            }), json.dumps({'their_did': msg.context['from_did']}))

        await self.agent.send_admin_message(
            Message({
                '@type': AdminBasicMessage.MESSAGE_RECEIVED,
                'id': self.agent.ui_token,
                'with': msg.context['from_did'],
                'message': {
                    'from': msg.context['from_did'],
                    'sent_time': msg['sent_time'],
                    'content': msg['content']
                }
            }))
Exemple #9
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(CONN.INVITE, self.invite_received)
     self.router.register(CONN.REQUEST, self.request_received)
     self.router.register(CONN.RESPONSE, self.response_received)
     self.router.register(CONN.MESSAGE, self.message_received)
     self.router.register(CONN_UI.SEND_INVITE, self.send_invite)
     self.router.register(CONN_UI.SEND_REQUEST, self.send_request)
     self.router.register(CONN_UI.SEND_RESPONSE, self.send_response)
     self.router.register(CONN_UI.SEND_MESSAGE, self.send_message)
Exemple #10
0
    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(CONN.INVITE, self.invite_received)
        self.router.register(CONN.REQUEST, self.request_received)
        self.router.register(CONN.RESPONSE, self.response_received)

        self.router.register(ADMIN_CONNECTIONS.SEND_INVITE, self.send_invite)
        self.router.register(ADMIN_CONNECTIONS.SEND_REQUEST, self.send_request)
        self.router.register(ADMIN_CONNECTIONS.SEND_RESPONSE,
                             self.send_response)
Exemple #11
0
class Admin(Module):
    FAMILY_NAME = "admin"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    STATE = FAMILY + "/state"
    STATE_REQUEST = FAMILY + "/state_request"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(self.STATE_REQUEST, self.state_request)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def state_request(self, _) -> Message:
        print("Processing state_request")

        if self.agent.initialized:
            invitations = await get_wallet_records(self.agent.wallet_handle,
                                                   "invitations")

            # load up pairwise connections
            pairwise_records = []
            agent_pairwises_list_str = await pairwise.list_pairwise(
                self.agent.wallet_handle)
            agent_pairwises_list = json.loads(agent_pairwises_list_str)
            for agent_pairwise_str in agent_pairwises_list:
                pairwise_record = json.loads(agent_pairwise_str)
                pairwise_record['metadata'] = json.loads(
                    pairwise_record['metadata'])
                pairwise_records.append(pairwise_record)

            await self.agent.send_admin_message(
                Message({
                    '@type': self.STATE,
                    'content': {
                        'initialized': self.agent.initialized,
                        'agent_name': self.agent.owner,
                        'invitations': invitations,
                        'pairwise_connections': pairwise_records,
                    }
                }))
        else:
            await self.agent.send_admin_message(
                Message({
                    '@type': self.STATE,
                    'content': {
                        'initialized': self.agent.initialized,
                    }
                }))
class AdminWalletConnection(Module):
    """ Class handling messages received from the UI.
    """
    FAMILY_NAME = "admin_walletconnection"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    CONNECT = FAMILY + "/connect"
    DISCONNECT = FAMILY + "/disconnect"
    USER_ERROR = FAMILY + "/user_error"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(AdminWalletConnection.CONNECT, self.connect)
        self.router.register(AdminWalletConnection.DISCONNECT, self.disconnect)

    async def route(self, msg: Message) -> None:
        """ Route a message to its registered callback
        """
        return await self.router.route(msg)

    async def connect(self, msg: Message) -> None:
        """ Connect to an existing wallet.
        """
        try:
            await self.agent.connect_wallet(msg['name'], msg['passphrase'])
        except WalletConnectionException:
            await self.agent.send_admin_message(
                Message({
                    '@type': AdminWalletConnection.USER_ERROR,
                    'error_code': 'invalid_passphrase',
                    'message': 'Invalid Passphrase',
                    'thread': {
                        'thid': msg['id']
                    }
                }))

        # Prompt a STATE message.
        return await self.agent.modules[Admin.FAMILY].state_request(None)

    async def disconnect(self, _) -> None:
        """ Disconnect from an existing wallet.
        """
        await self.agent.disconnect_wallet()

        # Prompt a STATE message.
        return await self.agent.modules[Admin.FAMILY].state_request(None)
Exemple #13
0
class TrustPing(Module):
    FAMILY_NAME = "trust_ping"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    PING = FAMILY + "/ping"
    PING_RESPONSE = FAMILY + "/ping_response"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(TrustPing.PING, self.ping)
        self.router.register(TrustPing.PING_RESPONSE, self.ping_response)

    async def route(self, msg: Message) -> None:
        return await self.router.route(msg)

    async def ping(self, msg: Message) -> None:
        r = await self.validate_common_message_blocks(msg, TrustPing.FAMILY)
        if not r:
            return

        await self.agent.send_admin_message(
            Message({
                '@type': AdminTrustPing.TRUSTPING_RECEIVED,
                'from': msg.context['from_did'],
            }))

        await self.agent.send_message_to_agent(
            msg.context['from_did'],
            Message({
                '@type': TrustPing.PING_RESPONSE,
                '~thread': {
                    Message.THREAD_ID: msg.id,
                    Message.SENDER_ORDER: 0
                }
            }))

    async def ping_response(self, msg: Message) -> None:
        await self.agent.send_admin_message(
            Message({
                '@type': AdminTrustPing.TRUSTPING_RESPONSE_RECEIVED,
                'from': msg.context['from_did'],
            }))
Exemple #14
0
class Admin(Module):

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(ADMIN.STATE_REQUEST, self.state_request)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def state_request(self, _) -> Message:

        invitations = []
        if self.agent.initialized:
            search_handle = await non_secrets.open_wallet_search(self.agent.wallet_handle, "invitations",
                                                                 json.dumps({}),
                                                                 json.dumps({'retrieveTotalCount': True}))
            results = await non_secrets.fetch_wallet_search_next_records(self.agent.wallet_handle, search_handle, 100)

            for r in json.loads(results)["records"] or []: # records is None if empty
                d = json.loads(r['value'])
                d["_id"] = r["id"] # include record id for further reference.
                invitations.append(d)
            #TODO: fetch in loop till all records are processed
            await non_secrets.close_wallet_search(search_handle)

        # load up pairwise connections
        pairwise_records = []
        agent_pairwises_list_str = await pairwise.list_pairwise(self.agent.wallet_handle)
        agent_pairwises_list = json.loads(agent_pairwises_list_str)
        for agent_pairwise_str in agent_pairwises_list:
            pairwise_record = json.loads(agent_pairwise_str)
            pairwise_record['metadata'] = json.loads(pairwise_record['metadata'])
            pairwise_records.append(pairwise_record)

        return Message({
            '@type': ADMIN.STATE,
            'content': {
                'initialized': self.agent.initialized,
                'agent_name': self.agent.owner,
                'invitations': invitations,
                'pairwise_connections': pairwise_records,
            }
        })
Exemple #15
0
class BasicMessage(Module):
    FAMILY_NAME = "basicmessage"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    MESSAGE = FAMILY + "/message"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(BasicMessage.MESSAGE, self.receive_message)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def receive_message(self, msg: Message):
        r = await self.validate_common_message_blocks(msg, BasicMessage.FAMILY)
        if not r:
            return r

        # store message in the wallet
        await non_secrets.add_wallet_record(
            self.agent.wallet_handle, "basicmessage",
            uuid.uuid4().hex,
            json.dumps({
                'from': msg.context['from_did'],
                'sent_time': msg['sent_time'],
                'content': msg['content']
            }), json.dumps({"their_did": msg.context['from_did']}))

        await self.agent.send_admin_message(
            Message({
                '@type': AdminBasicMessage.MESSAGE_RECEIVED,
                'id': self.agent.ui_token,
                'with': msg.context['from_did'],
                'message': {
                    'from': msg.context['from_did'],
                    'sent_time': msg['sent_time'],
                    'content': msg['content']
                }
            }))
Exemple #16
0
class AdminTrustPing(Module):
    FAMILY_NAME = "admin_trustping"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION + "/"

    SEND_TRUSTPING = FAMILY + "send_trustping"
    TRUSTPING_SENT = FAMILY + "trustping_sent"
    TRUSTPING_RECEIVED = FAMILY + "trustping_received"
    TRUSTPING_RESPONSE_RECEIVED = FAMILY + "trustping_response_received"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(AdminTrustPing.SEND_TRUSTPING, self.send_trustping)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def trustping_response(self, msg: Message) -> Message:
        print("trustping_response")
        print(msg)

    async def send_trustping(self, msg: Message) -> Message:
        """ UI activated method.
        """

        their_did_str = msg['to']

        message = Message({
            '@type': TrustPing.PING
        })

        await self.agent.send_message_to_agent(their_did_str, message)

        await self.agent.send_admin_message(
            Message({
                '@type': AdminTrustPing.TRUSTPING_SENT,
                'to': their_did_str,
            })
        )
Exemple #17
0
class TrustPing(Module):
    FAMILY_NAME = "trust_ping"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION + "/"

    PING = FAMILY + "ping"
    PING_REPONSE = FAMILY + "ping_response"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(TrustPing.PING, self.ping)
        self.router.register(TrustPing.PING_REPONSE, self.ping_response)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def ping(self, msg: Message) -> Message:
        await self.agent.send_admin_message(
            Message({
                '@type': AdminTrustPing.TRUSTPING_RECEIVED,
                'from': msg.context['from_did'],
            })
        )

        await self.agent.send_message_to_agent(
            msg.context['from_did'],
            Message({
                '@type': TrustPing.PING_REPONSE,
                '~thread': {'thid': msg.id}
            })
        )

    async def ping_response(self, msg: Message) -> Message:
        await self.agent.send_admin_message(
            Message({
                '@type': AdminTrustPing.TRUSTPING_RESPONSE_RECEIVED,
                'from': msg.context['from_did'],
            })
        )
Exemple #18
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(TrustPing.PING, self.ping)
     self.router.register(TrustPing.PING_RESPONSE, self.ping_response)
Exemple #19
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(AdminTrustPing.SEND_TRUSTPING,
                          self.send_trustping)
Exemple #20
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(Connection.REQUEST, self.request_received)
     self.router.register(Connection.RESPONSE, self.response_received)
Exemple #21
0
class Connection(Module):

    FAMILY_NAME = "connections"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION + "/"

    INVITE = FAMILY + "invitation"
    REQUEST = FAMILY + "request"
    RESPONSE = FAMILY + "response"


    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(Connection.REQUEST, self.request_received)
        self.router.register(Connection.RESPONSE, self.response_received)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def request_received(self, msg: Message) -> Message:
        """ Received connection request.

            Request format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/request",
                  "label": "Bob",
                  "connection":{
                      "did": "B.did@B:A",
                      "did_doc": {
                          "@context": "https://w3id.org/did/v1",
                          "publicKey": [{
                            "id": "did:example:123456789abcdefghi#keys-1",
                            "type": "Ed25519VerificationKey2018",
                            "controller": "did:example:123456789abcdefghi",
                            "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
                          }],
                          "service": [{
                            "type": "IndyAgent",
                            "recipientKeys" : [ "<verkey>" ], //pick one
                            "routingKeys": ["<example-agency-verkey>"],
                            "serviceEndpoint": "https://example.agency.com",
                          }]
                      }
                  }
                }
        """
        connection_key = msg.context['to_key']

        label = msg['label']
        their_did = msg['connection']['did']
        # NOTE: these values are pulled based on the minimal connectathon format. Full processing
        #  will require full DIDDoc storage and evaluation.
        their_vk = msg['connection']['did_doc']['publicKey'][0]['publicKeyBase58']
        their_endpoint = msg['connection']['did_doc']['service'][0]['serviceEndpoint']

        # Store their information from request
        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 my information for connection
        (my_did, my_vk) = await utils.create_and_store_my_did(self.agent.wallet_handle)

        # 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,
                'req_id': msg['@id'],
                'their_endpoint': their_endpoint,
                'their_vk': their_vk,
                'my_vk': my_vk,
                'connection_key': connection_key  # used to sign the response
            })
        )

        pending_connection = Message({
            '@type': AdminConnection.REQUEST_RECEIVED,
            'label': label,
            'did': their_did,
            'connection_key': connection_key,
            'endpoint': their_endpoint,
            'history': [{
                'date': str(datetime.datetime.now()),
                'msg': msg.to_dict()}],
            'status': "Request Received"
            # routingKeys not specified, but here is where they would be put in the invite.
        })
        try:
            await non_secrets.add_wallet_record(
                self.agent.wallet_handle,
                'invitations',
                connection_key,
                Serializer.pack(pending_connection),
                '{}'
            )
        except error.IndyError as indy_error:
            if indy_error.error_code == error.ErrorCode.WalletItemAlreadyExists:
                pass
            raise indy_error
        await self.agent.send_admin_message(pending_connection)




    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'])
Exemple #22
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(AdminBasicMessage.SEND_MESSAGE, self.send_message)
     self.router.register(AdminBasicMessage.GET_MESSAGES, self.get_messages)
Exemple #23
0
class AdminBasicMessage(Module):
    FAMILY_NAME = "admin_basicmessage"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION + "/"

    MESSAGE_RECEIVED = FAMILY + "message_received"
    SEND_MESSAGE = FAMILY + "send_message"
    MESSAGE_SENT = FAMILY + "message_sent"
    GET_MESSAGES = FAMILY + "get_messages"
    MESSAGES = FAMILY + "messages"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(AdminBasicMessage.SEND_MESSAGE, self.send_message)
        self.router.register(AdminBasicMessage.GET_MESSAGES, self.get_messages)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def send_message(self, msg: Message) -> Message:
        """ UI activated method.
        """

        # This lookup block finds the from address from the to address. This should be fixed, so that the from address
        #  comes in the admin message.
        their_did_str = msg['to']
        pairwise_conn_info_str = await pairwise.get_pairwise(
            self.agent.wallet_handle, their_did_str)
        pairwise_conn_info_json = json.loads(pairwise_conn_info_str)
        my_did_str = pairwise_conn_info_json['my_did']

        message_to_send = msg['message']
        sent_time = datetime.datetime.utcnow().replace(
            tzinfo=datetime.timezone.utc).isoformat(' ')

        # store message in the wallet
        await non_secrets.add_wallet_record(
            self.agent.wallet_handle, "basicmessage",
            uuid.uuid4().hex,
            json.dumps({
                'from': my_did_str,
                'sent_time': sent_time,
                'content': message_to_send
            }), json.dumps({"their_did": their_did_str}))

        message = Message({
            '@type': BasicMessage.MESSAGE,
            '~l10n': {
                'locale': 'en'
            },
            'sent_time': sent_time,
            'content': message_to_send
        })

        await self.agent.send_message_to_agent(their_did_str, message)

        await self.agent.send_admin_message(
            Message({
                '@type': AdminBasicMessage.MESSAGE_SENT,
                'id': self.agent.ui_token,
                'with': their_did_str,
                'message': {
                    'from': my_did_str,
                    'sent_time': sent_time,
                    'content': message_to_send
                }
            }))

    async def get_messages(self, msg: Message) -> Message:
        their_did = msg['with']
        search_handle = await non_secrets.open_wallet_search(
            self.agent.wallet_handle, "basicmessage",
            json.dumps({"their_did": their_did}), json.dumps({}))
        results = await non_secrets.fetch_wallet_search_next_records(
            self.agent.wallet_handle, search_handle, 100)

        messages = []
        for r in json.loads(
                results)["records"] or []:  # records is None if empty
            d = json.loads(r['value'])
            d["_id"] = r["id"]  # include record id for further reference.
            messages.append(d)
        #TODO: fetch in loop till all records are processed
        await non_secrets.close_wallet_search(search_handle)
        messages = sorted(messages, key=lambda n: n['sent_time'], reverse=True)

        await self.agent.send_admin_message(
            Message({
                '@type': AdminBasicMessage.MESSAGES,
                'with': their_did,
                'messages': messages
            }))
Exemple #24
0
class AdminStaticConnection(Module):
    FAMILY_NAME = "admin_staticconnections"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    # Message Types in this family
    CREATE_STATIC_CONNECTION = FAMILY + "/create_static_connection"
    STATIC_CONNECTION_CREATED = FAMILY + "/static_connection_created"

    def __init__(self, agent):
        self.agent = agent

        self.router = SimpleRouter()
        self.router.register(AdminStaticConnection.CREATE_STATIC_CONNECTION,
                             self.create_static_connection)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def create_static_connection(self, msg: Message) -> Message:
        """ Generate new connection invitation.

            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.

            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",
                    "did": "did:peer:oiSqsNYhMrjHiqZDTUthsw",
                    "key": "8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K",
                    "endpoint": "https://example.com/endpoint"
                }

            Currently, only peer DID is supported.
        """
        their_did = msg['did']
        their_vk = msg['vk']
        their_endpoint = msg['endpoint']
        label = msg['label']

        # Store their information from request
        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 my information for connection
        (my_did,
         my_vk) = await utils.create_and_store_my_did(self.agent.wallet_handle)

        # 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,
                'static': True
            }))

        await self.agent.send_admin_message(
            Message({
                '@type': AdminStaticConnection.STATIC_CONNECTION_CREATED,
                'label': label,
                'my_did': my_did,
                'my_vk': my_vk,
                'my_endpoint': self.agent.endpoint
            }))
Exemple #25
0
    def __init__(self, agent):
        self.agent = agent

        self.router = SimpleRouter()
        self.router.register(AdminStaticConnection.CREATE_STATIC_CONNECTION,
                             self.create_static_connection)
Exemple #26
0
class Connection(Module):

    FAMILY_NAME = "connections"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION

    INVITE = FAMILY + "/invitation"
    REQUEST = FAMILY + "/request"
    RESPONSE = FAMILY + "/response"

    def __init__(self, agent):
        self.agent = agent
        self.router = SimpleRouter()
        self.router.register(Connection.REQUEST, self.request_received)
        self.router.register(Connection.RESPONSE, self.response_received)

    async def route(self, msg: Message) -> None:
        return await self.router.route(msg)

    async def request_received(self, msg: Message) -> None:
        """ Received connection request.

            Request format:

                {
                  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/request",
                  "label": "Bob",
                  "connection":{
                      "did": "B.did@B:A",
                      "did_doc": {
                          "@context": "https://w3id.org/did/v1",
                          "publicKey": [{
                            "id": "did:example:123456789abcdefghi#keys-1",
                            "type": "Ed25519VerificationKey2018",
                            "controller": "did:example:123456789abcdefghi",
                            "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
                          }],
                          "service": [{
                            "type": "IndyAgent",
                            "recipientKeys" : [ "<verkey>" ], //pick one
                            "routingKeys": ["<example-agency-verkey>"],
                            "serviceEndpoint": "https://example.agency.com",
                          }]
                      }
                  }
                }
        """
        r = await self.validate_common_message_blocks(msg, Connection.FAMILY)
        if not r:
            return

        try:
            ConnectionMessage.Request.validate(msg)
        except Exception as e:
            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 request ', e)
            else:
                # Sending an error message back to the sender
                err_msg = self.build_problem_report_for_connections(Connection.FAMILY, ConnectionMessage.REQUEST_NOT_ACCEPTED, str(e))
                await self.agent.send_message_to_endpoint_and_key(vk, endpoint, err_msg)
            return

        connection_key = msg.context['to_key']

        label = msg['label']

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

        # Store their information from request
        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 my information for connection
        (my_did, my_vk) = await utils.create_and_store_my_did(self.agent.wallet_handle)

        # 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,
                'req_id': msg['@id'],
                'their_endpoint': their_endpoint,
                'their_vk': their_vk,
                'my_vk': my_vk,
                'connection_key': connection_key  # used to sign the response
            })
        )

        pending_connection = Message({
            '@type': AdminConnection.REQUEST_RECEIVED,
            'label': label,
            'did': their_did,
            'connection_key': connection_key,
            'endpoint': their_endpoint,
            'history': [{
                'date': str(datetime.datetime.now()),
                'msg': msg.to_dict()}],
            'status': "Request Received"
            # routingKeys not specified, but here is where they would be put in the invite.
        })
        try:
            await non_secrets.add_wallet_record(
                self.agent.wallet_handle,
                'invitations',
                connection_key,
                Serializer.serialize(pending_connection).decode('utf-8'),
                '{}'
            )
        except error.IndyError as indy_error:
            if indy_error.error_code == error.ErrorCode.WalletItemAlreadyExists:
                pass
            raise indy_error
        await self.agent.send_admin_message(pending_connection)

    async def response_received(self, msg: Message) -> None:
        """ 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

        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)

        # Verify that their_vk (from did doc) matches msg_vk
        msg_vk = msg.context['from_key']
        if their_vk != msg_vk:
            err_msg = \
                self.build_problem_report_for_connections(
                    Connection.FAMILY,
                    ConnectionMessage.KEY_ERROR,
                    "Key provided in response does not match expected key")
            verkey, endpoint = ConnectionMessage.extract_verkey_endpoint(msg)
            await self.agent.send_message_to_endpoint_and_key(verkey, endpoint, err_msg)
            return

        # 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.deserialize(
            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'])
Exemple #27
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(self.STATE_REQUEST, self.state_request)
Exemple #28
0
class AdminConnection(Module):
    FAMILY_NAME = "admin_connections"
    VERSION = "1.0"
    FAMILY = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/" + FAMILY_NAME + "/" + VERSION + "/"

    # Message Types in this family
    CONNECTION_LIST = FAMILY + "connection_list"
    CONNECTION_LIST_REQUEST = FAMILY + "connection_list_request"

    GENERATE_INVITE = FAMILY + "generate_invite"
    INVITE_GENERATED = FAMILY + "invite_generated"
    INVITE_RECEIVED = FAMILY + "invite_received"
    RECEIVE_INVITE = FAMILY + "receive_invite"

    SEND_REQUEST = FAMILY + "send_request"
    REQUEST_SENT = FAMILY + "request_sent"
    REQUEST_RECEIVED = FAMILY + "request_received"

    SEND_RESPONSE = FAMILY + "send_response"
    RESPONSE_SENT = FAMILY + "response_sent"
    RESPONSE_RECEIVED = FAMILY + "response_received"

    def __init__(self, agent):
        self.agent = agent

        self.router = SimpleRouter()
        self.router.register(AdminConnection.GENERATE_INVITE, self.generate_invite)
        self.router.register(AdminConnection.RECEIVE_INVITE, self.receive_invite)
        self.router.register(AdminConnection.SEND_REQUEST, self.send_request)
        self.router.register(AdminConnection.SEND_RESPONSE, self.send_response)

    async def route(self, msg: Message) -> Message:
        return await self.router.route(msg)

    async def generate_invite(self, msg: Message) -> Message:
        """ Generate new connection invitation.

            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.

            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",
                    "did": "did:peer:oiSqsNYhMrjHiqZDTUthsw",
                    "key": "8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K",
                    "endpoint": "https://example.com/endpoint"
                }

            Currently, only peer DID is supported.
        """
        connection_key = await did.create_key(self.agent.wallet_handle, "{}")

        # Store connection key
        await non_secrets.add_wallet_record(
            self.agent.wallet_handle,
            'connection_key',
            connection_key,
            connection_key,
            '{}'
        )

        invite_msg = Message({
            '@type': Connection.INVITE,
            'label': self.agent.owner,
            'recipientKeys': [connection_key],
            'serviceEndpoint': self.agent.endpoint,
            # routingKeys not specified, but here is where they would be put in the invite.
        })

        b64_invite = \
            base64.urlsafe_b64encode(bytes(Serializer.pack(invite_msg), 'utf-8')).decode('ascii')

        await self.agent.send_admin_message(
            Message({
                '@type': AdminConnection.INVITE_GENERATED,
                'invite': '{}?c_i={}'.format(self.agent.endpoint, b64_invite)
            })
        )

    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')
        )

        pending_connection = Message({
            '@type': AdminConnection.INVITE_RECEIVED,
            'label': invite_msg['label'],
            'connection_key': invite_msg['recipientKeys'][0],
            'endpoint': invite_msg['serviceEndpoint'],
            'history': [{
                'date': str(datetime.datetime.now()),
                'msg': invite_msg.to_dict()
            }],
            'status': "Invite Received"
        })
        await self.agent.send_admin_message(pending_connection)

        await non_secrets.add_wallet_record(
            self.agent.wallet_handle,
            'invitations',
            invite_msg['recipientKeys'][0],
            Serializer.pack(pending_connection),
            '{}'
        )

    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)

    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'])
Exemple #29
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(ADMIN_WALLETCONNECTION.CONNECT, self.connect)
Exemple #30
0
 def __init__(self, agent):
     self.agent = agent
     self.router = SimpleRouter()
     self.router.register(UI.STATE_REQUEST, self.ui_connect)
     self.router.register(UI.INITIALIZE, self.initialize_agent)