digitalbazaar / jsonld.js

A JSON-LD Processor and API implementation in JavaScript
https://json-ld.org/
Other
1.65k stars 195 forks source link

credentialSubject properties are not normalized #477

Closed lemoustachiste closed 2 years ago

lemoustachiste commented 2 years ago

Hi,

I have noticed that the properties that I define as part of the credentialSubject parent property are not getting normalized and taken into account.

"credentialSubject": {
    "name": "Sandy Beach",
    "email": "sandy@beach.com",
    "publicKey": "1EDGxptycdQC8kNsDHUAvPRQ6aQUThxUU",
    "id": "recipients-id",
    "claim": {
      "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABRwAAAFdCAYAAABhKaGrAAAACXBIWXMAAC4j",
      "description": "This is a description",
      "criteria": "this was a given",
      "url": "https://www.beach.com"
    }
  }

In that case, I've managed to get everything under claim to be referenced, but jsonld ignores name, email, publicKey and id.

Here is the jsonld normalization output:

<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/blockcerts#BlockcertsCredential> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://w3id.org/blockcerts#display> _:c14n1 .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://w3id.org/blockcerts#metadata> "{\"key\":\"value\"}" .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://w3id.org/security#nonce> "F8fyDvUh5Vc2Y1XaezwE-8Rdl9m625kgjuQrL4iLy" .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#expirationDate> "2022-09-18T10:47:24Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#issuanceDate> "2022-03-18T10:47:25Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#issuer> <did:ion:EiA_Z6LQILbB2zj_eVrqfQ2xDm4HNqeJUw5Kj2Z7bFOOeQ> .
_:c14n0 <https://schema.org/criteria> "this was a given" _:c14n2 .
_:c14n0 <https://schema.org/description> "This is a description" _:c14n2 .
_:c14n0 <https://schema.org/image> "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABRwAAAFdCAYAAABhKaGrAAAACXBIWXMAAC4j" _:c14n2 .
_:c14n0 <https://schema.org/url> "https://www.beach.com" _:c14n2 .
_:c14n1 <https://w3id.org/blockcerts#content> "<div>Hello world!</div>" .
_:c14n1 <https://w3id.org/blockcerts#contentMediaType> "text/html" .

I also notice that claim in itself seems to be a "ghost" property, where c14n0 looks like to be its reference but is not present in the output otherwise.

I am using VC context to define credentialSubject, and I am reluctant to overwrite the property with a more rigid structure as I may or may not be using the properties as subproperties of credentialSubject. It could also be that for instance image is used in 2 different places but I just want one generic definition of it. If that's a correct approach.

I am not sure how to configure so that the subproperties of credentialSubject are taken into account by jsonld, without strictly defining them as subproperties?

dmitrizagidulin commented 2 years ago

Hi @lemoustachiste -- if the fields are being ignored, the first thing I'd check is -- are they included in the list of contexts? As in, are any of the contexts in that document you're normalizing, do they include name, email, etc?

lemoustachiste commented 2 years ago

Hi @dmitrizagidulin, thanks for taking a look.

I forgot to mention that yes, they are defined in blockcerts v3 context that is added to the document, here is what I currently have defined:

"name": { "@id": "schema:name" },
"description": { "@id": "schema:description" },
"email": { "@id": "schema:email" },
"publicKey": { "@id": "sec:publicKey" },
"url": { "@id": "schema:url" },
"image": { "@id": "schema:image" },
"criteria": { "@id": "schema:criteria" },
"claim": { "@id": "schema:claim" }

These are all defined as "first level" properties, as in they are not nested in any other property.

davidlehn commented 2 years ago

A partial input example is difficult to debug. It would help to provide a full minimal example of input that causes trouble. When the problem isn't obvious, I first throw it in the playground and see what happens.

lemoustachiste commented 2 years ago

@davidlehn here is the document, I have replaced blockcerts v3 context url with the object as I've made a few updates that are not reflected yet online.

{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    {
  "@context": {
    "id": "@id",
    "type": "@type",
    "bc": "https://w3id.org/blockcerts#",
    "cp": "https://w3id.org/chainpoint#",
    "vc": "https://www.w3.org/2018/credentials/v1",
    "schema": "https://schema.org/",
    "sec": "https://w3id.org/security#",
    "xsd": "http://www.w3.org/2001/XMLSchema#",

    "MerkleProof2019": "sec:MerkleProof2019",

    "BlockcertsCredential": "bc:BlockcertsCredential",
    "introductionUrl": { "@id": "bc:introductionUrl", "@type": "@id" },
    "metadata": "bc:metadata",
    "display": {
      "@id": "bc:display",
      "@context": {
        "id": "@id",
        "type": "@type",
        "contentMediaType": {"@id": "bc:contentMediaType"},
        "contentEncoding": {"@id": "bc:contentEncoding"},
        "content": {"@id": "bc:content"}
      }
    },

    "CryptographicKey": "sec:Key",

    "domain": "sec:domain",
    "nonce": "sec:nonce",
    "proofValue": "sec:proofValue",
    "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"},
    "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"},
    "proofPurpose": {"@id": "sec:proofPurpose", "@type": "@vocab"},
    "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"},
    "created": {"@id": "https://purl.org/dc/terms/created", "@type": "xsd:dateTime"},
    "challenge": "sec:challenge",
    "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"},

    "name": { "@id": "schema:name" },
    "description": { "@id": "schema:description" },
    "email": { "@id": "schema:email" },
    "publicKey": { "@id": "sec:publicKey" },
    "url": { "@id": "schema:url" },
    "image": { "@id": "schema:image" },
    "criteria": { "@id": "schema:criteria" },
    "claim": { "@id": "schema:claim" }
  }
}

  ],
  "id": "urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb",
  "type": [
    "VerifiableCredential",
    "BlockcertsCredential"
  ],
  "issuer": "did:ion:EiA_Z6LQILbB2zj_eVrqfQ2xDm4HNqeJUw5Kj2Z7bFOOeQ",
  "issuanceDate": "2022-03-18T10:47:25Z",
  "expirationDate": "2022-09-18T10:47:24Z",
  "credentialSubject": {
    "name": "Sandy Beach",
    "email": "sandy@beach.com",
    "publicKey": "1EDGxptycdQC8kNsDHUAvPRQ6aQUThxUU",
    "id": "recipients-id",
    "claim": {
      "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABRwAAAFdCAYAAABhKaGrAAAACXBIWXMAAC4j",
      "description": "This is a description",
      "criteria": "this was a given",
      "url": "https://www.beach.com"
    }
  },
  "nonce": "F8fyDvUh5Vc2Y1XaezwE-8Rdl9m625kgjuQrL4iLy",
  "metadata": "{\"key\":\"value\"}",
  "display": {
    "contentMediaType": "text/html",
    "content": "<div>Hello world!</div>"
  }
}

I did take a look at the playground as per your suggestion, but I couldn't pinpoint anything too strange. I have noticed however that the normalized document is not the same there as it is for me. Maybe the only thing that I find potentially not as I expect it to be is around the id property for the credential subject, ie:

<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#credentialSubject> <https://json-ld.org/playground/recipients-id>

Thus referencing the missing properties:

<https://json-ld.org/playground/recipients-id> <https://schema.org/claim> _:c14n1 .
<https://json-ld.org/playground/recipients-id> <https://schema.org/email> "sandy@beach.com" .
<https://json-ld.org/playground/recipients-id> <https://schema.org/name> "Sandy Beach" .
<https://json-ld.org/playground/recipients-id> <https://w3id.org/security#publicKey> "1EDGxptycdQC8kNsDHUAvPRQ6aQUThxUU" .

Which I don't see in my local output. I am on version 5.2.0. To be noted that I have the same issue with pyld 2.0.3

davidlehn commented 2 years ago

On the playground the base of the document is set to the playground URL itself. When you use "id": "recepient-id" it's going to consider that a relative reference. (The spec [1] has definitions, and I'm just now informed that the spec has a note [2] that "relative reference" is now preferred to avoid confusion that "relative URI" is a URI rather than just a reference to a URI.) So due to the relative reference and the base playground URL, you see the above output.

VC signing code uses an empty base so will result in ids staying relative references rather that URIs and then they get dropped. Further, the VC spec requires a URI for identifiers [3]. I assume your real data will use something other than the literal recepient-id. If you want to see what the result will be, just change that to any URI like test:recepient-id.

Were there differences or problems other that the id issue?

I'll also note that right now I'm working on improving the situation for issues like this. For tooling using jsonld.js there will be an option to reject lossy situations such as dropping data that has relative references. It's coming soon to Digital Bazaar libraries and the playground but for now need to do manual checking.

[1] https://www.rfc-editor.org/rfc/rfc3986#section-4 [2] https://www.rfc-editor.org/rfc/rfc3986#section-1.2.3 [3] https://www.w3.org/TR/vc-data-model/#identifiers

lemoustachiste commented 2 years ago

So I've set a @base property which is correctly picked up by the playground:

"@context": [
    {
      "@base": "https://w3id.org/blockcerts/v3"
    },
    "https://www.w3.org/2018/credentials/v1",
    "https://w3id.org/blockcerts/v3"
  ],

Playground output:

<https://w3id.org/blockcerts/recipients-id> <https://schema.org/claim> _:c14n1 .
<https://w3id.org/blockcerts/recipients-id> <https://schema.org/email> "sandy@beach.com" .
<https://w3id.org/blockcerts/recipients-id> <https://schema.org/name> "Sandy Beach" .
<https://w3id.org/blockcerts/recipients-id> <https://w3id.org/security#publicKey> <https://w3id.org/blockcerts/1EDGxptycdQC8kNsDHUAvPRQ6aQUThxUU> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/blockcerts#BlockcertsCredential> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://w3id.org/blockcerts#display> _:c14n0 .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://w3id.org/blockcerts#metadata> "{\"key\":\"value\"}" .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://w3id.org/security#nonce> "F8fyDvUh5Vc2Y1XaezwE-8Rdl9m625kgjuQrL4iLy" .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#credentialSubject> <https://w3id.org/blockcerts/recipients-id> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#expirationDate> "2022-09-18T10:47:24Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#issuanceDate> "2022-03-18T10:47:25Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<urn:uuid:f30f3951-b6dc-4aef-86d8-390901df18eb> <https://www.w3.org/2018/credentials#issuer> <did:ion:EiA_Z6LQILbB2zj_eVrqfQ2xDm4HNqeJUw5Kj2Z7bFOOeQ> .
_:c14n0 <https://w3id.org/blockcerts#content> "<div>Hello world!</div>" .
_:c14n0 <https://w3id.org/blockcerts#contentMediaType> "text/html" .
_:c14n1 <https://schema.org/description> "This is a description" .
_:c14n1 <https://schema.org/image> <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABRwAAAFdCAYAAABhKaGrAAAACXBIWXMAAC4j> .
_:c14n1 <https://schema.org/url> <https://www.beach.com> .

But is still being ignored by the local libraries (JS or PY).

Prefixing with test: however did fix the issue. I'd like to understand why the @base one does not work? I'm not too certain of the shape of the credentialSubject's id, but I'd like to understand what I need to make as recommendation for it (if using base or adding colons to the value - we will likely support DIDs at one time but I expect initially it will be a system's id).

lemoustachiste commented 2 years ago

in terms of facing an issue this is fixed, but if you have time to explain to me why @base is not being picked up I'd be happy to learn.