Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issuance fix #156

Closed
wants to merge 46 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
68e7f88
feat: Init did:cheqd integration
DaevMithran Nov 4, 2024
a063fc9
feat: Support did:cheqd resolver
DaevMithran Nov 4, 2024
1c63da0
Use wallet methods to create keys and did
DaevMithran Nov 5, 2024
b900fd6
Implement register schema
DaevMithran Nov 5, 2024
5b2921f
Merge branch 'main' into acapy-cheqd
sownak Nov 5, 2024
cf059c8
fix wallet injection
DaevMithran Nov 5, 2024
b21e035
fix resource create && kid verkey assignment
DaevMithran Nov 6, 2024
2e5ee59
Implement credDefs
DaevMithran Nov 7, 2024
d5f7040
feat: add support for deactivate and update
sownak Nov 14, 2024
4f05111
Merge branch 'main' into acapy-cheqd
sownak Nov 14, 2024
b380e53
Merge branch 'acapy-cheqd' into feat/universal-registrar
sownak Nov 14, 2024
da40267
fix: simplified update() inputs
sownak Nov 14, 2024
177d6a3
update update function with new schema
sownak Nov 15, 2024
79a7e5b
fix: resolved review comments
sownak Nov 19, 2024
9099103
Add anoncreds issuance and presentation formats
jamshale Nov 6, 2024
1eeb4ba
Fix unit tests
jamshale Nov 6, 2024
8b67eca
Fix error in _formats_attach
jamshale Nov 6, 2024
7b2e419
Fix AnoncredsDID validation pattern
jamshale Nov 6, 2024
5c5b58a
Fix name
jamshale Nov 6, 2024
fc20219
Fix scenario test
jamshale Nov 17, 2024
d1ebcc9
Update demo with anoncreds format
jamshale Nov 17, 2024
c26a69c
Fix the scenario test and add better description
jamshale Nov 18, 2024
9a5cdef
Add service_healthy check for indy agent
jamshale Nov 18, 2024
95ceef3
Fix/update BDD tests
jamshale Nov 18, 2024
4251e29
Add issuer askar to holder anoncreds support
jamshale Nov 20, 2024
6ed7c17
Update BDD tests
jamshale Nov 20, 2024
b8fe744
Remove commented code
jamshale Nov 20, 2024
7205b13
Expand scenario test
jamshale Nov 21, 2024
4c6d7e7
Add better comments for format compatibilty imports
jamshale Nov 21, 2024
ea67fa5
Finalize cred def implementation
DaevMithran Nov 22, 2024
b4d1ad4
Merge remote-tracking branch 'origin/feat/universal-registrar' into a…
DaevMithran Nov 22, 2024
dd52607
Merge branch 'main' into acapy-cheqd
DaevMithran Nov 22, 2024
c822779
Merge anoncreds issuance and presentation
DaevMithran Nov 22, 2024
f96ccff
Merge branch 'acapy-cheqd' into issuance-presentation
DaevMithran Nov 22, 2024
909b658
Updated tests
sownak Nov 22, 2024
4db92b1
Support cheqd identifiers in issuance
DaevMithran Nov 25, 2024
9215611
Init did:cheqd tests
DaevMithran Nov 26, 2024
be0f050
Update scenarios
DaevMithran Nov 27, 2024
0ce2814
make image build on ARM64
Nov 27, 2024
5f0744f
fix example
Nov 27, 2024
f095afe
split main func
Nov 27, 2024
c3c3db7
add create schema
Nov 27, 2024
a1869e3
add more cases
Nov 27, 2024
b686135
Add issuance test
DaevMithran Nov 28, 2024
fc3d5cc
test: add integration tests [DEV-4613][DEV-4614] (#4)
DaevMithran Nov 28, 2024
04d565a
Use entropy instead of prover_did
jamshale Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions acapy_agent/anoncreds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ async def setup(context: InjectionContext):
await indy_registry.setup(context)
registry.register(indy_registry)

cheqd_registry = ClassProvider(
"acapy_agent.anoncreds.default.did_cheqd.registry.DIDCheqdRegistry",
# supported_identifiers=[],
# method_name="did:cheqd",
).provide(context.settings, context.injector)
await cheqd_registry.setup(context)
registry.register(cheqd_registry)

web_registry = ClassProvider(
"acapy_agent.anoncreds.default.did_web.registry.DIDWebRegistry",
# supported_identifiers=[],
Expand Down
6 changes: 3 additions & 3 deletions acapy_agent/anoncreds/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
from ..config.injection_context import InjectionContext
from ..core.error import BaseError
from ..core.profile import Profile
from .models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult
from .models.anoncreds_revocation import (
from .models.credential_definition import CredDef, CredDefResult, GetCredDefResult
from .models.revocation import (
GetRevListResult,
GetRevRegDefResult,
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
)
from .models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult
from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult

T = TypeVar("T")

Expand Down
Empty file.
339 changes: 339 additions & 0 deletions acapy_agent/anoncreds/default/did_cheqd/registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
"""DID Cheqd Registry."""

import logging
from typing import Optional, Pattern, Sequence
from uuid import uuid4

from aiohttp import web

from ....config.injection_context import InjectionContext
from ....core.profile import Profile
from ...base import (
BaseAnonCredsRegistrar,
BaseAnonCredsResolver,
AnonCredsRegistrationError,
)
from ...models.credential_definition import (
CredDef,
CredDefResult,
GetCredDefResult,
CredDefState,
CredDefValue,
)
from ...models.revocation import (
GetRevListResult,
GetRevRegDefResult,
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
)
from ...models.schema import (
AnonCredsSchema,
GetSchemaResult,
SchemaResult,
SchemaState,
)
from ....did.cheqd.manager import DidCheqdManager
from ....did.cheqd.registrar import DidCheqdRegistrar
from ....resolver.default.cheqd import CheqdDIDResolver
from ....messaging.valid import CheqdDID
from ....wallet.base import BaseWallet
from ....wallet.jwt import dict_to_b64

LOGGER = logging.getLogger(__name__)


class DIDCheqdRegistry(BaseAnonCredsResolver, BaseAnonCredsRegistrar):
"""DIDCheqdRegistry."""

registrar: DidCheqdRegistrar
resolver: CheqdDIDResolver

def __init__(self):
"""Initialize an instance.

Args:
None

"""
self.registrar = DidCheqdRegistrar()
self.resolver = CheqdDIDResolver()

@property
def supported_identifiers_regex(self) -> Pattern:
"""Supported Identifiers regex."""
return CheqdDID.PATTERN

@staticmethod
def make_schema_id(schema: AnonCredsSchema, resource_id: str) -> str:
"""Derive the ID for a schema."""
return f"{schema.issuer_id}/resources/{resource_id}"

@staticmethod
def make_credential_definition_id(
credential_definition: CredDef, resource_id: str
) -> str:
"""Derive the ID for a credential definition."""
return f"{credential_definition.issuer_id}/resources/{resource_id}"

@staticmethod
def split_schema_id(schema_id: str) -> (str, str):
"""Derive the ID for a schema."""
ids = schema_id.split("/")
return ids[0], ids[2]

async def setup(self, context: InjectionContext):
"""Setup."""
print("Successfully registered DIDCheqdRegistry")

async def get_schema(self, profile: Profile, schema_id: str) -> GetSchemaResult:
"""Get a schema from the registry."""
schema = await self.resolver.resolve_resource(schema_id)
(did, resource_id) = self.split_schema_id(schema_id)

anoncreds_schema = AnonCredsSchema(
issuer_id=did,
attr_names=schema["attrNames"],
name=schema["name"],
version=schema["version"],
)

return GetSchemaResult(
schema_id=schema_id,
schema=anoncreds_schema,
schema_metadata={},
resolution_metadata={
"resource_id": resource_id,
"resource_name": schema.get("name"),
"resource_type": "anonCredsSchema",
},
)

async def register_schema(
self,
profile: Profile,
schema: AnonCredsSchema,
options: Optional[dict] = None,
) -> SchemaResult:
"""Register a schema on the registry."""
resource_type = "anonCredsSchema"
resource_name = schema.name
resource_version = schema.version

LOGGER.debug("Registering schema")
cheqd_schema = {
"name": resource_name,
"type": resource_type,
"version": resource_version,
"data": dict_to_b64(
{
"name": schema.name,
"version": schema.version,
"attrNames": schema.attr_names,
}
),
}

LOGGER.debug("schema value: %s", cheqd_schema)
try:
resource_state = await self._create_and_publish_resource(
profile,
schema.issuer_id,
cheqd_schema,
)
job_id = resource_state.get("jobId")
resource = resource_state.get("resource")
resource_id = resource.get("id")
schema_id = self.make_schema_id(schema, resource_id)
except Exception as err:
raise AnonCredsRegistrationError(f"{err}")
return SchemaResult(
job_id=job_id,
schema_state=SchemaState(
state=SchemaState.STATE_FINISHED,
schema_id=schema_id,
schema=schema,
),
registration_metadata={
"resource_id": resource_id,
"resource_name": resource_name,
"resource_type": resource_type,
},
)

async def get_credential_definition(
self, profile: Profile, credential_definition_id: str
) -> GetCredDefResult:
"""Get a credential definition from the registry."""
credential_definition = await self.resolver.resolve_resource(
credential_definition_id
)
(did, resource_id) = self.split_schema_id(credential_definition_id)

anoncreds_credential_definition = CredDef(
issuer_id=did,
schema_id=credential_definition["schemaId"],
type=credential_definition["type"],
tag=credential_definition["tag"],
value=CredDefValue.deserialize(credential_definition["value"]),
)

return GetCredDefResult(
credential_definition_id=credential_definition_id,
credential_definition=anoncreds_credential_definition,
credential_definition_metadata={},
resolution_metadata={
"resource_id": resource_id,
"resource_name": credential_definition.get("tag"),
"resource_type": "anonCredsCredDef",
},
)

async def register_credential_definition(
self,
profile: Profile,
schema: GetSchemaResult,
credential_definition: CredDef,
options: Optional[dict] = None,
) -> CredDefResult:
"""Register a credential definition on the registry."""
resource_type = "anonCredsCredDef"
resource_name = credential_definition.tag

cred_def = {
"name": resource_name,
"type": resource_type,
"data": dict_to_b64(
{
"type": credential_definition.type,
"tag": credential_definition.tag,
"value": credential_definition.value.serialize(),
"schemaId": schema.schema_id,
}
),
"version": str(uuid4()),
}

resource_state = await self._create_and_publish_resource(
profile, credential_definition.issuer_id, cred_def
)
job_id = resource_state.get("jobId")
resource = resource_state.get("resource")
resource_id = resource.get("id")

credential_definition_id = self.make_credential_definition_id(
credential_definition, resource_id
)

return CredDefResult(
job_id=job_id,
credential_definition_state=CredDefState(
state=CredDefState.STATE_FINISHED,
credential_definition_id=credential_definition_id,
credential_definition=credential_definition,
),
registration_metadata={
"resource_id": resource_id,
"resource_name": resource_name,
"resource_type": resource_type,
},
credential_definition_metadata={},
)

async def get_revocation_registry_definition(
self, profile: Profile, revocation_registry_id: str
) -> GetRevRegDefResult:
"""Get a revocation registry definition from the registry."""
raise NotImplementedError()

async def register_revocation_registry_definition(
self,
profile: Profile,
revocation_registry_definition: RevRegDef,
options: Optional[dict] = None,
) -> RevRegDefResult:
"""Register a revocation registry definition on the registry."""
raise NotImplementedError()

async def get_revocation_list(
self,
profile: Profile,
revocation_registry_id: str,
timestamp_from: Optional[int] = 0,
timestamp_to: Optional[int] = None,
) -> GetRevListResult:
"""Get a revocation list from the registry."""
raise NotImplementedError()

async def register_revocation_list(
self,
profile: Profile,
rev_reg_def: RevRegDef,
rev_list: RevList,
options: Optional[dict] = None,
) -> RevListResult:
"""Register a revocation list on the registry."""
raise NotImplementedError()

async def update_revocation_list(
self,
profile: Profile,
rev_reg_def: RevRegDef,
prev_list: RevList,
curr_list: RevList,
revoked: Sequence[int],
options: Optional[dict] = None,
) -> RevListResult:
"""Update a revocation list on the registry."""
raise NotImplementedError()

@staticmethod
async def _create_and_publish_resource(
profile: Profile, did: str, options: dict
) -> dict:
"""Create, Sign and Publish a Resource."""
cheqd_manager = DidCheqdManager(profile)
async with profile.session() as session:
wallet = session.inject_or(BaseWallet)
if not wallet:
raise web.HTTPForbidden(reason="No wallet available")
try:
# request create resource operation
create_request_res = await cheqd_manager.registrar.create_resource(
did, options
)

job_id: str = create_request_res.get("jobId")
resource_state = create_request_res.get("resourceState")

LOGGER.debug("JOBID %s", job_id)
if resource_state.get("state") == "action":
signing_requests: dict = resource_state.get("signingRequest")
if not signing_requests:
raise Exception("No signing requests available for update.")
# sign all requests
signed_responses = await DidCheqdManager.sign_requests(
wallet, signing_requests
)

# publish resource
publish_resource_res = await cheqd_manager.registrar.create_resource(
did,
{
"jobId": job_id,
"secret": {"signingResponse": signed_responses},
},
)
resource_state = publish_resource_res.get("resourceState")
if resource_state.get("state") != "finished":
raise AnonCredsRegistrationError(
f"Error publishing Resource {resource_state.get("reason")}"
)
return resource_state
else:
raise AnonCredsRegistrationError(
f"Error publishing Resource {resource_state.get("reason")}"
)
except Exception as err:
raise AnonCredsRegistrationError(f"{err}")
1 change: 1 addition & 0 deletions acapy_agent/anoncreds/default/did_cheqd/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Routes for DID Cheqd Registry."""
Empty file.
Loading