async def create_schema_and_cred_def(self,
                                      schema_name,
                                      schema_attrs,
                                      revocation,
                                      version=None):
     with log_timer("Publish schema/cred def duration:"):
         log_status("#3/4 Create a new schema/cred def on the ledger")
         if not version:
             version = format("%d.%d.%d" % (
                 random.randint(1, 101),
                 random.randint(1, 101),
                 random.randint(1, 101),
             ))
         (
             _,
             cred_def_id,
         ) = await self.register_schema_and_creddef(  # schema id
             schema_name,
             version,
             schema_attrs,
             support_revocation=revocation,
             revocation_registry_size=TAILS_FILE_COUNT
             if revocation else None,
         )
         return cred_def_id
    async def issue_credential(
        self,
        cred_def_id: str,
        cred_attrs: list,
    ):
        log_status("#13 Issue credential offer to X")

        cred_preview = {
            "@type": CRED_PREVIEW_TYPE,
            "attributes": cred_attrs,
        }
        offer_request = {
            "connection_id": self.agent.connection_id,
            "comment": f"Offer on cred def id {cred_def_id}",
            "auto_remove": False,
            "credential_preview": cred_preview,
            "filter": {
                "indy": {
                    "cred_def_id": cred_def_id
                }
            },
            "trace": self.exchange_tracing,
        }
        cred_exchange = await self.agent.admin_POST(
            "/issue-credential-2.0/send-offer", offer_request)

        return cred_exchange
    async def generate_invitation(
        self,
        use_did_exchange: bool,
        auto_accept: bool = True,
        display_qr: bool = False,
        wait: bool = False,
    ):
        self._connection_ready = asyncio.Future()
        with log_timer("Generate invitation duration:"):
            # Generate an invitation
            log_status(
                "#7 Create a connection to alice and print out the invite details"
            )
            invi_rec = await self.get_invite(use_did_exchange, auto_accept)

        if display_qr:
            qr = QRCode(border=1)
            qr.add_data(invi_rec["invitation_url"])
            log_msg(
                "Use the following JSON to accept the invite from another demo agent."
                " Or use the QR code to connect from a mobile agent.")
            log_msg(json.dumps(invi_rec["invitation"]),
                    label="Invitation Data:",
                    color=None)
            qr.print_ascii(invert=True)

        if wait:
            log_msg("Waiting for connection...")
            await self.detect_connection()

        return invi_rec
示例#4
0
 async def handle_present_proof(self, message):
     global proof_message
     global proof_event
     if message["state"] == "presentation_received":
         log_status("Proof has been got")
         proof_message = message
         proof_event.set()
示例#5
0
    async def handle_issue_credential(self, message):
        state = message["state"]
        credential_exchange_id = message["credential_exchange_id"]
        prev_state = self.cred_state.get(credential_exchange_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[credential_exchange_id] = state

        self.log("Credential: state = {}, credential_exchange_id = {}".format(
            state,
            credential_exchange_id,
        ))

        if state == "request_received":
            log_status("#17 Issue credential to X")
            # issue credentials based on the credential_definition_id
            cred_attrs = self.cred_attrs[message["credential_definition_id"]]
            cred_preview = {
                "@type":
                CRED_PREVIEW_TYPE,
                "attributes": [{
                    "name": n,
                    "value": v
                } for (n, v) in cred_attrs.items()],
            }
            try:
                await self.issue_credential(cred_preview,
                                            credential_exchange_id)
            except ClientError:
                pass
示例#6
0
    async def handle_issue_credential(self, message):
        state = message["state"]
        credential_exchange_id = message["credential_exchange_id"]
        prev_state = self.cred_state.get(credential_exchange_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[credential_exchange_id] = state

        self.log(
            "Credential: state =",
            state,
            ", credential_exchange_id =",
            credential_exchange_id,
        )

        if state == "request_received":
            log_status("#17 Issue credential to X")
            # issue credentials based on the credential_definition_id
            cred_attrs = self.cred_attrs[message["credential_definition_id"]]
            cred_preview = {
                "@type": CRED_PREVIEW_TYPE,
                "attributes": [
                    {"name": n, "value": v} for (n, v) in cred_attrs.items()
                ],
            }
            await self.admin_POST(
                f"/issue-credential/records/{credential_exchange_id}/issue",
                {
                    "comment": f"Issuing credential, exchange {credential_exchange_id}",
                    "credential_preview": cred_preview,
                },
            )
示例#7
0
    async def handle_issue_credential_v2_0(self, message):
        state = message["state"]
        cred_ex_id = message["cred_ex_id"]
        prev_state = self.cred_state.get(cred_ex_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[cred_ex_id] = state

        self.log(f"Credential: state = {state}, cred_ex_id {cred_ex_id}")

        if state == "offer-received":
            log_status(
                "#15 After receiving credential offer, send credential request"
            )
            await self.admin_POST(
                f"/issue-credential-2.0/records/{cred_ex_id}/send-request")

        elif state == "done":
            cred_id = message["cred_id_stored"]
            self.log(f"Stored credential {cred_id} in wallet")
            log_status(f"#18.1 Stored credential {cred_id} in wallet")
            cred = await self.admin_GET(f"/credential/{cred_id}")
            log_json(cred, label="Credential details:")
            self.log("credential_id", cred_id)
            self.log("cred_def_id", cred["cred_def_id"])
            self.log("schema_id", cred["schema_id"])
    async def handle_present_proof(self, message):
        state = message["state"]

        presentation_exchange_id = message["presentation_exchange_id"]
        self.log(
            "Presentation: state =",
            state,
            ", presentation_exchange_id =",
            presentation_exchange_id,
        )

        if state == "presentation_received":
            # TODO handle received presentations
            # if presentation is a degree schema (proof of education),
            # check values received
            pres_req = message["presentation_request"]
            pres = message["presentation"]
            is_proof_of_education = (pres_req["name"] == "Proof of Education")
            if is_proof_of_education:
                log_status("#28.1 Received proof of education, check claims")
                for (referent,
                     attr_spec) in pres_req["requested_attributes"].items():
                    self.log(
                        f"{attr_spec['name']}: "
                        f"{pres['requested_proof']['revealed_attrs'][referent]['raw']}"
                    )
                for id_spec in pres["identifiers"]:
                    # just print out the schema/cred def id's of presented claims
                    self.log(f"schema_id: {id_spec['schema_id']}")
                    self.log(f"cred_def_id {id_spec['cred_def_id']}")
                # TODO placeholder for the next step
            else:
                # in case there are any other kinds of proofs received
                self.log("#28.1 Received ",
                         message["presentation_request"]["name"])
示例#9
0
async def handle_create_invitation(request):
    global agent
    connection = await agent.admin_POST("/connections/create-invitation")
    agent._connection_ready = asyncio.Future()
    agent.connection_id = connection["connection_id"]
    log_status("Invitation has been created !!")
    return web.json_response(connection["invitation"])
示例#10
0
    async def handle_issue_credential(self, message):
        state = message["state"]
        credential_exchange_id = message["credential_exchange_id"]
        prev_state = self.cred_state.get(credential_exchange_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[credential_exchange_id] = state

        self.log(
            "Credential: state =",
            state,
            ", credential_exchange_id =",
            credential_exchange_id,
        )

        if state == "offer_received":
            log_status("#15 After receiving credential offer, send credential request")
            await self.admin_POST(
                f"/issue-credential/records/{credential_exchange_id}/send-request"
            )

        elif state == "credential_acked":
            cred_id = message["credential_id"]
            self.log(f"Stored credential {cred_id} in wallet")
            log_status(f"#18.1 Stored credential {cred_id} in wallet")
            resp = await self.admin_GET(f"/credential/{cred_id}")
            log_json(resp, label="Credential details:")
            log_json(
                message["credential_request_metadata"],
                label="Credential request metadata:",
            )
            self.log("credential_id", message["credential_id"])
            self.log("credential_definition_id", message["credential_definition_id"])
            self.log("schema_id", message["schema_id"])
示例#11
0
async def handle_verify_signature(request):
    global agent

    data = await request.json()
    resp = {}

    #Check if any attribute not there.
    for element in ['message', 'their_did', 'signature']:
        if element not in data:
            return web.json_response({"status": "Attribute missing"})
    #Check if any attribute has not value.
    if (data['message'] == None or data['message'] == '') or (
            data['their_did'] == None or data['their_did']
            == '') or (data['signature'] == None or data['signature'] == ''):
        return web.json_response({"status": "Enter valid details"})

    message = data['message']
    their_did = data['their_did']
    signature = data['signature']

    log_msg("message : " + message)
    log_msg("their_did : " + their_did)
    log_msg("signature : " + signature)
    try:
        temp = signature.encode('iso-8859-15')
        temp1 = base64.b64decode(temp)
        signature = temp1.decode('utf-8')
    except:
        return web.json_response({"status": "Invalid signature"})

    while True:
        verify = await agent.admin_POST("/connections/verify-transaction", {
            "message": message,
            "their_did": their_did,
            "signature": signature
        })
        if verify['status'] != 'operation not complete':
            break
        else:
            log_status("Still waiting for pool to be closed!!")

    if verify['status'] == 'True':
        res = await agent.admin_GET(f"/connections",
                                    params={"their_did": their_did})
        if res != []:
            resp['status'] = "Signature verified"
            resp['connection_id'] = res[0]['connection_id']
        else:
            resp[
                'status'] = "Signature verified but not connected to the client agent"
    else:
        resp['status'] = "not verified"

    log_status("The status : " + verify['status'])

    return web.json_response(resp)
示例#12
0
async def main(start_port: int, show_timing: bool = False):
    global agent
    genesis = await default_genesis_txns()
    if not genesis:
        print("Error retrieving ledger genesis transactions")
        sys.exit(1)

    try:
        log_status(
            "Provision an agent and wallet, get back configuration details")
        agent = MSPAgent(start_port,
                         start_port + 1,
                         genesis_data=genesis,
                         timing=show_timing)
        await agent.listen_webhooks(start_port + 2)
        # await agent.register_did()

        with log_timer("Startup duration:"):
            await agent.start_process()
        log_msg("Admin url is at:", agent.admin_url)
        log_msg("Endpoint url is at:", agent.endpoint)

        app = web.Application()
        app.add_routes([
            web.get('/create_invitation', handle_create_invitation),
            web.post('/verify_signature', handle_verify_signature),
            web.post('/verify_proof', handle_verify_proof),
        ])

        cors = aiohttp_cors.setup(
            app,
            defaults={
                "*":
                aiohttp_cors.ResourceOptions(
                    allow_credentials=True,
                    expose_headers="*",
                    allow_headers="*",
                    allow_methods="*",
                )
            },
        )
        for route in app.router.routes():
            cors.add(route)

        setup_aiohttp_apispec(app=app,
                              title="Aries Cloud Agent two",
                              version="v1",
                              swagger_path="/api/doc")
        app.on_startup.append(on_startup)

        return app

    except Exception:
        log_status(
            "Error while provision an agent and wallet, get back configuration details"
        )
    async def handle_present_proof_v2_0(self, message):
        state = message["state"]
        pres_ex_id = message["pres_ex_id"]
        self.log(f"Presentation: state = {state}, pres_ex_id = {pres_ex_id}")

        if state == "presentation-received":
            log_status("#27 Process the proof provided by X")
            log_status("#28 Check if proof is valid")
            proof = await self.admin_POST(
                f"/present-proof-2.0/records/{pres_ex_id}/verify-presentation")
            self.log("Proof =", proof["verified"])
示例#14
0
async def main(start_port: int, show_timing: bool = False, container_name: str = "Simple_client"):
    global agent
    global client_name
    genesis = await default_genesis_txns()
    if not genesis:
        print("Error retrieving ledger genesis transactions")
        sys.exit(1)
    try:
        log_status("Provision an agent and wallet, get back configuration details")
        label=container_name
        client_name=label
        agent = ClientAgent(
            label, start_port, start_port + 1, genesis_data=genesis, timing=show_timing
        )
        await agent.listen_webhooks(start_port + 2)
        # await agent.register_did()
        with log_timer("Startup duration:"):
            await agent.start_process()
        log_msg("Admin url is at:", agent.admin_url)
        log_msg("Endpoint url is at:", agent.endpoint)

        async with aiofile.AIOFile("client_logger.csv", 'w') as afp:
            writer = aiofile.Writer(afp)
            await writer("")
            await afp.fsync()

        app = web.Application()
        app.add_routes([
            web.get('/get_client_name', handle_get_client_name),
            web.get('/get_connections', handle_get_connections),
            web.post('/input_invitation', handle_input_invitation),
            web.post('/sign_message', handle_sign_message),
            web.get('/get_signing_did', handle_get_signing_did),
            web.get('/readCommentsFromLogger', readCommentsFromLogger),
        ])

        cors = aiohttp_cors.setup(
            app,
            defaults={
                "*": aiohttp_cors.ResourceOptions(
                    allow_credentials=True,
                    expose_headers="*",
                    allow_headers="*",
                    allow_methods="*",
                )
            },
        )
        for route in app.router.routes():
            cors.add(route)

        return app
    except Exception:
        print("Error when starting to run server!!")
    async def handle_present_proof(self, message):
        state = message["state"]
        presentation_request = message["presentation_request"]
        presentation_exchange_id = message["presentation_exchange_id"]
        self.log(
            "Presentation: state =",
            state,
            ", presentation_exchange_id =",
            presentation_exchange_id,
        )

        if state == "presentation_received":
            log_status("#27 Process the proof provided by X")
            log_status("#28 Check if proof is valid")
            proof = await self.admin_POST(
                f"/present-proof/records/{presentation_exchange_id}/"
                "verify-presentation")
            self.log("Proof =", proof["verified"])
            if proof["verified"]:
                self.log(proof)
                self.log(proof["presentation"]["requested_proof"]
                         ["self_attested_attrs"]["0_name_uuid"])

                self.current_hospital_name = proof["presentation"][
                    "requested_proof"]["self_attested_attrs"]["0_name_uuid"]
                today = date.today()
                # TODO define attributes to send for credential
                self.cred_attrs[self.hospital_credential_def_id] = {
                    "hospital_name": self.current_hospital_name,
                    "date": str(today),
                }
                self.log("Issue", self.cred_attrs)
                cred_preview = {
                    "@type":
                    CRED_PREVIEW_TYPE,
                    "attributes": [{
                        "name": n,
                        "value": v
                    } for (n, v) in self.cred_attrs[
                        self.hospital_credential_def_id].items()],
                }
                self.log("preview", cred_preview)
                offer_request = {
                    "connection_id": self.active_connection_id,
                    "credential_definition_id":
                    self.hospital_credential_def_id,
                    "comment":
                    f"Offer on cred def id {self.hospital_credential_def_id}",
                    "credential_preview": cred_preview,
                }
                self.log("Issue Credential", offer_request)
                await self.admin_POST("/issue-credential/send-offer",
                                      offer_request)
示例#16
0
async def handle_create_invitation(request):
    with log_timer("Generate invitation duration:"):
        log_status(
            "#5 Create a connection to alice and print out the invite details"
        )
        connection = await agent.admin_POST("/connections/create-invitation")

    agent.connection_id = connection["connection_id"]
    log_json(connection, label="Invitation response:")
    log_msg("*****************")
    log_msg(json.dumps(connection["invitation"]), label="Invitation:", color=None)
    log_msg("*****************")

    return web.json_response(connection["invitation"])
示例#17
0
async def main(start_port: int,
               show_timing: bool = False,
               container_name: str = "Simple_client"):
    global temp_message
    global temp_data
    global agent
    genesis = await default_genesis_txns()
    if not genesis:
        print("Error retrieving ledger genesis transactions")
        sys.exit(1)
    try:
        log_status(
            "#7 Provision an agent and wallet, get back configuration details")
        label = container_name
        agent = ClientAgent(label,
                            start_port,
                            start_port + 1,
                            genesis_data=genesis,
                            timing=show_timing)
        await agent.listen_webhooks(start_port + 2)

        with log_timer("Startup duration:"):
            await agent.start_process()
        log_msg("Admin url is at:", agent.admin_url)
        log_msg("Endpoint url is at:", agent.endpoint)
        app = web.Application()

        app.add_routes([
            web.post('/input_invitation', handle_input_invitation),
        ])

        cors = aiohttp_cors.setup(
            app,
            defaults={
                "*":
                aiohttp_cors.ResourceOptions(
                    allow_credentials=True,
                    expose_headers="*",
                    allow_headers="*",
                    allow_methods="*",
                )
            },
        )
        for route in app.router.routes():
            cors.add(route)

        return app
    except Exception:
        print("Error when starting to run server!!")
示例#18
0
    async def handle_issue_credential_v2_0_indy(self, message):
        cred_req_metadata = message.get("cred_request_metadata")
        if cred_req_metadata:
            log_json(cred_req_metadata, label="Credential request metadata:")

        log_json(message, label="indy message:")
        cred_id = message.get("cred_id_stored")
        if cred_id:
            self.log(f"Stored credential {cred_id} in wallet")
            log_status(f"#18.1 Stored credential {cred_id} in wallet")
            cred = await self.admin_GET(f"/credential/{cred_id}")
            log_json(cred, label="Credential details:")
            self.log("credential_id", cred_id)
            self.log("cred_def_id", cred["cred_def_id"])
            self.log("schema_id", cred["schema_id"])
示例#19
0
async def handle_get_signing_did(request):
    log_status("Function for creating and getting common did has been called")
    global signing_did
    global signing_vk
    global agent

    if signing_did==None:
        result = await agent.admin_POST("/connections/create-signing-did")
        log_status("Signing did and verification key created")
        log_msg("Singing did : "+str(result['signing_did']))
        log_msg("Singing verkey : "+str(result['signing_vk']))
        signing_did=result['signing_did']
        signing_vk=result['signing_vk']

    return web.json_response({"signing_did" : signing_did})
示例#20
0
    async def handle_issue_credential(self, message):
        # state = message["state"]
        # credential_exchange_id = message["credential_exchange_id"]
        # prev_state = self.cred_state.get(credential_exchange_id)
        # if prev_state == state:
        #     return  # ignore
        # self.cred_state[credential_exchange_id] = state

        # self.log(
        #     "Credential: state = {}, credential_exchange_id = {}".format(
        #         state, credential_exchange_id,
        #     )
        # )

        if state == "request_received":
            log_status("#17 Issue credential to X")
示例#21
0
async def handle_create_invitation(request):
    global agent
    log_status("Create invitation has been called !!")

    connection = await agent.admin_POST("/connections/create-invitation")
    agent.connection_id = connection["connection_id"]
    agent._connection_ready = asyncio.Future()

    log_json(connection, label="Invitation response:")
    log_msg("*****************")
    log_msg(json.dumps(connection["invitation"]),
            label="Invitation:",
            color=None)
    log_msg("*****************")

    return web.json_response(connection["invitation"])
示例#22
0
    async def handle_issue_credential_v2_0(self, message):
        state = message["state"]
        cred_ex_id = message["cred_ex_id"]
        prev_state = self.cred_state.get(cred_ex_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[cred_ex_id] = state

        self.log(f"Credential: state = {state}, cred_ex_id = {cred_ex_id}")

        if state == "request-received":
            log_status("#17 Issue credential to X")
            # issue credential based on offer preview in cred ex record
            await self.admin_POST(
                f"/issue-credential-2.0/records/{cred_ex_id}/issue",
                {"comment": f"Issuing credential, exchange {cred_ex_id}"},
            )
示例#23
0
    async def handle_present_proof(self, message):
        state = message["state"]

        presentation_exchange_id = message["presentation_exchange_id"]
        self.log(
            "Presentation: state =",
            state,
            ", presentation_exchange_id =",
            presentation_exchange_id,
        )

        if state == "presentation_received":
            log_status("#27 Process the proof provided by X")
            log_status("#28 Check if proof is valid")
            proof = await self.admin_POST(
                f"/present-proof/records/{presentation_exchange_id}/"
                "verify-presentation")
            self.log("Proof =", proof["verified"])
    async def connect():
        # Generate an invitation
        log_status(
            "#5 Create a connection to alice and print out the invite details")
        connection = await agent.admin_POST("/connections/create-invitation")

        agent.active_connection_id = connection["connection_id"]
        agent.connection_list.append(connection["connection_id"])
        log_msg("all connections :", agent.connection_list)
        log_json(connection, label="Invitation response:")
        log_msg("*****************")
        log_msg(json.dumps(connection["invitation"]),
                label="Invitation:",
                color=None)
        log_msg("*****************")
        agent._connection_ready = asyncio.Future()

        return json.dumps(connection["invitation"])
示例#25
0
    async def handle_issue_credential(self, message):
        state = message["state"]
        credential_exchange_id = message["credential_exchange_id"]
        prev_state = self.cred_state.get(credential_exchange_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[credential_exchange_id] = state

        self.log("Credential: state = {}, credential_exchange_id = {}".format(
            state,
            credential_exchange_id,
        ))

        if state == "request_received":
            log_status("#17 Issue credential to X")
            # issue credentials based on the credential_definition_id
            cred_attrs = self.cred_attrs[message["credential_definition_id"]]
            cred_preview = {
                "@type":
                CRED_PREVIEW_TYPE,
                "attributes": [{
                    "name": n,
                    "value": v
                } for (n, v) in cred_attrs.items()],
            }
            try:
                cred_ex_rec = await self.admin_POST(
                    f"/issue-credential/records/{credential_exchange_id}/issue",
                    {
                        "comment":
                        (f"Issuing credential, exchange {credential_exchange_id}"
                         ),
                        "credential_preview":
                        cred_preview,
                    },
                )
                rev_reg_id = cred_ex_rec.get("revoc_reg_id")
                cred_rev_id = cred_ex_rec.get("revocation_id")
                if rev_reg_id:
                    self.log(f"Revocation registry ID: {rev_reg_id}")
                if cred_rev_id:
                    self.log(f"Credential revocation ID: {cred_rev_id}")
            except ClientError:
                pass
async def generate_new_connection(agent):
    # handle new invitation
    with log_timer("Generate invitation duration:"):
        # Generate an invitation
        log_status(
            "#5 Create a connection to alice and print out the invite details"
        )
        connection = await agent.admin_POST("/connections/create-invitation")

    agent.active_connection_id = connection["connection_id"]
    agent.connection_list.append(connection["connection_id"])
    log_msg("all connections :", agent.connection_list)
    log_json(connection, label="Invitation response:")
    log_msg("*****************")
    log_msg(json.dumps(connection["invitation"]), label="Invitation:", color=None)
    log_msg("*****************")

    log_msg("Waiting for connection...")
    await agent.detect_connection()
    async def handle_issue_credential_v2_0_indy(self, message):
        rev_reg_id = message.get("rev_reg_id")
        cred_rev_id = message.get("cred_rev_id")
        cred_id_stored = message.get("cred_id_stored")

        if cred_id_stored:
            cred_id = message["cred_id_stored"]
            log_status(f"#18.1 Stored credential {cred_id} in wallet")
            cred = await self.admin_GET(f"/credential/{cred_id}")
            log_json(cred, label="Credential details:")
            self.log("credential_id", cred_id)
            self.log("cred_def_id", cred["cred_def_id"])
            self.log("schema_id", cred["schema_id"])
            # track last successfully received credential
            self.last_credential_received = cred

        if rev_reg_id and cred_rev_id:
            self.log(f"Revocation registry ID: {rev_reg_id}")
            self.log(f"Credential revocation ID: {cred_rev_id}")
示例#28
0
async def create_schema_and_cred_def(agent, revocation):
    with log_timer("Publish schema/cred def duration:"):
        log_status("#3/4 Create a new schema/cred def on the ledger")
        version = format(
            "%d.%d.%d"
            % (
                random.randint(1, 101),
                random.randint(1, 101),
                random.randint(1, 101),
            )
        )
        (_, cred_def_id,) = await agent.register_schema_and_creddef(  # schema id
            "degree schema",
            version,
            ["name", "date", "degree", "age", "timestamp"],
            support_revocation=revocation,
            revocation_registry_size=TAILS_FILE_COUNT if revocation else None,
        )
        return cred_def_id
示例#29
0
    async def handle_issue_credential_v2_0(self, message):
        state = message["state"]
        cred_ex_id = message["cred_ex_id"]
        prev_state = self.cred_state.get(cred_ex_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[cred_ex_id] = state

        self.log(f"Credential: state = {state}, cred_ex_id {cred_ex_id}")

        if state == "offer-received":
            log_status(
                "#15 After receiving credential offer, send credential request"
            )
            await self.admin_POST(
                f"/issue-credential-2.0/records/{cred_ex_id}/send-request")

        elif state == "done":
            # Moved to indy detail record handler
            pass
    async def handle_issue_credential_v2_0(self, message):
        state = message["state"]
        cred_ex_id = message["cred_ex_id"]
        prev_state = self.cred_state.get(cred_ex_id)
        if prev_state == state:
            return  # ignore
        self.cred_state[cred_ex_id] = state

        self.log(f"Credential: state = {state}, cred_ex_id = {cred_ex_id}")

        if state == "request-received":
            log_status("#17 Issue credential to X")
            # issue credential based on offer preview in cred ex record
            await self.admin_POST(
                f"/issue-credential-2.0/records/{cred_ex_id}/issue",
                {"comment": f"Issuing credential, exchange {cred_ex_id}"},
            )
        elif state == "offer-received":
            log_status(
                "#15 After receiving credential offer, send credential request"
            )
            if message["by_format"]["cred_offer"].get("indy"):
                await self.admin_POST(
                    f"/issue-credential-2.0/records/{cred_ex_id}/send-request")
            elif message["by_format"]["cred_offer"].get("ld_proof"):
                holder_did = await self.admin_POST(
                    "/wallet/did/create",
                    {
                        "method": "key",
                        "options": {
                            "key_type": "bls12381g2"
                        }
                    },
                )
                data = {"holder_did": holder_did["result"]["did"]}
                await self.admin_POST(
                    f"/issue-credential-2.0/records/{cred_ex_id}/send-request",
                    data)
        elif state == "done":
            pass