Example #1
0
 async def handle(self, content_type, data):
     try:
         if content_type == DIDExchange.MESSAGE_CONTENT_TYPE:
             kwargs = json.loads(data)
             msg = Message(**kwargs)
         elif content_type in WIRED_CONTENT_TYPES:
             msg = await DIDExchange.unpack_agent_message(data, self.get_wallet())
         else:
             raise RuntimeError('Unknown content_type "%s"' % content_type)
         await self.__log('Receive', msg.to_dict())
         if msg.type == DIDExchange.INVITE:
             await self.__receive_invitation(msg)
         elif msg.type == DIDExchange.RESPONSE:
             await self.__receive_connection_response(msg)
         elif msg.type == DIDExchange.PROBLEM_REPORT:
             if self.status == DIDExchangeStatus.Requested:
                 # Stay in same state - retryable
                 pass
             else:
                 raise ImpossibleStatus()
         else:
             logging.error('Unexpected message type: %s' % msg.type)
     except Exception as e:
         if not isinstance(e, MachineIsDone):
             logging.exception('Base machine terminated with exception')
         await self.done()
Example #2
0
 async def handle(cls,
                  agent_name: str,
                  wire_message: bytes,
                  my_label: str = None,
                  my_endpoint: str = None) -> bool:
     unpacked = await WalletAgent.unpack_message(agent_name, wire_message)
     kwargs = json.loads(unpacked['message'])
     message = Message(**kwargs)
     print('***** feature 0037 handle message *****')
     if 'sender_verkey' in unpacked:
         sender_verkey = unpacked['sender_verkey']
     else:
         sender_verkey = None
     if 'recipient_verkey' in unpacked:
         recipient_verkey = unpacked['recipient_verkey']
     else:
         recipient_verkey = None
     print('sender_verkey: ' + sender_verkey)
     print('recipient_verkey: ' + recipient_verkey)
     print(json.dumps(message.to_dict(), indent=2, sort_keys=True))
     print('***************************************')
     if message.get('@type', None) is None:
         return False
     if not cls.endorsement(message):
         return False
     state_machine_id = cls.get_state_machine_id(unpacked['sender_verkey'])
     if message.type in [
             PresentProofProtocol.REQUEST_PRESENTATION, AckMessage.ACK
     ]:
         if message.type == PresentProofProtocol.REQUEST_PRESENTATION:
             machine_class = PresentProofProtocol.ProverStateMachine
             await WalletAgent.start_state_machine(
                 status=PresentProofStatus.Null,
                 ttl=PresentProofProtocol.STATE_MACHINE_TTL,
                 agent_name=agent_name,
                 machine_class=machine_class,
                 machine_id=state_machine_id)
         await WalletAgent.invoke_state_machine(
             agent_name=agent_name,
             id_=state_machine_id,
             content_type=cls.WIRED_CONTENT_TYPE,
             data=wire_message)
         return True
     elif message.type in [PresentProofProtocol.PRESENTATION]:
         await WalletAgent.invoke_state_machine(
             agent_name=agent_name,
             id_=state_machine_id,
             content_type=cls.WIRED_CONTENT_TYPE,
             data=wire_message)
         return True
     elif message.type == PresentProofProtocol.PROBLEM_REPORT:
         await WalletAgent.invoke_state_machine(
             agent_name=agent_name,
             id_=state_machine_id,
             content_type=cls.WIRED_CONTENT_TYPE,
             data=wire_message)
         return True
     else:
         return False
Example #3
0
 def validate(msg: Message):
     msg.check_for_attrs(
         [
             ('@type', RoutingMessage.FORWARD),
             'to',
             'msg',
         ]
     )
Example #4
0
 def validate(msg: Message):
     msg.check_for_attrs(
         [
             ('@type', AckMessage.ACK),
             'status',
             '~thread',
         ]
     )
Example #5
0
 def validate_pre_sig(response: Message):
     response.check_for_attrs(
         [
             ('@type', DIDExchange.RESPONSE),
             '~thread',
             'connection~sig'
         ]
     )
Example #6
0
    def validate(msg: Message):
        msg.check_for_attrs([
            ('@type', BasicMessage.MESSAGE),
            '~l10n',
            'sent_time',
            'content',
        ])

        Message.check_for_attrs_in_message([('locale', 'en')], msg['~l10n'])
Example #7
0
    async def pack(msg: Message, wallet: WalletConnection, their_ver_key, routing_keys: list, my_ver_key=None) -> bytes:
        if not routing_keys:
            raise RuntimeError('routing_keys must not be empty')
        payload = await wallet.pack_message(
            Serializer.serialize(msg).decode(RoutingMessage.ENC),
            their_ver_key,
            my_ver_key
        )
        keys_map = {}
        for n in range(len(routing_keys)-1, 0, -1):  # example: IF routing_keys = ['k1', 'k2', 'k3'] THEN n = [2,1]
            outer_key = routing_keys[n]
            inner_key = routing_keys[n-1]
            keys_map[outer_key] = inner_key
        keys_map[routing_keys[0]] = their_ver_key

        for outer_key in routing_keys:
            inner_key = keys_map[outer_key]
            forwarded = Message({
                '@type': RoutingMessage.FORWARD,
                'to': inner_key,
                'msg': json.loads(payload.decode(RoutingMessage.ENC))
            })
            payload = await wallet.pack_message(
                Serializer.serialize(forwarded).decode(RoutingMessage.ENC),
                outer_key,
            )
        return payload
Example #8
0
 def build(comment: str = None, response_requested: bool = True):
     creation = {'@type': TrustPing.PING, '@id': str(uuid.uuid4())}
     if comment:
         creation['comment'] = comment
     if response_requested in [True, False]:
         creation['response_requested'] = response_requested
     return Message(creation)
Example #9
0
 def build(req_id: str, my_did: str, my_vk: str, endpoint: str) -> Message:
     return Message({
         '@type': DIDExchange.RESPONSE,
         '@id': str(uuid.uuid4()),
         '~thread': {Message.THREAD_ID: req_id, Message.SENDER_ORDER: 0},
         '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": endpoint,
                 }],
             }
         }
     })
Example #10
0
    async def handle(cls,
                     agent_name: str,
                     wire_message: bytes,
                     my_label: str = None,
                     my_endpoint: str = None) -> bool:
        unpacked = await WalletAgent.unpack_message(agent_name, wire_message)
        kwargs = json.loads(unpacked['message'])
        message = Message(**kwargs)
        if message.get('@type', None) is None:
            return False
        if not cls.endorsement(message):
            return False
        for protocol_version in ["1.1", "1.0"]:

            type_issue_credential = cls.set_protocol_version(
                cls.ISSUE_CREDENTIAL, protocol_version)
            type_offer_credential = cls.set_protocol_version(
                cls.OFFER_CREDENTIAL, protocol_version)
            type_request_credential = cls.set_protocol_version(
                cls.REQUEST_CREDENTIAL, protocol_version)
            state_machine_id = cls.get_state_machine_id(
                unpacked['sender_verkey'])

            if message.type in [type_issue_credential, type_offer_credential]:
                machine_class = IssueCredentialProtocol.HolderSateMachine
                if message.type == type_offer_credential:
                    await WalletAgent.start_state_machine(
                        status=IssueCredentialStatus.Null,
                        ttl=IssueCredentialProtocol.STATE_MACHINE_TTL,
                        agent_name=agent_name,
                        machine_class=machine_class,
                        machine_id=state_machine_id,
                        protocol_version=protocol_version)
                await WalletAgent.invoke_state_machine(
                    agent_name=agent_name,
                    id_=state_machine_id,
                    content_type=cls.WIRED_CONTENT_TYPE,
                    data=wire_message)
                return True
            elif message.type in [type_request_credential, AckMessage.ACK]:
                await WalletAgent.invoke_state_machine(
                    agent_name=agent_name,
                    id_=state_machine_id,
                    content_type=cls.WIRED_CONTENT_TYPE,
                    data=wire_message)
                return True
        return False
Example #11
0
 def build(ping_id: str):
     return Message({
         '@type': TrustPing.PING_RESPONSE,
         '~thread': {
             Message.THREAD_ID: ping_id,
             Message.SENDER_ORDER: 0
         }
     })
Example #12
0
 async def handle(cls, agent_name: str, wire_message: bytes, my_label: str=None, my_endpoint: str=None) -> bool:
     unpacked = await WalletAgent.unpack_message(agent_name, wire_message)
     kwargs = json.loads(unpacked['message'])
     message = Message(**kwargs)
     if message.get('@type', None) is None:
         return False
     if message.type == cls.REQUEST:
         state_machine_id = unpacked['sender_verkey']
         machine_class = DIDExchange.DIDExchangeInviterStateMachine
         await WalletAgent.start_state_machine(
             agent_name=agent_name, machine_class=machine_class, machine_id=state_machine_id, endpoint=my_endpoint,
             label=my_label, status=DIDExchangeStatus.Invited
         )
         await WalletAgent.invoke_state_machine(
             agent_name=agent_name, id_=state_machine_id,
             content_type=cls.WIRED_CONTENT_TYPE, data=wire_message
         )
         return True
     elif message.type == DIDExchange.RESPONSE:
         state_machine_id = message['connection~sig']['signer']
         await WalletAgent.invoke_state_machine(
             agent_name=agent_name, id_=state_machine_id,
             content_type=cls.WIRED_CONTENT_TYPE, data=wire_message
         )
         return True
     elif message.type in [TrustPing.PING, TrustPing.PING_RESPONSE]:
         state_machine_id = unpacked['sender_verkey']
         await WalletAgent.invoke_state_machine(
             agent_name=agent_name, id_=state_machine_id,
             content_type=cls.WIRED_CONTENT_TYPE, data=wire_message
         )
         return True
     elif message.type == DIDExchange.PROBLEM_REPORT:
         state_machine_id = message.to_dict().get('connection~sig', {}).get('signer')
         if state_machine_id:
             await WalletAgent.invoke_state_machine(
                 agent_name=agent_name, id_=state_machine_id,
                 content_type=cls.WIRED_CONTENT_TYPE, data=wire_message
             )
             return True
         else:
             logging.error('Problem report', message.as_json())
             return True
     else:
         return False
Example #13
0
 def build(thread_id: str, status: str="OK", sender_order: int=0) -> Message:
     return Message({
         '@type': AckMessage.ACK,
         'status': status,
         '~thread': {
             Message.THREAD_ID: thread_id,
             Message.SENDER_ORDER: sender_order
         }
     })
Example #14
0
    async def receive_invite_message(cls, msg: Message, agent_name: str, pass_phrase: str, my_label: str, my_endpoint: str, ttl: int) -> str:
        """ 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.
        """
        if not cls.endorsement(msg):
            return None
        connection_key = msg['recipientKeys'][0]
        state_machine_id = connection_key
        log_channel_name = 'invite-log/' + uuid.uuid4().hex
        await WalletAgent.start_state_machine(
            agent_name=agent_name,
            machine_class=DIDExchange.DIDExchangeInviteeStateMachine,
            machine_id=state_machine_id,
            ttl=ttl,
            endpoint=my_endpoint,
            label=my_label,
            status=DIDExchangeStatus.Null,
            log_channel_name=log_channel_name
        )
        await WalletAgent.invoke_state_machine(
            agent_name=agent_name,
            id_=state_machine_id,
            content_type=cls.MESSAGE_CONTENT_TYPE,
            data=msg.as_json()
        )
        return log_channel_name
Example #15
0
 async def unpack(forwarded: Message, wallet: WalletConnection) -> (Message, str, str):
     RoutingMessage.validate(forwarded)
     forwarded_wired = json.dumps(forwarded['msg']).encode(RoutingMessage.ENC)
     unpacked = await wallet.unpack_message(forwarded_wired)
     kwargs = json.loads(unpacked['message'])
     forwarder = Message(**kwargs)
     sender_verkey = unpacked.get('sender_verkey', None)
     recipient_verkey = unpacked.get('recipient_verkey', None)
     return forwarder, recipient_verkey, sender_verkey
Example #16
0
 def build_problem_report_for_connections(cls, problem_code, problem_str, thread_id: str=None) -> Message:
     initialized = {
         "@type": "{}/problem_report".format(cls.FAMILY),
         "problem-code": problem_code,
         "explain": problem_str
     }
     if thread_id:
         initialized['~thread'] = {Message.THREAD_ID: thread_id, Message.SENDER_ORDER: 0}
     return Message(initialized)
Example #17
0
        def validate(request):
            request.check_for_attrs(
                [
                    ('@type', DIDExchange.REQUEST),
                    '@id',
                    'label',
                    DIDExchange.CONNECTION
                ]
            )

            Message.check_for_attrs_in_message(
                [
                    DIDDoc.DID,
                    DIDDoc.DID_DOC
                ],
                request[DIDExchange.CONNECTION]
            )

            DIDDoc.validate(request[DIDExchange.CONNECTION][DIDDoc.DID_DOC])
Example #18
0
 async def validate_common_message_blocks(cls, msg: Message,
                                          problem_code: str,
                                          context: Context):
     try:
         msg.validate_common_blocks()
         return True, None
     except MessageValidationException as e:
         logging.exception('Validation error while parsing message: %s' %
                           msg.as_json())
         if context.their_did:
             err_msg = cls.build_problem_report_for_connections(
                 problem_code, str(e.exception), thread_id=msg.id)
             return False, err_msg
         else:
             return False, None
     except Exception as e:
         logging.exception('Validation error while parsing message: %s' %
                           str(e))
         return False, None
Example #19
0
 def build(content: str) -> Message:
     sent_time = datetime.datetime.utcnow().replace(
         tzinfo=datetime.timezone.utc).isoformat(' ')
     return Message({
         '@type': BasicMessage.MESSAGE,
         '~l10n': {
             'locale': 'en'
         },
         'sent_time': sent_time,
         'content': content
     })
Example #20
0
async def test_forwarding_message():
    wallet1_name = 'test_wallet_1'
    wallet2_name = 'test_wallet_2'
    pass_phrase = 'pass_phrase'
    await remove_wallets(wallet1_name, wallet2_name)

    conn_sender = WalletConnection(wallet1_name, pass_phrase)
    conn_recipient = WalletConnection(wallet2_name, pass_phrase)
    await conn_sender.create()
    await conn_recipient.create()
    try:
        await conn_sender.open()
        await conn_recipient.open()
        # build expected message
        message = BasicMessage.build(content='Test content')
        # generate keys
        sender_verkey = await conn_sender.create_key()
        recipient_verkey = await conn_recipient.create_key()
        routing_key1 = await conn_recipient.create_key()
        routing_key2 = await conn_recipient.create_key()
        routing_keys = [routing_key1, routing_key2]
        print('-------- values ----------')
        print('sender_verkey: ' + sender_verkey)
        print('recipient_verkey: ' + recipient_verkey)
        print('routing_keys: ' + str(routing_keys))
        print('--------------------------')
        # emulate communication
        wired = await RoutingMessage.pack(message, conn_sender,
                                          recipient_verkey, routing_keys,
                                          sender_verkey)
        unpacked = await conn_recipient.unpack_message(wired)
        kwargs = json.loads(unpacked['message'])
        message = Message(**kwargs)
        assert message.type == RoutingMessage.FORWARD
        assert unpacked.get('recipient_verkey') == routing_key2
        assert unpacked.get('sender_verkey') is None
        assert message.data.get('to') == routing_key1

        message, recipient_vk, sender_vk = await RoutingMessage.unpack(
            message, conn_recipient)
        assert message.type == RoutingMessage.FORWARD
        assert recipient_vk == routing_key1
        assert sender_vk is None
        assert message.data.get('to') == recipient_verkey

        message, recipient_vk, sender_vk = await RoutingMessage.unpack(
            message, conn_recipient)
        assert message.type == BasicMessage.MESSAGE
        assert recipient_vk == recipient_verkey
        assert sender_vk == sender_verkey
        assert message.data.get('content') == 'Test content'
    finally:
        await conn_sender.delete()
        await conn_recipient.delete()
Example #21
0
 def propose_credential(
         cls,
         comment: str = None,
         locale: str = DEF_LOCALE,
         proposal_attrib: List[ProposedAttrib] = None,
         schema_id: str = None,
         schema_name: str = None,
         schema_version: str = None,
         schema_issuer_did: str = None,
         cred_def_id: str = None,
         issuer_did: str = None,
         proposal_attrib_translation: List[AttribTranslation] = None):
     data = {
         '@type': cls.PROPOSE_CREDENTIAL,
         '~l10n': {
             "locale": locale
         },
     }
     if comment:
         data['comment'] = comment
     if schema_id:
         data['schema_id'] = schema_id
     if schema_name:
         data['schema_name'] = schema_name
     if schema_version:
         data['schema_version'] = schema_version
     if schema_issuer_did:
         data['schema_issuer_did'] = schema_issuer_did
     if cred_def_id:
         data['cred_def_id'] = cred_def_id
     if issuer_did:
         data['issuer_did'] = issuer_did
     if proposal_attrib:
         data['credential_proposal'] = {
             "@type": cls.CREDENTIAL_PREVIEW_TYPE,
             "attributes": [attrib.to_json() for attrib in proposal_attrib]
         }
         if proposal_attrib_translation:
             data['~attach'] = [{
                 "@type": cls.CREDENTIAL_TRANSLATION_TYPE,
                 "id": cls.CREDENTIAL_TRANSLATION_ID,
                 '~l10n': {
                     "locale": locale
                 },
                 "mime-type": "application/json",
                 "data": {
                     "json": [
                         trans.to_json()
                         for trans in proposal_attrib_translation
                     ]
                 }
             }]
     return Message(data)
Example #22
0
        def validate(response: Message, req_id: str):
            response.check_for_attrs(
                [
                    ('@type', DIDExchange.RESPONSE),
                    '~thread',
                    'connection'
                ]
            )

            Message.check_for_attrs_in_message(
                [
                    (Message.THREAD_ID, req_id)
                ],
                response['~thread']
            )

            Message.check_for_attrs_in_message(
                [
                    DIDDoc.DID,
                    DIDDoc.DID_DOC
                ],
                response[DIDExchange.CONNECTION]
            )

            DIDDoc.validate(response[DIDExchange.CONNECTION][DIDDoc.DID_DOC])
Example #23
0
 def extract_verkey_endpoint(msg: Message,
                             key: str) -> (Optional, Optional):
     """
     Extract verkey and endpoint that will be used to send message back to the sender of this message. Might return None.
     """
     did_doc = BasicMessage.extract_did_doc(msg, key)
     vks = did_doc.get('publicKey')
     vk = vks[0].get('publicKeyBase58') if vks and isinstance(
         vks, list) and len(vks) > 0 else None
     endpoints = msg.get(key, {}).get(DIDDoc.DID_DOC, {}).get('service')
     endpoint = endpoints[0].get(
         'serviceEndpoint') if endpoints and isinstance(
             endpoints, list) and len(endpoints) > 0 else None
     return vk, endpoint
Example #24
0
        def build(label: str, connection_key: str, endpoint: str) -> str:
            msg = Message({
                '@type': DIDExchange.INVITE,
                'label': label,
                'recipientKeys': [connection_key],
                'serviceEndpoint': endpoint,
                # routing_keys not specified, but here is where they would be put in the invite.
            })

            b64_invite = base64.urlsafe_b64encode(
                bytes(
                    Serializer.serialize(msg).decode('utf-8'),
                    'ascii'
                )
            ).decode('ascii')
            return '{}?c_i={}'.format(endpoint, b64_invite)
Example #25
0
    def validate(did_doc):
        Message.check_for_attrs_in_message(
            ['@context', 'publicKey', 'service'], did_doc)

        for publicKeyBlock in did_doc['publicKey']:
            Message.check_for_attrs_in_message(
                ['id', 'type', 'controller', 'publicKeyBase58'],
                publicKeyBlock)

        for serviceBlock in did_doc['service']:
            Message.check_for_attrs_in_message(
                [('type', 'IndyAgent'), 'recipientKeys', 'serviceEndpoint'],
                serviceBlock)
Example #26
0
    async def generate_invite_message(cls, label: str, endpoint: str, agent_name: str, pass_phrase: str, extra: dict=None) -> 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.
        """
        await WalletAgent.ensure_agent_is_open(agent_name, pass_phrase)
        connection_key = await WalletAgent.create_key(agent_name, pass_phrase)
        # Store connection key
        # await WalletAgent.add_wallet_record(agent_name, pass_phrase, 'connection_key', connection_key, connection_key)
        data = {
            '@type': cls.INVITE,
            'label': label,
            'recipientKeys': [connection_key],
            'serviceEndpoint': endpoint,
            # routingKeys not specified, but here is where they would be put in the invite.
        }
        if extra:
            data.update(extra)
        invite_msg = Message(data)
        return invite_msg
Example #27
0
 async def __receive_connection_ack(self, msg: Message):
     if self.status == DIDExchangeStatus.Responded:
         try:
             TrustPing.Ping.validate(msg)
             if msg.get('response_requested'):
                 pong = TrustPing.Pong.build(msg.id)
                 to_did = msg.context['to_did']
                 await DIDExchange.send_message_to_agent(to_did, pong, self.get_wallet())
         except:
             err_msg = DIDExchange.build_problem_report_for_connections(
                 DIDExchange.RESPONSE_FOR_UNKNOWN_REQUEST,
                 'Uncknown ack thread id',
                 thread_id=msg.id
             )
             to_did = msg.context['to_did']
             await DIDExchange.send_message_to_agent(to_did, err_msg, self.get_wallet())
         else:
             await self.done()
     else:
         raise ImpossibleStatus()
Example #28
0
        async def __validate_cred_offer(self, msg: Message, context: Context):
            offer_attaches = msg.to_dict().get('offers~attach', None)
            if isinstance(offer_attaches, dict):
                offer_attaches = [offer_attaches]
            if (not type(offer_attaches) is list) or (
                    type(offer_attaches) is list and len(offer_attaches) == 0):
                await self.__send_problem_report(
                    problem_code=IssueCredentialProtocol.
                    OFFER_PROCESSING_ERROR,
                    problem_str=
                    'Expected offer~attach must contains credOffer and credDef',
                    context=context,
                    thread_id=msg.id)
                await self.done()

            offer = offer_attaches[0]
            offer_body = None
            cred_def_body = None
            for attach in offer_attaches:
                raw_base64 = attach.get('data', {}).get('base64', None)
                if raw_base64:
                    payload = json.loads(base64.b64decode(raw_base64).decode())
                    offer_fields = [
                        'key_correctness_proof', 'nonce', 'schema_id',
                        'cred_def_id'
                    ]
                    cred_def_fields = [
                        'value', 'type', 'ver', 'schemaId', 'id', 'tag'
                    ]
                    if all([field in payload.keys() for field in offer_fields
                            ]):  # check if cred offer content
                        offer_body = {
                            attr: val
                            for attr, val in payload.items()
                            if attr in offer_fields
                        }
                    if all(
                        [field in payload.keys() for field in cred_def_fields
                         ]):  # check if cred def content
                        cred_def_body = {
                            attr: val
                            for attr, val in payload.items()
                            if attr in cred_def_fields
                        }

            if not offer_body:
                await self.__send_problem_report(
                    problem_code=IssueCredentialProtocol.
                    OFFER_PROCESSING_ERROR,
                    problem_str=
                    'Expected offer~attach must contains Payload with offer',
                    context=context,
                    thread_id=msg.id)
                await self.done()
            if cred_def_body:
                cred_def_id = cred_def_body['id']
                await indy_sdk_utils.store_cred_def(self.get_wallet(),
                                                    cred_def_id, cred_def_body)
            else:
                await self.__send_problem_report(
                    problem_code=IssueCredentialProtocol.
                    OFFER_PROCESSING_ERROR,
                    problem_str=
                    'Expected offer~attach must contains Payload with cred_def data',
                    context=context,
                    thread_id=msg.id)
                await self.done()
            attaches = msg.to_dict().get('~attach', None)
            if attaches:
                if isinstance(attaches, dict):
                    attaches = [attaches]
                for attach in attaches:
                    if attach.get(
                            '@type', None
                    ) == IssueCredentialProtocol.ISSUER_SCHEMA_TYPE:
                        issuer_schema_body = attach['data']['json']
                        issuer_schema_id = issuer_schema_body['id']
                        await indy_sdk_utils.store_issuer_schema(
                            self.get_wallet(), issuer_schema_id,
                            issuer_schema_body)
            return offer, offer_body, cred_def_body
Example #29
0
        async def handle(self, content_type, data):
            try:
                if content_type in WIRED_CONTENT_TYPES:
                    msg, context = await PresentProofProtocol.unpack_agent_message(
                        data, self.get_wallet())
                    self.to = context.their_did
                    success, err_msg = await PresentProofProtocol.validate_common_message_blocks(
                        msg, PresentProofProtocol.REQUEST_NOT_ACCEPTED,
                        context)
                    if not success and err_msg:
                        await PresentProofProtocol.send_message_to_agent(
                            context.their_did, err_msg, self.get_wallet())
                else:
                    raise RuntimeError('Unsupported content_type "%s"' %
                                       content_type)
                if msg.type == PresentProofProtocol.REQUEST_PRESENTATION:
                    if self.status == PresentProofStatus.Null:
                        await self.__log('Received request presentation',
                                         msg.to_dict())

                        request_attach = msg['request_presentations~attach']
                        if isinstance(request_attach, list):
                            request_attach = request_attach[0]
                        payload = json.loads(
                            base64.b64decode(
                                request_attach['data']['base64']).decode())
                        proof_request = payload

                        search_handle = await self.get_wallet(
                        ).prover_search_credentials_for_proof_req(
                            proof_request=proof_request)
                        try:
                            requested_attributes = proof_request.get(
                                'requested_attributes', {})
                            requested_predicates = proof_request.get(
                                'requested_predicates', {})
                            schemas_json = dict()
                            cred_defs_json = dict()
                            prover_requested_creds = {
                                'self_attested_attributes': {},
                                'requested_attributes': {},
                                'requested_predicates': {}
                            }
                            for attr_referent in requested_attributes.keys():
                                cred_for_attr = await self.get_wallet(
                                ).prover_fetch_credentials_for_proof_req(
                                    search_handle=search_handle,
                                    item_referent=attr_referent,
                                    count=1)
                                if cred_for_attr:
                                    cred_info = cred_for_attr[0]['cred_info']
                                    schema_id = cred_info['schema_id']
                                    schemas_json[
                                        schema_id] = await indy_sdk_utils.get_issuer_schema(
                                            self.get_wallet(), schema_id)
                                    cred_def_id = cred_info['cred_def_id']
                                    cred_defs_json[
                                        cred_def_id] = await indy_sdk_utils.get_cred_def(
                                            self.get_wallet(), cred_def_id)
                                    prover_requested_creds[
                                        'requested_attributes'][
                                            attr_referent] = {
                                                'cred_id':
                                                cred_info['referent'],
                                                'revealed': True
                                            }
                            for pred_referent in requested_predicates.keys():
                                cred_for_predicate = await self.get_wallet(
                                ).prover_fetch_credentials_for_proof_req(
                                    search_handle=search_handle,
                                    item_referent=pred_referent,
                                    count=1)
                                if cred_for_predicate:
                                    cred_info = cred_for_predicate[0][
                                        'cred_info']
                                    schema_id = cred_info['schema_id']
                                    schemas_json[
                                        schema_id] = await indy_sdk_utils.get_issuer_schema(
                                            self.get_wallet(), schema_id)
                                    cred_def_id = cred_info['cred_def_id']
                                    cred_defs_json[
                                        cred_def_id] = await indy_sdk_utils.get_cred_def(
                                            self.get_wallet(), cred_def_id)
                                    prover_requested_creds[
                                        'requested_predicates'][
                                            pred_referent] = {
                                                'cred_id':
                                                cred_info['referent'],
                                            }

                        finally:
                            await self.get_wallet(
                            ).prover_close_credentials_search_for_proof_req(
                                search_handle)

                        master_secret_name = settings.INDY['WALLET_SETTINGS'][
                            'PROVER_MASTER_SECRET_NAME']
                        proof = await self.get_wallet().prover_create_proof(
                            proof_req=proof_request,
                            requested_creds=prover_requested_creds,
                            link_secret_id=master_secret_name,
                            schemas=schemas_json,
                            cred_defs=cred_defs_json,
                            rev_states=None)

                        self.ack_message_id = uuid.uuid4().hex
                        data = {
                            "@type":
                            PresentProofProtocol.PRESENTATION,
                            "@id":
                            self.ack_message_id,
                            "presentations~attach": [{
                                "@id":
                                "libindy-presentation-" + self.ack_message_id,
                                "mime-type":
                                "application/json",
                                "data": {
                                    "base64":
                                    base64.b64encode(
                                        json.dumps(proof).encode()).decode()
                                }
                            }]
                        }
                        message_proof = Message(data)
                        await PresentProofProtocol.send_message_to_agent(
                            self.to, message_proof, self.get_wallet())
                        self.status = PresentProofStatus.PresentationSent
                        await self.__log(event='Send Proof', details=data)
                    else:
                        await self.__send_problem_report(
                            problem_code=PresentProofProtocol.
                            REQUEST_PROCESSING_ERROR,
                            problem_str='Impossible state machine state',
                            context=context,
                            thread_id=msg.id)
                        raise ImpossibleStatus
                elif msg.type == AckMessage.ACK:
                    await self.__log('Received ack', msg.to_dict())
                    if self.status == PresentProofStatus.PresentationSent:
                        await self.done()
                    else:
                        await self.__send_problem_report(
                            problem_code=PresentProofProtocol.
                            RESPONSE_NOT_ACCEPTED,
                            problem_str='UnExpected message type for status',
                            context=context,
                            thread_id=msg.id)
                        raise ImpossibleStatus
                elif msg.type == PresentProofProtocol.PROBLEM_REPORT:
                    await self.__log('Received problem report', msg.to_dict())
                    await self.done()
                else:
                    await self.__send_problem_report(
                        problem_code=PresentProofProtocol.
                        RESPONSE_FOR_UNKNOWN_REQUEST,
                        problem_str='Unknown message type',
                        context=context,
                        thread_id=msg.id)
            except Exception as e:
                if not isinstance(e, MachineIsDone):
                    logging.exception('Base machine terminated with exception')
                await self.done()
Example #30
0
        async def handle(self, content_type, data):
            try:
                if content_type == PresentProofProtocol.MESSAGE_CONTENT_TYPE:
                    command = str(data.get('command', None))
                    if command == PresentProofProtocol.CMD_START:
                        await self.__log('Start verifying', data)
                        # Store Context
                        comment = data.get('comment', None)
                        locale = data.get(
                            'locale', None) or PresentProofProtocol.DEF_LOCALE
                        proof_request = data['proof_request']
                        self.proof_request_buffer = json.dumps(proof_request)
                        translation = data.get('translation', None)
                        translation = [
                            AttribTranslation(**item) for item in translation
                        ] if translation else None

                        id_suffix = uuid.uuid4().hex
                        data = {
                            "@type":
                            PresentProofProtocol.REQUEST_PRESENTATION,
                            "comment":
                            "some comment",
                            "request_presentations~attach": [{
                                "@id":
                                "libindy-request-presentation-" + id_suffix,
                                "mime-type":
                                "application/json",
                                "data": {
                                    "base64":
                                    base64.b64encode(
                                        json.dumps(
                                            proof_request).encode()).decode()
                                }
                            }]
                        }

                        if comment:
                            data['comment'] = comment
                            data['~l10n'] = {"locale": locale}
                            self.comment = comment
                            self.locale = locale

                        if translation:
                            data['~attach'] = [{
                                "@type": PresentProofProtocol.
                                CREDENTIAL_TRANSLATION_TYPE,
                                "id":
                                PresentProofProtocol.CREDENTIAL_TRANSLATION_ID,
                                '~l10n': {
                                    "locale": locale
                                },
                                "mime-type": "application/json",
                                "data": {
                                    "json":
                                    [trans.to_json() for trans in translation]
                                }
                            }]
                        if self.expires_time:
                            data['~timing'] = {
                                "expires_time": self.expires_time
                            }

                        message_request = Message(data)
                        await PresentProofProtocol.send_message_to_agent(
                            self.to, message_request, self.get_wallet())
                        self.status = PresentProofStatus.RequestSent
                        await self.__log(event='Send Request-Presentation',
                                         details=data)

                    elif command == PresentProofProtocol.CMD_STOP:
                        if self.to and self.status != PresentProofStatus.Null:
                            err_msg = PresentProofProtocol.build_problem_report_for_connections(
                                problem_code=PresentProofProtocol.
                                REQUEST_NOT_ACCEPTED,
                                problem_str='Actor unexpected stopped issuing',
                            )
                            await PresentProofProtocol.send_message_to_agent(
                                self.to, err_msg, self.get_wallet())
                        await self.__log('Actor unexpected stopped issuing')
                        await self.done()
                    else:
                        raise RuntimeError('Unknown command: %s' % command)
                elif content_type in WIRED_CONTENT_TYPES:
                    msg, context = await PresentProofProtocol.unpack_agent_message(
                        data, self.get_wallet())
                    success, err_msg = await PresentProofProtocol.validate_common_message_blocks(
                        msg, PresentProofProtocol.REQUEST_NOT_ACCEPTED,
                        context)
                    if not success and err_msg:
                        await PresentProofProtocol.send_message_to_agent(
                            context.their_did, err_msg, self.get_wallet())
                    if msg.type == PresentProofProtocol.PRESENTATION:
                        await self.__log('Received presentation',
                                         msg.to_dict())
                        if self.status == PresentProofStatus.RequestSent:
                            presentation_attach = msg['presentations~attach']
                            if isinstance(presentation_attach, list):
                                presentation_attach = presentation_attach[0]
                            payload = json.loads(
                                base64.b64decode(presentation_attach['data']
                                                 ['base64']).decode())
                            proof = payload
                            proof_request = json.loads(
                                self.proof_request_buffer)
                            await self.__log('verifier proof-request',
                                             proof_request)
                            await self.__log(core.const.PROOF, proof)
                            schemas = dict()
                            cred_defs = dict()

                            for ident in proof['identifiers']:
                                schema_id = ident['schema_id']
                                cred_def_id = ident['cred_def_id']
                                schema = await indy_sdk_utils.get_issuer_schema(
                                    self.get_wallet(), schema_id
                                ) or await get_issuer_schema(schema_id)
                                if schema:
                                    schemas[schema_id] = schema
                                else:
                                    _, schema = await core.ledger.get_schema(
                                        context.my_did, schema_id)
                                    schemas[schema_id] = schema
                                cred_def = await indy_sdk_utils.get_cred_def(
                                    self.get_wallet(), cred_def_id
                                ) or await get_cred_def_meta(cred_def_id)
                                if cred_def:
                                    cred_defs[
                                        cred_def_id] = self.__prepare_cred_def(
                                            cred_def)
                                else:
                                    _, cred_def = await core.ledger.get_cred_def(
                                        context.my_did, cred_def_id)
                                    await indy_sdk_utils.store_cred_def(
                                        self.get_wallet(), cred_def_id,
                                        cred_def)
                                    cred_defs[
                                        cred_def_id] = self.__prepare_cred_def(
                                            cred_def)

                            await self.__log('schemas', schemas)
                            await self.__log('cred_defs', cred_defs)

                            success, error_message = await verifier_verify_proof(
                                proof_request=proof_request,
                                proof=proof,
                                schemas=schemas,
                                credential_defs=cred_defs,
                                rev_reg_defs=None,
                                rev_regs=None)
                            await self.__log(
                                'verify result',
                                dict(success=success,
                                     error_message=error_message))
                            if success:
                                ack = AckMessage.build(msg.id)
                                await PresentProofProtocol.send_message_to_agent(
                                    self.to, ack, self.get_wallet())
                                await self.__log(event='Send Ack',
                                                 details=ack.to_dict())
                                await self.__log(
                                    event=core.const.VERIFY_SUCCESS)
                            else:
                                if error_message:
                                    if 'Invalid structure' in error_message:
                                        error_message = None
                                await self.__send_problem_report(
                                    problem_code=PresentProofProtocol.
                                    VERIFY_ERROR,
                                    problem_str=error_message or
                                    'Proof verification finished with errors',
                                    context=context,
                                    thread_id=msg.id)
                                await self.__log(core.const.VERIFY_ERROR)
                            await self.done()

                        else:
                            await self.__send_problem_report(
                                problem_code=PresentProofProtocol.
                                RESPONSE_NOT_ACCEPTED,
                                problem_str='Impossible state',
                                context=context,
                                thread_id=msg.id)
                            raise ImpossibleStatus()
                    elif msg.type == PresentProofProtocol.PROBLEM_REPORT:
                        await self.__log('Received problem report',
                                         msg.to_dict())
                        await self.done()
                    else:
                        await self.__send_problem_report(
                            problem_code=PresentProofProtocol.
                            RESPONSE_FOR_UNKNOWN_REQUEST,
                            problem_str='Unknown message type',
                            context=context,
                            thread_id=msg.id)
            except Exception as e:
                if not isinstance(e, MachineIsDone):
                    print('------------- FEATURE 0037 --------------')
                    print('Exception')
                    print(str(e))
                    print('----------------------------------------')
                    logging.exception(
                        'Base machine terminated with exception: %s' % str(e))
                await self.done()