@bedrock/vc-delivery 7.13.0 → 7.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,20 +31,22 @@ export class ExchangeProcessor {
31
31
  * @param {object} options.workflow - The workflow.
32
32
  * @param {object} options.exchangeRecord - The exchange record.
33
33
  * @param {Function} [options.prepareStep] - The `prepareStep` handler.
34
- * @param {Function} [options.inputRequired] - The `inputRequired` handler.
34
+ * @param {Function} [options.isStepComplete] - The `isStepComplete` handler.
35
35
  * @param {Function} [options.issue] - The `issue` handler.
36
+ * @param {Function} [options.inputRequired] - The `inputRequired` handler.
36
37
  * @param {Function} [options.verify] - The `verify` handler.
37
38
  *
38
39
  * @returns {ExchangeProcessor} An `ExchangeProcessor` instance.
39
40
  */
40
41
  constructor({
41
- workflow, exchangeRecord, prepareStep, inputRequired,
42
+ workflow, exchangeRecord, prepareStep, inputRequired, isStepComplete,
42
43
  issue, verify
43
44
  } = {}) {
44
45
  this.workflow = workflow;
45
46
  this.exchangeRecord = exchangeRecord;
46
47
  this.prepareStep = prepareStep?.bind(this);
47
48
  this.inputRequired = inputRequired?.bind(this);
49
+ this.isStepComplete = isStepComplete?.bind(this);
48
50
  this.issue = issue ?? defaultIssue.bind(this);
49
51
  this.verify = verify ?? defaultVerify.bind(this);
50
52
  }
@@ -229,7 +231,9 @@ export class ExchangeProcessor {
229
231
  async _tryProcess({
230
232
  receivedPresentation, receivedPresentationRequest, retryState
231
233
  } = {}) {
232
- const {workflow, exchangeRecord, prepareStep, inputRequired} = this;
234
+ const {
235
+ workflow, exchangeRecord, prepareStep, inputRequired, isStepComplete
236
+ } = this;
233
237
  const {exchange, meta} = exchangeRecord;
234
238
 
235
239
  // initialize exchange results
@@ -423,38 +427,52 @@ export class ExchangeProcessor {
423
427
  // FIXME: implement
424
428
  //if(response?.verifiablePresentation) {}
425
429
 
426
- // 4.12. If `step.redirectUrl` is set:
427
- if(step.redirectUrl) {
428
- // 4.12.1. If `response` is `null` then set it to an empty object.
429
- if(!response) {
430
- response = {};
430
+ // 4.12. Call subalgorithm `isStepComplete`, passing `workflow`,
431
+ // `exchange`, `step`, `receivedPresentation`, and
432
+ // `receivedPresentationRequest` to perform any protocol-specific
433
+ // behavior to determine if the step is complete. Set `stepComplete`
434
+ // to the result of `isStepComplete`, defaulting to `true`.
435
+ const stepComplete = await isStepComplete?.({
436
+ workflow, exchange, step,
437
+ receivedPresentation, receivedPresentationRequest
438
+ }) ?? true;
439
+
440
+ // 4.13. If `stepComplete` is `true`:
441
+ if(stepComplete) {
442
+ // 4.13.1. If `step.redirectUrl` is set:
443
+ if(step.redirectUrl) {
444
+ // 4.13.1.1. If `response` is `null` then set it to an empty object.
445
+ if(!response) {
446
+ response = {};
447
+ }
448
+ // 4.13.1.2. Set `response.redirectUrl` to `step.redirectUrl`.
449
+ response.redirectUrl = step.redirectUrl;
431
450
  }
432
- // 4.12.2. Set `response.redirectUrl` to `step.redirectUrl`.
433
- response.redirectUrl = step.redirectUrl;
434
- }
435
451
 
436
- // 4.13. If `step.nextStep` is not set then set `exchange.state` to
437
- // `complete`.
438
- if(!step.nextStep) {
439
- exchange.state = 'complete';
440
- } else {
441
- // 4.14. Otherwise, delete `exchange.variables.results[step.nextStep]`
442
- // if it exists, and set `exchange.step` to `step.nextStep`.
443
- delete exchange.variables.results[step.nextStep];
444
- exchange.step = step.nextStep;
452
+ // 4.13.2. If `step.nextStep` is not set then set `exchange.state` to
453
+ // `complete`.
454
+ if(!step.nextStep) {
455
+ exchange.state = 'complete';
456
+ } else {
457
+ // 4.13.3. Otherwise, delete
458
+ // `exchange.variables.results[step.nextStep]` if it exists, and
459
+ // set `exchange.step` to `step.nextStep`.
460
+ delete exchange.variables.results[step.nextStep];
461
+ exchange.step = step.nextStep;
462
+ }
445
463
  }
446
464
 
447
- // 4.15. Save the exchange (and call any non-blocking callback in
465
+ // 4.14. Save the exchange (and call any non-blocking callback in
448
466
  // the step).
449
467
  await _updateExchange({workflow, exchange, meta, step});
450
468
 
451
- // 4.16. If `exchange.state` is `complete`, return `response` if it is
469
+ // 4.15. If `exchange.state` is `complete`, return `response` if it is
452
470
  // not `null`, otherwise return an empty object.
453
471
  if(exchange.state === 'complete') {
454
472
  return response ?? {};
455
473
  }
456
474
 
457
- // 4.17. Set `receivedPresentation` to `null`.
475
+ // 4.16. Set `receivedPresentation` to `null`.
458
476
  receivedPresentation = null;
459
477
  }
460
478
  } catch(e) {
@@ -489,14 +507,6 @@ async function _getStep({workflow, exchange}) {
489
507
  workflow, exchange, stepName: currentStep
490
508
  });
491
509
 
492
- // if next step is the same as the current step, throw an error
493
- if(step.nextStep === currentStep) {
494
- throw new BedrockError('Cyclical step detected.', {
495
- name: 'DataError',
496
- details: {httpStatusCode: 500, public: true}
497
- });
498
- }
499
-
500
510
  // if `step.nextStep` and `step.redirectUrl` and are both set, throw an error
501
511
  if(step.nextStep && step.redirectUrl) {
502
512
  throw new BedrockError(
@@ -547,10 +557,11 @@ async function _createVerifiablePresentationRequest({
547
557
  }
548
558
  response.verifiablePresentationRequest.challenge = challenge;
549
559
 
550
- // 4. Set `exchange.variables.results[exchange.step]` to an object with the
551
- // property `responsePresentationRequest` set to
552
- // `response.verifiablePresentationRequest`.
560
+ // 4. Set `exchange.variables.results[exchange.step]` to an object, if it
561
+ // does not already exist, and set the property `responsePresentationRequest`
562
+ // to `response.verifiablePresentationRequest`.
553
563
  exchange.variables.results[exchange.step] = {
564
+ ...exchange.variables.results[exchange.step],
554
565
  responsePresentationRequest: response.verifiablePresentationRequest
555
566
  };
556
567
  }
@@ -430,6 +430,9 @@ async function _processExchange({
430
430
  const exchangeProcessor = new ExchangeProcessor({
431
431
  workflow, exchangeRecord,
432
432
  async prepareStep({exchange, step}) {
433
+ // FIXME: handle OID4VCI 1.0+ credential request
434
+
435
+ // FIXME: OID4VCI Draft 13:
433
436
  // validate body against expected credential requests
434
437
  const {openId: {expectedCredentialRequests}} = exchange;
435
438
  let credentialRequests;
@@ -437,7 +440,7 @@ async function _processExchange({
437
440
  ({credential_requests: credentialRequests} = req.body);
438
441
  } else {
439
442
  if(expectedCredentialRequests.length > 1) {
440
- // FIXME: batch endpoint has been removed in OID4VCI 1.0; if used,
443
+ // FIXME: batch endpoint has been removed in OID4VCI 1.0+; if used,
441
444
  // then it is for a legacy OID4VCI draft 13 request, so this should
442
445
  // be reworked
443
446
  throw new Error('batch_credential_endpoint must be used');
@@ -457,9 +460,15 @@ async function _processExchange({
457
460
 
458
461
  // check to see if step supports OID4VP during OID4VCI
459
462
  if(step.openId) {
460
- // if there is no `presentationSubmission`, request one
463
+ // FIXME: either OID4VCI 1.1+ w/IAE (interactive authz endpoint) or
464
+ // OID4VCI-1.0/draft13+OID4VP will have received VP results which will
465
+ // be stored with this step; OID4VCI 1.0- does not have IAE so if this
466
+ // call is made, presume such a client and return an error with the
467
+ // OID4VP request, OID4VCI 1.1+ clients will know to use IAE instead
468
+
469
+ // if there is no verified presentation yet, request one
461
470
  const {results} = exchange.variables;
462
- if(!results[exchange.step]?.openId?.presentationSubmission) {
471
+ if(!results[exchange.step]?.verifyPresentationResults?.verified) {
463
472
  // note: only the "default" `clientProfileId` is supported at this
464
473
  // time because there isn't presently a defined way to specify
465
474
  // alternatives
@@ -520,6 +529,16 @@ async function _processExchange({
520
529
  workflow, exchange, step, issueRequestsParams,
521
530
  verifiablePresentation, format
522
531
  });
532
+ },
533
+ isStepComplete({exchange}) {
534
+ // FIXME: check step's current `openId` results to see which issue
535
+ // requests have been processed; if any still exist, then the step is not
536
+ // yet complete
537
+ const {results} = exchange.variables;
538
+ if(!results[exchange.step]?.openId) {
539
+ // FIXME: implement
540
+ }
541
+ return true;
523
542
  }
524
543
  });
525
544
  const response = await exchangeProcessor.process();
@@ -175,7 +175,7 @@ export async function processAuthorizationResponse({req, clientProfileId}) {
175
175
  },
176
176
  inputRequired({step}) {
177
177
  // indicate input always required to avoid automatically advancing
178
- // to the next step, but clear `step.verifiablePresentationRequest`
178
+ // to issuance, but clear `step.verifiablePresentationRequest`
179
179
  // to avoid overwriting previous value
180
180
  delete step.verifiablePresentationRequest;
181
181
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/vc-delivery",
3
- "version": "7.13.0",
3
+ "version": "7.13.2",
4
4
  "type": "module",
5
5
  "description": "Bedrock Verifiable Credential Delivery",
6
6
  "main": "./lib/index.js",
@@ -715,6 +715,8 @@ export function useExchangeBody() {
715
715
  type: 'object',
716
716
  additionalProperties: false,
717
717
  properties: {
718
+ referenceId: {type: 'string'},
719
+ verifiablePresentationRequest: {type: 'object'},
718
720
  verifiablePresentation: {
719
721
  anyOf: [
720
722
  envelopedVerifiablePresentation,