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

feat: Simpler create VC/VP #309

Merged
merged 1 commit into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
68 changes: 64 additions & 4 deletions __tests__/shared/verifiableData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export default (testContext: {
const verifiableCredential = await agent.createVerifiableCredential({
credential: {
issuer: { id: identifier.did },
'@context': ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiableCredential'],
'@context': ['https://www.w3.org/2018/credentials/v1', 'https://example.com/1/2/3'],
type: ['VerifiableCredential', 'Custom'],
issuanceDate: new Date().toISOString(),
credentialSubject: {
id: 'did:web:example.com',
Expand All @@ -40,6 +40,11 @@ export default (testContext: {
})

expect(verifiableCredential).toHaveProperty('proof.jwt')
expect(verifiableCredential['@context']).toEqual([
'https://www.w3.org/2018/credentials/v1',
'https://example.com/1/2/3',
])
expect(verifiableCredential['type']).toEqual(['VerifiableCredential', 'Custom'])

const hash = await agent.dataStoreSaveVerifiableCredential({ verifiableCredential })
expect(typeof hash).toEqual('string')
Expand All @@ -48,6 +53,24 @@ export default (testContext: {
expect(verifiableCredential).toEqual(verifiableCredential2)
})

it('should create verifiable credential (simple)', async () => {
const verifiableCredential = await agent.createVerifiableCredential({
credential: {
issuer: { id: identifier.did },
credentialSubject: {
id: 'did:web:example.com',
you: 'Rock',
},
},
proofFormat: 'jwt',
})

expect(verifiableCredential).toHaveProperty('proof.jwt')
expect(verifiableCredential).toHaveProperty('issuanceDate')
expect(verifiableCredential['@context']).toEqual(['https://www.w3.org/2018/credentials/v1'])
expect(verifiableCredential['type']).toEqual(['VerifiableCredential'])
})

it('should create verifiable presentation', async () => {
const verifiableCredential = await agent.createVerifiableCredential({
credential: {
Expand All @@ -67,15 +90,52 @@ export default (testContext: {
presentation: {
holder: identifier.did,
verifier: [],
'@context': ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiablePresentation'],
'@context': ['https://www.w3.org/2018/credentials/v1', 'https://example.com/1/2/3'],
type: ['VerifiablePresentation', 'Custom'],
issuanceDate: new Date().toISOString(),
verifiableCredential: [verifiableCredential],
},
proofFormat: 'jwt',
})

expect(verifiablePresentation).toHaveProperty('proof.jwt')
expect(verifiablePresentation['@context']).toEqual([
'https://www.w3.org/2018/credentials/v1',
'https://example.com/1/2/3',
])
expect(verifiablePresentation['type']).toEqual(['VerifiablePresentation', 'Custom'])

const hash = await agent.dataStoreSaveVerifiablePresentation({ verifiablePresentation })
expect(typeof hash).toEqual('string')

const verifiablePresentation2 = await agent.dataStoreGetVerifiablePresentation({ hash })
expect(verifiablePresentation).toEqual(verifiablePresentation2)
})

it('should create verifiable presentation (simple)', async () => {
const verifiableCredential = await agent.createVerifiableCredential({
credential: {
issuer: { id: identifier.did },
credentialSubject: {
id: 'did:web:example.com',
you: 'Rock',
},
},
proofFormat: 'jwt',
})

const verifiablePresentation = await agent.createVerifiablePresentation({
presentation: {
holder: identifier.did,
verifier: [],
verifiableCredential: [verifiableCredential],
},
proofFormat: 'jwt',
})

expect(verifiablePresentation).toHaveProperty('proof.jwt')
expect(verifiablePresentation['@context']).toEqual(['https://www.w3.org/2018/credentials/v1'])
expect(verifiablePresentation['type']).toEqual(['VerifiablePresentation'])

const hash = await agent.dataStoreSaveVerifiablePresentation({ verifiablePresentation })
expect(typeof hash).toEqual('string')
Expand Down
39 changes: 34 additions & 5 deletions packages/daf-w3c/api/daf-w3c.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import { IResolver } from 'daf-core';
import { Message } from 'daf-message-handler';
import { VerifiableCredential } from 'daf-core';
import { VerifiablePresentation } from 'daf-core';
import { W3CCredential } from 'daf-core';
import { W3CPresentation } from 'daf-core';

// @public
export class CredentialIssuer implements IAgentPlugin {
Expand All @@ -30,17 +28,48 @@ export class CredentialIssuer implements IAgentPlugin {
readonly schema: any;
}

// @public
export type EncodingFormat = 'jwt';

// @public
export interface ICreateVerifiableCredentialArgs {
credential: W3CCredential;
// Warning: (ae-forgotten-export) The symbol "EncodingFormat" needs to be exported by the entry point index.d.ts
credential: {
'@context'?: string[];
id?: string;
type?: string[];
issuer: {
id: string;
[x: string]: any;
};
issuanceDate?: string;
expirationDate?: string;
credentialSubject: {
id?: string;
[x: string]: any;
};
credentialStatus?: {
id: string;
type: string;
};
[x: string]: any;
};
proofFormat: EncodingFormat;
save?: boolean;
}

// @public
export interface ICreateVerifiablePresentationArgs {
presentation: W3CPresentation;
presentation: {
id?: string;
holder: string;
issuanceDate?: string;
expirationDate?: string;
'@context'?: string[];
type?: string[];
verifier: string[];
verifiableCredential: VerifiableCredential[];
[x: string]: any;
};
proofFormat: EncodingFormat;
save?: boolean;
}
Expand Down
58 changes: 52 additions & 6 deletions packages/daf-w3c/src/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,20 @@ export interface ICreateVerifiablePresentationArgs {
*
* The signer of the Presentation is chosen based on the `holder` property
* of the `presentation`
*
* '@context', 'type' and 'issuanceDate' will be added automatically if omitted
*/
presentation: W3CPresentation
presentation: {
id?: string
holder: string
issuanceDate?: string
expirationDate?: string
'@context'?: string[]
type?: string[]
verifier: string[]
verifiableCredential: VerifiableCredential[]
[x: string]: any
}

/**
* If this parameter is true, the resulting VerifiablePresentation is sent to the
Expand Down Expand Up @@ -75,8 +87,26 @@ export interface ICreateVerifiableCredentialArgs {
*
* The signer of the Credential is chosen based on the `issuer.id` property
* of the `credential`
*
* '@context', 'type' and 'issuanceDate' will be added automatically if omitted
*/
credential: W3CCredential
credential: {
'@context'?: string[]
id?: string
type?: string[]
issuer: { id: string; [x: string]: any }
issuanceDate?: string
expirationDate?: string
credentialSubject: {
id?: string
[x: string]: any
}
credentialStatus?: {
id: string
type: string
}
[x: string]: any
}

/**
* If this parameter is true, the resulting VerifiablePresentation is sent to the
Expand Down Expand Up @@ -169,15 +199,23 @@ export class CredentialIssuer implements IAgentPlugin {
context: IContext,
): Promise<VerifiablePresentation> {
try {
const presentation: W3CPresentation = {
...args.presentation,
'@context': args.presentation['@context'] || ['https://www.w3.org/2018/credentials/v1'],
//FIXME: make sure 'VerifiablePresentation' is the first element in this array:
type: args.presentation.type || ['VerifiablePresentation'],
issuanceDate: args.presentation.issuanceDate || new Date().toISOString(),
}

//FIXME: if the identifier is not found, the error message should reflect that.
const identifier = await context.agent.didManagerGet({ did: args.presentation.holder })
const identifier = await context.agent.didManagerGet({ did: presentation.holder })
//FIXME: `args` should allow picking a key or key type
const key = identifier.keys.find((k) => k.type === 'Secp256k1')
if (!key) throw Error('No signing key for ' + identifier.did)
//FIXME: Throw an `unsupported_format` error if the `args.proofFormat` is not `jwt`
const signer = (data: string) => context.agent.keyManagerSignJWT({ kid: key.kid, data })
debug('Signing VP with', identifier.did)
const jwt = await createVerifiablePresentationJwt(args.presentation, { did: identifier.did, signer })
const jwt = await createVerifiablePresentationJwt(presentation, { did: identifier.did, signer })
//FIXME: flagging this as a potential privacy leak.
debug(jwt)
const verifiablePresentation = normalizePresentation(jwt)
Expand All @@ -197,16 +235,24 @@ export class CredentialIssuer implements IAgentPlugin {
context: IContext,
): Promise<VerifiableCredential> {
try {
const credential: W3CCredential = {
...args.credential,
'@context': args.credential['@context'] || ['https://www.w3.org/2018/credentials/v1'],
//FIXME: make sure 'VerifiableCredential' is the first element in this array:
type: args.credential.type || ['VerifiableCredential'],
issuanceDate: args.credential.issuanceDate || new Date().toISOString(),
}

//FIXME: if the identifier is not found, the error message should reflect that.
const identifier = await context.agent.didManagerGet({ did: args.credential.issuer.id })
const identifier = await context.agent.didManagerGet({ did: credential.issuer.id })
//FIXME: `args` should allow picking a key or key type
const key = identifier.keys.find((k) => k.type === 'Secp256k1')
if (!key) throw Error('No signing key for ' + identifier.did)
//FIXME: Throw an `unsupported_format` error if the `args.proofFormat` is not `jwt`
const signer = (data: string) => context.agent.keyManagerSignJWT({ kid: key.kid, data })

debug('Signing VC with', identifier.did)
const jwt = await createVerifiableCredentialJwt(args.credential, { did: identifier.did, signer })
const jwt = await createVerifiableCredentialJwt(credential, { did: identifier.did, signer })
//FIXME: flagging this as a potential privacy leak.
debug(jwt)
const verifiableCredential = normalizeCredential(jwt)
Expand Down
1 change: 1 addition & 0 deletions packages/daf-w3c/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {
ICredentialIssuer,
ICreateVerifiableCredentialArgs,
ICreateVerifiablePresentationArgs,
EncodingFormat,
} from './action-handler'
const schema = require('../plugin.schema.json')
export { schema }