Skip to content

Conversation

@bparth24
Copy link

@bparth24 bparth24 commented Nov 12, 2025

Implements the W3C VC Rendering Methods spec for NFC rendering with both static
and dynamic modes. Includes comprehensive tests and maintains backward
compatibility with the legacy NfcRenderingTemplate2024 format.

Disclaimer: I will remove the commented code in helper.js once approved and before merging.

Implements NFC rendering support for verifiable credentials following
the W3C VC Rendering Methods specification. Provides both static and
dynamic rendering modes:

- Static mode: Decodes pre-encoded payloads from template/payload fields
- Dynamic mode: Extracts credential data using JSON pointer paths
- Supports multibase (base58/base64url) and data URI encoding
- Compatible with W3C spec renderSuite types (nfc, nfc-static, nfc-dynamic)
- Maintains backward compatibility with legacy NfcRenderingTemplate2024

Public API includes supportsNFC() to check NFC capability and
renderToNfc() to generate NFC payload bytes from credentials.
Implements test suite covering NFC rendering functionality:

- Tests supportsNFC() with various renderSuite configurations
- Tests renderToNfc() static rendering with multibase, base64url, and data URIs
- Tests renderToNfc() dynamic rendering with renderProperty extraction
- Tests EAD credential handling with single/multiple field extraction
- Tests legacy NfcRenderingTemplate2024 type compatibility
- Tests error handling for invalid credentials and missing parameters
- Includes real-world credential tests fetched from external sources

Ensures compliance with W3C VC Rendering Methods specification.
Replaces legacy NFC rendering implementation in helper.js with calls
to the new standardized nfcRenderer library functions:

- Replace toNFCPayload() implementation with renderToNfc() call
- Replace hasNFCPayload() implementation with supportsNFC() call
- Remove unused base58 and base64url imports
- Comment out legacy helper functions: _getNFCRenderingTemplate2024()
  and _decodeMultibase()
- Comment out multibaseDecoders constant (now handled in nfcRenderer.js)

This change consolidates NFC rendering logic into a single reusable
library while maintaining backward compatibility with existing API.
The new implementation supports both W3C spec formats and legacy
NfcRenderingTemplate2024 type.
Implements field validation:
- TemplateRenderMethod: requires 'template' field only (W3C spec)
- NfcRenderingTemplate2024: requires 'payload' field only (legacy)
- Rejects credentials with both fields present

Updates _renderStatic() and _hasStaticPayload() functions with
explicit field checking and clear error messages.

Adds comprehensive validation tests and fixes existing tests to
use correct fields for their respective render method types.
@bparth24
Copy link
Author

@BigBlueHat cc: @dlongley

I have enforced some level of type compliance for template and payload field in this commit - 83386f1.

Replace separate static/dynamic rendering with unified pipeline where template is always required and renderProperty validates credential fields. Update implementation and tests to reflect single rendering flow: filter credential -> decode template -> return bytes.

Changes:
- Consolidate rendering functions into _decodeTemplateToBytes().
- Add _filterCredential() for renderProperty validation.
- Remove obsolete static vs dynamic distinction.
- Update all tests to match unified architecture.
- Fix test encodings and add comprehensive error coverage.
Comment on lines 73 to 76
throw new Error(
'NFC rendering requires a template field. ' +
'The template should contain the pre-encoded NFC payload.'
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message will get out-of-date if a template becomes something other than a "pre-encoded NFC payload" (and same linting issue as above with dropped lonely parenthesis):

Suggested change
throw new Error(
'NFC rendering requires a template field. ' +
'The template should contain the pre-encoded NFC payload.'
);
throw new Error('NFC render method is missing the "template" field.');

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though, on second thought, I think the _findNfcRenderMethod should probably only find valid NFC render methods. Maybe we'd want to console.warn() any invalid methods found, but that might be better than turning on UI elements that won't work anyway ... this is debatable / would love to hear more opinions. We can leave it how it is now (where "inoperable"/"invalid" NFC render methods are still "found") until we decide to change this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't set the user up for failure. They won't know why it's not working, but letting them know as early as possible that it doesn't work--and avoiding it showing up in places where we know it will not work--seems best for taking care of the user.

So, pre-filter or any other way of keeping a broken NFC credential out of the critical path.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dlongley @BigBlueHat

Addressed in this commit - 60702cf.

Comment on lines 350 to 357
// validate: should not have both fields
if(renderMethod.template && renderMethod.payload) {
throw new Error(
'TemplateRenderMethod requires "template". ' +
'It should not have both fields.'
);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the error text below might be confusing to a reader, i.e, "What two fields?". However, for TemplateRenderMethod, payload isn't specified at all (in the spec) and we don't expect it to be, so it would just be ignored. I had mentioned before this might be an error case, but I think that would have only been for the legacy NFC render (2024) method ... but I don't think it ever used template. In other words, I suspect we don't have to check for the case where both appear at all, it's an "ignore unknown fields" case for both the modern renderer and the legacy one.

Suggested change
// validate: should not have both fields
if(renderMethod.template && renderMethod.payload) {
throw new Error(
'TemplateRenderMethod requires "template". ' +
'It should not have both fields.'
);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be that we should only ever use payload and the current Render Method spec to move nfc out of the TemplateRenderMethod area. We don't currently template them, we don't have a plan for how we'd do that (yet), and we don't even have a use case for doing them...so, it would be preferred to not introduce so much power when it's not needed.

This would provide a much simpler code path here and reduce risk/confusion/debate around the Render Method specification and templating.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dlongley @BigBlueHat

Addressed in this commit - 60702cf.

Comment on lines 364 to 370
// validate: should not have both fields
if(renderMethod.template && renderMethod.payload) {
throw new Error(
'NfcRenderingTemplate2024 should not have both template ' +
'and payload fields.'
);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, unless there was ever legitimate use of "template" in an NfcRenderingTemplate2024 renderer, we should treat the presence of both properties as an "ignore unknown field" case. Only if we ever defined "template" and used it in the absence of "payload" should we throw here -- so if we don't have that case, we actually shouldn't throw this error.

Suggested change
// validate: should not have both fields
if(renderMethod.template && renderMethod.payload) {
throw new Error(
'NfcRenderingTemplate2024 should not have both template ' +
'and payload fields.'
);
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dlongley

Addressed in this commit - 60702cf.

Comment on lines +671 to +684
function _base64ToBytes({base64String} = {}) {
// use atob in browser, Buffer in Node
if(typeof atob !== 'undefined') {
const binaryString = atob(base64String);
const bytes = new Uint8Array(binaryString.length);
for(let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}

// Node.js environment
return Buffer.from(base64String, 'base64');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work -- static analyzers will see Buffer and inject a polyfill into the browser bundle. There are other patterns that solve this that we should use instead. The utilities have to be split and different aliased files loaded. For example:

https://github.com/digitalbazaar/http-digest-header/blob/v2.3.0/lib/util-browser.js
https://github.com/digitalbazaar/http-digest-header/blob/v2.3.0/lib/util.js

Also note the more modern API Uint8Array.toBase64.

Comment on lines +686 to +699
// ========================
// JSON pointer utilities
// ========================

/**
* Resolve a JSON pointer in an object per RFC 6901.
*
* @private
* @param {object} options - Options object.
* @param {object} options.obj - The object to traverse.
* @param {string} options.pointer - JSON pointer string.
* @returns {*} The value at the pointer location or undefined.
*/
function _resolveJSONPointer({obj, pointer} = {}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This we really need to get into a shared library (or reuse an existing shared library that doesn't bring in any of its own problems).

@bparth24 bparth24 self-assigned this Nov 26, 2025
Update _findNfcRenderMethod() to only return valid render methods with required template/payload fields. This prevents UI from showing NFC options that won't work.

Changes:
- Add template/payload validation in _findNfcRenderMethod().
- Remove 'both fields' validation (ignore unknown fields per spec).
- Simplify error message for missing template field.
- Use TypeError for type validation instead of Error.
- Group declaration and validation without whitespace.
- Rename supportsNFC to supportsNfc for camelCase consistency.
- Rename _findNFCRenderMethod to _findNfcRenderMethod for camelCase consistency.
- Update tests to expect 'does not support NFC' error.
- Convert 'both fields' error test to success test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants