Skip to content

Commit

Permalink
Merge pull request #6 from transmute-industries/spec-tests
Browse files Browse the repository at this point in the history
w3c spec validation for issuer and presentation
  • Loading branch information
OR13 authored Feb 8, 2024
2 parents 39baf6f + 8198cab commit edada79
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 16 deletions.
62 changes: 61 additions & 1 deletion src/cr1/validator/w3c.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,64 @@ const identifiers = (result: ValidationResult, pointer: string, value: any) => {
}
}

// https://www.w3.org/TR/vc-data-model-2.0/#issuer
const issuer = (result: ValidationResult, pointer: string, value: any) => {
if (pointer.endsWith('/issuer') || pointer.endsWith('/issuer/id')) {
const issuerAllowed = stringIsAValidUrl(value, allowedProtocols)
if (!issuerAllowed) {
result.warnings.push({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `Issuer MUST be a valid URL or an object containing an id property that is a valid URL`,
pointer,
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#issuer'
})
}
}
}

// https://www.w3.org/TR/vc-data-model-2.0/#presentations-0
const holder = (result: ValidationResult, pointer: string, value: any) => {
if (pointer.endsWith('/holder') || pointer.endsWith('/holder/id')) {
const issuerAllowed = stringIsAValidUrl(value, allowedProtocols)
if (!issuerAllowed) {
result.warnings.push({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `Holder MUST be a valid URL or an object containing an id property that is a valid URL`,
pointer,
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#presentations-0'
})
}
}
}

// https://www.w3.org/TR/vc-data-model-2.0/#presentations-0
const verifiableCredential = (result: ValidationResult, pointer: string, value: any) => {
const nonObjectPointer = pointer?.split('/verifiableCredential/').pop() as string
if (pointer.startsWith('/verifiableCredential/') && nonObjectPointer.length === 1 && !Number.isNaN(parseInt(nonObjectPointer))) {
if (typeof value !== 'object') {
result.warnings.push({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `verifiableCredential MUST NOT be non-object values such as numbers, strings, or URLs`,
pointer,
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#presentations-0'
})
}
}
const pointerIndex = pointer?.split('/verifiableCredential/').pop()?.split("/")[0]
if (pointer.endsWith(`/verifiableCredential/${pointerIndex}/id`)) {
if (!value.includes('data:')) {
result.warnings.push({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `verifiableCredential id value of the object MUST be a data: URL`,
pointer,
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#enveloped-verifiable-credentials'
})
}
}
}



// https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#types
const types = (result: ValidationResult, pointer: string, value: any) => {
// I'm not writing a test for:
Expand Down Expand Up @@ -98,7 +156,9 @@ export const conformance = (result: ValidationResult) => {
identifiers(result, pointer, value)
types(result, pointer, value)
names_and_descriptions(result, pointer, value)

issuer(result, pointer, value)
holder(result, pointer, value)
verifiableCredential(result, pointer, value);
}

return result
Expand Down
266 changes: 251 additions & 15 deletions test/w3c-cr-1/5-data-model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,36 @@ it("should warn about interoperability issues with decentralized identifiers", a
const validation = await review(fixtures.minimal_credential_with_dids);
expect(validation.warnings).toEqual([
{
message: "Identifier will not be well understood: did:example:123",
pointer: "/issuer",
reference:
"https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers",
message: 'Identifier will not be well understood: did:example:123',
pointer: '/issuer',
reference: 'https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers'
},
{
message: "Identifier will not be well understood: did:example2:456",
pointer: "/credentialSubject/id",
reference:
"https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers",
message: 'Issuer MUST be a valid URL or an object containing an id property that is a valid URL',
pointer: '/issuer',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#issuer'
},
{
message: 'Identifier will not be well understood: did:example2:456',
pointer: '/credentialSubject/id',
reference: 'https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers'
}
]);
});

it("should warn when identifier URLs are bad", async () => {
const validation = await review(fixtures.minimal_credential_with_bad_urls);
expect(validation.warnings).toEqual([
{
message:
"Identifier will not be well understood: httttttttps://university.example/issuers/565049",
pointer: "/issuer",
reference:
"https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers",
message: 'Identifier will not be well understood: httttttttps://university.example/issuers/565049',
pointer: '/issuer',
reference: 'https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers'
},
{
message: 'Issuer MUST be a valid URL or an object containing an id property that is a valid URL',
pointer: '/issuer',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#issuer'
}
]);
});

Expand Down Expand Up @@ -174,13 +180,243 @@ credentialSubject:
});

// https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#issuer
// MUST BE: URL, or Object with ID that is URL
describe("Issuer", () => {
it.todo("complete me")
it("can be object with id as url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiableCredential
issuer:
id: https://university.example/issuers/565049
credentialSubject:
- id: https://university.example/issuers/1
- id: https://university.example/issuers/2
`)
);
expect(validation.warnings).toEqual([]);
})

it("can be url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiableCredential
issuer: https://university.example/issuers/565049
credentialSubject:
- id: https://university.example/issuers/1
- id: https://university.example/issuers/2
`)
);
expect(validation.warnings).toEqual([]);
})

it("gives warning if issuer not valid url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiableCredential
issuer: test
credentialSubject:
- id: https://university.example/issuers/1
- id: https://university.example/issuers/2
`)
);
expect(validation.warnings[1]).toStrictEqual({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `Issuer MUST be a valid URL or an object containing an id property that is a valid URL`,
pointer: '/issuer',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#issuer'
});
})

it("gives warning if issuer.id not valid url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiableCredential
issuer:
id: test
credentialSubject:
- id: https://university.example/issuers/1
- id: https://university.example/issuers/2
`)
);
expect(validation.warnings[1]).toStrictEqual({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `Issuer MUST be a valid URL or an object containing an id property that is a valid URL`,
pointer: '/issuer/id',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#issuer'
});
})
});

// https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#presentations-0
describe("Presentations", () => {
it.todo("complete me")
describe("verifiableCredential", () => {
it("can be an array of enveloped credentials and credentials", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder:
id: https://university.example/issuers/565049
verifiableCredential:
- "@context": https://www.w3.org/ns/credentials/v2
id: data:application/vc+ld+json+sd-jwt;QzVjV...RMjU
type: EnvelopedVerifiableCredential
- "@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiableCredential
issuer:
id: https://university.example/issuers/565049
credentialSubject:
- id: https://university.example/issuers/1
- id: https://university.example/issuers/2
`)
);
expect(validation.warnings).toEqual([{
message: 'Identifier will not be well understood: data:application/vc+ld+json+sd-jwt;QzVjV...RMjU',
pointer: '/verifiableCredential/0/id',
reference: 'https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers'
}]);
})

it("warns when non-object value is used", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder:
id: https://university.example/issuers/565049
verifiableCredential:
- badValue
`)
);

expect(validation.warnings).toEqual([{
message: 'verifiableCredential MUST NOT be non-object values such as numbers, strings, or URLs',
pointer: '/verifiableCredential/0',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#presentations-0'
}]);
})

it("warns when enveloped credential id is not valid", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder:
id: https://university.example/issuers/565049
verifiableCredential:
- "@context": https://www.w3.org/ns/credentials/v2
id: QzVjV...RMjU
type: EnvelopedVerifiableCredential
- "@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiableCredential
issuer:
id: https://university.example/issuers/565049
credentialSubject:
- id: https://university.example/issuers/1
- id: https://university.example/issuers/2
`)
);

expect(validation.warnings).toEqual([{
message: 'Identifier will not be well understood: QzVjV...RMjU',
pointer: '/verifiableCredential/0/id',
reference: 'https://www.w3.org/TR/2024/CRD-vc-data-model-2.0-20240205/#identifiers'
},
{
message: 'verifiableCredential id value of the object MUST be a data: URL',
pointer: '/verifiableCredential/0/id',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#enveloped-verifiable-credentials'
}]);
})
});
describe("holder", () => {
it("can be object with id as url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder:
id: https://university.example/issuers/565049
`)
);
expect(validation.warnings).toEqual([]);
})

it("can be url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder: https://university.example/issuers/565049
`)
);
expect(validation.warnings).toEqual([]);
})

it("gives warning if issuer not valid url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder: test
`)
);
expect(validation.warnings[0]).toStrictEqual({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `Holder MUST be a valid URL or an object containing an id property that is a valid URL`,
pointer: '/holder',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#presentations-0'
});
})

it("gives warning if issuer.id not valid url", async () => {
const validation = await review(
text(`
"@context":
- https://www.w3.org/ns/credentials/v2
type:
- VerifiablePresentation
holder:
id: test
`)
);
expect(validation.warnings[1]).toStrictEqual({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message: `Holder MUST be a valid URL or an object containing an id property that is a valid URL`,
pointer: '/holder/id',
reference: 'https://www.w3.org/TR/vc-data-model-2.0/#presentations-0'
});
})
});

});

// it.todo('data model tests')
Expand Down

0 comments on commit edada79

Please sign in to comment.