Skip to content

Instantly share code, notes, and snippets.

@dlongley
Created May 10, 2024 19:18
Show Gist options
  • Save dlongley/93c0ba17b25e500d72c1ad131fe7e869 to your computer and use it in GitHub Desktop.
Save dlongley/93c0ba17b25e500d72c1ad131fe7e869 to your computer and use it in GitHub Desktop.
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