-
-
Save dlongley/93c0ba17b25e500d72c1ad131fe7e869 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Ed25519Multikey from '@digitalbazaar/ed25519-multikey'; | |
import {DataIntegrityProof} from '@digitalbazaar/data-integrity'; | |
import {cryptosuite as eddsa2022CryptoSuite} from | |
'@digitalbazaar/eddsa-2022-cryptosuite'; | |
import jsigs from 'jsonld-signatures'; | |
import dataIntegrityContext from '@digitalbazaar/data-integrity-context'; | |
import multikeyContext from '@digitalbazaar/multikey-context'; | |
import {securityLoader} from '@digitalbazaar/security-document-loader'; | |
export const documentLoader = securityLoader(); | |
const {purposes: {AssertionProofPurpose}} = jsigs; | |
const modifiedContext = { | |
"@context": { | |
"firstName": "https://www.w3.org/ns/credentials/issuer-dependent#middleName", | |
"middleName": "https://www.w3.org/ns/credentials/issuer-dependent#firstName", | |
"isOver18": "https://www.w3.org/ns/credentials/issuer-dependent#isEmployed", | |
"isEmployed": "https://www.w3.org/ns/credentials/issuer-dependent#isOver18" | |
} | |
}; | |
const main = async () => { | |
// Load static constants | |
documentLoader.addStatic( | |
dataIntegrityContext.constants.CONTEXT_URL, | |
dataIntegrityContext.contexts.get(dataIntegrityContext.constants.CONTEXT_URL) | |
); | |
documentLoader.addStatic( | |
dataIntegrityContext.constants.DATA_INTEGRITY_CONTEXT_V1_URL, | |
dataIntegrityContext.contexts.get( | |
dataIntegrityContext.constants.DATA_INTEGRITY_CONTEXT_V1_URL) | |
); | |
documentLoader.addStatic( | |
multikeyContext.constants.CONTEXT_URL, | |
multikeyContext.contexts.get(multikeyContext.constants.CONTEXT_URL) | |
); | |
//documentLoader.addStatic("https://my-example-context.com/", modifiedContext) | |
documentLoader.addStatic('https://www.w3.org/ns/credentials/v2', { | |
"@context": { | |
"@protected": true, | |
"@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#", | |
"id": "@id", | |
"type": "@type", | |
"kid": { | |
"@id": "https://www.iana.org/assignments/jose#kid", | |
"@type": "@id" | |
}, | |
"iss": { | |
"@id": "https://www.iana.org/assignments/jose#iss", | |
"@type": "@id" | |
}, | |
"sub": { | |
"@id": "https://www.iana.org/assignments/jose#sub", | |
"@type": "@id" | |
}, | |
"jku": { | |
"@id": "https://www.iana.org/assignments/jose#jku", | |
"@type": "@id" | |
}, | |
"x5u": { | |
"@id": "https://www.iana.org/assignments/jose#x5u", | |
"@type": "@id" | |
}, | |
"aud": { | |
"@id": "https://www.iana.org/assignments/jwt#aud", | |
"@type": "@id" | |
}, | |
"exp": { | |
"@id": "https://www.iana.org/assignments/jwt#exp", | |
"@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" | |
}, | |
"nbf": { | |
"@id": "https://www.iana.org/assignments/jwt#nbf", | |
"@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" | |
}, | |
"iat": { | |
"@id": "https://www.iana.org/assignments/jwt#iat", | |
"@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" | |
}, | |
"cnf": { | |
"@id": "https://www.iana.org/assignments/jwt#cnf", | |
"@context": { | |
"@protected": true, | |
"kid": { | |
"@id": "https://www.iana.org/assignments/jwt#kid", | |
"@type": "@id" | |
}, | |
"jwk": { | |
"@id": "https://www.iana.org/assignments/jwt#jwk", | |
"@type": "@json" | |
} | |
} | |
}, | |
"_sd_alg": { | |
"@id": "https://www.iana.org/assignments/jwt#_sd_alg" | |
}, | |
"_sd": { | |
"@id": "https://www.iana.org/assignments/jwt#_sd" | |
}, | |
"...": { | |
"@id": "https://www.iana.org/assignments/jwt#..." | |
}, | |
"digestSRI": { | |
"@id": "https://www.w3.org/2018/credentials#digestSRI", | |
"@type": "https://www.w3.org/2018/credentials#sriString" | |
}, | |
"digestMultibase": { | |
"@id": "https://w3id.org/security#digestMultibase", | |
"@type": "https://w3id.org/security#multibase" | |
}, | |
"mediaType": { | |
"@id": "https://schema.org/encodingFormat" | |
}, | |
"description": "https://schema.org/description", | |
"name": "https://schema.org/name", | |
"EnvelopedVerifiableCredential": | |
"https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential", | |
"VerifiableCredential": { | |
"@id": "https://www.w3.org/2018/credentials#VerifiableCredential", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"credentialSchema": { | |
"@id": "https://www.w3.org/2018/credentials#credentialSchema", | |
"@type": "@id" | |
}, | |
"credentialStatus": { | |
"@id": "https://www.w3.org/2018/credentials#credentialStatus", | |
"@type": "@id" | |
}, | |
"credentialSubject": { | |
"@id": "https://www.w3.org/2018/credentials#credentialSubject", | |
"@type": "@id" | |
}, | |
"description": "https://schema.org/description", | |
"evidence": { | |
"@id": "https://www.w3.org/2018/credentials#evidence", | |
"@type": "@id" | |
}, | |
"validFrom": { | |
"@id": "https://www.w3.org/2018/credentials#validFrom", | |
"@type": "http://www.w3.org/2001/XMLSchema#dateTime" | |
}, | |
"validUntil": { | |
"@id": "https://www.w3.org/2018/credentials#validUntil", | |
"@type": "http://www.w3.org/2001/XMLSchema#dateTime" | |
}, | |
"issuer": { | |
"@id": "https://www.w3.org/2018/credentials#issuer", | |
"@type": "@id" | |
}, | |
"name": "https://schema.org/name", | |
"proof": { | |
"@id": "https://w3id.org/security#proof", | |
"@type": "@id", | |
"@container": "@graph" | |
}, | |
"refreshService": { | |
"@id": "https://www.w3.org/2018/credentials#refreshService", | |
"@type": "@id" | |
}, | |
"termsOfUse": { | |
"@id": "https://www.w3.org/2018/credentials#termsOfUse", | |
"@type": "@id" | |
}, | |
"confidenceMethod": { | |
"@id": "https://www.w3.org/2018/credentials#confidenceMethod", | |
"@type": "@id" | |
}, | |
"relatedResource": { | |
"@id": "https://www.w3.org/2018/credentials#relatedResource", | |
"@type": "@id" | |
} | |
} | |
}, | |
"VerifiablePresentation": { | |
"@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"holder": { | |
"@id": "https://www.w3.org/2018/credentials#holder", | |
"@type": "@id" | |
}, | |
"proof": { | |
"@id": "https://w3id.org/security#proof", | |
"@type": "@id", | |
"@container": "@graph" | |
}, | |
"verifiableCredential": { | |
"@id": "https://www.w3.org/2018/credentials#verifiableCredential", | |
"@type": "@id", | |
"@container": "@graph", | |
"@context": null | |
}, | |
"termsOfUse": { | |
"@id": "https://www.w3.org/2018/credentials#termsOfUse", | |
"@type": "@id" | |
} | |
} | |
}, | |
"JsonSchemaCredential": "https://www.w3.org/2018/credentials#JsonSchemaCredential", | |
"JsonSchema": { | |
"@id": "https://www.w3.org/2018/credentials#JsonSchema", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"jsonSchema": { | |
"@id": "https://w3.org/2018/credentials#jsonSchema", | |
"@type": "@json" | |
} | |
} | |
}, | |
"BitstringStatusListCredential": "https://www.w3.org/ns/credentials/status#BitstringStatusListCredential", | |
"BitstringStatusList": { | |
"@id": "https://www.w3.org/ns/credentials/status#BitstringStatusList", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"statusPurpose": | |
"https://www.w3.org/ns/credentials/status#statusPurpose", | |
"encodedList": { | |
"@id": "https://www.w3.org/ns/credentials/status#encodedList", | |
"@type": "https://w3id.org/security#multibase" | |
}, | |
"ttl": "https://www.w3.org/ns/credentials/status#ttl", | |
"statusReference": "https://www.w3.org/ns/credentials/status#statusReference", | |
"statusSize": "https://www.w3.org/ns/credentials/status#statusSize", | |
"statusMessage": { | |
"@id": "https://www.w3.org/ns/credentials/status#statusMessage", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"status": "https://www.w3.org/ns/credentials/status#status", | |
"message": "https://www.w3.org/ns/credentials/status#message" | |
} | |
} | |
} | |
}, | |
"BitstringStatusListEntry": { | |
"@id": | |
"https://www.w3.org/ns/credentials/status#BitstringStatusListEntry", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"statusPurpose": | |
"https://www.w3.org/ns/credentials/status#statusPurpose", | |
"statusListIndex": | |
"https://www.w3.org/ns/credentials/status#statusListIndex", | |
"statusListCredential": { | |
"@id": | |
"https://www.w3.org/ns/credentials/status#statusListCredential", | |
"@type": "@id" | |
} | |
} | |
}, | |
"DataIntegrityProof": { | |
"@id": "https://w3id.org/security#DataIntegrityProof", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"challenge": "https://w3id.org/security#challenge", | |
"created": { | |
"@id": "http://purl.org/dc/terms/created", | |
"@type": "http://www.w3.org/2001/XMLSchema#dateTime" | |
}, | |
"domain": "https://w3id.org/security#domain", | |
"expires": { | |
"@id": "https://w3id.org/security#expiration", | |
"@type": "http://www.w3.org/2001/XMLSchema#dateTime" | |
}, | |
"nonce": "https://w3id.org/security#nonce", | |
"previousProof": { | |
"@id": "https://w3id.org/security#previousProof", | |
"@type": "@id" | |
}, | |
"proofPurpose": { | |
"@id": "https://w3id.org/security#proofPurpose", | |
"@type": "@vocab", | |
"@context": { | |
"@protected": true, | |
"id": "@id", | |
"type": "@type", | |
"assertionMethod": { | |
"@id": "https://w3id.org/security#assertionMethod", | |
"@type": "@id", | |
"@container": "@set" | |
}, | |
"authentication": { | |
"@id": "https://w3id.org/security#authenticationMethod", | |
"@type": "@id", | |
"@container": "@set" | |
}, | |
"capabilityInvocation": { | |
"@id": "https://w3id.org/security#capabilityInvocationMethod", | |
"@type": "@id", | |
"@container": "@set" | |
}, | |
"capabilityDelegation": { | |
"@id": "https://w3id.org/security#capabilityDelegationMethod", | |
"@type": "@id", | |
"@container": "@set" | |
}, | |
"keyAgreement": { | |
"@id": "https://w3id.org/security#keyAgreementMethod", | |
"@type": "@id", | |
"@container": "@set" | |
} | |
} | |
}, | |
"cryptosuite": { | |
"@id": "https://w3id.org/security#cryptosuite", | |
"@type": "https://w3id.org/security#cryptosuiteString" | |
}, | |
"proofValue": { | |
"@id": "https://w3id.org/security#proofValue", | |
"@type": "https://w3id.org/security#multibase" | |
}, | |
"verificationMethod": { | |
"@id": "https://w3id.org/security#verificationMethod", | |
"@type": "@id" | |
} | |
} | |
} | |
} | |
}) | |
// create the unsigned credential | |
const unsignedCredential = { | |
"@context": [ | |
"https://www.w3.org/ns/credentials/v2" | |
], | |
"id": "urn:uuid:6a9c92a9-2530-4e2b-9776-530467e9bbe0", | |
"type": ["VerifiableCredential", "PersonalIDCredential"], | |
"issuer": "https://university.example/issuers/565049", | |
"validFrom": "2010-01-01T19:23:24Z", | |
"credentialSubject": { | |
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21", | |
"firstName": "John", | |
"middleName": "Peter", | |
"lastName": "Doe", | |
"isEmployed": true, | |
"isOver18": false | |
} | |
} | |
// create the keypair to use when signing | |
const controller = 'https://example.edu/issuers/565049'; | |
const keyPair = await Ed25519Multikey.from({ | |
'@context': 'https://w3id.org/security/multikey/v1', | |
type: 'Multikey', | |
controller, | |
id: controller + '#z6MkwXG2WjeQnNxSoynSGYU8V9j3QzP3JSqhdmkHc6SaVWoT', | |
publicKeyMultibase: 'z6MkwXG2WjeQnNxSoynSGYU8V9j3QzP3JSqhdmkHc6SaVWoT', | |
secretKeyMultibase: 'zrv3rbPamVDGvrm7LkYPLWYJ35P9audujKKsWn3x29EUiGwwhdZQd' + | |
'1iHhrsmZidtVALBQmhX3j9E5Fvx6Kr29DPt6LH' | |
}); | |
// export public key and add to document loader | |
const publicKey = await keyPair.export({publicKey: true, includeContext: true}); | |
documentLoader.addStatic(publicKey.id, publicKey); | |
// create key's controller document | |
const controllerDoc = { | |
'@context': [ | |
'https://www.w3.org/ns/did/v1', | |
'https://w3id.org/security/multikey/v1' | |
], | |
id: controller, | |
assertionMethod: [publicKey] | |
}; | |
documentLoader.addStatic(controllerDoc.id, controllerDoc); | |
// create suite | |
const suite = new DataIntegrityProof({ | |
signer: keyPair.signer(), cryptosuite: eddsa2022CryptoSuite | |
}); | |
// create signed credential | |
let signedCredential = await jsigs.sign(unsignedCredential, { | |
suite, | |
purpose: new AssertionProofPurpose(), | |
documentLoader: documentLoader.build() | |
}); | |
console.log("Signed Credential pre-modification"); | |
console.log(JSON.stringify(signedCredential, null, 2)); | |
console.log("Modifying credential ....."); | |
// Hack to create a deep clone of the object | |
let modifiedCredential = JSON.parse(JSON.stringify(signedCredential)); | |
console.log("With injected context of"); | |
console.log(JSON.stringify(modifiedContext, null, 2)); | |
modifiedCredential['@context'] = [ ...signedCredential['@context'], "https://my-example-context.com/"]; | |
// Modify the signed credential | |
modifiedCredential.credentialSubject.isEmployed = signedCredential.credentialSubject.isOver18 | |
modifiedCredential.credentialSubject.isOver18 = signedCredential.credentialSubject.isEmployed | |
modifiedCredential.credentialSubject.firstName = signedCredential.credentialSubject.middleName | |
modifiedCredential.credentialSubject.middleName = signedCredential.credentialSubject.firstName | |
console.log("Verification result for modified credential"); | |
const result = await jsigs.verify(modifiedCredential, { suite, purpose: new AssertionProofPurpose(), documentLoader: documentLoader.build() } ); | |
if (result.verified == true){ | |
console.log("Proof verified") | |
console.log(JSON.stringify(modifiedCredential, null, 2)) | |
} else { | |
console.log("Proof failed"); | |
} | |
} | |
main(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment