Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: current CType meta schema ignores additional properties in claim contents #726

Merged
merged 14 commits into from
Feb 21, 2023
Merged
34 changes: 24 additions & 10 deletions packages/core/src/credential/Credential.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ import * as Claim from '../claim'
import * as CType from '../ctype'
import * as Credential from './Credential'

const testCType = CType.fromProperties('raw ctype', {
name: { type: 'string' },
const testCType = CType.fromProperties('Credential', {
a: { type: 'string' },
b: { type: 'string' },
c: { type: 'string' },
})

function buildCredential(
Expand Down Expand Up @@ -292,9 +294,19 @@ describe('Credential', () => {
Credential.verifyAgainstCType(builtCredential, testCType)
).toThrow()
})

it('two Credentials on an empty ctype will have different root hashes', async () => {
const ctype = CType.fromProperties('CType', {})
const claimA1 = Claim.fromCTypeAndClaimContents(ctype, {}, identityAlice)
const claimA2 = Claim.fromCTypeAndClaimContents(ctype, {}, identityAlice)

expect(Credential.fromClaim(claimA1).rootHash).not.toEqual(
Credential.fromClaim(claimA2).rootHash
)
})
})

describe('Credential', () => {
describe('Presentations', () => {
let keyAlice: KeyTool
let keyCharlie: KeyTool
let identityAlice: DidDocument
Expand Down Expand Up @@ -327,12 +339,11 @@ describe('Credential', () => {
sign: SignCallback
): Promise<[ICredentialPresentation, IAttestation]> {
// create claim

const ctype = CType.fromProperties('Credential', {
name: { type: 'string' },
})

const claim = Claim.fromCTypeAndClaimContents(ctype, contents, claimer.uri)
const claim = Claim.fromCTypeAndClaimContents(
testCType,
contents,
claimer.uri
)
// build credential with legitimations
const credential = Credential.fromClaim(claim, {
legitimations,
Expand Down Expand Up @@ -576,7 +587,10 @@ describe('create presentation', () => {
let attester: DidDocument
let credential: ICredential

const ctype = CType.fromProperties(testCType.title, testCType.properties)
const ctype = CType.fromProperties('otherCType', {
name: { type: 'string' },
age: { type: 'number' },
})

// Returns a full DID that has the same subject of the first light DID, but the same key authentication key as the second one, if provided, or as the first one otherwise.
function createMinimalFullDidFromLightDid(
Expand Down
105 changes: 102 additions & 3 deletions packages/core/src/ctype/CType.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,72 @@

import { JsonSchema } from '@kiltprotocol/utils'

export const CTypeModel: JsonSchema.Schema = {
export const CTypeModelV1: JsonSchema.Schema & { $id: string } = {
// $id is not contained in schema when fetched from ipfs bc that is impossible with a content-addressed system
$id: 'ipfs://bafybeifzfxz6tfd2xo7ijxbfceaxo3l655yg7sovlsnpxgq2rwfl4kbfgm',
$schema: 'http://json-schema.org/draft-07/schema#',
title: 'CType Metaschema (V1)',
description:
'Describes a CType, which is a JSON schema for validating KILT claim types.',
type: 'object',
properties: {
ntn-x2 marked this conversation as resolved.
Show resolved Hide resolved
$id: { pattern: '^kilt:ctype:0x[0-9a-f]+$', type: 'string' },
$schema: {
type: 'string',
// can't use a const referencing schema id for a content-addressed schema
},
title: { type: 'string' },
type: { const: 'object', type: 'string' },
properties: {
patternProperties: {
'^.+$': {
oneOf: [
{
additionalProperties: false,
properties: {
$ref: {
pattern: '^kilt:ctype:0x[0-9a-f]+(#/properties/.+)?$',
format: 'uri',
type: 'string',
},
},
required: ['$ref'],
},
{
additionalProperties: false,
properties: {
format: { enum: ['date', 'time', 'uri'], type: 'string' },
type: {
ntn-x2 marked this conversation as resolved.
Show resolved Hide resolved
enum: ['boolean', 'integer', 'number', 'string'],
type: 'string',
},
},
required: ['type'],
},
],
type: 'object',
},
},
type: 'object',
},
additionalProperties: { const: false, type: 'boolean' },
},
additionalProperties: false,
required: [
'$id',
'$schema',
'additionalProperties',
'properties',
'title',
'type',
],
}

export const CTypeModelDraft01: JsonSchema.Schema & { $id: string } = {
$id: 'http://kilt-protocol.org/draft-01/ctype#',
$schema: 'http://json-schema.org/draft-07/schema#',
title: 'CType Metaschema (draft-01)',
description: `Describes a CType, which is a JSON schema for validating KILT claim types. This version has known issues, the use of schema ${CTypeModelV1.$id} is recommended instead.`,
type: 'object',
properties: {
$id: {
Expand Down Expand Up @@ -65,7 +128,44 @@ export const CTypeModel: JsonSchema.Schema = {
required: ['$id', 'title', '$schema', 'properties', 'type'],
}

export const MetadataModel = {
/**
* Schema describing any currently known CType; this means it either conforms to V1 or draft-01 of the CType schema.
* Using this schema allows CType validation to be agnostic to which version is used.
*/
export const CTypeModel: JsonSchema.Schema = {
$schema: 'http://json-schema.org/draft-07/schema',
oneOf: [
// Option A): conforms to draft-01 of the CType meta sschema, which defines that the CType's $schema property must be equal to the CType meta schema's $id.
{ $ref: CTypeModelDraft01.$id },
// Option B): The CType's $schema property references V1 of the CType meta schema, in which case this meta schema must apply.
// The structure is different because V1 does not define the exact value of the $schema property because its $id is derived from the hash of its contents.
{
allOf: [
// verifies that both of two (sub-)schemas validate against CType object.
{
// subschema 1: $schema is equal to CType meta schema V1's $id.
properties: {
ntn-x2 marked this conversation as resolved.
Show resolved Hide resolved
$schema: {
type: 'string',
const: CTypeModelV1.$id,
rflechtner marked this conversation as resolved.
Show resolved Hide resolved
},
},
},
{
// subschema 2: CType meta schema V1.
$ref: CTypeModelV1.$id,
},
],
},
],
// CType meta schemas are embedded here, so that the references ($ref) can be resolved without having to load them first.
definitions: {
[CTypeModelDraft01.$id]: CTypeModelDraft01,
[CTypeModelV1.$id]: CTypeModelV1,
},
}

export const MetadataModel: JsonSchema.Schema = {
$id: 'http://kilt-protocol.org/draft-01/ctype-metadata',
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
Expand Down Expand Up @@ -103,7 +203,6 @@ export const MetadataModel = {
},
properties: {
type: 'object',
properties: {},
patternProperties: {
'^.*$': {
type: 'object',
Expand Down
Loading