async def get_credentials(self, start: int, count: int, wql: dict): """ Get credentials stored in the wallet. Args: start: Starting index count: Number of records to return wql: wql query dict """ result = [] try: rows = self._profile.store.scan( CATEGORY_CREDENTIAL, wql, start, count, self._profile.settings.get("wallet.askar_profile"), ) async for row in rows: cred = Credential.load(row.raw_value) result.append(_make_cred_info(row.name, cred)) except AskarError as err: raise IndyHolderError("Error retrieving credentials") from err except CredxError as err: raise IndyHolderError("Error loading stored credential") from err return result
def _make_cred_info(cred_id, cred: Credential): cred_info = cred.to_dict() # not secure! rev_info = cred_info["signature"]["r_credential"] return { "referent": cred_id, "schema_id": cred_info["schema_id"], "cred_def_id": cred_info["cred_def_id"], "rev_reg_id": cred_info["rev_reg_id"], "cred_rev_id": str(rev_info["i"]) if rev_info else None, "attrs": {name: val["raw"] for (name, val) in cred_info["values"].items()}, }
async def _get_credential(self, credential_id: str) -> Credential: """Get an unencoded Credential instance from the store.""" try: async with self._profile.session() as session: cred = await session.handle.fetch(CATEGORY_CREDENTIAL, credential_id) except AskarError as err: raise IndyHolderError("Error retrieving credential") from err if not cred: raise WalletNotFoundError( f"Credential {credential_id} not found in wallet {self.profile.name}" ) try: return Credential.load(cred.raw_value) except CredxError as err: raise IndyHolderError("Error loading requested credential") from err
async def get_credentials_for_presentation_request_by_referent( self, presentation_request: dict, referents: Sequence[str], start: int, count: int, extra_query: dict = {}, ): """ Get credentials stored in the wallet. Args: presentation_request: Valid presentation request from issuer referents: Presentation request referents to use to search for creds start: Starting index count: Maximum number of records to return extra_query: wql query dict """ # FIXME not using extra_query if not referents: referents = ( *presentation_request["requested_attributes"], *presentation_request["requested_predicates"], ) creds = {} for reft in referents: names = set() if reft in presentation_request["requested_attributes"]: attr = presentation_request["requested_attributes"][reft] if "name" in attr: names.add(_normalize_attr_name(attr["name"])) elif "names" in attr: names.update( _normalize_attr_name(name) for name in attr["names"]) # for name in names: # tag_filter[f"attr::{_normalize_attr_name(name)}::marker"] = "1" restr = attr.get("restrictions") elif reft in presentation_request["requested_predicates"]: pred = presentation_request["requested_predicates"][reft] if "name" in pred: names.add(_normalize_attr_name(pred["name"])) # tag_filter[f"attr::{_normalize_attr_name(name)}::marker"] = "1" restr = pred.get("restrictions") else: raise IndyHolderError( f"Unknown presentation request referent: {reft}") tag_filter = { "$exist": list(f"attr::{name}::value" for name in names) } if restr: # FIXME check if restr is a list or dict? validate WQL format tag_filter = {"$and": [tag_filter] + restr} rows = self._profile.store.scan(CATEGORY_CREDENTIAL, tag_filter, start, count) async for row in rows: if row.name in creds: creds[row.name]["presentation_referents"].add(reft) else: cred_info = _make_cred_info(row.name, Credential.load(row.raw_value)) creds[row.name] = { "cred_info": cred_info, "interval": presentation_request.get("non_revoked"), "presentation_referents": {reft}, } for cred in creds.values(): cred["presentation_referents"] = list( cred["presentation_referents"]) return list(creds.values())
async def store_credential( self, credential_definition: dict, credential_data: dict, credential_request_metadata: dict, credential_attr_mime_types: dict = None, credential_id: str = None, rev_reg_def: dict = None, ) -> str: """ Store a credential in the wallet. Args: credential_definition: Credential definition for this credential credential_data: Credential data generated by the issuer credential_request_metadata: credential request metadata generated by the issuer credential_attr_mime_types: dict mapping attribute names to (optional) MIME types to store as non-secret record, if specified credential_id: optionally override the stored credential id rev_reg_def: revocation registry definition in json Returns: the ID of the stored credential """ try: secret = await self.get_master_secret() cred = Credential.load(credential_data) cred_recvd = await asyncio.get_event_loop().run_in_executor( None, cred.process, credential_request_metadata, secret, credential_definition, rev_reg_def, ) except CredxError as err: raise IndyHolderError( "Error processing received credential") from err schema_id = cred_recvd.schema_id schema_id_parts = re.match(r"^(\w+):2:([^:]+):([^:]+)$", schema_id) if not schema_id_parts: raise IndyHolderError( f"Error parsing credential schema ID: {schema_id}") cred_def_id = cred_recvd.cred_def_id cdef_id_parts = re.match(r"^(\w+):3:CL:([^:]+):([^:]+)$", cred_def_id) if not cdef_id_parts: raise IndyHolderError( f"Error parsing credential definition ID: {cred_def_id}") credential_id = credential_id or str(uuid.uuid4()) tags = { "schema_id": schema_id, "schema_issuer_did": schema_id_parts[1], "schema_name": schema_id_parts[2], "schema_version": schema_id_parts[3], "issuer_did": cdef_id_parts[1], "cred_def_id": cred_def_id, "rev_reg_id": cred_recvd.rev_reg_id or "None", } # FIXME - sdk has some special handling for fully qualified DIDs here mime_types = {} for k, attr_value in credential_data["values"].items(): attr_name = _normalize_attr_name(k) # tags[f"attr::{attr_name}::marker"] = "1" tags[f"attr::{attr_name}::value"] = attr_value["raw"] if credential_attr_mime_types and k in credential_attr_mime_types: mime_types[k] = credential_attr_mime_types[k] try: async with self._profile.transaction() as txn: await txn.handle.insert( CATEGORY_CREDENTIAL, credential_id, cred_recvd.to_json_buffer(), tags=tags, ) if mime_types: await txn.handle.insert( IndyHolder.RECORD_TYPE_MIME_TYPES, credential_id, value_json=mime_types, ) await txn.commit() except AskarError as err: raise IndyHolderError("Error storing credential") from err return credential_id
master_secret, master_secret_id, cred_offer) print(cred_req.to_json()) issuer_rev_index = 1 cred, rev_reg_updated, _rev_delta = Credential.create( cred_def, cred_def_pvt, cred_offer, cred_req, {"attr": "test"}, None, CredentialRevocationConfig( rev_reg_def, rev_reg_def_private, rev_reg, issuer_rev_index, rev_reg_def.tails_location, ), ) print(cred, rev_reg_updated) print(cred.to_json()) cred_received = cred.process(cred_req_metadata, master_secret, cred_def, rev_reg_def) print(cred_received) timestamp = int(time())