Skip to content

Commit

Permalink
feat: Message object with validation
Browse files Browse the repository at this point in the history
  • Loading branch information
simonas-notcat committed Dec 9, 2019
1 parent d185517 commit 8bf6a9d
Show file tree
Hide file tree
Showing 41 changed files with 547 additions and 842 deletions.
123 changes: 123 additions & 0 deletions docs/MessageValidator.md
Original file line number Diff line number Diff line change
@@ -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
```
10 changes: 5 additions & 5 deletions examples/expressjs-ethr/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 7 additions & 7 deletions examples/expressjs-ethr/src/web-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
}
})
}
Expand Down
1 change: 0 additions & 1 deletion examples/expressjs-ethr/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down
56 changes: 28 additions & 28 deletions examples/expressjs-ethr/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -677,18 +677,18 @@ 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"
graphql-tag "^2.10.1"
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"
Expand Down
5 changes: 3 additions & 2 deletions packages/daf-cli/src/credential.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
15 changes: 7 additions & 8 deletions packages/daf-cli/src/msg.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as Daf from 'daf-core'
import { core } from './setup'
import program from 'commander'

Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions packages/daf-cli/src/sdr.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions packages/daf-cli/src/services.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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)
})

Expand Down
Loading

0 comments on commit 8bf6a9d

Please sign in to comment.