Skip to content

Commit

Permalink
Merge pull request #1734 from Indicio-tech/feat/revocation-notificati…
Browse files Browse the repository at this point in the history
…on-v2

Feat/revocation notification v2
  • Loading branch information
ianco authored May 31, 2022
2 parents a4013f4 + ac4fe65 commit 00d97b3
Show file tree
Hide file tree
Showing 22 changed files with 714 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,11 @@
"minimum_minor_version": 0,
"current_minor_version": 0,
"path": "v1_0",
}
},
{
"major_version": 2,
"minimum_minor_version": 0,
"current_minor_version": 0,
"path": "v2_0",
},
]
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Meta:
"rev_reg_id",
"cred_rev_id",
"connection_id",
"version",
}

def __init__(
Expand All @@ -38,6 +39,7 @@ def __init__(
connection_id: str = None,
thread_id: str = None,
comment: str = None,
version: str = None,
**kwargs,
):
"""Construct record."""
Expand All @@ -47,6 +49,7 @@ def __init__(
self.connection_id = connection_id
self.thread_id = thread_id
self.comment = comment
self.version = version

@property
def revocation_notification_id(self) -> Optional[str]:
Expand All @@ -73,6 +76,7 @@ async def query_by_ids(
rev_reg_id: the rev reg id by which to filter
"""
tag_filter = {
**{"version": "v1_0"},
**{"cred_rev_id": cred_rev_id for _ in [""] if cred_rev_id},
**{"rev_reg_id": rev_reg_id for _ in [""] if rev_reg_id},
}
Expand Down Expand Up @@ -101,6 +105,7 @@ async def query_by_rev_reg_id(
rev_reg_id: the rev reg id by which to filter
"""
tag_filter = {
**{"version": "v1_0"},
**{"rev_reg_id": rev_reg_id for _ in [""] if rev_reg_id},
}

Expand Down Expand Up @@ -157,3 +162,7 @@ class Meta:
description="Optional comment to include in revocation notification",
required=False,
)
version = fields.Str(
description="Version of Revocation Notification to send out",
required=False,
)
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def rec():
connection_id="mock_connection_id",
thread_id="mock_thread_id",
comment="mock_comment",
version="v1_0",
)


Expand Down Expand Up @@ -50,6 +51,7 @@ async def test_storage(profile, rec):
another = RevNotificationRecord(
rev_reg_id="mock_rev_reg_id",
cred_rev_id="mock_cred_rev_id",
version="v1_0",
)
await another.save(session)
await RevNotificationRecord.query_by_ids(
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Handler for revoke message."""

from .....messaging.base_handler import BaseHandler
from .....messaging.request_context import RequestContext
from .....messaging.responder import BaseResponder

from ..messages.revoke import Revoke


class RevokeHandler(BaseHandler):
"""Handler for revoke message."""

RECIEVED_TOPIC = "acapy::revocation-notification-v2::received"
WEBHOOK_TOPIC = "acapy::webhook::revocation-notification-v2"

async def handle(self, context: RequestContext, responder: BaseResponder):
"""Handle revoke message."""
assert isinstance(context.message, Revoke)
self._logger.debug(
"Received notification of revocation for %s cred %s with comment: %s",
context.message.revocation_format,
context.message.credential_id,
context.message.comment,
)
# Emit a webhook
if context.settings.get("revocation.monitor_notification"):
await context.profile.notify(
self.WEBHOOK_TOPIC,
{
"revocation_format": context.message.revocation_format,
"credential_id": context.message.credential_id,
"comment": context.message.comment,
},
)

# Emit an event
await context.profile.notify(
self.RECIEVED_TOPIC,
{
"revocation_format": context.message.revocation_format,
"credential_id": context.message.credential_id,
"comment": context.message.comment,
},
)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Test RevokeHandler."""

import pytest

from ......config.settings import Settings
from ......core.event_bus import EventBus, MockEventBus
from ......core.in_memory import InMemoryProfile
from ......core.profile import Profile
from ......messaging.request_context import RequestContext
from ......messaging.responder import MockResponder, BaseResponder
from ...messages.revoke import Revoke
from ..revoke_handler import RevokeHandler


@pytest.fixture
def event_bus():
yield MockEventBus()


@pytest.fixture
def responder():
yield MockResponder()


@pytest.fixture
def profile(event_bus):
yield InMemoryProfile.test_profile(bind={EventBus: event_bus})


@pytest.fixture
def message():
yield Revoke(
revocation_format="indy-anoncreds",
credential_id="mock_cred_revocation_id",
comment="mock_comment",
)


@pytest.fixture
def context(profile: Profile, message: Revoke):
request_context = RequestContext(profile)
request_context.message = message
yield request_context


@pytest.mark.asyncio
async def test_handle(
context: RequestContext, responder: BaseResponder, event_bus: MockEventBus
):
await RevokeHandler().handle(context, responder)
assert event_bus.events
[(_, received)] = event_bus.events
assert received.topic == RevokeHandler.RECIEVED_TOPIC
assert "revocation_format" in received.payload
assert "credential_id" in received.payload
assert "comment" in received.payload


@pytest.mark.asyncio
async def test_handle_monitor(
context: RequestContext, responder: BaseResponder, event_bus: MockEventBus
):
context.settings["revocation.monitor_notification"] = True
await RevokeHandler().handle(context, responder)
[(_, webhook), (_, received)] = event_bus.events

assert webhook.topic == RevokeHandler.WEBHOOK_TOPIC
assert "revocation_format" in received.payload
assert "credential_id" in received.payload
assert "comment" in webhook.payload

assert received.topic == RevokeHandler.RECIEVED_TOPIC
assert "revocation_format" in received.payload
assert "credential_id" in received.payload
assert "comment" in received.payload
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Message type identifiers for Revocation Notification protocol."""

from ...didcomm_prefix import DIDCommPrefix


SPEC_URI = (
"https://github.com/hyperledger/aries-rfcs/blob/main/features/"
"0721-revocation-notification-v2/README.md"
)
PROTOCOL = "revocation_notification"
VERSION = "2.0"
BASE = f"{PROTOCOL}/{VERSION}"

# Message types
REVOKE = f"{BASE}/revoke"

PROTOCOL_PACKAGE = "aries_cloudagent.protocols.revocation_notification.v2_0"
MESSAGE_TYPES = DIDCommPrefix.qualify_all(
{REVOKE: f"{PROTOCOL_PACKAGE}.messages.revoke.Revoke"}
)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Revoke message."""

from marshmallow import fields, validate
from .....messaging.agent_message import AgentMessage, AgentMessageSchema
from .....messaging.decorators.please_ack_decorator import (
PleaseAckDecorator,
PleaseAckDecoratorSchema,
)
from .....messaging.valid import UUIDFour
from ..message_types import PROTOCOL_PACKAGE, REVOKE

HANDLER_CLASS = f"{PROTOCOL_PACKAGE}.handlers.revoke_handler.RevokeHandler"


class Revoke(AgentMessage):
"""Class representing revoke message."""

class Meta:
"""Revoke Meta."""

handler_class = HANDLER_CLASS
message_type = REVOKE
schema_class = "RevokeSchema"

def __init__(
self,
*,
revocation_format: str,
credential_id: str,
please_ack: PleaseAckDecorator = None,
comment: str = None,
**kwargs,
):
"""Initialize revoke message."""
super().__init__(**kwargs)
self.revocation_format = revocation_format
self.credential_id = credential_id
self.comment = comment


class RevokeSchema(AgentMessageSchema):
"""Schema of Revoke message."""

class Meta:
"""RevokeSchema Meta."""

model_class = Revoke

revocation_format = fields.Str(
required=True,
description=("The format of the credential revocation ID"),
example="indy-anoncreds",
validate=validate.OneOf(["indy-anoncreds"]),
)
credential_id = fields.Str(
required=True,
description=("Credential ID of the issued credential to be revoked"),
example=UUIDFour.EXAMPLE,
)
please_ack = fields.Nested(
PleaseAckDecoratorSchema,
required=False,
description="Whether or not the holder should acknowledge receipt",
data_key="~please_ack",
)
comment = fields.Str(
required=False,
description="Human readable information about revocation notification",
)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Test Revoke Message."""

from ..revoke import Revoke


def test_instantiate():
msg = Revoke(
revocation_format="indy-anoncreds",
credential_id="test-id",
comment="test",
)
assert msg.revocation_format == "indy-anoncreds"
assert msg.credential_id == "test-id"
assert msg.comment == "test"
Empty file.
Loading

0 comments on commit 00d97b3

Please sign in to comment.