Skip to content

Commit

Permalink
Fix #7: Verification of SD-JWT
Browse files Browse the repository at this point in the history
Signed-off-by: George J Padayatti <[email protected]>
  • Loading branch information
georgepadayatti committed Apr 30, 2024
1 parent a1460f1 commit 34211be
Show file tree
Hide file tree
Showing 17 changed files with 965 additions and 17 deletions.
32 changes: 32 additions & 0 deletions alembic/versions/3be60cbb77ee_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""empty message
Revision ID: 3be60cbb77ee
Revises: f2622afe5eae
Create Date: 2024-05-01 00:34:20.174467
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '3be60cbb77ee'
down_revision: Union[str, None] = 'f2622afe5eae'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('verification_record', sa.Column('verified', sa.Boolean(), nullable=True))
op.create_unique_constraint(None, 'verification_record', ['id'])
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'verification_record', type_='unique')
op.drop_column('verification_record', 'verified')
# ### end Alembic commands ###
44 changes: 44 additions & 0 deletions alembic/versions/f2622afe5eae_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""empty message
Revision ID: f2622afe5eae
Revises: 792325ac96d1
Create Date: 2024-05-01 00:31:33.929153
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision: str = 'f2622afe5eae'
down_revision: Union[str, None] = '792325ac96d1'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('verification_record',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organisationId', sa.UUID(), nullable=False),
sa.Column('vp_token_request_state', sa.String(), nullable=True),
sa.Column('vp_token_request', sa.String(), nullable=True),
sa.Column('vp_token_qr_code', sa.String(), nullable=True),
sa.Column('vp_token_response', sa.String(), nullable=True),
sa.Column('presentationSubmission', postgresql.JSON(astext_type=sa.Text()), nullable=True),
sa.Column('status', sa.String(), nullable=False),
sa.Column('createdAt', sa.DateTime(), nullable=True),
sa.Column('updatedAt', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['organisationId'], ['organisation.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('id')
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('verification_record')
# ### end Alembic commands ###
195 changes: 194 additions & 1 deletion eudi_wallet/ebsi/entry_points/server/routes/v2/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@
V2RequestContext,
v2_inject_request_context,
)

from eudi_wallet.ebsi.repositories.v2.verification_record import (
SqlAlchemyVerificationRecordRepository,
)
from eudi_wallet.ebsi.value_objects.application.organisation import (
DataAgreementExchangeModes,
)
from eudi_wallet.ebsi.usecases.v2.organisation.create_verification_request_usecase import (
CreateVerificationRequestUsecase,
)
from eudi_wallet.ebsi.usecases.v2.organisation.register_organisation_usecase import (
RegisterOrganisationUsecase,
)
Expand Down Expand Up @@ -57,6 +62,20 @@
from eudi_wallet.ebsi.utils.common import (
validate_data_attribute_schema_against_data_attribute_values,
)
from sdjwt.pex import (
validate_and_deserialise_presentation_definition,
PresentationDefinitionValidationError,
)
from eudi_wallet.ebsi.usecases.v2.organisation.read_verification_request_usecase import (
ReadVerificationRequestUsecase,
)
from eudi_wallet.ebsi.usecases.v2.organisation.delete_verification_request_usecase import (
DeleteVerificationRequestUsecase,
)

from eudi_wallet.ebsi.usecases.v2.organisation.list_verification_request_usecase import (
ListVerificationRequestUsecase,
)

config_routes = web.RouteTableDef()

Expand Down Expand Up @@ -721,3 +740,177 @@ async def handle_config_delete_credential_offer(
return web.HTTPNoContent()
else:
return web.HTTPBadRequest(text="Credential offer not deleted")


class CreateVerificationReq(BaseModel):
presentationDefinition: Optional[dict] = None
requestByReference: bool = False


@config_routes.post(
"/organisation/{organisationId}/config/verification/send",
name="handle_post_create_verification_request",
) # type: ignore
@v2_inject_request_context()
async def handle_post_create_verification_request(
request: Request, context: V2RequestContext
):
assert context.app_context.db_session is not None
assert context.app_context.logger is not None
assert context.app_context.domain is not None
assert context.legal_entity_service is not None
repository = SqlAlchemyVerificationRecordRepository(
session=context.app_context.db_session, logger=context.app_context.logger
)

# Validate organisation ID in the path parameter
organisation_id = request.match_info.get("organisationId")
if organisation_id is None:
raise web.HTTPBadRequest(reason="Invalid organisation id")

try:
data = await request.json()
request_body = CreateVerificationReq(**data)

# Validate presentation definition
validate_and_deserialise_presentation_definition(
presentation_definition=request_body.presentationDefinition
)

usecase = CreateVerificationRequestUsecase(
repository=repository,
logger=context.app_context.logger,
)

_, verification_record = usecase.execute(
key_did=context.legal_entity_service.key_did,
domain=context.app_context.domain,
organisation_id=organisation_id,
presentation_definition=request_body.presentationDefinition,
requestByReference=request_body.requestByReference,
)
return web.json_response(verification_record.to_dict())
except ValidationError as e:
raise web.HTTPBadRequest(reason=json.dumps(e.errors()))
except PresentationDefinitionValidationError as e:
raise web.HTTPBadRequest(reason=str(e))


@config_routes.get(
"/organisation/{organisationId}/config/verification/history/{verificationRecordId}",
name="handle_get_read_verification_history",
) # type: ignore
@v2_inject_request_context()
async def handle_get_read_verification_history(
request: Request, context: V2RequestContext
):
assert context.app_context.db_session is not None
assert context.app_context.logger is not None
assert context.app_context.domain is not None
assert context.legal_entity_service is not None
repository = SqlAlchemyVerificationRecordRepository(
session=context.app_context.db_session, logger=context.app_context.logger
)
organisation_id = request.match_info.get("organisationId")
if organisation_id is None:
raise web.HTTPBadRequest(reason="Invalid organisation ID")

verification_record_id = request.match_info.get("verificationRecordId")
if verification_record_id is None:
raise web.HTTPBadRequest(reason="Invalid verification record ID")

try:
usecase = ReadVerificationRequestUsecase(
repository=repository,
logger=context.app_context.logger,
)

verification_record = usecase.execute(
verification_record_id=verification_record_id
)
return web.json_response(verification_record.to_dict())
except ValidationError as e:
raise web.HTTPBadRequest(reason=json.dumps(e.errors()))
except PresentationDefinitionValidationError as e:
raise web.HTTPBadRequest(reason=str(e))


@config_routes.delete(
"/organisation/{organisationId}/config/verification/history/{verificationRecordId}",
name="handle_delete_verification_history",
) # type: ignore
@v2_inject_request_context()
async def handle_delete_verification_history(
request: Request, context: V2RequestContext
):
assert context.app_context.db_session is not None
assert context.app_context.logger is not None
assert context.app_context.domain is not None
assert context.legal_entity_service is not None
repository = SqlAlchemyVerificationRecordRepository(
session=context.app_context.db_session, logger=context.app_context.logger
)
organisation_id = request.match_info.get("organisationId")
if organisation_id is None:
raise web.HTTPBadRequest(reason="Invalid organisation ID")

verification_record_id = request.match_info.get("verificationRecordId")
if verification_record_id is None:
raise web.HTTPBadRequest(reason="Invalid verification record ID")

try:
usecase = DeleteVerificationRequestUsecase(
repository=repository,
logger=context.app_context.logger,
)

is_deleted = usecase.execute(
organisation_id=organisation_id,
verification_record_id=verification_record_id,
)
if is_deleted:
return web.json_response(status=204)
else:
return web.json_response(status=400)
except ValidationError as e:
raise web.HTTPBadRequest(reason=json.dumps(e.errors()))
except PresentationDefinitionValidationError as e:
raise web.HTTPBadRequest(reason=str(e))


@config_routes.get(
"/organisation/{organisationId}/config/verification/history",
name="handle_list_verification_history",
) # type: ignore
@v2_inject_request_context()
async def handle_list_verification_history(request: Request, context: V2RequestContext):
assert context.app_context.db_session is not None
assert context.app_context.logger is not None
assert context.app_context.domain is not None
assert context.legal_entity_service is not None
repository = SqlAlchemyVerificationRecordRepository(
session=context.app_context.db_session, logger=context.app_context.logger
)
organisation_id = request.match_info.get("organisationId")
if organisation_id is None:
raise web.HTTPBadRequest(reason="Invalid organisation ID")

try:
usecase = ListVerificationRequestUsecase(
repository=repository,
logger=context.app_context.logger,
)

verification_records = usecase.execute(
organisation_id=organisation_id,
)
return web.json_response(
[
verification_record.to_dict()
for verification_record in verification_records
]
)
except ValidationError as e:
raise web.HTTPBadRequest(reason=json.dumps(e.errors()))
except PresentationDefinitionValidationError as e:
raise web.HTTPBadRequest(reason=str(e))
Loading

0 comments on commit 34211be

Please sign in to comment.