Skip to content

Commit

Permalink
Add ability to create and sign basic VCs
Browse files Browse the repository at this point in the history
  • Loading branch information
sondreb committed Nov 30, 2022
1 parent 8b770d8 commit 5b019d8
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 11 deletions.
2 changes: 1 addition & 1 deletion examples/did-configuration.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"@context": "https://identity.foundation/.well-known/did-configuration/v1",
"linked_dids": [
"eyJraWQiOiJkaWQ6aXM6ZGQ2ZjRjZjNiMThhOGM2NmJmMzJiMzVhZGUxNWQxMDkyYTM2NmZjNzFlZDhkODEzOTVlOTI2OGVhOGMzNWZjNSNrZXkwIiwiYWxnIjoiRVMyNTZLIiwidHlwIjoiSldUIn0.eyJpYXQiOjE2NjkxNDg3MzUsImV4cCI6MjE0NzQ4MzY0NywidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL2lkZW50aXR5LmZvdW5kYXRpb24vLndlbGwta25vd24vZGlkLWNvbmZpZ3VyYXRpb24vdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkRvbWFpbkxpbmthZ2VDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmlzOmRkNmY0Y2YzYjE4YThjNjZiZjMyYjM1YWRlMTVkMTA5MmEzNjZmYzcxZWQ4ZDgxMzk1ZTkyNjhlYThjMzVmYzUiLCJvcmlnaW4iOiJodHRzOi8vbG9jYWxob3N0OjQyNTAifX0sIm5iZiI6MTY2OTE0ODczNSwic3ViIjoiZGlkOmlzOmRkNmY0Y2YzYjE4YThjNjZiZjMyYjM1YWRlMTVkMTA5MmEzNjZmYzcxZWQ4ZDgxMzk1ZTkyNjhlYThjMzVmYzUiLCJpc3MiOiJkaWQ6aXM6ZGQ2ZjRjZjNiMThhOGM2NmJmMzJiMzVhZGUxNWQxMDkyYTM2NmZjNzFlZDhkODEzOTVlOTI2OGVhOGMzNWZjNSJ9.tCCmgPcapltHD-J_T2I0kBujvHQ2du_0dMS1m2GATTz2dVa8zg7SbL6WrrIaaXtgYzF71bA7ZIDU-jfY7zOceA"
"eyJraWQiOiJkaWQ6aXM6ZGQ2ZjRjZjNiMThhOGM2NmJmMzJiMzVhZGUxNWQxMDkyYTM2NmZjNzFlZDhkODEzOTVlOTI2OGVhOGMzNWZjNSNrZXkwIiwiYWxnIjoiRVMyNTZLIiwidHlwIjoiSldUIn0.eyJpYXQiOjE2Njk4MjE2NjMsImV4cCI6MjE0NzQ4MzY0NywidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL2lkZW50aXR5LmZvdW5kYXRpb24vLndlbGwta25vd24vZGlkLWNvbmZpZ3VyYXRpb24vdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkRvbWFpbkxpbmthZ2VDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmlzOmRkNmY0Y2YzYjE4YThjNjZiZjMyYjM1YWRlMTVkMTA5MmEzNjZmYzcxZWQ4ZDgxMzk1ZTkyNjhlYThjMzVmYzUiLCJvcmlnaW4iOiJodHRzOi8vbG9jYWxob3N0OjQyNTAifX0sIm5iZiI6MTY2OTgyMTY2Mywic3ViIjoiZGlkOmlzOmRkNmY0Y2YzYjE4YThjNjZiZjMyYjM1YWRlMTVkMTA5MmEzNjZmYzcxZWQ4ZDgxMzk1ZTkyNjhlYThjMzVmYzUiLCJpc3MiOiJkaWQ6aXM6ZGQ2ZjRjZjNiMThhOGM2NmJmMzJiMzVhZGUxNWQxMDkyYTM2NmZjNzFlZDhkODEzOTVlOTI2OGVhOGMzNWZjNSJ9.YHFiAQw6qP2UFnjTWu-JI0jgSn0jN4y_GlJy3Um4tZJ1vwlH0FftS7xGACOOomaUQvMjf-Myht_cbqjda72_mw"
]
}
2 changes: 1 addition & 1 deletion examples/did-configuration2.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"@context": "https://identity.foundation/.well-known/did-configuration/v1",
"linked_dids": [
"eyJraWQiOiJkaWQ6aXM6MGYyNTRlNTVhMjYzM2Q0NjhlOTJhYTdkZDVhNzZjMGM5MTAxZmFiOGUyODJjOGMyMGIzZmVmZGUwZDY4ZjIxNyNrZXkwIiwiYWxnIjoiRVMyNTZLIiwidHlwIjoiSldUIn0.eyJpYXQiOjE2NjkxNDg3MzUsImV4cCI6MjE0NzQ4MzY0NywidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL2lkZW50aXR5LmZvdW5kYXRpb24vLndlbGwta25vd24vZGlkLWNvbmZpZ3VyYXRpb24vdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkRvbWFpbkxpbmthZ2VDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmlzOjBmMjU0ZTU1YTI2MzNkNDY4ZTkyYWE3ZGQ1YTc2YzBjOTEwMWZhYjhlMjgyYzhjMjBiM2ZlZmRlMGQ2OGYyMTciLCJvcmlnaW4iOiJodHRzOi8vbG9jYWxob3N0OjQyNTEifX0sIm5iZiI6MTY2OTE0ODczNSwic3ViIjoiZGlkOmlzOjBmMjU0ZTU1YTI2MzNkNDY4ZTkyYWE3ZGQ1YTc2YzBjOTEwMWZhYjhlMjgyYzhjMjBiM2ZlZmRlMGQ2OGYyMTciLCJpc3MiOiJkaWQ6aXM6MGYyNTRlNTVhMjYzM2Q0NjhlOTJhYTdkZDVhNzZjMGM5MTAxZmFiOGUyODJjOGMyMGIzZmVmZGUwZDY4ZjIxNyJ9.tLBGGai_IRHN2QF0mzpc-odsJo-jpO_wKi8rpwbAaSI5SvscLis35J8CAvCegQ00Ir58iu1PwpQBXU-8JZXnaA"
"eyJraWQiOiJkaWQ6aXM6MGYyNTRlNTVhMjYzM2Q0NjhlOTJhYTdkZDVhNzZjMGM5MTAxZmFiOGUyODJjOGMyMGIzZmVmZGUwZDY4ZjIxNyNrZXkwIiwiYWxnIjoiRVMyNTZLIiwidHlwIjoiSldUIn0.eyJpYXQiOjE2Njk4MjE2NjMsImV4cCI6MjE0NzQ4MzY0NywidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL2lkZW50aXR5LmZvdW5kYXRpb24vLndlbGwta25vd24vZGlkLWNvbmZpZ3VyYXRpb24vdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkRvbWFpbkxpbmthZ2VDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmlzOjBmMjU0ZTU1YTI2MzNkNDY4ZTkyYWE3ZGQ1YTc2YzBjOTEwMWZhYjhlMjgyYzhjMjBiM2ZlZmRlMGQ2OGYyMTciLCJvcmlnaW4iOiJodHRzOi8vbG9jYWxob3N0OjQyNTEifX0sIm5iZiI6MTY2OTgyMTY2Mywic3ViIjoiZGlkOmlzOjBmMjU0ZTU1YTI2MzNkNDY4ZTkyYWE3ZGQ1YTc2YzBjOTEwMWZhYjhlMjgyYzhjMjBiM2ZlZmRlMGQ2OGYyMTciLCJpc3MiOiJkaWQ6aXM6MGYyNTRlNTVhMjYzM2Q0NjhlOTJhYTdkZDVhNzZjMGM5MTAxZmFiOGUyODJjOGMyMGIzZmVmZGUwZDY4ZjIxNyJ9.6JcejON57gO7xqlk4xIVlT76kF9sjcdJuq1fS9bv6l7spUtIj8IYPOFhnCM269ch8fgOvLehHHrfR9L7ARosZQ"
]
}
30 changes: 30 additions & 0 deletions examples/vc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"header": {
"kid": "did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217#key0",
"alg": "ES256K",
"typ": "JWT"
},
"payload": {
"iat": 1669821664,
"exp": 2147483647,
"vc": {
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": [
"VerifiableCredential",
"EmailVerification"
],
"credentialSubject": {
"id": "did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217",
"sameAs": "mail@mail.com"
}
},
"nbf": 1669821664,
"sub": "did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217",
"jti": "123",
"iss": "did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217"
},
"signature": "_BXoFYsrROeh7N3T4HbTWO8Io7nQrPQFUKNQTQ9BODIpmfYNT4gna4XMqSr5Ex7KZFod9xJodoRHE91Te6OBOA",
"data": "eyJraWQiOiJkaWQ6aXM6MGYyNTRlNTVhMjYzM2Q0NjhlOTJhYTdkZDVhNzZjMGM5MTAxZmFiOGUyODJjOGMyMGIzZmVmZGUwZDY4ZjIxNyNrZXkwIiwiYWxnIjoiRVMyNTZLIiwidHlwIjoiSldUIn0.eyJpYXQiOjE2Njk4MjE2NjQsImV4cCI6MjE0NzQ4MzY0NywidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkVtYWlsVmVyaWZpY2F0aW9uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmlzOjBmMjU0ZTU1YTI2MzNkNDY4ZTkyYWE3ZGQ1YTc2YzBjOTEwMWZhYjhlMjgyYzhjMjBiM2ZlZmRlMGQ2OGYyMTciLCJzYW1lQXMiOiJtYWlsQG1haWwuY29tIn19LCJuYmYiOjE2Njk4MjE2NjQsInN1YiI6ImRpZDppczowZjI1NGU1NWEyNjMzZDQ2OGU5MmFhN2RkNWE3NmMwYzkxMDFmYWI4ZTI4MmM4YzIwYjNmZWZkZTBkNjhmMjE3IiwianRpIjoiMTIzIiwiaXNzIjoiZGlkOmlzOjBmMjU0ZTU1YTI2MzNkNDY4ZTkyYWE3ZGQ1YTc2YzBjOTEwMWZhYjhlMjgyYzhjMjBiM2ZlZmRlMGQ2OGYyMTcifQ"
}
50 changes: 50 additions & 0 deletions src/__tests__/examples.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,53 @@ test('Generate Examples', async () => {
save('did-document-operation-replace-6.txt', replacement);
save('did-document-operation-replace-6.json', JSON.stringify(decodeJWT(replacement), null, 2));
});

test('Generate Verifiable Credential', async () => {
const tool = new BlockcoreIdentityTools();
const privateKey = Uint8Array.from([
224, 238, 59, 150, 73, 84, 228, 234, 104, 62, 83, 160, 122, 31, 108, 129, 74, 29, 104, 195, 192, 81, 158, 11, 167,
100, 217, 121, 110, 12, 178, 14,
]);

const signer = tool.getSigner(privateKey);
const publicKey = tool.getPublicKeyFromPrivateKey(privateKey);
const verificationMethod = tool.getVerificationMethod(publicKey);
const identity = new BlockcoreIdentity(verificationMethod);

const kid = `${verificationMethod.controller}${verificationMethod.id}`;
const issuer = tool.getIssuer(identity.did, privateKey);

const vc = await identity.verifiableCredential(
{ id: 'did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217', sameAs: 'mail@mail.com' },
issuer,
kid,
'123',
'EmailVerification',
);

console.log(vc);

expect(vc != null).toBeTruthy();

save('vc.json', JSON.stringify(decodeJWT(vc), null, 2));

// const didDocument = identity.document({
// service: [
// {
// id: '#blockexplorer',
// type: 'BlockExplorer',
// serviceEndpoint: 'https://explorer.blockcore.net',
// },
// ],
// });

// expect(didDocument != null).toBeTruthy();

// // The default pattern for key identifier is #key{keyIndex}.
// const kid = didDocument.id + '#key0';
// const jws = await identity.sign(
// signer,
// { version: 0, iat: tool.getTimestampInSeconds(), didDocument: didDocument },
// kid,
// );
});
50 changes: 50 additions & 0 deletions src/__tests__/vc.test.ts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { OperationCanceledException } from 'typescript';
import { BlockcoreIdentityTools, BlockcoreIdentity } from '../index';

test('Create Verifiable Credentials', async () => {
const tool = new BlockcoreIdentityTools();
const privateKey = Uint8Array.from([
224, 238, 59, 150, 73, 84, 228, 234, 104, 62, 83, 160, 122, 31, 108, 129, 74, 29, 104, 195, 192, 81, 158, 11, 167,
100, 217, 121, 110, 12, 178, 14,
]);

const signer = tool.getSigner(privateKey);
const publicKey = tool.getPublicKeyFromPrivateKey(privateKey);
const verificationMethod = tool.getVerificationMethod(publicKey);
const identity = new BlockcoreIdentity(verificationMethod);

const kid = `${verificationMethod.controller}${verificationMethod.id}`;
const issuer = tool.getIssuer(identity.did, privateKey);

const vc = await identity.verifiableCredential(
{ id: 'did:is:0f254e55a2633d468e92aa7dd5a76c0c9101fab8e282c8c20b3fefde0d68f217', sameAs: 'mail@mail.com' },
issuer,
kid,
'123',
'EmailVerification',
);

console.log(vc);

expect(vc != null).toBeTruthy();

// const didDocument = identity.document({
// service: [
// {
// id: '#blockexplorer',
// type: 'BlockExplorer',
// serviceEndpoint: 'https://explorer.blockcore.net',
// },
// ],
// });

// expect(didDocument != null).toBeTruthy();

// // The default pattern for key identifier is #key{keyIndex}.
// const kid = didDocument.id + '#key0';
// const jws = await identity.sign(
// signer,
// { version: 0, iat: tool.getTimestampInSeconds(), didDocument: didDocument },
// kid,
// );
});
40 changes: 31 additions & 9 deletions src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,28 @@ export class BlockcoreIdentity {

/** Generates a well known configuration for DID resolver host. */
public async configurationVerifiableCredential(domain: string, issuer: any, kid: string) {
return this.verifiableCredential(
{
id: this.did,
origin: domain,
},
issuer,
kid,
null,
'DomainLinkageCredential',
'https://identity.foundation/.well-known/did-configuration/v1',
);
}

/** Generates a well known configuration for DID resolver host. */
public async verifiableCredential(
claim: any,
issuer: any,
kid: string,
id: string | undefined | null,
type: string,
context: string | undefined | null = undefined,
) {
const date = new Date();
const expiredate = new Date(new Date().setFullYear(date.getFullYear() + 100));
let expiredateNumber = Math.floor(expiredate.getTime() / 1000);
Expand All @@ -76,21 +98,21 @@ export class BlockcoreIdentity {
nbf: currentDateNumber,
sub: this.did,
vc: {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://identity.foundation/.well-known/did-configuration/v1',
],
type: ['VerifiableCredential', 'DomainLinkageCredential'],
credentialSubject: {
id: this.did,
origin: domain,
},
'@context': context
? ['https://www.w3.org/2018/credentials/v1', context]
: ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiableCredential', type],
credentialSubject: claim,
//"expirationDate": expiredate.toISOString(),
//"issuanceDate": date.toISOString(),
//"issuer": this.id,
},
};

if (id) {
vcPayload.jti = id;
}

const vcJwt = await createVerifiableCredentialJwt(vcPayload, issuer, { header: { kid: kid } });

return vcJwt;
Expand Down

0 comments on commit 5b019d8

Please sign in to comment.