transmute-industries / verifiable-credentials

v2
https://github.com/transmute-industries/verifiable-credentials
Apache License 2.0
9 stars 1 forks source link

Verifiable Credentials JSON Schema Validation - Custom Errors #9

Open tsnyder-gs1us opened 1 month ago

tsnyder-gs1us commented 1 month ago

Is it possible to use custom JSON Schema error messages? Here is an example JSON Schema with error messages.

const schema = {
  type: "object",
  required: ["foo", "bar"],
  properties: {
    foo: {type: "integer"},
    bar: {type: "string"},
  },
  errorMessage: {
    type: "should be an object", // will not replace internal "type" error for the property "foo"
    required: {
      foo: 'should have an integer property "foo"',
      bar: 'should have a string property "bar"',
    },
  },
}

Looks, like custom error messages only work when the ajv-errors: https://ajv.js.org/packages/ajv-errors.html is used.

Have you considered adding custom error message support to the VC library?

OR13 commented 1 month ago

You can see the default JSON Schema validation error messages here: https://github.com/transmute-industries/verifiable-credentials/pull/10

The default JSON Schema version is 2020 and the JSON Schema formats backage (that understands dates and uri's) is included by default.

OR13 commented 1 month ago

Example of a test asserting a schema validation error for an unexpected property:

const validation1 = await validator.validate({
    type: "application/vc+ld+json+jwt",
    content: issued,
  });
  expect(validation1.valid).toBe(false);
  expect(validation1.schema).toEqual({
    "https://vendor.example/api/schemas/product-passport": {
      "valid": false,
      "errors": [
        {
          "instancePath": "/credentialSubject",
          "schemaPath": "#/properties/credentialSubject/additionalProperties",
          "keyword": "additionalProperties",
          "params": {
            "additionalProperty": "unexpectedProperty"
          },
          "message": "must NOT have additional properties"
        }
      ]
    }
  })
OR13 commented 1 month ago

Keep in mind that the media types this library supports will likely change, based on this:

https://mailarchive.ietf.org/arch/msg/media-types/KbAgK9iEwLTILvubXD4fQRHMFho/

OR13 commented 1 month ago

PR #10 adds support for custom errors in AJV, for example:

 const validator = await transmute.validator({
    resolver: {
      resolve: async ({ id, type, content }) => {
        // Resolve external resources according to verifier policy
        // In this case, we return inline exampes...
        if (id === `${baseURL}/schemas/product-passport`) {
          return {
            type: `application/schema+json`,
            content: transmute.text.encoder.encode(`
{
  "$id": "${baseURL}/schemas/product-passport",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Example JSON Schema",
  "description": "This is a test schema",
  "type": "object",
  "properties": {
    "credentialSubject": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "degree": {
          "type": "object"
        }
      },
      "additionalProperties": false,
      "errorMessage": {
        "additionalProperties": "🔥 This is a custom error message for extra properties 🔥"
      }
    }
  }
}
            `),
          };
        }

        if (content != undefined && type === `application/vc+ld+json+jwt`) {
          const { kid } = jose.decodeProtectedHeader(
            transmute.text.decoder.decode(content)
          );
          // lookup public key on a resolver
          if (kid === `did:example:123#key-42`) {
            return {
              type: "application/jwk+json",
              content: publicKey,
            };
          }
        }
        throw new Error("Resolver option not supported.");
      },
    },
  });
  const validation1 = await validator.validate({
    type: "application/vc+ld+json+jwt",
    content: issued,
  });
  expect(validation1.valid).toBe(false);
  expect(validation1.schema).toEqual({
    "https://vendor.example/api/schemas/product-passport": {
      "valid": false,
      "errors": [
        {
          "instancePath": "/credentialSubject",
          "schemaPath": "#/properties/credentialSubject/errorMessage",
          "keyword": "errorMessage",
          "params": {
            "errors": [
              {
                "instancePath": "/credentialSubject",
                "schemaPath": "#/properties/credentialSubject/additionalProperties",
                "keyword": "additionalProperties",
                "params": {
                  "additionalProperty": "unexpectedProperty"
                },
                "message": "must NOT have additional properties",
                "emUsed": true
              },
            ]
          },
          "message": "🔥 This is a custom error message for extra properties 🔥"
        }
      ]
    }
  }
  )
OR13 commented 3 weeks ago

Support for this has been merged to main, but the interface has been adjusted in https://github.com/transmute-industries/verifiable-credentials/pull/13