Skip to content

Commit c8ac1d8

Browse files
Mark connection as auditor and ability to query data agreement instances
Added handlers for marking, unmarking, removing auditor connections Added handler for querying data agreement instances Signed-off-by: George J Padayatti <[email protected]>
1 parent bb55f8e commit c8ac1d8

File tree

4 files changed

+471
-3
lines changed

4 files changed

+471
-3
lines changed

mydata_did/v1_0/manager.py

Lines changed: 215 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ class ADAManagerError(BaseError):
9797

9898
class ADAManager:
9999

100+
# Record for indication a connection is labelled as Auditor (client)
101+
RECORD_TYPE_AUDITOR_CONNECTION = "auditor_connection"
102+
100103
# Record for indicating a connection is labelled as MyData DID registry (client)
101104
RECORD_TYPE_MYDATA_DID_REGISTRY_CONNECTION = "mydata_did_registry_connection"
102105

@@ -363,6 +366,33 @@ async def fetch_mydata_did_registry_connection_record(self) -> typing.Tuple[typi
363366
except (StorageError, StorageNotFoundError, StorageDuplicateError) as e:
364367
return None, e
365368

369+
async def fetch_auditor_connection_record(self) -> typing.Tuple[typing.Union[ConnectionRecord, None], typing.Union[None, Exception]]:
370+
# Wallet instance from context
371+
wallet: IndyWallet = await self.context.inject(BaseWallet)
372+
373+
# Storage instance from context
374+
storage: BaseStorage = await self.context.inject(BaseStorage)
375+
376+
auditor_connection_record = None
377+
378+
try:
379+
380+
# Search for existing connection_id marked as Auditor
381+
auditor_connection_record: StorageRecord = await storage.search_records(
382+
self.RECORD_TYPE_AUDITOR_CONNECTION,
383+
).fetch_single()
384+
385+
# Auditor connection identifier
386+
auditor_connection_id = auditor_connection_record.value
387+
388+
# Fetch connection record from storage
389+
connection_record: ConnectionRecord = await ConnectionRecord.retrieve_by_id(self.context, auditor_connection_id)
390+
391+
return connection_record, None
392+
393+
except (StorageError, StorageNotFoundError, StorageDuplicateError) as e:
394+
return None, e
395+
366396
async def send_create_did_message(self, did: str) -> MyDataDIDRegistryDIDCommTransactionRecord:
367397
"""
368398
Send create-did didcomm message to MyData DID Registry.
@@ -1828,6 +1858,126 @@ async def list_da_personal_data_category_from_wallet(self) -> typing.List[str]:
18281858
f"Failed to fetch all data agreements from wallet: {e}"
18291859
)
18301860

1861+
async def mark_connection_id_as_auditor(self, connection_record: ConnectionRecord):
1862+
"""Associate the connection with Auditor"""
1863+
1864+
assert connection_record.connection_id, "Connection ID is required"
1865+
1866+
try:
1867+
1868+
# Fetch storage from context
1869+
storage: IndyStorage = await self.context.inject(BaseStorage)
1870+
1871+
# Search for existing connection_id marked as Auditor
1872+
connection_record_list = await storage.search_records(
1873+
self.RECORD_TYPE_AUDITOR_CONNECTION,
1874+
{"connection_id": connection_record.connection_id},
1875+
).fetch_all()
1876+
1877+
# If no record found, create a new one
1878+
if not connection_record_list:
1879+
record = StorageRecord(
1880+
self.RECORD_TYPE_AUDITOR_CONNECTION,
1881+
connection_record.connection_id,
1882+
{"connection_id": connection_record.connection_id},
1883+
)
1884+
1885+
await storage.add_record(record)
1886+
else:
1887+
# Update the existing record with the new connection_id
1888+
record = connection_record_list[0]
1889+
1890+
await storage.update_record_value(record=record, value=connection_record.connection_id)
1891+
await storage.update_record_tags(record=record, tags={"connection_id": connection_record.connection_id})
1892+
1893+
except StorageError as e:
1894+
# Raise an error
1895+
raise ADAManagerError(
1896+
f"Failed to mark connection as Auditor: {e}"
1897+
)
1898+
except StorageDuplicateError as e:
1899+
# Raise an error
1900+
raise ADAManagerError(
1901+
f"Failed to mark connection as Auditor: {e}"
1902+
)
1903+
1904+
async def fetch_current_auditor_connection_id(self) -> typing.Union[None, str]:
1905+
"""
1906+
Fetch current Auditor connection id.
1907+
"""
1908+
1909+
try:
1910+
1911+
# Fetch storage from context
1912+
storage: IndyStorage = await self.context.inject(BaseStorage)
1913+
1914+
# Search for existing connection_id marked as Auditor
1915+
connection_record_list = await storage.search_records(
1916+
self.RECORD_TYPE_AUDITOR_CONNECTION,
1917+
).fetch_all()
1918+
1919+
if len(connection_record_list) > 1:
1920+
# Raise an error
1921+
raise ADAManagerError(
1922+
f"More than one connection marked as Auditor"
1923+
)
1924+
1925+
if not connection_record_list:
1926+
# if no record found
1927+
return None
1928+
else:
1929+
# if record found
1930+
record = connection_record_list[0]
1931+
1932+
return record.value
1933+
except StorageError as e:
1934+
# Raise an error
1935+
raise ADAManagerError(
1936+
f"Failed to fetch current Auditor connection id: {e}"
1937+
)
1938+
except StorageDuplicateError as e:
1939+
# Raise an error
1940+
raise ADAManagerError(
1941+
f"Failed to fetch current Auditor connection id: {e}"
1942+
)
1943+
1944+
async def unmark_connection_id_as_auditor(self) -> bool:
1945+
"""
1946+
Disassociate the connection with Auditor.
1947+
"""
1948+
1949+
try:
1950+
1951+
# Fetch storage from context
1952+
storage: IndyStorage = await self.context.inject(BaseStorage)
1953+
1954+
# Search for existing connection_id marked as Auditor
1955+
connection_record_list = await storage.search_records(
1956+
self.RECORD_TYPE_AUDITOR_CONNECTION,
1957+
).fetch_all()
1958+
1959+
if not connection_record_list:
1960+
# if no record found
1961+
return False
1962+
else:
1963+
# if record found
1964+
record = connection_record_list[0]
1965+
1966+
await storage.delete_record(record)
1967+
1968+
return True
1969+
1970+
except StorageError as e:
1971+
# Raise an error
1972+
raise ADAManagerError(
1973+
f"Failed to unmark connection as Auditor: {e}"
1974+
)
1975+
except StorageDuplicateError as e:
1976+
# Raise an error
1977+
raise ADAManagerError(
1978+
f"Failed to unmark connection as Auditor: {e}"
1979+
)
1980+
18311981
async def mark_connection_id_as_mydata_did_registry(self, connection_record: ConnectionRecord):
18321982
"""
18331983
Associate the connection with MyData DID registry.
@@ -2095,7 +2245,7 @@ async def delete_data_agreement_instance_metadata(self, *, tag_query: dict = Non
20952245
for storage_record in storage_records:
20962246
await storage.delete_record(storage_record)
20972247

2098-
async def query_data_agreement_instance_metadata(self, *, tag_query: dict = None) -> typing.List[dict]:
2248+
async def query_data_agreement_instance_metadata(self, *, tag_query: dict = None) -> typing.List[StorageRecord]:
20992249
"""Query data agreement instance metadata"""
21002250

21012251
# Fetch storage from context
@@ -2619,3 +2769,67 @@ async def construct_data_agreement_termination_terminate_message(self, *, data_
26192769
)
26202770

26212771
return (updated_data_agreement_instance, data_agreement_terminate_message)
2772+
2773+
async def query_data_agreement_instances(self, tag_query: dict = None) -> typing.List[dict]:
2774+
"""Query data agreement instances"""
2775+
2776+
da_instance_metadata_records = await self.query_data_agreement_instance_metadata(
2777+
tag_query=tag_query
2778+
)
2779+
2780+
data_agreement_instances = []
2781+
2782+
for da_instance_metadata_record in da_instance_metadata_records:
2783+
2784+
# Identify the method of use
2785+
2786+
if da_instance_metadata_record.tags.get("method_of_use") == DataAgreementV1Record.METHOD_OF_USE_DATA_SOURCE:
2787+
2788+
try:
2789+
# Fetch credential exchange record
2790+
cred_ex_record: V10CredentialExchange = await V10CredentialExchange.retrieve_by_id(
2791+
self.context,
2792+
da_instance_metadata_record.tags.get(
2793+
"data_exchange_record_id")
2794+
)
2795+
2796+
if cred_ex_record.data_agreement:
2797+
# Load the data agreement to DataAgreementInstance
2798+
data_agreement_instance: DataAgreementInstance = DataAgreementInstanceSchema().load(
2799+
cred_ex_record.data_agreement
2800+
)
2801+
2802+
# Append the data agreement instance to data_agreement_instances
2803+
data_agreement_instances.append({
2804+
"data_exchange_record_id": da_instance_metadata_record.tags.get("data_exchange_record_id"),
2805+
"data_agreement": data_agreement_instance.serialize()
2806+
})
2807+
2808+
except StorageError:
2809+
pass
2810+
2811+
if da_instance_metadata_record.tags.get("method_of_use") == DataAgreementV1Record.METHOD_OF_USE_DATA_USING_SERVICE:
2812+
try:
2813+
# Fetch presentation exchange record
2814+
pres_ex_record: V10PresentationExchange = await V10PresentationExchange.retrieve_by_id(
2815+
self.context,
2816+
da_instance_metadata_record.tags.get(
2817+
"data_exchange_record_id")
2818+
)
2819+
2820+
if pres_ex_record.data_agreement:
2821+
# Load the data agreement to DataAgreementInstance
2822+
data_agreement_instance: DataAgreementInstance = DataAgreementInstanceSchema().load(
2823+
pres_ex_record.data_agreement
2824+
)
2825+
2826+
# Append the data agreement instance to data_agreement_instances
2827+
data_agreement_instances.append({
2828+
"data_exchange_record_id": da_instance_metadata_record.tags.get("data_exchange_record_id"),
2829+
"data_agreement": data_agreement_instance.serialize()
2830+
})
2831+
2832+
except StorageError:
2833+
pass
2834+
2835+
return data_agreement_instances

mydata_did/v1_0/message_types.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
DATA_AGREEMENT_TERMINATION_TERMINATE_ACK = f"data-agreement-termination/1.0/terminate-ack"
4040
DATA_AGREEMENT_TERMINATION_PROBLEM_REPORT = f"data-agreement-termination/1.0/problem-report"
4141

42+
# Message types for ADA RFC 0004 - Data Agreement Proofs Protocol 1.0
43+
DATA_AGREEMENT_PROOFS_VERIFY = f"data-agreement-proofs/1.0/verify"
44+
DATA_AGREEMENT_PROOFS_VERIFIED = f"data-agreement-proofs/1.0/verified"
45+
DATA_AGREEMENT_PROOFS_UNVERIFIED = f"data-agreement-proofs/1.0/unverified"
46+
4247
# Protocol package path
4348
PROTOCOL_PACKAGE = "mydata_did.v1_0"
4449

mydata_did/v1_0/models/data_agreement_instance_model.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,7 @@ class Meta:
219219
proof_chain = fields.List(
220220
fields.Nested(DataAgreementProofSchema),
221221
description="Data agreement proof chain",
222-
data_key="proofChain",
223-
required=True
222+
data_key="proofChain"
224223
)
225224

226225
# Data agreement principle did

0 commit comments

Comments
 (0)