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: credential preview attributes mismatch schema attributes #625

Merged
merged 18 commits into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/core/src/modules/credentials/CredentialUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { LinkedAttachment } from '../../utils/LinkedAttachment'
import type { IndyLedgerService } from '../ledger'
import type { CredValues } from 'indy-sdk'

import { hash as sha256 } from '@stablelib/sha256'
Expand Down Expand Up @@ -175,4 +176,24 @@ export class CredentialUtils {
// Check if number is integer and in range of int32
return Number.isInteger(number) && number >= minI32 && number <= maxI32
}

public static async checkAttributesMatch(
ledgerService: IndyLedgerService,
credentialPreview: CredentialPreview,
schema_id: string
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
schema_id: string
schemaId: string

) {
const schema = await ledgerService.getSchema(schema_id)
const schemaAttributes = schema.attrNames
const credAttributes = credentialPreview.attributes.map((a) => a.name)

const difference = credAttributes
.filter((x) => !schemaAttributes.includes(x))
.concat(schemaAttributes.filter((x) => !credAttributes.includes(x)))

if (difference.length > 0) {
throw new AriesFrameworkError(
`The credential preview attributes do not match the schema attributes (difference is: ${difference}, needs: ${schemaAttributes})`
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { CredentialMetadataKeys } from '../repository/credentialMetadataTypes'
import { CredentialService } from '../services'

import { CredentialProblemReportMessage } from './../messages/CredentialProblemReportMessage'
import { credDef, credOffer, credReq } from './fixtures'
import { credDef, credOffer, credReq, schema } from './fixtures'

// Mock classes
jest.mock('../repository/CredentialRepository')
Expand Down Expand Up @@ -175,6 +175,7 @@ describe('CredentialService', () => {
)

mockFunction(ledgerService.getCredentialDefinition).mockReturnValue(Promise.resolve(credDef))
mockFunction(ledgerService.getSchema).mockReturnValue(Promise.resolve(schema))
})

describe('createCredentialOffer', () => {
Expand Down Expand Up @@ -259,6 +260,44 @@ describe('CredentialService', () => {
],
})
})

test('throw error if credential preview attributes do not match with schema attributes', async () => {
const credentialPreview = CredentialPreview.fromRecord({
test: 'credential',
error: 'yes',
})

expect(
credentialService.createOffer(
{
...credentialTemplate,
preview: credentialPreview,
},
connection
)
).rejects.toThrowError(
`The credential preview attributes do not match the schema attributes (difference is: test,error, needs: name,age)`
)

const credentialPreviewWithExtra = CredentialPreview.fromRecord({
test: 'credential',
error: 'yes',
name: 'John',
age: '99',
})

await expect(
credentialService.createOffer(
{
...credentialTemplate,
preview: credentialPreviewWithExtra,
},
connection
)
).rejects.toThrowError(
`The credential preview attributes do not match the schema attributes (difference is: test,error, needs: name,age)`
)
})
})

describe('processCredentialOffer', () => {
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/modules/credentials/__tests__/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Schema } from 'indy-sdk'

export const credDef = {
ver: '1.0',
id: 'TL1EaPFCZ8Si5aUrqScBDt:3:CL:16:TAG',
Expand Down Expand Up @@ -49,3 +51,12 @@ export const credReq = {
},
nonce: '784158051402761459123237',
}

export const schema: Schema = {
name: 'schema',
attrNames: ['name', 'age'],
id: 'TL1EaPFCZ8Si5aUrqScBDt:2:test-schema-1599055118161:1.0',
seqNo: 989798923653,
ver: '1.0',
version: '1.0',
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ export class CredentialService {
credentialRecord.autoAcceptCredential =
credentialTemplate.autoAcceptCredential ?? credentialRecord.autoAcceptCredential

// Check if credential preview attributes match the schema attributes
CredentialUtils.checkAttributesMatch(this.ledgerService, preview, credOffer.schema_id)

await this.updateState(credentialRecord, CredentialState.OfferSent)

return { message: credentialOfferMessage, credentialRecord }
Expand Down Expand Up @@ -302,6 +305,9 @@ export class CredentialService {
? CredentialUtils.createAndLinkAttachmentsToPreview(linkedAttachments, preview)
: preview

// Check if credential preview attributes match the schema attributes
CredentialUtils.checkAttributesMatch(this.ledgerService, credentialPreview, credOffer.schema_id)

// Construct offer message
const credentialOfferMessage = new OfferCredentialMessage({
comment,
Expand Down
47 changes: 42 additions & 5 deletions packages/core/tests/credentials-auto-accept.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ import testLogger from './logger'
const credentialPreview = CredentialPreview.fromRecord({
name: 'John',
age: '99',
'x-ray': 'some x-ray',
profile_picture: 'profile picture',
})

const newCredentialPreview = CredentialPreview.fromRecord({
name: 'John',
age: '99',
lastname: 'Appleseed',
'x-ray': 'another x-ray value',
profile_picture: 'another profile picture',
})

describe('auto accept credentials', () => {
Expand Down Expand Up @@ -261,6 +264,16 @@ describe('auto accept credentials', () => {
name: 'age',
value: '99',
},
{
name: 'x-ray',
'mime-type': 'text/plain',
value: 'some x-ray',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'profile picture',
},
],
},
'offers~attach': expect.any(Array),
Expand Down Expand Up @@ -363,8 +376,14 @@ describe('auto accept credentials', () => {
value: '99',
},
{
name: 'lastname',
value: 'Appleseed',
name: 'x-ray',
'mime-type': 'text/plain',
value: 'another x-ray value',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'another profile picture',
},
],
},
Expand Down Expand Up @@ -422,6 +441,16 @@ describe('auto accept credentials', () => {
name: 'age',
value: '99',
},
{
name: 'x-ray',
'mime-type': 'text/plain',
value: 'some x-ray',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'profile picture',
},
],
},
'offers~attach': expect.any(Array),
Expand Down Expand Up @@ -453,16 +482,24 @@ describe('auto accept credentials', () => {
'@type': 'https://didcomm.org/issue-credential/1.0/credential-preview',
attributes: [
{
'mime-type': 'text/plain',
name: 'name',
value: 'John',
},
{
'mime-type': 'text/plain',
name: 'age',
value: '99',
},
{
name: 'lastname',
value: 'Appleseed',
name: 'x-ray',
'mime-type': 'text/plain',
value: 'another x-ray value',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'another profile picture',
},
],
},
Expand Down
48 changes: 46 additions & 2 deletions packages/core/tests/credentials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ import testLogger from './logger'
const credentialPreview = CredentialPreview.fromRecord({
name: 'John',
age: '99',
'x-ray': 'some x-ray',
profile_picture: 'profile picture',
})

const credentialPreviewWithoutProfilePicture = CredentialPreview.fromRecord({
name: 'John',
age: '99',
'x-ray': 'some x-ray',
})

const credentialPreviewWithoutXray = CredentialPreview.fromRecord({
name: 'John',
age: '99',
profile_picture: 'profile picture',
})

describe('credentials', () => {
Expand Down Expand Up @@ -80,6 +94,16 @@ describe('credentials', () => {
'mime-type': 'text/plain',
value: '99',
},
{
name: 'x-ray',
'mime-type': 'text/plain',
value: 'some x-ray',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'profile picture',
},
],
},
'offers~attach': expect.any(Array),
Expand Down Expand Up @@ -180,6 +204,16 @@ describe('credentials', () => {
'mime-type': 'text/plain',
value: '99',
},
{
name: 'x-ray',
'mime-type': 'text/plain',
value: 'some x-ray',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'profile picture',
},
],
},
'offers~attach': expect.any(Array),
Expand Down Expand Up @@ -251,7 +285,7 @@ describe('credentials', () => {
test('Alice starts with credential proposal, with attachments, to Faber', async () => {
testLogger.test('Alice sends credential proposal to Faber')
let aliceCredentialRecord = await aliceAgent.credentials.proposeCredential(aliceConnection.id, {
credentialProposal: credentialPreview,
credentialProposal: credentialPreviewWithoutProfilePicture,
credentialDefinitionId: credDefId,
linkedAttachments: [
new LinkedAttachment({
Expand Down Expand Up @@ -300,6 +334,11 @@ describe('credentials', () => {
'mime-type': 'text/plain',
value: '99',
},
{
name: 'x-ray',
'mime-type': 'text/plain',
value: 'some x-ray',
},
{
name: 'profile_picture',
'mime-type': 'image/png',
Expand Down Expand Up @@ -374,7 +413,7 @@ describe('credentials', () => {
test('Faber starts with credential, with attachments, offer to Alice', async () => {
testLogger.test('Faber sends credential offer to Alice')
faberCredentialRecord = await faberAgent.credentials.offerCredential(faberConnection.id, {
preview: credentialPreview,
preview: credentialPreviewWithoutXray,
credentialDefinitionId: credDefId,
comment: 'some comment about credential',
linkedAttachments: [
Expand Down Expand Up @@ -414,6 +453,11 @@ describe('credentials', () => {
'mime-type': 'text/plain',
value: '99',
},
{
name: 'profile_picture',
'mime-type': 'text/plain',
value: 'profile picture',
},
{
name: 'x-ray',
value: 'hl:zQmdsy1SSKztP7CGRiP2SuMV41Xxy9g69QswhUiSeo3d4pH',
Expand Down