@@ -20,27 +20,33 @@ def loadEnds(app):
20
20
app .add_route ("/identifiers/{name}/ipex/admit" , admitColEnd )
21
21
grantColEnd = IpexGrantCollectionEnd ()
22
22
app .add_route ("/identifiers/{name}/ipex/grant" , grantColEnd )
23
+ applyColEnd = IpexApplyCollectionEnd ()
24
+ app .add_route ("/identifiers/{name}/ipex/apply" , applyColEnd )
25
+ offerColEnd = IpexOfferCollectionEnd ()
26
+ app .add_route ("/identifiers/{name}/ipex/offer" , offerColEnd )
27
+ agreeColEnd = IpexAgreeCollectionEnd ()
28
+ app .add_route ("/identifiers/{name}/ipex/agree" , agreeColEnd )
23
29
24
30
25
31
class IpexAdmitCollectionEnd :
26
32
27
33
@staticmethod
28
34
def on_post (req , rep , name ):
29
- """ Registries GET endpoint
35
+ """ IPEX Admit POST endpoint
30
36
31
37
Parameters:
32
38
req: falcon.Request HTTP request
33
39
rep: falcon.Response HTTP response
34
40
name (str): human readable name for AID
35
41
36
42
---
37
- summary: List credential issuance and revocation registies
38
- description: List credential issuance and revocation registies
43
+ summary: Accept a credential being issued or presented in response to an IPEX grant
44
+ description: Accept a credential being issued or presented in response to an IPEX grant
39
45
tags:
40
46
- Registries
41
47
responses:
42
48
200:
43
- description: array of current credential issuance and revocation registies
49
+ description: long running operation of IPEX admit
44
50
45
51
"""
46
52
agent = req .context .agent
@@ -154,21 +160,21 @@ class IpexGrantCollectionEnd:
154
160
155
161
@staticmethod
156
162
def on_post (req , rep , name ):
157
- """ Registries GET endpoint
163
+ """ IPEX Grant POST endpoint
158
164
159
165
Parameters:
160
166
req: falcon.Request HTTP request
161
167
rep: falcon.Response HTTP response
162
168
name (str): human readable name for AID
163
169
164
170
---
165
- summary: List credential issuance and revocation registies
166
- description: List credential issuance and revocation registies
171
+ summary: Reply to IPEX agree message or initiate an IPEX exchange with a credential issuance or presentation
172
+ description: Reply to IPEX agree message or initiate an IPEX exchange with a credential issuance or presentation
167
173
tags:
168
- - Registries
174
+ - Credentials
169
175
responses:
170
176
200:
171
- description: array of current credential issuance and revocation registies
177
+ description: long running operation of IPEX grant
172
178
173
179
"""
174
180
agent = req .context .agent
@@ -266,3 +272,203 @@ def sendMultisigExn(agent, hab, ked, sigs, atc, rec):
266
272
agent .grants .append (dict (said = grant ['d' ], pre = hab .pre , rec = [holder ]))
267
273
268
274
return agent .monitor .submit (serder .pre , longrunning .OpTypes .exchange , metadata = dict (said = serder .said ))
275
+
276
+
277
+ class IpexApplyCollectionEnd :
278
+
279
+ @staticmethod
280
+ def on_post (req , rep , name ):
281
+ """ IPEX Apply POST endpoint
282
+
283
+ Parameters:
284
+ req: falcon.Request HTTP request
285
+ rep: falcon.Response HTTP response
286
+ name (str): human readable name for AID
287
+
288
+ ---
289
+ summary: Request a credential from another party by initiating an IPEX exchange
290
+ description: Request a credential from another party by initiating an IPEX exchange
291
+ tags:
292
+ - Credentials
293
+ responses:
294
+ 200:
295
+ description: long running operation of IPEX apply
296
+
297
+ """
298
+ agent = req .context .agent
299
+ # Get the hab
300
+ hab = agent .hby .habByName (name )
301
+ if hab is None :
302
+ raise falcon .HTTPNotFound (description = f"alias={ name } is not a valid reference to an identifier" )
303
+
304
+ body = req .get_media ()
305
+
306
+ ked = httping .getRequiredParam (body , "exn" )
307
+ sigs = httping .getRequiredParam (body , "sigs" )
308
+ rec = httping .getRequiredParam (body , "rec" )
309
+
310
+ route = ked ['r' ]
311
+
312
+ match route :
313
+ case "/ipex/apply" :
314
+ op = IpexApplyCollectionEnd .sendApply (agent , hab , ked , sigs , rec )
315
+ case _:
316
+ raise falcon .HTTPBadRequest (description = f"invalid message route { route } " )
317
+
318
+ rep .status = falcon .HTTP_200
319
+ rep .data = op .to_json ().encode ("utf-8" )
320
+
321
+ @staticmethod
322
+ def sendApply (agent , hab , ked , sigs , rec ):
323
+ for recp in rec : # Have to verify we already know all the recipients.
324
+ if recp not in agent .hby .kevers :
325
+ raise falcon .HTTPBadRequest (description = f"attempt to send to unknown AID={ recp } " )
326
+
327
+ # use that data to create th Serder and Sigers for the exn
328
+ serder = serdering .SerderKERI (sad = ked )
329
+ sigers = [coring .Siger (qb64 = sig ) for sig in sigs ]
330
+
331
+ # Now create the stream to send, need the signer seal
332
+ kever = hab .kever
333
+ seal = eventing .SealEvent (i = hab .pre , s = "{:x}" .format (kever .lastEst .s ), d = kever .lastEst .d )
334
+
335
+ # in this case, ims is a message is a sealed and signed message - signed by Signify (KERIA can't sign anything here...)
336
+ ims = eventing .messagize (serder = serder , sigers = sigers , seal = seal )
337
+
338
+ # make a copy and parse
339
+ agent .hby .psr .parseOne (ims = bytearray (ims ))
340
+
341
+ agent .exchanges .append (dict (said = serder .said , pre = hab .pre , rec = rec , topic = 'credential' ))
342
+ return agent .monitor .submit (serder .pre , longrunning .OpTypes .exchange , metadata = dict (said = serder .said ))
343
+
344
+ class IpexOfferCollectionEnd :
345
+
346
+ @staticmethod
347
+ def on_post (req , rep , name ):
348
+ """ IPEX Offer POST endpoint
349
+
350
+ Parameters:
351
+ req: falcon.Request HTTP request
352
+ rep: falcon.Response HTTP response
353
+ name (str): human readable name for AID
354
+
355
+ ---
356
+ summary: Reply to IPEX apply message or initiate an IPEX exchange with an offer for a credential with certain characteristics
357
+ description: Reply to IPEX apply message or initiate an IPEX exchange with an offer for a credential with certain characteristics
358
+ tags:
359
+ - Credentials
360
+ responses:
361
+ 200:
362
+ description: long running operation of IPEX offer
363
+
364
+ """
365
+ agent = req .context .agent
366
+ hab = agent .hby .habByName (name )
367
+ if hab is None :
368
+ raise falcon .HTTPNotFound (description = f"alias={ name } is not a valid reference to an identifier" )
369
+
370
+ body = req .get_media ()
371
+
372
+ ked = httping .getRequiredParam (body , "exn" )
373
+ sigs = httping .getRequiredParam (body , "sigs" )
374
+ atc = httping .getRequiredParam (body , "atc" )
375
+ rec = httping .getRequiredParam (body , "rec" )
376
+
377
+ route = ked ['r' ]
378
+
379
+ match route :
380
+ case "/ipex/offer" :
381
+ op = IpexOfferCollectionEnd .sendOffer (agent , hab , ked , sigs , atc , rec )
382
+ case _:
383
+ raise falcon .HTTPBadRequest (description = f"invalid route { route } " )
384
+
385
+ rep .status = falcon .HTTP_200
386
+ rep .data = op .to_json ().encode ("utf-8" )
387
+
388
+ @staticmethod
389
+ def sendOffer (agent , hab , ked , sigs , atc , rec ):
390
+ for recp in rec : # Have to verify we already know all the recipients.
391
+ if recp not in agent .hby .kevers :
392
+ raise falcon .HTTPBadRequest (description = f"attempt to send to unknown AID={ recp } " )
393
+
394
+ # use that data to create th Serder and Sigers for the exn
395
+ serder = serdering .SerderKERI (sad = ked )
396
+ sigers = [coring .Siger (qb64 = sig ) for sig in sigs ]
397
+
398
+ # Now create the stream to send, need the signer seal
399
+ kever = hab .kever
400
+ seal = eventing .SealEvent (i = hab .pre , s = "{:x}" .format (kever .lastEst .s ), d = kever .lastEst .d )
401
+
402
+ ims = eventing .messagize (serder = serder , sigers = sigers , seal = seal )
403
+ ims = ims + atc .encode ("utf-8" )
404
+
405
+ # make a copy and parse
406
+ agent .hby .psr .parseOne (ims = bytearray (ims ))
407
+
408
+ agent .exchanges .append (dict (said = serder .said , pre = hab .pre , rec = rec , topic = 'credential' ))
409
+ return agent .monitor .submit (serder .pre , longrunning .OpTypes .exchange , metadata = dict (said = serder .said ))
410
+
411
+ class IpexAgreeCollectionEnd :
412
+
413
+ @staticmethod
414
+ def on_post (req , rep , name ):
415
+ """ IPEX Agree POST endpoint
416
+
417
+ Parameters:
418
+ req: falcon.Request HTTP request
419
+ rep: falcon.Response HTTP response
420
+ name (str): human readable name for AID
421
+
422
+ ---
423
+ summary: Reply to IPEX offer message acknowledged willingness to accept offered credential
424
+ description: Reply to IPEX offer message acknowledged willingness to accept offered credential
425
+ tags:
426
+ - Credentials
427
+ responses:
428
+ 200:
429
+ description: long running operation of IPEX agree
430
+
431
+ """
432
+ agent = req .context .agent
433
+ hab = agent .hby .habByName (name )
434
+ if hab is None :
435
+ raise falcon .HTTPNotFound (description = f"alias={ name } is not a valid reference to an identifier" )
436
+
437
+ body = req .get_media ()
438
+
439
+ ked = httping .getRequiredParam (body , "exn" )
440
+ sigs = httping .getRequiredParam (body , "sigs" )
441
+ rec = httping .getRequiredParam (body , "rec" )
442
+
443
+ route = ked ['r' ]
444
+
445
+ match route :
446
+ case "/ipex/agree" :
447
+ op = IpexAgreeCollectionEnd .sendAgree (agent , hab , ked , sigs , rec )
448
+ case _:
449
+ raise falcon .HTTPBadRequest (description = f"invalid route { route } " )
450
+
451
+ rep .status = falcon .HTTP_200
452
+ rep .data = op .to_json ().encode ("utf-8" )
453
+
454
+ @staticmethod
455
+ def sendAgree (agent , hab , ked , sigs , rec ):
456
+ for recp in rec : # Have to verify we already know all the recipients.
457
+ if recp not in agent .hby .kevers :
458
+ raise falcon .HTTPBadRequest (description = f"attempt to send to unknown AID={ recp } " )
459
+
460
+ # use that data to create th Serder and Sigers for the exn
461
+ serder = serdering .SerderKERI (sad = ked )
462
+ sigers = [coring .Siger (qb64 = sig ) for sig in sigs ]
463
+
464
+ # Now create the stream to send, need the signer seal
465
+ kever = hab .kever
466
+ seal = eventing .SealEvent (i = hab .pre , s = "{:x}" .format (kever .lastEst .s ), d = kever .lastEst .d )
467
+
468
+ ims = eventing .messagize (serder = serder , sigers = sigers , seal = seal )
469
+
470
+ # make a copy and parse
471
+ agent .hby .psr .parseOne (ims = bytearray (ims ))
472
+
473
+ agent .exchanges .append (dict (said = serder .said , pre = hab .pre , rec = rec , topic = 'credential' ))
474
+ return agent .monitor .submit (serder .pre , longrunning .OpTypes .exchange , metadata = dict (said = serder .said ))
0 commit comments