Skip to content

Commit

Permalink
Merge pull request #86 from Indicio-tech/feature/connectionless-issue…
Browse files Browse the repository at this point in the history
…-example

feat: add connectionless issuance example
  • Loading branch information
dbluhm authored Apr 24, 2024
2 parents 9fd1e29 + a862461 commit 6770d84
Show file tree
Hide file tree
Showing 2 changed files with 334 additions and 0 deletions.
93 changes: 93 additions & 0 deletions examples/connectionless/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
version: "3"
services:
alice:
image: ghcr.io/hyperledger/aries-cloudagent-python:py3.9-0.11.0
ports:
- "3001:3001"
environment:
RUST_LOG: 'aries-askar::log::target=error'
command: >
start
--label Alice
--inbound-transport http 0.0.0.0 3000
--outbound-transport http
--endpoint http://alice:3000
--admin 0.0.0.0 3001
--admin-insecure-mode
--tails-server-base-url http://tails:6543
--genesis-url https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_testnet_genesis
--wallet-type askar
--wallet-name alice
--wallet-key insecure
--auto-provision
--log-level debug
--debug-webhooks
healthcheck:
test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null
start_period: 30s
interval: 7s
timeout: 5s
retries: 5
depends_on:
tails:
condition: service_started

bob:
image: ghcr.io/hyperledger/aries-cloudagent-python:py3.9-0.11.0
ports:
- "3002:3001"
environment:
RUST_LOG: 'aries-askar::log::target=error'
command: >
start
--label Bob
--inbound-transport http 0.0.0.0 3000
--outbound-transport http
--endpoint http://bob:3000
--admin 0.0.0.0 3001
--admin-insecure-mode
--tails-server-base-url http://tails:6543
--genesis-url https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_testnet_genesis
--wallet-type askar
--wallet-name bob
--wallet-key insecure
--auto-provision
--log-level debug
--debug-webhooks
--monitor-revocation-notification
healthcheck:
test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null
start_period: 30s
interval: 7s
timeout: 5s
retries: 5

tails:
image: ghcr.io/bcgov/tails-server:latest
ports:
- 6543:6543
environment:
- GENESIS_URL=https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_testnet_genesis
command: >
tails-server
--host 0.0.0.0
--port 6543
--storage-path /tmp/tails-files
--log-level INFO
example:
container_name: controller
build:
context: ../..
environment:
- ALICE=http://alice:3001
- BOB=http://bob:3001
volumes:
- ../../acapy_controller:/usr/src/app/acapy_controller:z
- ./example.py:/usr/src/app/example.py:ro,z
command: python -m example
depends_on:
alice:
condition: service_healthy
bob:
condition: service_healthy
241 changes: 241 additions & 0 deletions examples/connectionless/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
"""Minimal reproducible example script.
This script is for you to use to reproduce a bug or demonstrate a feature.
"""

import asyncio
from dataclasses import dataclass
from os import getenv

from acapy_controller import Controller
from acapy_controller.controller import Minimal
from acapy_controller.logging import logging_to_stdout
from acapy_controller.protocols import (
InvitationRecord,
V20CredExRecordDetail,
V20CredExRecordIndy,
indy_anoncred_onboard,
indy_anoncred_credential_artifacts,
)

ALICE = getenv("ALICE", "http://alice:3001")
BOB = getenv("BOB", "http://bob:3001")


@dataclass
class ConnectionlessV20CredExRecord(Minimal):
"""Minimal record for connectionless v2 cred ex record."""

cred_ex_id: str


async def icv2():
"""Test Controller protocols."""
async with Controller(base_url=ALICE) as alice, Controller(base_url=BOB) as bob:
await indy_anoncred_onboard(alice)
_, cred_def = await indy_anoncred_credential_artifacts(
alice, ["firstname", "lastname"]
)

attributes = {"firstname": "Bob", "lastname": "Builder"}
offer = await alice.post(
"/issue-credential-2.0/create-offer",
json={
"auto_issue": False,
"auto_remove": False,
"comment": "Credential from minimal example",
"trace": False,
"filter": {"indy": {"cred_def_id": cred_def.credential_definition_id}},
"credential_preview": {
"type": "issue-credential-2.0/2.0/credential-preview", # pyright: ignore
"attributes": [
{
"mime_type": None,
"name": name,
"value": value,
}
for name, value in attributes.items()
],
},
},
response=ConnectionlessV20CredExRecord,
)
invite = await alice.post(
"/out-of-band/create-invitation",
json={
"attachments": [{"id": offer.cred_ex_id, "type": "credential-offer"}]
},
response=InvitationRecord,
)
bob.event_queue.flush()
await bob.post("/out-of-band/receive-invitation", json=invite.invitation)
bob_cred_ex = await bob.event_with_values(
topic="issue_credential_v2_0",
state="offer-received",
event_type=ConnectionlessV20CredExRecord,
)
bob_cred_ex_id = bob_cred_ex.cred_ex_id

alice.event_queue.flush()
bob_cred_ex = await bob.post(
f"/issue-credential-2.0/records/{bob_cred_ex_id}/send-request",
response=ConnectionlessV20CredExRecord,
)

alice_cred_ex = await alice.event_with_values(
topic="issue_credential_v2_0",
state="request-received",
event_type=ConnectionlessV20CredExRecord,
)
alice_cred_ex_id = alice_cred_ex.cred_ex_id

alice_cred_ex = await alice.post(
f"/issue-credential-2.0/records/{alice_cred_ex_id}/issue",
json={},
response=V20CredExRecordDetail,
)

await bob.event_with_values(
topic="issue_credential_v2_0",
cred_ex_id=bob_cred_ex_id,
state="credential-received",
)

bob_cred_ex = await bob.post(
f"/issue-credential-2.0/records/{bob_cred_ex_id}/store",
json={},
response=V20CredExRecordDetail,
)
alice_cred_ex = await alice.event_with_values(
topic="issue_credential_v2_0",
event_type=ConnectionlessV20CredExRecord,
cred_ex_id=alice_cred_ex_id,
state="done",
)
await alice.event_with_values(
topic="issue_credential_v2_0_indy",
event_type=V20CredExRecordIndy,
)

bob_cred_ex = await bob.event_with_values(
topic="issue_credential_v2_0",
event_type=ConnectionlessV20CredExRecord,
cred_ex_id=bob_cred_ex_id,
state="done",
)
await bob.event_with_values(
topic="issue_credential_v2_0_indy",
event_type=V20CredExRecordIndy,
)


@dataclass
class ConnectionlessV10CredExRecord(Minimal):
"""Minimal record for v1 cred ex record."""

credential_exchange_id: str


async def icv1():
"""Issue credential v1."""
async with Controller(base_url=ALICE) as alice, Controller(base_url=BOB) as bob:
await indy_anoncred_onboard(alice)
_, cred_def = await indy_anoncred_credential_artifacts(
alice, ["firstname", "lastname"]
)

attributes = {"firstname": "Bob", "lastname": "Builder"}
offer = await alice.post(
"/issue-credential/create-offer",
json={
"auto_issue": False,
"auto_remove": False,
"comment": "Credential from minimal example",
"trace": False,
"cred_def_id": cred_def.credential_definition_id,
"credential_preview": {
"@type": "issue-credential/1.0/credential-preview",
"attributes": [
{
"mime_type": None,
"name": name,
"value": value,
}
for name, value in attributes.items()
],
},
},
response=ConnectionlessV10CredExRecord,
)
invite = await alice.post(
"/out-of-band/create-invitation",
json={
"attachments": [
{"id": offer.credential_exchange_id, "type": "credential-offer"}
]
},
response=InvitationRecord,
)
bob.event_queue.flush()
await bob.post("/out-of-band/receive-invitation", json=invite.invitation)
bob_cred_ex = await bob.event_with_values(
topic="issue_credential",
state="offer_received",
event_type=ConnectionlessV10CredExRecord,
)
bob_cred_ex_id = bob_cred_ex.credential_exchange_id

alice.event_queue.flush()
bob_cred_ex = await bob.post(
f"/issue-credential/records/{bob_cred_ex_id}/send-request",
response=ConnectionlessV10CredExRecord,
)

alice_cred_ex = await alice.event_with_values(
topic="issue_credential",
state="request_received",
event_type=ConnectionlessV10CredExRecord,
)
alice_cred_ex_id = alice_cred_ex.credential_exchange_id

alice_cred_ex = await alice.post(
f"/issue-credential/records/{alice_cred_ex_id}/issue",
json={},
response=ConnectionlessV10CredExRecord,
)

await bob.event_with_values(
topic="issue_credential",
credential_exchange_id=bob_cred_ex_id,
state="credential_received",
)

bob_cred_ex = await bob.post(
f"/issue-credential/records/{bob_cred_ex_id}/store",
json={},
response=ConnectionlessV10CredExRecord,
)
alice_cred_ex = await alice.event_with_values(
topic="issue_credential",
event_type=ConnectionlessV10CredExRecord,
credential_exchange_id=alice_cred_ex_id,
state="credential_acked",
)

bob_cred_ex = await bob.event_with_values(
topic="issue_credential",
event_type=ConnectionlessV10CredExRecord,
credential_exchange_id=bob_cred_ex_id,
state="credential_acked",
)


async def main():
"""Run."""
await icv1()
await icv2()


if __name__ == "__main__":
logging_to_stdout()
asyncio.run(main())

0 comments on commit 6770d84

Please sign in to comment.