Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
155 changes: 10 additions & 145 deletions src/keria/app/agenting.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import datetime
from dataclasses import asdict, dataclass, field
from typing import List, Union
from urllib.parse import urlparse, urljoin
from types import MappingProxyType
from deprecation import deprecated

Expand All @@ -33,7 +32,6 @@
habbing,
storing,
signaling,
oobiing,
agenting,
forwarding,
querying,
Expand All @@ -45,8 +43,7 @@
from keri.app.keeping import Algos
from keri.core import coring, parsing, eventing, routing, serdering
from keri.core.coring import Ilks
from keri.core.signing import Salter
from keri.db.basing import OobiRecord
from keri.app import oobiing
from keri.vc import protocoling

from keria.end import ending
Expand All @@ -59,7 +56,7 @@

from keria.utils.openapi import dataclassFromFielddom

from . import aiding, notifying, indirecting, credentialing, ipexing, delegating
from . import aiding, notifying, indirecting, credentialing, ipexing, delegating, oobier
from . import grouping as keriagrouping
from .serving import GracefulShutdownDoer
from .. import log_name, ogler, set_log_level
Expand Down Expand Up @@ -589,6 +586,7 @@ def __init__(self, hby, rgy, agentHab, agency, caid, **opts):
.exc (Exchanger): Handles peer-to-peer message routing and processing.
.submitter (Submitter): Submits the last event from a KEL to the witnesses to obtain receipts and propagate to all other witnesses.
.monitor (Monitor): Monitors the agent's state and performs long-running tasks like credential issuance and revocation.
.oobier (Oobier): Generates managed-identifier OOBIs and submits OOBI resolution operations.
.rvy (Revery): Reply event message processor for routing and processing 'rpy' messages.
.kvy (Kevery): Key Event Log (KEL) event processor for routing and processing KEL messages.
.tvy (Tevery): TEL event processor for routing and processing TEL messages.
Expand Down Expand Up @@ -741,6 +739,7 @@ def __init__(self, hby, rgy, agentHab, agency, caid, **opts):
submitter=self.submitter,
exchanger=self.exc,
)
self.oobier = oobier.Oobier(hby=self.hby, monitor=self.monitor)

self.rvy = routing.Revery(db=hby.db, cues=self.cues)
self.kvy = eventing.Kevery(
Expand Down Expand Up @@ -1591,8 +1590,6 @@ def loadEnds(app):

oobiColEnd = OOBICollectionEnd()
app.add_route("/oobis", oobiColEnd)
oobiResEnd = OobiResourceEnd()
app.add_route("/oobis/{alias}", oobiResEnd)

statesEnd = KeyStateCollectionEnd()
app.add_route("/states", statesEnd)
Expand Down Expand Up @@ -1940,9 +1937,6 @@ def on_get(req, rep):


class OOBICollectionEnd:
def __init__(self):
"""Create OOBI Collection endpoint instance"""

@staticmethod
def on_post(req, rep):
"""Resolve OOBI endpoint.
Expand Down Expand Up @@ -1987,147 +1981,18 @@ def on_post(req, rep):
agent = req.context.agent
body = req.get_media()

if "url" in body:
oobi = body["url"]
dt = helping.nowUTC()

obr = OobiRecord(date=helping.toIso8601(dt))
if "oobialias" in body:
obr.oobialias = body["oobialias"]

agent.hby.db.oobis.pin(keys=(oobi,), val=obr)

elif "rpy" in body:
raise falcon.HTTPNotImplemented(
description="'rpy' support not implemented yet"
)

else:
raise falcon.HTTPBadRequest(
description="invalid OOBI request body, either 'rpy' or 'url' is required"
)

oid = Salter().qb64
op = agent.monitor.submit(
oid, longrunning.OpTypes.oobi, metadata=dict(oobi=oobi)
)
try:
op = agent.oobier.resolve(body)
except NotImplementedError as ex:
raise falcon.HTTPNotImplemented(description=str(ex))
except kering.ValidationError as ex:
raise falcon.HTTPBadRequest(description=str(ex))

rep.status = falcon.HTTP_202
rep.content_type = "application/json"
rep.data = op.to_json().encode("utf-8")


class OobiResourceEnd:
@staticmethod
def on_get(req, rep, alias):
"""OOBI GET endpoint

Parameters:
req: falcon.Request HTTP request
rep: falcon.Response HTTP response
alias: option route parameter for specific identifier to get

---
summary: Get OOBI for specific identifier
description: Generate OOBI for the identifier of the specified alias and role
tags:
- OOBIs
parameters:
- in: path
name: alias
schema:
type: string
required: true
description: human readable alias for the identifier generate OOBI for
- in: query
name: role
schema:
type: string
required: true
description: role for which to generate OOBI
responses:
200:
description: An array of Identifier key state information
content:
application/json:
schema:
$ref: '#/components/schemas/OOBI'
"""
agent = req.context.agent
hab = agent.hby.habByName(alias)
if hab is None:
raise falcon.HTTPBadRequest(description="Invalid alias to generate OOBI")

role = req.params["role"]

res = dict(role=role)
if role in (kering.Roles.witness,): # Fetch URL OOBIs for all witnesses
oobis = []
for wit in hab.kever.wits:
urls = hab.fetchUrls(
eid=wit, scheme=kering.Schemes.http
) or hab.fetchUrls(eid=wit, scheme=kering.Schemes.https)
if not urls:
raise falcon.HTTPNotFound(
description=f"unable to query witness {wit}, no http endpoint"
)

url = (
urls[kering.Schemes.http]
if kering.Schemes.http in urls
else urls[kering.Schemes.https]
)
up = urlparse(url)
oobis.append(urljoin(up.geturl(), f"/oobi/{hab.pre}/witness/{wit}"))
res["oobis"] = oobis
elif role in (kering.Roles.controller,): # Fetch any controller URL OOBIs
oobis = []
urls = hab.fetchUrls(
eid=hab.pre, scheme=kering.Schemes.http
) or hab.fetchUrls(eid=hab.pre, scheme=kering.Schemes.https)
if not urls:
raise falcon.HTTPNotFound(
description=f"unable to query controller {hab.pre}, no http endpoint"
)

url = (
urls[kering.Schemes.http]
if kering.Schemes.http in urls
else urls[kering.Schemes.https]
)
up = urlparse(url)
oobis.append(urljoin(up.geturl(), f"/oobi/{hab.pre}/controller"))
res["oobis"] = oobis
elif role in (kering.Roles.agent,):
oobis = []
roleUrls = hab.fetchRoleUrls(
hab.pre, scheme=kering.Schemes.http, role=kering.Roles.agent
) or hab.fetchRoleurls(
hab.pre, scheme=kering.Schemes.https, role=kering.Roles.agent
)
if not roleUrls:
raise falcon.HTTPNotFound(
description=f"unable to query controller {hab.pre}, no http endpoint"
)

for eid, urls in roleUrls["agent"].items():
url = (
urls[kering.Schemes.http]
if kering.Schemes.http in urls
else urls[kering.Schemes.https]
)
up = urlparse(url)
oobis.append(urljoin(up.geturl(), f"/oobi/{hab.pre}/agent/{eid}"))
res["oobis"] = oobis
else:
rep.status = falcon.HTTP_404
return

rep.status = falcon.HTTP_200
rep.content_type = "application/json"
rep.data = json.dumps(res).encode("utf-8")


class QueryCollectionEnd:
@staticmethod
def on_post(req, rep):
Expand Down
137 changes: 15 additions & 122 deletions src/keria/app/aiding.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import json
from dataclasses import asdict, dataclass, field
from typing import Dict, Optional, List, Union
from urllib.parse import urlparse, urljoin
from keri import kering
from keri import core
from keri.app import habbing
Expand Down Expand Up @@ -1298,20 +1297,6 @@ def info(hab, rm, full=False):
return data


Role = namedtupleToEnum(kering.Roles, "Role")


@dataclass
class OOBI:
"""Data class for OOBI URLs"""

role: Role # type: ignore
oobis: List[str] = field(
default_factory=list,
metadata={"marshmallow_field": fields.List(fields.String(), required=True)},
)


class IdentifierOOBICollectionEnd:
"""
This class represents the OOBI subresource collection endpoint for identifiers
Expand Down Expand Up @@ -1344,6 +1329,13 @@ def on_get(req, rep, name):
type: string
required: true
description: The role for which to fetch the OOBI URLs. Can be a witness, controller, agent, or mailbox.
- in: query
name: includeEid
schema:
type: boolean
default: false
required: false
description: Include endpoint-qualified agent OOBIs for multisig identifiers.
responses:
200:
description: Successfully fetched the OOBI URLs. The response body contains the OOBI URLs.
Expand All @@ -1360,121 +1352,22 @@ def on_get(req, rep, name):
if not name:
raise falcon.HTTPBadRequest(description="name is required")

hab = (
agent.hby.habs[name]
if name in agent.hby.habs
else agent.hby.habByName(name)
)
if not hab:
raise falcon.HTTPNotFound(description="invalid alias or prefix {name}")

if "role" not in req.params:
raise falcon.HTTPBadRequest(description="role parameter required")

role = req.params["role"]
include_eid = req.params.get("includeEid", "").lower() in ("true", "1")

res = dict(role=role)
if role in (kering.Roles.witness,): # Fetch URL OOBIs for all witnesses
oobis = []
for wit in hab.kever.wits:
urls = hab.fetchUrls(
eid=wit, scheme=kering.Schemes.http
) or hab.fetchUrls(eid=wit, scheme=kering.Schemes.https)
if not urls:
raise falcon.HTTPNotFound(
description=f"unable to query witness {wit}, no http endpoint"
)

url = (
urls[kering.Schemes.http]
if kering.Schemes.http in urls
else urls[kering.Schemes.https]
)
up = urlparse(url)
oobis.append(urljoin(up.geturl(), f"/oobi/{hab.pre}/witness/{wit}"))
res["oobis"] = oobis
elif role in (kering.Roles.controller,): # Fetch any controller URL OOBIs
oobis = []
urls = hab.fetchUrls(
eid=hab.pre, scheme=kering.Schemes.http
) or hab.fetchUrls(eid=hab.pre, scheme=kering.Schemes.https)
if not urls:
raise falcon.HTTPNotFound(
description=f"unable to query controller {hab.pre}, no http endpoint"
)

url = (
urls[kering.Schemes.http]
if kering.Schemes.http in urls
else urls[kering.Schemes.https]
)
up = urlparse(url)
oobis.append(urljoin(up.geturl(), f"/oobi/{hab.pre}/controller"))
res["oobis"] = oobis
elif role in (kering.Roles.agent,): # Fetch URL OOBIs for all witnesses
roleUrls = hab.fetchRoleUrls(
cid=hab.pre, role=kering.Roles.agent, scheme=kering.Schemes.http
) or hab.fetchRoleUrls(
cid=hab.pre, role=kering.Roles.agent, scheme=kering.Schemes.https
)
if kering.Roles.agent not in roleUrls:
res["oobis"] = []
else:
aoobis = roleUrls[kering.Roles.agent]

oobis = list()
for agent in set(aoobis.keys()):
murls = aoobis.naball(agent)
for murl in murls:
urls = []
if kering.Schemes.http in murl:
urls.extend(murl.naball(kering.Schemes.http))
if kering.Schemes.https in murl:
urls.extend(murl.naball(kering.Schemes.https))
for url in urls:
up = urlparse(url)
oobis.append(
urljoin(up.geturl(), f"/oobi/{hab.pre}/agent/{agent}")
)

res["oobis"] = oobis
elif role in (kering.Roles.mailbox,): # Fetch URL OOBIs for all witnesses
roleUrls = hab.fetchRoleUrls(
cid=hab.pre, role=kering.Roles.mailbox, scheme=kering.Schemes.http
) or hab.fetchRoleUrls(
cid=hab.pre, role=kering.Roles.mailbox, scheme=kering.Schemes.https
)
if kering.Roles.mailbox not in roleUrls:
res["oobis"] = []
else:
aoobis = roleUrls[kering.Roles.mailbox]

oobis = list()
for mailbox in set(aoobis.keys()):
murls = aoobis.naball(mailbox)
for murl in murls:
urls = []
if kering.Schemes.http in murl:
urls.extend(murl.naball(kering.Schemes.http))
if kering.Schemes.https in murl:
urls.extend(murl.naball(kering.Schemes.https))
for url in urls:
up = urlparse(url)
oobis.append(
urljoin(
up.geturl(), f"/oobi/{hab.pre}/mailbox/{mailbox}"
)
)

res["oobis"] = oobis
else:
raise falcon.HTTPBadRequest(
description=f"unsupport role type {role} for oobi request"
)
try:
result = agent.oobier.get(name, role, include_eid=include_eid)
except kering.MissingEntryError as ex:
raise falcon.HTTPNotFound(description=str(ex))
except kering.ValidationError as ex:
raise falcon.HTTPBadRequest(description=str(ex))

rep.status = falcon.HTTP_200
rep.content_type = "application/json"
rep.data = json.dumps(res).encode("utf-8")
rep.data = json.dumps(asdict(result)).encode("utf-8")


@dataclass
Expand Down
Loading
Loading