diff --git a/docs/MessageValidator.md b/docs/MessageValidator.md new file mode 100644 index 000000000..8a1713f17 --- /dev/null +++ b/docs/MessageValidator.md @@ -0,0 +1,123 @@ +# Message validator + +The main responsibility of Message Validator is to take any raw message as an input and output a standard `ValidatedMessage` object, or `null` if message type is unsupported. + +## Data flow explanation + +In this example we will take a look how this chain of validators works: + +```ts +const messageValidator = new DBG.MessageValidator() +messageValidator + .setNext(new URL.MessageValidator()) + .setNext(new DidJwt.MessageValidator()) + .setNext(new W3c.MessageValidator()) + .setNext(new Sd.MessageValidator()) + +const core = new Daf.core({ + // ..., + messageValidator, + // ... +}) + +// After scanning QR Code: +// qrcodeData = 'https://example.com/ssi?c_i=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzU2MzIyNDQsInR5cGUiOiJzZHIiLCJ0YWciOiJzZXNzLTEyMyIsImNsYWltcyI6W3siZXNzZW50aWFsIjp0cnVlLCJjbGFpbVR5cGUiOiJuYW1lIiwicmVhc29uIjoiV2UgbmVlZCB0aGlzIHRvIGNvbXBseSB3aXRoIGxvY2FsIGxhdyJ9XSwiaXNzIjoiZGlkOmV0aHI6MHg2YjFkMGRiMzY3NjUwZjIxYmFlNDg1MDM0N2M3YTA0N2YwNGRlNDM2In0.lhv_sGFQX0258CJF50J9cRdF7mmzo9Jx137oWTu0VF3A1CkEI88dDYA5Usj0HKH_2tHKA5b-S1_Akb-mDz9v9QE' + +const msg = new Daf.Message({ raw: qrcodeData, meta: { sourceType: 'QRCode' }) + +const message = await core.validateMessage(msg) + +if (message.isValid()) { + message.id() // hash... + message.from() // did:ethr:0x6b1d0db367650f21bae4850347c7a047f04de436 + message.to() // null + message.type() // sdr + message.data() // { iss: 'did:ethr:0x6b1d0db367650f21bae4850347c7a047f04de436', tag: 'sess-123, claims: [{claimType: 'name', ...}] ... + message.meta() + /* + [ + { sourceType: 'QRCode' }, + { sourceType: 'URL', sourceId: 'https://example.com/ssi' }, + { sourceType: 'JWT', sourceId: 'ES256K-R' }, + ] + */ +} + +``` + +### DBG.MessageValidator + +Outputs debug info. And passes through the same message object to the next validator + +### URL.MessageValidator + +- Detects that message raw format is a URL +- Finds JWT +- Replaces raw contents with JWT, and adds meta + +```ts +// jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzU2MzIyNDQsInR5cGUiOiJzZHIiLCJ0YWciOiJzZXNzLTEyMyIsImNsYWltcyI6W3siZXNzZW50aWFsIjp0cnVlLCJjbGFpbVR5cGUiOiJuYW1lIiwicmVhc29uIjoiV2UgbmVlZCB0aGlzIHRvIGNvbXBseSB3aXRoIGxvY2FsIGxhdyJ9XSwiaXNzIjoiZGlkOmV0aHI6MHg2YjFkMGRiMzY3NjUwZjIxYmFlNDg1MDM0N2M3YTA0N2YwNGRlNDM2In0.lhv_sGFQX0258CJF50J9cRdF7mmzo9Jx137oWTu0VF3A1CkEI88dDYA5Usj0HKH_2tHKA5b-S1_Akb-mDz9v9QE' + +msg.transform({ + raw: jwt, + meta: { sourceType: 'URL', sourceId: 'https://example.com/ssi' }, +}) +``` + +- Passes message object to the next validator + +### DidJwt.MessageValidator + +- Detects that message raw format is JWT +- Validates signature +- Replaces message raw contents with decoded JWT payload + +```ts +/* +validated.payload = { + "iat": 1575632244, + "type": "sdr", + "tag": "sess-123", + "claims": [ + { + "essential": true, + "claimType": "name", + "reason": "We need this to comply with local law" + } + ], + "iss": "did:ethr:0x6b1d0db367650f21bae4850347c7a047f04de436" +} +*/ + +msg.transform({ + raw: jwt, + data: validated.payload, + meta: { sourceType: validated.header.typ, sourceId: validated.header.alg }, +}) +``` + +- Passes message object to the next validator + +### W3c.MessageValidator + +- Fails to detect VP or VC +- Passes through unchanged message object to the next validator + +### Sd.MessageValidator + +- Detects that message is a valid did-jwt with a type of 'sdr' +- Sets required fields and returns validate message + +```ts +const { raw, data, meta } = msg.getLast() + +msg.hash(raw) +msg.setThreadId(null) +msg.setFrom(raw.iss) +msg.setTo(null) +msg.setType(data.type) +msg.setTimestamp(data.nbf) +msg.setData(data) + +return msg +``` diff --git a/examples/expressjs-ethr/src/setup.ts b/examples/expressjs-ethr/src/setup.ts index d06855777..12a14a78e 100644 --- a/examples/expressjs-ethr/src/setup.ts +++ b/examples/expressjs-ethr/src/setup.ts @@ -42,11 +42,11 @@ if (process.env.DAF_UNIVERSAL_RESOLVER_URL) { const identityControllers = [new EthrDidFsController(identityStoreFilename)] const messageValidator = new DBG.MessageValidator() -messageValidator.setNext(new DIDComm.MessageValidator()).setNext( - new DidJwt.MessageValidator({ - payloadValidators: [new W3c.PayloadValidator(), new SD.PayloadValidator()], - }), -) +messageValidator + .setNext(new DIDComm.MessageValidator()) + .setNext(new DidJwt.MessageValidator()) + .setNext(new W3c.MessageValidator()) + .setNext(new SD.MessageValidator()) const actionHandler = new DBG.ActionHandler() actionHandler diff --git a/examples/expressjs-ethr/src/web-server.ts b/examples/expressjs-ethr/src/web-server.ts index ba6704bce..f755df4b9 100644 --- a/examples/expressjs-ethr/src/web-server.ts +++ b/examples/expressjs-ethr/src/web-server.ts @@ -112,16 +112,16 @@ async function main() { }) }) - core.on(Daf.EventTypes.validatedMessage, async (message: Daf.Types.ValidatedMessage, b: any) => { - debug('New message %s', message.hash) + core.on(Daf.EventTypes.validatedMessage, async (message: Daf.Message, b: any) => { + debug('New message %s', message.id) debug('Meta %O', message.meta) console.log(message) await dataStore.saveMessage(message) - if (message.type === W3C.MessageTypes.vp && message.tag) { + if (message.type === W3C.MessageTypes.vp && message.threadId) { // TODO check for required vcs - const sessionId = message.tag - await io.in(sessionId).emit('loggedin', { did: message.issuer }) + const sessionId = message.threadId + await io.in(sessionId).emit('loggedin', { did: message.from }) sessionStore.get(sessionId, (error, session) => { if (error) { console.log(error) @@ -130,10 +130,10 @@ async function main() { if (session) { console.log('Got session', session) console.log('View count', session.viewcount) - session.did = message.issuer + session.did = message.from sessionStore.set(sessionId, session) } else { - console.log('No session: ' + message.tag) + console.log('No session: ' + message.threadId) } }) } diff --git a/examples/expressjs-ethr/tsconfig.json b/examples/expressjs-ethr/tsconfig.json index c5b3db8a8..861c423dc 100644 --- a/examples/expressjs-ethr/tsconfig.json +++ b/examples/expressjs-ethr/tsconfig.json @@ -23,7 +23,6 @@ { "path": "../../packages/daf-ethr-did-react-native" }, { "path": "../../packages/daf-node-sqlite3" }, { "path": "../../packages/daf-node-sqlite3" }, - { "path": "../../packages/daf-random" }, { "path": "../../packages/daf-resolver" }, { "path": "../../packages/daf-resolver-universal" }, { "path": "../../packages/daf-selective-disclosure" }, diff --git a/examples/expressjs-ethr/yarn.lock b/examples/expressjs-ethr/yarn.lock index d34f9fe92..5702e9178 100644 --- a/examples/expressjs-ethr/yarn.lock +++ b/examples/expressjs-ethr/yarn.lock @@ -586,65 +586,65 @@ cross-fetch@^3.0.4: node-fetch "2.6.0" whatwg-fetch "3.0.0" -daf-core@../../packages/daf-core, daf-core@^0.8.0: - version "0.8.0" +daf-core@../../packages/daf-core, daf-core@^0.9.0: + version "0.9.0" dependencies: blakejs "^1.1.0" debug "^4.1.1" events "^3.0.0" -daf-data-store@../../packages/daf-data-store, daf-data-store@^0.8.0: - version "0.8.0" +daf-data-store@../../packages/daf-data-store, daf-data-store@^0.9.0: + version "0.9.0" dependencies: blakejs "^1.1.0" - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" sql-bricks-sqlite "^0.1.0" daf-debug@../../packages/daf-debug: - version "0.8.0" + version "0.9.0" dependencies: - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" daf-did-comm@../../packages/daf-did-comm: - version "0.8.0" + version "0.9.0" dependencies: DIDComm-js "git://github.com/uport-project/DIDComm-js.git#fix/build-issues" - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" uuid "^3.3.3" -daf-did-jwt@../../packages/daf-did-jwt, daf-did-jwt@^0.8.0: - version "0.8.0" +daf-did-jwt@../../packages/daf-did-jwt, daf-did-jwt@^0.9.0: + version "0.9.0" dependencies: - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" did-jwt "^3.0.0" did-resolver "^1.1.0" daf-ethr-did-fs@../../packages/daf-ethr-did-fs: - version "0.8.0" + version "0.9.0" dependencies: - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" ethr-did "^1.1.0" daf-node-sqlite3@../../packages/daf-node-sqlite3: - version "0.8.0" + version "0.9.0" dependencies: - daf-data-store "^0.8.0" + daf-data-store "^0.9.0" debug "^4.1.1" sqlite3 "^4.1.0" daf-resolver-universal@../../packages/daf-resolver-universal: - version "0.8.0" + version "0.9.0" dependencies: cross-fetch "^3.0.4" debug "^4.1.1" daf-resolver@../../packages/daf-resolver: - version "0.8.0" + version "0.9.0" dependencies: debug "^4.1.1" did-resolver "^1.1.0" @@ -653,22 +653,22 @@ daf-resolver@../../packages/daf-resolver: web-did-resolver "^1.2.0" daf-selective-disclosure@../../packages/daf-selective-disclosure: - version "0.8.0" + version "0.9.0" dependencies: - daf-core "^0.8.0" - daf-did-jwt "^0.8.0" + daf-core "^0.9.0" + daf-did-jwt "^0.9.0" debug "^4.1.1" did-jwt "^3.0.0" daf-sodium-fs@../../packages/daf-sodium-fs: - version "0.8.0" + version "0.9.0" dependencies: - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" libsodium-wrappers "^0.7.6" daf-trust-graph@../../packages/daf-trust-graph: - version "0.8.0" + version "0.9.0" dependencies: apollo-cache-inmemory "^1.6.3" apollo-client "^2.6.4" @@ -677,7 +677,7 @@ daf-trust-graph@../../packages/daf-trust-graph: apollo-link-ws "^1.0.19" apollo-utilities "^1.3.2" cross-fetch "^3.0.4" - daf-core "^0.8.0" + daf-core "^0.9.0" debug "^4.1.1" did-jwt "^3.0.0" graphql "^14.0.0" @@ -685,10 +685,10 @@ daf-trust-graph@../../packages/daf-trust-graph: subscriptions-transport-ws "^0.9.0" daf-w3c@../../packages/daf-w3c: - version "0.8.0" + version "0.9.0" dependencies: - daf-core "^0.8.0" - daf-did-jwt "^0.8.0" + daf-core "^0.9.0" + daf-did-jwt "^0.9.0" debug "^4.1.1" did-jwt-vc "^0.1.2" did-resolver "^1.1.0" diff --git a/packages/daf-cli/src/credential.ts b/packages/daf-cli/src/credential.ts index a41d0ede1..8f3d76df5 100644 --- a/packages/daf-cli/src/credential.ts +++ b/packages/daf-cli/src/credential.ts @@ -1,3 +1,4 @@ +import * as Daf from 'daf-core' import * as W3c from 'daf-w3c' import * as DIDComm from 'daf-did-comm' import { core, dataStore } from './setup' @@ -63,7 +64,7 @@ program await dataStore.initialize() if (!cmd.send) { - await core.onRawMessage({ raw: jwt }) + await core.validateMessage(new Daf.Message({ raw: jwt, meta: { type: 'cli' } })) } else { const sendAction: DIDComm.ActionSendJWT = { type: DIDComm.ActionTypes.sendJwt, @@ -207,7 +208,7 @@ program await dataStore.initialize() if (!cmd.send) { - await core.onRawMessage({ raw: jwt }) + await core.validateMessage(new Daf.Message({ raw: jwt, meta: { type: 'cli' } })) } else { const sendAction: DIDComm.ActionSendJWT = { type: DIDComm.ActionTypes.sendJwt, diff --git a/packages/daf-cli/src/msg.ts b/packages/daf-cli/src/msg.ts index 3bb636cc2..8e7990a66 100644 --- a/packages/daf-cli/src/msg.ts +++ b/packages/daf-cli/src/msg.ts @@ -1,3 +1,4 @@ +import * as Daf from 'daf-core' import { core } from './setup' import program from 'commander' @@ -6,14 +7,12 @@ program .description('Handle raw message (JWT)') .action(async raw => { try { - const result = await core.onRawMessage({ - raw, - meta: [ - { - sourceType: 'cli', - }, - ], - }) + const result = await core.validateMessage( + new Daf.Message({ + raw, + meta: { type: 'cli' }, + }), + ) console.log(result) } catch (e) { console.error(e) diff --git a/packages/daf-cli/src/sdr.ts b/packages/daf-cli/src/sdr.ts index 3d9bdb306..dc7af0b79 100644 --- a/packages/daf-cli/src/sdr.ts +++ b/packages/daf-cli/src/sdr.ts @@ -1,4 +1,4 @@ -import * as W3c from 'daf-w3c' +import * as Daf from 'daf-core' import * as DIDComm from 'daf-did-comm' import * as SD from 'daf-selective-disclosure' import { core, dataStore } from './setup' @@ -94,7 +94,7 @@ program await dataStore.initialize() if (!cmd.send) { - await core.onRawMessage({ raw: jwt }) + await core.validateMessage(new Daf.Message({ raw: jwt, meta: { type: 'cli' } })) } else if (answers.sub !== '') { const sendAction: DIDComm.ActionSendJWT = { type: DIDComm.ActionTypes.sendJwt, diff --git a/packages/daf-cli/src/services.ts b/packages/daf-cli/src/services.ts index a18300ea9..7615746e5 100644 --- a/packages/daf-cli/src/services.ts +++ b/packages/daf-cli/src/services.ts @@ -1,4 +1,4 @@ -import { EventTypes, Types } from 'daf-core' +import { EventTypes, Message } from 'daf-core' import { core, dataStore } from './setup' import program from 'commander' import { setInterval } from 'timers' @@ -14,7 +14,7 @@ program export const listen = async (pollSeconds?: number) => { await dataStore.initialize() - core.on(EventTypes.validatedMessage, async (msg: Types.ValidatedMessage) => { + core.on(EventTypes.validatedMessage, async (msg: Message) => { console.log('New message type:', msg.type) }) diff --git a/packages/daf-cli/src/setup.ts b/packages/daf-cli/src/setup.ts index cbea96be2..50d90cca6 100644 --- a/packages/daf-cli/src/setup.ts +++ b/packages/daf-cli/src/setup.ts @@ -47,11 +47,11 @@ if (process.env.DAF_UNIVERSAL_RESOLVER_URL) { const identityControllers = [new EthrDidFsController(identityStoreFilename)] const messageValidator = new DBG.MessageValidator() -messageValidator.setNext(new DIDComm.MessageValidator()).setNext( - new DidJwt.MessageValidator({ - payloadValidators: [new W3c.PayloadValidator(), new SD.PayloadValidator()], - }), -) +messageValidator + .setNext(new DIDComm.MessageValidator()) + .setNext(new DidJwt.MessageValidator()) + .setNext(new W3c.MessageValidator()) + .setNext(new SD.MessageValidator()) const actionHandler = new DBG.ActionHandler() actionHandler @@ -90,7 +90,7 @@ export const core = new Daf.Core({ const db = new NodeSqlite3(dataStoreFilename) export const dataStore = new DataStore(db) -core.on(Daf.EventTypes.validatedMessage, async (message: Daf.Types.ValidatedMessage) => { +core.on(Daf.EventTypes.validatedMessage, async (message: Daf.Message) => { debug('New message %O', message) await dataStore.saveMessage(message) }) diff --git a/packages/daf-core/src/__tests__/message.test.ts b/packages/daf-core/src/__tests__/message.test.ts new file mode 100644 index 000000000..1fb41ac39 --- /dev/null +++ b/packages/daf-core/src/__tests__/message.test.ts @@ -0,0 +1,58 @@ +import { Message } from '../message' + +jest.mock('blakejs') +import { blake2bHex } from 'blakejs' + +it('empty message should not be valid', () => { + const msg = new Message({ raw: '', meta: { type: '' } }) + expect(msg.type).toEqual(null) + expect(msg.threadId).toEqual(null) + expect(msg.from).toEqual(null) + expect(msg.to).toEqual(null) + expect(msg.isValid()).toEqual(false) +}) + +it('valid message should be valid', () => { + const msg = new Message({ raw: 'raw', meta: { type: 'test' } }) + msg.id = '123' + expect(msg.id).toEqual('123') + + msg.type = 'someType' + expect(msg.type).toEqual('someType') + + msg.threadId = '456' + expect(msg.threadId).toEqual('456') + + msg.from = 'did:example:abc' + expect(msg.from).toEqual('did:example:abc') + + msg.to = 'did:example:xyz' + expect(msg.to).toEqual('did:example:xyz') + + expect(msg.isValid()).toEqual(true) +}) + +it('should return raw and meta from last transformation', () => { + const msg = new Message({ raw: 'raw1', meta: { type: 'type1' } }) + msg.transform({ raw: 'raw2', meta: { type: 'type2' } }) + + expect(msg.raw).toEqual('raw2') + expect(msg.meta).toEqual({ type: 'type2' }) +}) + +it('should return all meta data in right order', () => { + const msg = new Message({ raw: 'raw1', meta: { type: 'type1' } }) + msg.transform({ raw: 'raw2', meta: { type: 'type2' } }) + msg.transform({ raw: 'raw3', meta: { type: 'type3' } }) + + expect(msg.allMeta).toEqual([{ type: 'type1' }, { type: 'type2' }, { type: 'type3' }]) +}) + +it('should use blake hash of last raw as id if id is not set', () => { + const msg = new Message({ raw: 'raw1', meta: { type: 'type1' } }) + + msg.transform({ raw: 'raw2', meta: { type: 'type2' } }) + blake2bHex.mockReturnValue('hash123') + + expect(msg.id).toEqual('hash123') +}) diff --git a/packages/daf-core/src/core.ts b/packages/daf-core/src/core.ts index d991ea68e..23bad94a8 100644 --- a/packages/daf-core/src/core.ts +++ b/packages/daf-core/src/core.ts @@ -4,9 +4,9 @@ import { IdentityManager, IdentityController } from './identity-manager' import { ServiceManager, ServiceControllerWithConfig, LastMessageTimestamp } from './service-manager' import { MessageValidator } from './message-validator' import { ActionHandler } from './action-handler' -import { ValidatedMessage, PreValidatedMessage, RawMessage, Action } from './types' +import { Action } from './types' import { EncryptionKeyManager } from './encryption-manager' -import blake from 'blakejs' +import { Message } from './message' import Debug from 'debug' const debug = Debug('core') @@ -50,7 +50,7 @@ export class Core extends EventEmitter { this.serviceManager = new ServiceManager({ serviceControllersWithConfig: config.serviceControllersWithConfig, - onRawMessage: this.onRawMessage.bind(this), + validateMessage: this.validateMessage.bind(this), didResolver: this.didResolver, }) @@ -69,41 +69,19 @@ export class Core extends EventEmitter { await this.serviceManager.syncServices(lastMessageTimestamps) } - public async onRawMessage(rawMessage: RawMessage): Promise { - debug('Raw message %O', rawMessage) + public async validateMessage(message: Message): Promise { + debug('Raw message %O', message) try { - const preValidatedMessage = await this.messageValidator.validate(rawMessage, this) - if (preValidatedMessage !== null && this.isValidatedMessage(preValidatedMessage)) { - const validatedMessage = { - ...preValidatedMessage, - hash: blake.blake2bHex(preValidatedMessage.raw), - } + const validatedMessage = await this.messageValidator.validate(message, this) + if (validatedMessage.isValid()) { this.emit(EventTypes.validatedMessage, validatedMessage) return validatedMessage } } catch (error) { - this.emit(EventTypes.error, error, rawMessage) + this.emit(EventTypes.error, error, message) + return Promise.reject(error) } - return null - } - - private isValidatedMessage(message: PreValidatedMessage): boolean { - if (message === null) { - return false - } - if (!message.type || message.type == '') { - debug('Missing `type` in %o', message) - return false - } - if (!message.issuer || message.issuer == '') { - debug('Missing `issuer` in %o', message) - return false - } - if (!message.raw || message.raw == '') { - debug('Missing `raw` in %o', message) - return false - } - return true + return Promise.reject('Unsupported message type') } public async handleAction(action: Action): Promise { diff --git a/packages/daf-core/src/graphql-core.ts b/packages/daf-core/src/graphql-core.ts index 0896c1c14..5c173e02d 100644 --- a/packages/daf-core/src/graphql-core.ts +++ b/packages/daf-core/src/graphql-core.ts @@ -1,17 +1,24 @@ import { Core } from './core' +import { Message } from './message' interface Context { core: Core } -const newMessage = async (_: any, args: { raw: string, sourceType: string, sourceId?: string }, ctx: Context) => { - return await ctx.core.onRawMessage({ - raw: args.raw, - meta: [{ - sourceType: args.sourceType, - sourceId: args.sourceId - }] - }) +const newMessage = async ( + _: any, + args: { raw: string; sourceType: string; sourceId?: string }, + ctx: Context, +) => { + return await ctx.core.validateMessage( + new Message({ + raw: args.raw, + meta: { + type: args.sourceType, + id: args.sourceId, + }, + }), + ) } export const resolvers = { diff --git a/packages/daf-core/src/index.ts b/packages/daf-core/src/index.ts index 38cec8b41..f22ea1830 100644 --- a/packages/daf-core/src/index.ts +++ b/packages/daf-core/src/index.ts @@ -3,6 +3,7 @@ export { AbstractActionHandler } from './action-handler' export { EncryptionKeyManager, KeyPair } from './encryption-manager' export { IdentityController, IdentityManager, Issuer } from './identity-manager' export { AbstractMessageValidator } from './message-validator' +export { Message } from './message' export { ServiceController, ServiceControllerOptions, diff --git a/packages/daf-core/src/message-validator.ts b/packages/daf-core/src/message-validator.ts index ce29fe1ce..d50586496 100644 --- a/packages/daf-core/src/message-validator.ts +++ b/packages/daf-core/src/message-validator.ts @@ -1,12 +1,9 @@ -import { RawMessage, ValidatedMessage, PreValidatedMessage } from './types' +import { Message } from './message' import { Core } from './core' export interface MessageValidator { setNext(messageValidator: MessageValidator): MessageValidator - validate: ( - rawMessage: RawMessage, - core: Core, - ) => Promise + validate: (message: Message, core: Core) => Promise } export abstract class AbstractMessageValidator implements MessageValidator { @@ -17,13 +14,10 @@ export abstract class AbstractMessageValidator implements MessageValidator { return messageValidator } - public async validate( - rawMessage: RawMessage, - core: Core, - ): Promise { + public async validate(message: Message, core: Core): Promise { if (this.nextMessageValidator) { - return this.nextMessageValidator.validate(rawMessage, core) + return this.nextMessageValidator.validate(message, core) } - return null + return Promise.reject('Unsupported message type') } } diff --git a/packages/daf-core/src/message.ts b/packages/daf-core/src/message.ts new file mode 100644 index 000000000..a933f1122 --- /dev/null +++ b/packages/daf-core/src/message.ts @@ -0,0 +1,91 @@ +import { blake2bHex } from 'blakejs' +import Debug from 'Debug' +const debug = Debug('daf:message') + +export interface MetaData { + type?: string + id?: string + data?: any +} + +interface Transformation { + raw: string + data?: any + meta: MetaData +} + +export class Message { + private _id: string | null = null + public type: string | null = null + public threadId: string | null = null + public from: string | null = null + public to: string | null = null + public timestamp: number | null = null + public vc?: any + + private transformations: Transformation[] + + constructor({ raw, meta }: { raw: string; meta: MetaData }) { + this.transformations = [{ raw, meta }] + } + + transform(transformation: { raw: string; data?: any; meta: MetaData }) { + if (!transformation.raw || transformation.raw === '') { + throw Error('Transformation raw is empty') + } + if (!transformation.meta || !transformation.meta.type || transformation.meta.type === '') { + throw Error('Transformation meta is empty') + } + this.transformations.push(transformation) + } + + get raw() { + const lastTransformation = this.transformations[this.transformations.length - 1] + return lastTransformation?.raw + } + + get meta() { + const lastTransformation = this.transformations[this.transformations.length - 1] + return lastTransformation?.meta + } + + get data() { + const lastTransformation = this.transformations[this.transformations.length - 1] + return lastTransformation?.data + } + + get allMeta() { + return this.transformations.map(item => item.meta) + } + + set id(id) { + this._id = id + } + + get id() { + if (this._id !== null) { + return this._id + } else { + return blake2bHex(this.raw) + } + } + + isValid() { + if (this.from === null) { + return false + } + if (this.type === null || this.type === '') { + debug('Missing `type` in %o', this) + return false + } + if (this.from === null || this.from === '') { + debug('Missing `from` in %o', this) + return false + } + if (!this.raw || this.raw === null || this.raw === '') { + debug('Missing `raw` in %o', this) + return false + } + return true + } +} diff --git a/packages/daf-core/src/service-manager.ts b/packages/daf-core/src/service-manager.ts index 3b0435072..c7f88b443 100644 --- a/packages/daf-core/src/service-manager.ts +++ b/packages/daf-core/src/service-manager.ts @@ -1,13 +1,13 @@ import { DIDDocument } from 'did-resolver' import { Resolver } from './core' import { Issuer } from './identity-manager' -import { RawMessage, ValidatedMessage } from './types' +import { Message } from './message' export interface ServiceControllerOptions { config: any issuer: Issuer didDoc: DIDDocument - onRawMessage: (rawMessage: RawMessage) => Promise + validateMessage: (message: Message) => Promise } export interface ServiceInstanceId { @@ -34,18 +34,18 @@ export type ServiceControllerWithConfig = { interface Options { didResolver: Resolver serviceControllersWithConfig: ServiceControllerWithConfig[] - onRawMessage: (rawMessage: RawMessage) => Promise + validateMessage: (message: Message) => Promise } export class ServiceManager { private serviceControllersWithConfig: ServiceControllerWithConfig[] - private onRawMessage: (rawMessage: RawMessage) => Promise + private validateMessage: (message: Message) => Promise private serviceControllers: ServiceController[] private didResolver: Resolver constructor(options: Options) { this.serviceControllersWithConfig = options.serviceControllersWithConfig - this.onRawMessage = options.onRawMessage + this.validateMessage = options.validateMessage this.serviceControllers = [] this.didResolver = options.didResolver } @@ -60,7 +60,7 @@ export class ServiceManager { config, issuer, didDoc, - onRawMessage: this.onRawMessage, + validateMessage: this.validateMessage, }), ) } diff --git a/packages/daf-core/src/types.ts b/packages/daf-core/src/types.ts index 4cd51743e..0a67f7687 100644 --- a/packages/daf-core/src/types.ts +++ b/packages/daf-core/src/types.ts @@ -1,33 +1,4 @@ -export interface ServiceMetaData { - sourceType?: string - sourceId?: string - data?: any -} - -export interface RawMessage { - raw: string - meta?: ServiceMetaData[] -} - -export interface PreValidatedMessage { - type: string - issuer: string - subject?: string - time?: string - tag?: string - raw: string - verified?: any - custom?: any - meta?: ServiceMetaData[] -} - -export interface ValidatedMessage extends PreValidatedMessage { - hash: string -} - export interface Action { type: string - parentMessage?: ValidatedMessage - parentMessageHash?: string data: any } diff --git a/packages/daf-data-store/src/data-store.ts b/packages/daf-data-store/src/data-store.ts index 1d81b2339..1deb454d2 100644 --- a/packages/daf-data-store/src/data-store.ts +++ b/packages/daf-data-store/src/data-store.ts @@ -1,4 +1,4 @@ -import { Types } from 'daf-core' +import { Message } from 'daf-core' import { DbDriver } from './types' import { runMigrations } from './migrations' import sql from 'sql-bricks-sqlite' @@ -263,33 +263,32 @@ export class DataStore { return shortId } - async saveMessage(message: Types.ValidatedMessage) { - const source_type = message.meta && message.meta[0].sourceType - const source_id = message.meta && message.meta[0].sourceId + async saveMessage(message: Message) { const query = sql .insert('messages', { - hash: message.hash, - iss: message.issuer, - sub: message.subject, - nbf: message.time, + hash: message.id, + iss: message.from, + sub: message.to, + nbf: message.timestamp, type: message.type, - tag: message.tag, + tag: message.threadId, jwt: message.raw, + data: message.data && JSON.stringify(message.data), meta: message.meta && JSON.stringify(message.meta), - source_type, - source_id, + source_type: message.meta.type, + source_id: message.meta.id, }) .toParams() await this.db.run(query.text, query.values) if (message.type == 'w3c.vp' || message.type == 'w3c.vc') { - for (const vc of message.custom.vc) { - await this.saveVerifiableCredential(vc, message.hash) + for (const vc of message.vc) { + await this.saveVerifiableCredential(vc, message.id) } } - return { hash: message.hash, iss: { did: message.issuer } } + return { hash: message.id, iss: { did: message.from } } } async saveVerifiableCredential(vc: any, messageHash: string) { diff --git a/packages/daf-debug/src/message-validator.ts b/packages/daf-debug/src/message-validator.ts index eb9b1c56b..b7ff424c3 100644 --- a/packages/daf-debug/src/message-validator.ts +++ b/packages/daf-debug/src/message-validator.ts @@ -1,14 +1,11 @@ -import { Core, AbstractMessageValidator, Types } from 'daf-core' +import { Core, AbstractMessageValidator, Message } from 'daf-core' import Debug from 'debug' const debug = Debug('message') export class MessageValidator extends AbstractMessageValidator { - async validate( - rawMessage: Types.RawMessage, - core: Core, - ): Promise { - debug('%o', rawMessage) - return super.validate(rawMessage, core) + async validate(message: Message, core: Core): Promise { + debug('%o', message) + return super.validate(message, core) } } diff --git a/packages/daf-did-comm/src/action-handler.ts b/packages/daf-did-comm/src/action-handler.ts index aeb109b24..3a45e742d 100644 --- a/packages/daf-did-comm/src/action-handler.ts +++ b/packages/daf-did-comm/src/action-handler.ts @@ -1,4 +1,4 @@ -import { Core, AbstractActionHandler, Types } from 'daf-core' +import { Core, AbstractActionHandler, Types, Message } from 'daf-core' import { DIDComm } from 'DIDComm-js' import uuid from 'uuid' import Debug from 'debug' @@ -32,29 +32,18 @@ export class ActionHandler extends AbstractActionHandler { debug('Resolving didDoc') const didDoc = await core.didResolver.resolve(data.to) - const service = - didDoc && - didDoc.service && - didDoc.service.find(item => item.type == 'MessagingService') + const service = didDoc && didDoc.service && didDoc.service.find(item => item.type == 'MessagingService') const publicKey = didDoc && didDoc.publicKey && - didDoc.publicKey.find( - item => item.type == 'Curve25519EncryptionPublicKey', - ) + didDoc.publicKey.find(item => item.type == 'Curve25519EncryptionPublicKey') if (service) { try { let body = data.jwt - if ( - publicKey && - publicKey.publicKeyHex && - core.encryptionKeyManager - ) { + if (publicKey && publicKey.publicKeyHex && core.encryptionKeyManager) { await this.didcomm.ready - const senderKeyPair = await core.encryptionKeyManager.getKeyPairForDid( - data.from, - ) + const senderKeyPair = await core.encryptionKeyManager.getKeyPairForDid(data.from) if (senderKeyPair) { const dm = JSON.stringify({ '@type': 'JWT', @@ -78,7 +67,7 @@ export class ActionHandler extends AbstractActionHandler { debug('Status', res.status, res.statusText) if (res.status == 200) { - await core.onRawMessage({ raw: data.jwt }) + await core.validateMessage(new Message({ raw: data.jwt, meta: { type: 'DIDComm-sent' } })) } return res.status == 200 diff --git a/packages/daf-did-comm/src/message-validator.ts b/packages/daf-did-comm/src/message-validator.ts index 2fff5577c..be5bd3193 100644 --- a/packages/daf-did-comm/src/message-validator.ts +++ b/packages/daf-did-comm/src/message-validator.ts @@ -1,4 +1,4 @@ -import { Core, AbstractMessageValidator, Types } from 'daf-core' +import { Core, AbstractMessageValidator, Message } from 'daf-core' import { DIDComm } from 'DIDComm-js' import Debug from 'debug' const debug = Debug('did-comm-message-validator') @@ -11,38 +11,45 @@ export class MessageValidator extends AbstractMessageValidator { this.didcomm = new DIDComm() } - async validate( - rawMessage: Types.RawMessage, - core: Core, - ): Promise { + async validate(message: Message, core: Core): Promise { if (core.encryptionKeyManager) { try { - const parsed = JSON.parse(rawMessage.raw) + const parsed = JSON.parse(message.raw) if (parsed.ciphertext && parsed.protected) { const keyPairs = await core.encryptionKeyManager.listKeyPairs() for (const keyPair of keyPairs) { - const unpacked = await this.didcomm.unpackMessage( - rawMessage.raw, - keyPair, - ) + const unpacked = await this.didcomm.unpackMessage(message.raw, keyPair) if (unpacked.message) { debug('Unpacked for publicKey %s', keyPair.publicKeyHex) debug(unpacked.message) - return super.validate( - { - raw: unpacked.message, - meta: [ - ...rawMessage.meta, - { - sourceType: 'DIDComm', - data: { - raw: rawMessage.raw, - }, - }, - ], - }, - core, - ) + + try { + const json = JSON.parse(unpacked.message) + if (json['@type'] === 'JWT') { + message.transform({ + raw: json.data, + meta: { type: 'DIDComm' }, + }) + } else { + if (json['@id']) message.id = json['@id'] + if (json['@type']) message.type = json['@type'] + message.transform({ + raw: unpacked.message, + data: json, + meta: { type: 'DIDComm' }, + }) + } + return super.validate(message, core) + } catch (e) { + debug(e) + } + + message.transform({ + raw: unpacked.message, + meta: { type: 'DIDComm' }, + }) + + return super.validate(message, core) } } } @@ -50,6 +57,6 @@ export class MessageValidator extends AbstractMessageValidator { // not a JSON string } } - return super.validate(rawMessage, core) + return super.validate(message, core) } } diff --git a/packages/daf-did-jwt/src/index.ts b/packages/daf-did-jwt/src/index.ts index 5f6692408..b15f40ccd 100644 --- a/packages/daf-did-jwt/src/index.ts +++ b/packages/daf-did-jwt/src/index.ts @@ -1 +1 @@ -export { MessageValidator, DidJwtPayloadValidator } from './message-validator' +export { MessageValidator } from './message-validator' diff --git a/packages/daf-did-jwt/src/message-validator.ts b/packages/daf-did-jwt/src/message-validator.ts index 5f2cd2edc..129fef630 100644 --- a/packages/daf-did-jwt/src/message-validator.ts +++ b/packages/daf-did-jwt/src/message-validator.ts @@ -1,64 +1,25 @@ -import { Core, AbstractMessageValidator, Types, Resolver } from 'daf-core' +import { Core, AbstractMessageValidator, Message, Resolver } from 'daf-core' import { verifyJWT, decodeJWT } from 'did-jwt' import Debug from 'debug' const debug = Debug('did-jwt-validator') -export interface DidJwtPayloadValidator { - validate: ( - verifiedJwt: any, - didResolver: Resolver, - ) => Promise -} - -interface Options { - payloadValidators: DidJwtPayloadValidator[] -} - export class MessageValidator extends AbstractMessageValidator { - private payloadValidators: DidJwtPayloadValidator[] - - constructor(options: Options) { - super() - this.payloadValidators = options.payloadValidators - } - - async validate( - rawMessage: Types.RawMessage, - core: Core, - ): Promise { - let jwt = rawMessage.raw - - try { - // This can be DIDComm message '{"@type": "JWT", "data": "..."}' - const json = JSON.parse(rawMessage.raw) - if (json['@type'] === 'JWT') { - jwt = json.data - } - } catch (e) {} - - let verified + async validate(message: Message, core: Core): Promise { try { - const decoded = decodeJWT(jwt) + const decoded = decodeJWT(message.raw) const audience = decoded.payload.aud - verified = await verifyJWT(jwt, { resolver: core.didResolver, audience }) + const verified = await verifyJWT(message.raw, { resolver: core.didResolver, audience }) debug('Valid JWT.') - for (const payloadValidator of this.payloadValidators) { - try { - const validMessage = await payloadValidator.validate( - verified, - core.didResolver, - ) - return { - ...validMessage, - meta: rawMessage.meta, - } - } catch (e) {} - } + message.transform({ + raw: message.raw, + data: verified.payload, + meta: { type: decoded.header.typ, id: decoded.header.alg }, + }) } catch (e) { debug(e.message) } - return super.validate(rawMessage, core) + return super.validate(message, core) } } diff --git a/packages/daf-random/CHANGELOG.md b/packages/daf-random/CHANGELOG.md deleted file mode 100644 index bd81d819c..000000000 --- a/packages/daf-random/CHANGELOG.md +++ /dev/null @@ -1,104 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [0.9.0](https://github.com/uport-project/daf/compare/v0.8.0...v0.9.0) (2019-12-05) - -**Note:** Version bump only for package daf-random - - - - - -# [0.8.0](https://github.com/uport-project/daf/compare/v0.7.8...v0.8.0) (2019-12-04) - -**Note:** Version bump only for package daf-random - - - - - -# [0.7.0](https://github.com/uport-project/daf/compare/v0.6.1...v0.7.0) (2019-11-29) - -**Note:** Version bump only for package daf-random - - - - - -# [0.6.0](https://github.com/uport-project/daf/compare/v0.5.2...v0.6.0) (2019-11-27) - -**Note:** Version bump only for package daf-random - - - - - -## [0.5.1](https://github.com/uport-project/daf/compare/v0.5.0...v0.5.1) (2019-11-26) - -**Note:** Version bump only for package daf-random - - - - - -# [0.5.0](https://github.com/uport-project/daf/compare/v0.4.0...v0.5.0) (2019-11-26) - -**Note:** Version bump only for package daf-random - - - - - -# [0.4.0](https://github.com/uport-project/daf/compare/v0.3.0...v0.4.0) (2019-11-25) - -**Note:** Version bump only for package daf-random - - - - - -# [0.3.0](https://github.com/uport-project/daf/compare/v0.2.0...v0.3.0) (2019-11-24) - -**Note:** Version bump only for package daf-random - - - - - -# [0.2.0](https://github.com/uport-project/daf/compare/v0.1.0...v0.2.0) (2019-11-23) - -**Note:** Version bump only for package daf-random - - - - - -# [0.1.0](https://github.com/uport-project/daf/compare/v0.0.26...v0.1.0) (2019-11-22) - -**Note:** Version bump only for package daf-random - - - - - -## [0.0.26](https://github.com/uport-project/daf/compare/v0.0.25...v0.0.26) (2019-11-22) - -**Note:** Version bump only for package daf-random - - - - - -## [0.0.25](https://github.com/uport-project/daf/compare/v0.0.24...v0.0.25) (2019-11-21) - -**Note:** Version bump only for package daf-random - - - - - -## [0.0.24](https://github.com/uport-project/daf/compare/v0.0.23...v0.0.24) (2019-11-19) - -**Note:** Version bump only for package daf-random diff --git a/packages/daf-random/LICENSE b/packages/daf-random/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/packages/daf-random/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/daf-random/README.md b/packages/daf-random/README.md deleted file mode 100644 index bd0beb615..000000000 --- a/packages/daf-random/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# DAF Random message service - -Useful for testing message handling \ No newline at end of file diff --git a/packages/daf-random/package.json b/packages/daf-random/package.json deleted file mode 100644 index 9bf14d7a3..000000000 --- a/packages/daf-random/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "daf-random", - "description": "DAF Random message service", - "version": "0.9.0", - "main": "build/index.js", - "types": "build/index.d.ts", - "scripts": { - "build": "tsc" - }, - "dependencies": { - "daf-core": "^0.9.0", - "debug": "^4.1.1", - "faker": "^4.1.0" - }, - "devDependencies": { - "@types/debug": "^4.1.5", - "@types/faker": "^4.1.7", - "typescript": "^3.7.2" - }, - "files": [ - "build/**/*", - "src/**/*", - "README.md", - "LICENSE" - ], - "repository": "git@github.com:uport-project/daf.git", - "author": "Simonas Karuzas ", - "license": "Apache-2.0", - "keywords": [], - "gitHead": "ec317e0f10cffe731648a8c2d8f58def3d3c85ff" -} diff --git a/packages/daf-random/src/__tests__/default.test.ts b/packages/daf-random/src/__tests__/default.test.ts deleted file mode 100644 index 5d321ae22..000000000 --- a/packages/daf-random/src/__tests__/default.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -describe('daf-random', () => { - const a = 100 - it('should run a dummy test', () => { - expect(a).toEqual(100) - }) -}) diff --git a/packages/daf-random/src/index.ts b/packages/daf-random/src/index.ts deleted file mode 100644 index 8f01b2666..000000000 --- a/packages/daf-random/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { MessageValidator } from './message-validator' -export { MessageService } from './service-controller' diff --git a/packages/daf-random/src/message-validator.ts b/packages/daf-random/src/message-validator.ts deleted file mode 100644 index bc5ead8f6..000000000 --- a/packages/daf-random/src/message-validator.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AbstractMessageValidator, Types } from 'daf-core' - -export class MessageValidator extends AbstractMessageValidator { - async validate( - rawMessage: Types.RawMessage, - core: any, - ): Promise { - if (rawMessage.meta && rawMessage.meta[0].sourceType == 'random') { - return { - type: 'random', - issuer: 'did:web:example.com', - meta: rawMessage.meta, - raw: rawMessage.raw, - } - } - - return super.validate(rawMessage, core) - } -} diff --git a/packages/daf-random/src/service-controller.ts b/packages/daf-random/src/service-controller.ts deleted file mode 100644 index 8b1b5017e..000000000 --- a/packages/daf-random/src/service-controller.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ServiceController, ServiceControllerOptions } from 'daf-core' -import faker from 'faker' - -export class MessageService implements ServiceController { - private options: ServiceControllerOptions - - constructor(options: ServiceControllerOptions) { - this.options = options - } - - instanceId() { - return { - did: this.options.issuer.did, - sourceType: 'random', - } - } - - async sync(since: number) { - setTimeout(() => { - this.options.onRawMessage({ - raw: `From sync: ${faker.random.words(1)}`, - meta: [ - { - sourceType: this.instanceId().sourceType, - sourceId: faker.random.uuid(), - data: { subject: this.options.issuer.did }, - }, - ], - }) - }, 1000) - - setTimeout(() => { - this.options.onRawMessage({ - raw: `This should throw an error`, - }) - }, 1000) - - // VC - setTimeout(() => { - this.options.onRawMessage({ - raw: `eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzA3MDU0OTMsInN1YiI6ImRpZDpldGhyOjB4NDY0OTcyNWQ5NjE4MGJhODQ0MTVjNDdmMTNlZDUxYWMxOTRhODQxNSIsIm5iZiI6MTU3MDcwNTQ5MywidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJjb21wYW55TmFtZSI6IkRyZWFtIEpvYiBMTEMuIiwic2FsYXJ5IjoiJDEwMCwwMDAiLCJkYXRlT2ZFbXBsb3ltZW50IjoiMjAxOSJ9fSwiaXNzIjoiZGlkOmV0aHI6MHgxM2EyMjcxZWY4ZTE4NTIwMGE1ZTlhYzI3YWE5ODZmZThmMDcwYjVkIn0.5KaBg5qhQWtDHhXWkXHGeCHs43F6zl_LnzVz8g_GsqjfG3Jtkuwrwf_bYIBC-G7ug8UIo_qFSsn5NWSte9iKsQE`, - }) - }, 2000) - - // VP - setTimeout(() => { - this.options.onRawMessage({ - raw: `eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzA3MDU0OTEsInRhZyI6InBhcmVudDozZjE0YmNjNTRlNWRmZTMxYWRkMWYxZGVkZDFmMGFkYWE5ZDgxZjVkODgyZDFiMGQzNWQ0OWRmNWY3MTBhMDkzOWQzNmFhNjg0OTJjZTg5OWYyNmUxNjdmYzVlODljOTQyNGUyMGIwMDA3MWI4NDc4MWIxOGQ4YjhlMDIzZmNmMyIsInN1YiI6ImRpZDpldGhyOjB4MTNhMjI3MWVmOGUxODUyMDBhNWU5YWMyN2FhOTg2ZmU4ZjA3MGI1ZCIsInZwIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwidmVyaWZpYWJsZUNyZWRlbnRpYWwiOlsiZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOa3N0VWlKOS5leUpwWVhRaU9qRTFOekEzTURVME9ERXNJbk4xWWlJNkltUnBaRHBsZEdoeU9qQjRORFkwT1RjeU5XUTVOakU0TUdKaE9EUTBNVFZqTkRkbU1UTmxaRFV4WVdNeE9UUmhPRFF4TlNJc0ltNWlaaUk2TVRVM01EY3dOVFE0TVN3aWRtTWlPbnNpUUdOdmJuUmxlSFFpT2xzaWFIUjBjSE02THk5M2QzY3Vkek11YjNKbkx6SXdNVGd2WTNKbFpHVnVkR2xoYkhNdmRqRWlYU3dpZEhsd1pTSTZXeUpXWlhKcFptbGhZbXhsUTNKbFpHVnVkR2xoYkNKZExDSmpjbVZrWlc1MGFXRnNVM1ZpYW1WamRDSTZleUpqYVhSNVNXUWlPaUpKUmxsRlVGTkpNU0o5ZlN3aWFYTnpJam9pWkdsa09tVjBhSEk2TUhobE5UQTFNR05rT1dNeFpUUXhZemd6TkRReE56WTNNbVF3WWpBeE9UUXdOekl5WXpVME1qZ3dJbjAudDlIQTdPa1ZPTHFsZmN0dVZRYTNrMXJYaDFVOXNfZkw0Tk5nSFJLVFd5dEJDdHFPRjcwSjBaUnJCa3BIUzAyb3dxYVoyZWRtU2NSamE1UjF6YXBNbmdBIiwiZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOa3N0VWlKOS5leUpwWVhRaU9qRTFOekEzTURVME9EZ3NJbk4xWWlJNkltUnBaRHBsZEdoeU9qQjRORFkwT1RjeU5XUTVOakU0TUdKaE9EUTBNVFZqTkRkbU1UTmxaRFV4WVdNeE9UUmhPRFF4TlNJc0ltNWlaaUk2TVRVM01EY3dOVFE0T0N3aWRtTWlPbnNpUUdOdmJuUmxlSFFpT2xzaWFIUjBjSE02THk5M2QzY3Vkek11YjNKbkx6SXdNVGd2WTNKbFpHVnVkR2xoYkhNdmRqRWlYU3dpZEhsd1pTSTZXeUpXWlhKcFptbGhZbXhsUTNKbFpHVnVkR2xoYkNKZExDSmpjbVZrWlc1MGFXRnNVM1ZpYW1WamRDSTZleUp6WTJodmIyeE9ZVzFsSWpvaVZHaGxJRlZ1YVhabGNuTnBkSGtnYjJZZ1ZYQnZjblJzWVc1a2FXRWlMQ0p3Y205bmNtRnRUbUZ0WlNJNklrWnlaVzVqYUNCc2FXNW5kV2x6ZEdsamN5SXNJbWR5WVdSMVlYUnBiMjVaWldGeUlqb2lNakF4T1NJc0ltWnBibUZzUjNKaFpHVnpJam9pUWlzaWZYMHNJbWx6Y3lJNkltUnBaRHBsZEdoeU9qQjROMlZsWldObE9HUTVaakUxTURNME9UVmxOV1V5T1dKaFpHVTBOalkyTURNMk5EUmlOemxpWmlKOS5wUDB6YXlLcnJENmtCamJYN2N5N1F1SVEtcjloQ1ZTejlMc1J3dzRhMVI2bUdBSlZHX3pOYmJEeW05U29vQ0NRaUlPc2U3UUtKNmN6eloxNjdZTWwyQUEiXX0sImlzcyI6ImRpZDpldGhyOjB4NDY0OTcyNWQ5NjE4MGJhODQ0MTVjNDdmMTNlZDUxYWMxOTRhODQxNSJ9.IiZBHVbO6mBcS4FwDHKgFkR_sKe7kH7k8baBgcprAtJUnnFP2-9egBHvy4Mw_QguZxEeZXrhhB1JwqGPczqIcgA`, - }) - }, 3000) - - // SDR - setTimeout(() => { - this.options.onRawMessage({ - raw: `eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzE3MzUwMTEsInN1YiI6ImRpZDpldGhyOjB4NDY0OTcyNWQ5NjE4MGJhODQ0MTVjNDdmMTNlZDUxYWMxOTRhODQxNSIsInR5cGUiOiJzZHIiLCJ2aXNpYmlsaXR5IjoiQk9USCIsImNsYWltcyI6eyJlbWFpbCI6eyJlc3NlbnRpYWwiOmZhbHNlLCJzdWIiOiJkaWQ6ZXRocjoweDQ2NDk3MjVkOTYxODBiYTg0NDE1YzQ3ZjEzZWQ1MWFjMTk0YTg0MTUiLCJpc3MiOlt7ImRpZCI6ImRpZDp3ZWI6dXBvcnQuY2xhaW1zIiwidXJsIjoiaHR0cHM6Ly91cG9ydC5jbGFpbXMvZW1haWwifSx7ImRpZCI6ImRpZDp3ZWI6c29ib2wuaW8iLCJ1cmwiOiJodHRwczovL3NvYm9sLmlvL3ZlcmlmeSJ9XSwicmVhc29uIjoiV2hlIG5lZWQgdG8gYmUgYWJsZSB0byBlbWFpbCB5b3UifSwibmF0aW9uYWxJZGVudGl0eSI6eyJlc3NlbnRpYWwiOnRydWUsInN1YiI6ImRpZDpldGhyOjB4NDY0OTcyNWQ5NjE4MGJhODQ0MTVjNDdmMTNlZDUxYWMxOTRhODQxNSIsImlzcyI6W3siZGlkIjoiZGlkOndlYjppZHZlcmlmaWVyLmNsYWltcyIsInVybCI6Imh0dHBzOi8vaWR2ZXJpZmllci5leGFtcGxlIn1dLCJyZWFzb24iOiJUbyBiZSBhYmxlIHRvIGxlZ2FsbHkgb3BlbiB5b3VyIGFjY291bnQifX0sImlzcyI6ImRpZDpldGhyOjB4OWZkZWU3MjI2OTBjYzVkY2RjOWZkNzA3NTEzMmM0OTQ0MjJjZjU0MiJ9.zebbbIznBqWbAEuHJME3mVHetohQXvbiFwGoWv-7xfo_bol-qHbrxKq7jZazKvHFy7HRy0QIqS2MjjOwkrq-_wA`, - }) - }, 3500) - } - - async init() { - setInterval(() => { - this.options.onRawMessage({ - raw: `From init: ${faker.random.words(4)}`, - meta: [ - { - sourceType: this.instanceId().sourceType, - sourceId: faker.random.uuid(), - data: { subject: this.options.issuer.did }, - }, - ], - }) - }, 4000) - - return true - } -} diff --git a/packages/daf-random/tsconfig.json b/packages/daf-random/tsconfig.json deleted file mode 100644 index 166b53ace..000000000 --- a/packages/daf-random/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig.settings.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "build" - }, - "references": [{ "path": "../daf-core" }] -} diff --git a/packages/daf-selective-disclosure/src/index.ts b/packages/daf-selective-disclosure/src/index.ts index 263ded6fa..b0fc15e39 100644 --- a/packages/daf-selective-disclosure/src/index.ts +++ b/packages/daf-selective-disclosure/src/index.ts @@ -1,4 +1,4 @@ -export { PayloadValidator, MessageTypes } from './payload-validator' +export { MessageValidator, MessageTypes } from './message-validator' export { ActionHandler, ActionTypes, ActionSignSdr, SDRInput, CredentialRequestInput } from './action-handler' import * as Gql from './graphql' export { Gql } diff --git a/packages/daf-selective-disclosure/src/message-validator.ts b/packages/daf-selective-disclosure/src/message-validator.ts new file mode 100644 index 000000000..28b67c722 --- /dev/null +++ b/packages/daf-selective-disclosure/src/message-validator.ts @@ -0,0 +1,27 @@ +import { Core, AbstractMessageValidator, Message } from 'daf-core' + +import Debug from 'debug' +const debug = Debug('daf:sdr-validator') + +export const MessageTypes = { + sdr: 'sdr', +} + +export class MessageValidator extends AbstractMessageValidator { + async validate(message: Message, core: Core): Promise { + const { type, id } = message.meta + + if (type === 'JWT' && id === 'ES256K-R' && message.data.type == MessageTypes.sdr && message.data.claims) { + debug('JWT type is', MessageTypes.sdr) + + message.type = MessageTypes.sdr + message.from = message.data.iss + message.to = message.data.sub + message.threadId = message.data.tag + message.timestamp = message.data.nbf || message.data.iat + return message + } + + return super.validate(message, core) + } +} diff --git a/packages/daf-selective-disclosure/src/payload-validator.ts b/packages/daf-selective-disclosure/src/payload-validator.ts deleted file mode 100644 index 8cafb921a..000000000 --- a/packages/daf-selective-disclosure/src/payload-validator.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { DidJwtPayloadValidator } from 'daf-did-jwt' -import { Types, Resolver } from 'daf-core' - -import Debug from 'debug' -const debug = Debug('sdr-validator') - -export const MessageTypes = { - sdr: 'sdr', -} - -export class PayloadValidator implements DidJwtPayloadValidator { - async validate(verifiedJwt: any, didResolver: Resolver): Promise { - const p = verifiedJwt.payload - if (p.type == MessageTypes.sdr && p.claims) { - debug('JWT type is', MessageTypes.sdr) - - return { - type: MessageTypes.sdr, - raw: verifiedJwt.jwt, - issuer: verifiedJwt.payload.iss, - subject: verifiedJwt.payload.sub, - time: verifiedJwt.payload.iat, - tag: verifiedJwt.payload.tag, - verified: verifiedJwt, - } - } else { - return Promise.reject() - } - } -} diff --git a/packages/daf-trust-graph/src/action-handler.ts b/packages/daf-trust-graph/src/action-handler.ts index d65f77a8a..0c638d4ea 100644 --- a/packages/daf-trust-graph/src/action-handler.ts +++ b/packages/daf-trust-graph/src/action-handler.ts @@ -1,4 +1,4 @@ -import { Core, AbstractActionHandler, Types } from 'daf-core' +import { Core, AbstractActionHandler, Types, Message } from 'daf-core' import { defaultTrustGraphUri, defaultTrustGraphWsUri } from './config' import Debug from 'debug' @@ -35,13 +35,8 @@ export class ActionHandler extends AbstractActionHandler { debug('Resolving didDoc') const didDoc = await core.didResolver.resolve(data.to) - const service = - didDoc && - didDoc.service && - didDoc.service.find(item => item.type == 'TrustGraph') - const serviceEndpoint = service - ? service.serviceEndpoint - : defaultTrustGraphUri + const service = didDoc && didDoc.service && didDoc.service.find(item => item.type == 'TrustGraph') + const serviceEndpoint = service ? service.serviceEndpoint : defaultTrustGraphUri const uri = (this.options && this.options.uri) || serviceEndpoint try { @@ -50,8 +45,7 @@ export class ActionHandler extends AbstractActionHandler { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - query: - 'mutation addEdge($edgeJWT: String!) { addEdge(edgeJWT: $edgeJWT) { hash }}', + query: 'mutation addEdge($edgeJWT: String!) { addEdge(edgeJWT: $edgeJWT) { hash }}', variables: { edgeJWT: data.jwt }, }), }) @@ -59,7 +53,7 @@ export class ActionHandler extends AbstractActionHandler { debug('Status', res.status, res.statusText) if (res.status == 200) { - await core.onRawMessage({ raw: data.jwt }) + await core.validateMessage(new Message({ raw: data.jwt, meta: { type: 'trustGraph', id: uri } })) } return res.status == 200 diff --git a/packages/daf-trust-graph/src/service-controller.ts b/packages/daf-trust-graph/src/service-controller.ts index 77ba3e1e2..ca9b1d935 100644 --- a/packages/daf-trust-graph/src/service-controller.ts +++ b/packages/daf-trust-graph/src/service-controller.ts @@ -10,6 +10,7 @@ import { SubscriptionClient } from 'subscriptions-transport-ws' import { ServiceController, ServiceControllerOptions, ServiceInstanceId } from 'daf-core' import * as queries from './queries' +import * as Daf from 'daf-core' import { defaultTrustGraphUri, defaultTrustGraphWsUri } from './config' import Debug from 'debug' @@ -123,21 +124,21 @@ export class TrustGraphServiceController implements ServiceController { }) for (const edge of data.findEdges) { - await this.options.onRawMessage({ - raw: edge.jwt, - meta: [ - { - sourceType: this.instanceId().sourceType, - sourceId: this.uri, + await this.options.validateMessage( + new Daf.Message({ + raw: edge.jwt, + meta: { + type: this.instanceId().sourceType, + id: this.uri, }, - ], - }) + }), + ) } } async init() { - const { options, wsUri } = this - const sourceType = this.instanceId().sourceType + const { options, wsUri, uri } = this + const type = this.instanceId().sourceType if (wsUri) { debug('Subscribing to edgeAdded for', options.issuer.did) @@ -149,15 +150,12 @@ export class TrustGraphServiceController implements ServiceController { }) .subscribe({ async next(result) { - options.onRawMessage({ - raw: result.data.edgeAdded.jwt, - meta: [ - { - sourceType, - sourceId: wsUri, - }, - ], - }) + options.validateMessage( + new Daf.Message({ + raw: result.data.edgeAdded.jwt, + meta: { type, id: uri }, + }), + ) }, error(err) { debug('Error', err) diff --git a/packages/daf-w3c/src/index.ts b/packages/daf-w3c/src/index.ts index ad0fcadc3..d26e19936 100644 --- a/packages/daf-w3c/src/index.ts +++ b/packages/daf-w3c/src/index.ts @@ -1,9 +1,4 @@ -export { PayloadValidator, MessageTypes } from './payload-validator' -export { - ActionHandler, - ActionTypes, - ActionSignW3cVp, - ActionSignW3cVc, -} from './action-handler' +export { MessageValidator, MessageTypes } from './message-validator' +export { ActionHandler, ActionTypes, ActionSignW3cVp, ActionSignW3cVc } from './action-handler' import * as Gql from './graphql' export { Gql } diff --git a/packages/daf-w3c/src/message-validator.ts b/packages/daf-w3c/src/message-validator.ts new file mode 100644 index 000000000..55a1158c4 --- /dev/null +++ b/packages/daf-w3c/src/message-validator.ts @@ -0,0 +1,59 @@ +import { Core, AbstractMessageValidator, Message } from 'daf-core' + +import { + verifyCredential, + validateVerifiableCredentialAttributes, + validatePresentationAttributes, +} from 'did-jwt-vc' + +import Debug from 'debug' +const debug = Debug('w3c-validator') + +export const MessageTypes = { + vc: 'w3c.vc', + vp: 'w3c.vp', +} + +export class MessageValidator extends AbstractMessageValidator { + async validate(message: Message, core: Core): Promise { + const { type, id } = message.meta + + if (type === 'JWT' && id === 'ES256K-R') { + try { + validatePresentationAttributes(message.data) + + debug('JWT is', MessageTypes.vp) + + const vc = await Promise.all( + message.data.vp.verifiableCredential.map((vcJwt: string) => + verifyCredential(vcJwt, core.didResolver), + ), + ) + + message.type = MessageTypes.vp + message.from = message.data.iss + message.to = message.data.aud + message.threadId = message.data.tag + message.timestamp = message.data.nbf || message.data.iat + message.vc = vc + + return message + } catch (e) {} + + try { + validateVerifiableCredentialAttributes(message.data) + debug('JWT is', MessageTypes.vc) + + message.type = MessageTypes.vc + message.from = message.data.iss + message.to = message.data.sub + message.threadId = message.data.tag + message.timestamp = message.data.nbf || message.data.iat + message.vc = [{ payload: message.data, jwt: message.raw }] + return message + } catch (e) {} + } + + return super.validate(message, core) + } +} diff --git a/packages/daf-w3c/src/payload-validator.ts b/packages/daf-w3c/src/payload-validator.ts deleted file mode 100644 index 919087517..000000000 --- a/packages/daf-w3c/src/payload-validator.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { DidJwtPayloadValidator } from 'daf-did-jwt' -import { Types, Resolver } from 'daf-core' -import { - verifyCredential, - validateVerifiableCredentialAttributes, - validatePresentationAttributes, -} from 'did-jwt-vc' - -import Debug from 'debug' -const debug = Debug('w3c-validator') - -export const MessageTypes = { - vc: 'w3c.vc', - vp: 'w3c.vp', -} - -export class PayloadValidator implements DidJwtPayloadValidator { - async validate(verifiedJwt: any, didResolver: Resolver): Promise { - try { - validatePresentationAttributes(verifiedJwt.payload) - - debug('JWT is', MessageTypes.vp) - - const vc = await Promise.all( - verifiedJwt.payload.vp.verifiableCredential.map((vcJwt: string) => - verifyCredential(vcJwt, didResolver), - ), - ) - - return { - type: MessageTypes.vp, - raw: verifiedJwt.jwt, - issuer: verifiedJwt.payload.iss, - subject: verifiedJwt.payload.aud, - tag: verifiedJwt.payload.tag, - time: verifiedJwt.payload.nbf || verifiedJwt.payload.iat, - verified: verifiedJwt, - custom: { - vc, - }, - } - } catch (e) {} - - try { - validateVerifiableCredentialAttributes(verifiedJwt.payload) - debug('JWT is', MessageTypes.vc) - return { - type: MessageTypes.vc, - raw: verifiedJwt.jwt, - issuer: verifiedJwt.payload.iss, - subject: verifiedJwt.payload.sub, - tag: verifiedJwt.payload.tag, - time: verifiedJwt.payload.nbf || verifiedJwt.payload.iat, - verified: verifiedJwt, - custom: { - vc: [verifiedJwt], - }, - } - } catch (e) {} - - return Promise.reject() - } -}