Skip to content

Commit

Permalink
support for nested selective disclosure (#109)
Browse files Browse the repository at this point in the history
Support for nested selective disclosure by using a flattened content model.  This PR also has a breaking change on `createPresentation` call. 
**not supported** - selective disclosure of array values

- refactored the function signature to accept an options object. This would allow you to easily omit specific properties and make the function more extensible in the future.

```
interface CreatePresentationOptions {
  document: IDocument;
  signCallback: SignCallback;
  selectedAttributes?: string[];
  challenge?: string;
}
```
Modified  createPresentation function:
```
export async function createPresentation({
  document,
  signCallback,
  selectedAttributes = [],
  challenge,
}: CreatePresentationOptions): Promise<IDocumentPresentation> {
  // ... (rest of the function remains unchanged)
}
```
We can now call the function with just the properties you need. It makes the call more readable and easily extensible.

```
const presentation = await createPresentation({
    document: document,
    signCallback: async ({ data }) => ({
      signature: holderKeys.authentication.sign(data),
      keyType: holderKeys.authentication.type,
      keyUri: `${holderDid.uri}${holderDid.authentication[0].id}`,
    }),
    // selectedAttributes: ['name', 'id', 'address.pin', 'address.location', 'address'],
    challenge: challenge
});
```

In the call above, we can easily omit selectedAttributes. If you want to include selectedAttributes, you can add that property to the options object.

This structure allows for much cleaner function calls, especially when a function has several parameters, and some of them are optional. We should refactor other calls to follow this model.
  • Loading branch information
smohan-dw authored Aug 9, 2023
1 parent 517f839 commit 05ca9dd
Show file tree
Hide file tree
Showing 12 changed files with 375 additions and 295 deletions.
174 changes: 88 additions & 86 deletions demo/src/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import { generateRequestCredentialMessage } from './utils/request_credential_mes
import { getChainCredits, addAuthority } from './utils/createAuthorities'
import { createAccount } from './utils/createAccount'

import type {
SignCallback,
// DocumenentMetaData,
} from '@cord.network/types'
// import type {
// SignCallback,
// // DocumenentMetaData,
// } from '@cord.network/types'

function getChallenge(): string {
return Cord.Utils.UUID.generate()
Expand Down Expand Up @@ -94,26 +94,23 @@ async function main() {
await createDid(authorIdentity)
const delegateOneKeys = generateKeypairs(delegateOneMnemonic)
console.log(
`🏛 Delegate (${delegateOneDid?.assertionMethod![0].type}): ${
delegateOneDid.uri
`🏛 Delegate (${delegateOneDid?.assertionMethod![0].type}): ${delegateOneDid.uri
}`
)
// Create Delegate Two DID
const { mnemonic: delegateTwoMnemonic, document: delegateTwoDid } =
await createDid(authorIdentity)
const delegateTwoKeys = generateKeypairs(delegateTwoMnemonic)
console.log(
`🏛 Delegate (${delegateTwoDid?.assertionMethod![0].type}): ${
delegateTwoDid.uri
`🏛 Delegate (${delegateTwoDid?.assertionMethod![0].type}): ${delegateTwoDid.uri
}`
)
// Create Delegate 3 DID
const { mnemonic: delegate3Mnemonic, document: delegate3Did } =
await createDid(authorIdentity)
const delegate3Keys = generateKeypairs(delegate3Mnemonic)
console.log(
`🏛 Delegate (${delegate3Did?.assertionMethod![0].type}): ${
delegate3Did.uri
`🏛 Delegate (${delegate3Did?.assertionMethod![0].type}): ${delegate3Did.uri
}`
)
console.log('✅ Identities created!')
Expand Down Expand Up @@ -208,13 +205,13 @@ async function main() {
schema,
registryDelegate,
registry.identifier,
callBackFn
callBackFn
)
console.dir(document, {
depth: null,
colors: true,
})
let x = await createStream(
await createStream(
delegateTwoDid.uri,
authorIdentity,
async ({ data }) => ({
Expand All @@ -225,69 +222,71 @@ async function main() {
)
console.log('✅ Credential created!')

console.log('🖍️ Stream update...')
let newContent: any = {
name: 'Adi',
age: 23,
id: '123456789987654311',
gender: 'Male',
country: 'India',
}

const updatedDocument = await Cord.Document.updateStream(
document,
newContent,
schema,
callBackFn,
{}
)
console.log('🔖 Document after the updation\n', updatedDocument)

console.log('⚓ Anchoring the updated document on the blockchain...')
const api = Cord.ConfigService.get('api')
const { streamHash } = Cord.Stream.fromDocument(updatedDocument)
const authorization = Cord.Registry.uriToIdentifier(
updatedDocument.authorization
)
const streamTx = api.tx.stream.update(
updatedDocument.identifier.replace('stream:cord:', ''),
// updatedDocument.identifier,
streamHash,
authorization
)
// console.log('🖍️ Stream update...')
// let newContent: any = {
// name: 'Adi',
// age: 23,
// id: '123456789987654311',
// gender: 'Male',
// country: 'India',
// }
//
// const updatedDocument = await Cord.Document.updateStream(
// document,
// newContent,
// schema,
// callBackFn,
// {}
// )
// console.log('🔖 Document after the updation\n', updatedDocument)
//
// console.log('⚓ Anchoring the updated document on the blockchain...')
// const api = Cord.ConfigService.get('api')
// const { streamHash } = Cord.Stream.fromDocument(updatedDocument)
// const authorization = Cord.Registry.uriToIdentifier(
// updatedDocument.authorization
// )
// const streamTx = api.tx.stream.update(
// updatedDocument.identifier.replace('stream:cord:', ''),
// // updatedDocument.identifier,
// streamHash,
// authorization
// )
//
// const authorizedStreamTx = await Cord.Did.authorizeTx(
// delegateTwoDid.uri,
// streamTx,
// async ({ data }) => ({
// signature: delegateTwoKeys.assertionMethod.sign(data),
// keyType: delegateTwoKeys.assertionMethod.type,
// }),
// authorIdentity.address
// )
// try {
// await Cord.Chain.signAndSubmitTx(authorizedStreamTx, authorIdentity)
// }
// catch (e) {
// console.log('Error: \n', e.message)
// }
//

const authorizedStreamTx = await Cord.Did.authorizeTx(
delegateTwoDid.uri,
streamTx,
async ({ data }) => ({
signature: delegateTwoKeys.assertionMethod.sign(data),
keyType: delegateTwoKeys.assertionMethod.type,
}),
authorIdentity.address
)
try{
await Cord.Chain.signAndSubmitTx(authorizedStreamTx, authorIdentity)
}
catch(e) {
console.log('Error: \n',e.message)
}




// Step 5: Create a Presentation
console.log(`\n❄️ Presentation Creation `)
console.log(`\n❄️ Selective Disclosure Presentation Creation `)
const challenge = getChallenge()
const presentation = await createPresentation(
updatedDocument,
async ({ data }) => ({
const presentation = await createPresentation({
document: document,
signCallback: async ({ data }) => ({
signature: holderKeys.authentication.sign(data),
keyType: holderKeys.authentication.type,
keyUri: `${holderDid.uri}${holderDid.authentication[0].id}`,
}),
['name', 'id'],
challenge
)
// Comment the below line to have a full disclosure
selectedAttributes: ['name', 'id', 'address.pin', 'address.location',],
challenge: challenge
});

console.dir(presentation, {
depth: null,
colors: true,
Expand All @@ -302,30 +301,33 @@ async function main() {
})

if (isValid) {
console.log('✅ 301 :Verification successful! 🎉')
console.log('✅ Verification successful! 🎉')
} else {
console.log('✅ 301 :Verification failed! 🚫')
console.log('✅ Verification failed! 🚫')
}

console.log(`\n❄️ Messaging `)
const schemaId = Cord.Schema.idToChain(schema.$id)
console.log(' Generating the message - Sender -> Receiver')
const message = await generateRequestCredentialMessage(
holderDid.uri,
verifierDid.uri,
schemaId
)

console.log(' Encrypting the message - Sender -> Receiver')
const encryptedMessage = await encryptMessage(
message,
holderDid.uri,
verifierDid.uri,
holderKeys.keyAgreement
)
// Uncomment the following section to enable messaging demo
//
// console.log(`\n❄️ Messaging `)
// const schemaId = Cord.Schema.idToChain(schema.$id)
// console.log(' Generating the message - Sender -> Receiver')
// const message = await generateRequestCredentialMessage(
// holderDid.uri,
// verifierDid.uri,
// schemaId
// )
//
// console.log(' Encrypting the message - Sender -> Receiver')
// const encryptedMessage = await encryptMessage(
// message,
// holderDid.uri,
// verifierDid.uri,
// holderKeys.keyAgreement
// )
//
// console.log(' Decrypting the message - Receiver')
// await decryptMessage(encryptedMessage, verifierKeys.keyAgreement)

console.log(' Decrypting the message - Receiver')
await decryptMessage(encryptedMessage, verifierKeys.keyAgreement)

// Step 7: Revoke a Credential
console.log(`\n❄️ Revoke credential - ${document.identifier}`)
Expand Down
6 changes: 5 additions & 1 deletion demo/src/utils/createDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ export async function createDocument(
country: 'India',
address: {
street: 'a',
pin: 54032
pin: 54032,
location: {
state: 'karnataka',
country: 'india'
}
}
},
holder,
Expand Down
30 changes: 23 additions & 7 deletions demo/src/utils/createPresentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,33 @@ import * as Cord from '@cord.network/sdk'
* @param {string} [challenge] - A challenge string that will be signed by the user's private key.
* @returns A promise that resolves to a document presentation.
*/
export async function createPresentation(
document: Cord.IDocument,
signCallback: Cord.SignCallback,
selectedAttributes?: string[],
challenge?: string
): Promise<Cord.IDocumentPresentation> {
export async function createPresentation({
document,
signCallback,
selectedAttributes = [],
challenge,
}: Cord.PresentationOptions): Promise<Cord.IDocumentPresentation> {
// Create a presentation with only the specified fields revealed, if specified.
return Cord.Document.createPresentation({
document,
signCallback,
selectedAttributes,
challenge,
})
});
}


// export async function createPresentation(
// document,
// signCallback: Cord.SignCallback,
// selectedAttributes?: string[],
// challenge?: string
// ): Promise<Cord.IDocumentPresentation> {
// // Create a presentation with only the specified fields revealed, if specified.
// return Cord.Document.createPresentation({
// document,
// signCallback,
// selectedAttributes,
// challenge,
// })
// }
Loading

0 comments on commit 05ca9dd

Please sign in to comment.