Skip to content

Commit

Permalink
Merge pull request #13 from blockchain-certificates/feat/more-integra…
Browse files Browse the repository at this point in the history
…tion-with-jsonld

Feat/more integration with jsonld
  • Loading branch information
Julien Fraichot authored Feb 12, 2021
2 parents cd16f04 + 5e28dbd commit f9ce6ad
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 14 deletions.
11 changes: 6 additions & 5 deletions src/MerkleProof2019.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface VCDocument {

export interface MerkleProof2019API {
options?: MerkleProof2019Options;
type?: 'MerkleProof2019';
type?: 'MerkleProof2019' | string;
issuer?: any; // TODO: define issuer type
verificationMethod?: string;
document: VCDocument;
Expand Down Expand Up @@ -74,6 +74,7 @@ export class MerkleProof2019 extends (LinkedDataProof as any) {
throw new Error('A document signed by MerkleProof2019 is required for the verification process.');
}

this.type = type;
this.issuer = issuer;
this.verificationMethod = verificationMethod;
this.document = document;
Expand All @@ -92,12 +93,12 @@ export class MerkleProof2019 extends (LinkedDataProof as any) {
this.proof = base58Decoder.decode();
}

async verifyProof (): Promise<MerkleProof2019VerificationResult> {
async verifyProof ({ documentLoader } = { documentLoader: (url): any => {} }): Promise<MerkleProof2019VerificationResult> {
let verified: boolean;
let error: string = '';
try {
this.validateTransactionId();
await this.computeLocalHash();
await this.computeLocalHash(documentLoader);
await this.fetchTransactionData();
this.compareHashes();
this.confirmMerkleRoot();
Expand All @@ -120,8 +121,8 @@ export class MerkleProof2019 extends (LinkedDataProof as any) {
ensureHashesEqual(this.localDocumentHash, this.proof.targetHash);
}

private async computeLocalHash (): Promise<void> {
this.localDocumentHash = await computeLocalHash(this.document);
private async computeLocalHash (documentLoader): Promise<void> {
this.localDocumentHash = await computeLocalHash(this.document, documentLoader);
}

private getChain (): void {
Expand Down
21 changes: 16 additions & 5 deletions src/inspectors/computeLocalHash.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import jsonld from 'jsonld';
import JsonLdError from 'jsonld/lib/JsonLdError';
import sha256 from 'sha256';
import { CONTEXTS as ContextsMap } from '../constants/contexts';
import { toUTF8Data } from '../utils/data';
Expand Down Expand Up @@ -28,7 +29,7 @@ function setJsonLdDocumentLoader (): any { // not typed by jsonld
return jsonld.documentLoaders.node();
}

export default async function computeLocalHash (document: any): Promise<string> { // TODO: define VC type
export default async function computeLocalHash (document: any, documentLoader = (url: string): any => null): Promise<string> { // TODO: define VC type
const expandContext = document['@context'];
const theDocument = JSON.parse(JSON.stringify(document));

Expand All @@ -38,7 +39,12 @@ export default async function computeLocalHash (document: any): Promise<string>
}

const jsonldDocumentLoader = setJsonLdDocumentLoader();
const customLoader = function (url, callback): any { // Not typed by JSONLD
const customLoader = async function (url, callback): Promise<any> { // Not typed by JSONLD
const context = await documentLoader(url);
if (context) {
return callback(null, context);
}

if (url in CONTEXTS) {
return callback(null, {
contextUrl: null,
Expand All @@ -57,12 +63,17 @@ export default async function computeLocalHash (document: any): Promise<string>
normalizeArgs.expandContext = expandContext;
}

return new Promise((resolve, reject) => {
jsonld.normalize(theDocument, normalizeArgs, (err, normalized) => {
return await new Promise((resolve, reject) => {
jsonld.normalize(theDocument, normalizeArgs, (err: JsonLdError, normalized) => {
const isErr = !!err;
if (isErr) {
console.log('error', err);
reject(
new Error(`Failed to normalize document: ${err as string}`)
new JsonLdError(
'Failed to normalize document',
err.name,
err.details
)
);
} else {
resolve(sha256(toUTF8Data(normalized)));
Expand Down
16 changes: 16 additions & 0 deletions tests/MerkleProof2019.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ describe('MerkleProof2019 test suite', function () {
});
});

describe('given the type is passed', function () {
it('should register the type', function () {
const fixtureType: string = 'fixtureType';
const instance = new MerkleProof2019({ type: fixtureType, document: blockcertsV3Fixture });
expect(instance.type).toBe(fixtureType);
});
});

describe('verifyProof method', function () {
describe('when the process is successful', function () {
let result: MerkleProof2019VerificationResult;
Expand Down Expand Up @@ -105,6 +113,14 @@ describe('MerkleProof2019 test suite', function () {
error: ''
});
});

describe('and it is called with a documentLoader', function () {
it('should call the documentLoader method', async function () {
const stubLoader: sinon.SinonStub = sinon.stub().resolves(null);
await instance.verifyProof({ documentLoader: stubLoader });
expect(stubLoader.callCount > 0).toBe(true);
});
});
});
});

Expand Down
31 changes: 27 additions & 4 deletions tests/inspectors/computeLocalHash.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sinon from 'sinon';
import jsonld from 'jsonld';
import JsonLdError from 'jsonld/lib/JsonLdError';
import blockcertsV3Fixture, { documentHash } from '../fixtures/blockcerts-v3';
import computeLocalHash from '../../src/inspectors/computeLocalHash';

Expand All @@ -11,19 +12,41 @@ describe('computeLocalHash test suite', function () {
});
});

describe('given it is provided with a documentLoader', function () {
it('should call the documentLoader', async function () {
const stubLoader = sinon.stub().resolves(null);
await computeLocalHash(blockcertsV3Fixture, stubLoader);
expect(stubLoader.callCount > 0).toBe(true);
});
});

describe('given the normalization of the document fails', function () {
it('should reject with an error', async function () {
const mockJsonLdError: JsonLdError = {
message: 'Failed',
name: 'jsonld.InvalidUrl',
details: {
code: 'loading document failed',
url: 'https://blockcerts.org/credentials/v1',
httpStatusCode: 404
}
};
const normalizeStub: sinon.SinonStub = sinon.stub(jsonld, 'normalize')
.callsFake(
function (fakeDoc: any, fakeArgs: any, cb: (err: string, document: any) => any) {
function (fakeDoc: any, fakeArgs: any, cb: (err: JsonLdError, document: any) => any) {
// https://github.com/standard/standard/issues/1352 silly people trying to be too smart
// eslint-disable-next-line standard/no-callback-literal
cb('This is an error', {});
cb(mockJsonLdError, {});
}
);
await expect(async () => {

try {
await computeLocalHash(blockcertsV3Fixture);
}).rejects.toThrow('Failed to normalize document: This is an error');
} catch (e) {
expect(e.message).toBe('Failed to normalize document');
expect(e.name).toBe(mockJsonLdError.name);
expect(e.details).toEqual(mockJsonLdError.details);
}
normalizeStub.restore();
});
});
Expand Down

0 comments on commit f9ce6ad

Please sign in to comment.