UNPKG

ula-vc-data-management

Version:
286 lines (256 loc) 13.8 kB
/* * Copyright 2020 Coöperatieve Rabobank U.A. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as chai from 'chai' import * as sinon from 'sinon' import * as sinonChai from 'sinon-chai' import * as chaiAsPromised from 'chai-as-promised' import { VerifiableCredentialRepository } from '../../../src' import { DataStorageMock } from '../../mock/data-storage-mock' import { CredentialStatus, IProof, IVerifiableCredential, VerifiableCredential } from 'vp-toolkit-models' const testProof: IProof = { type: 'Secp256k1Signature2019', created: new Date('01-01-2019 12:34:00'), verificationMethod: 'pubkey', nonce: '71512644-2f4f-4bb9-9c9d-9f5e1fc9a1d2' } const testCredParams: IVerifiableCredential = { id: 'did:protocol:address', type: ['VerifiableCredential'], issuer: 'did:protocol:issueraddress', issuanceDate: new Date('01-01-2019 12:00:00'), credentialSubject: { id: 'did:protocol:holderaddress', 'https://schema.org/givenName': 'John' }, proof: testProof, credentialStatus: new CredentialStatus({ id: '0x6AbAAFB672f60C16C604A29426aDA1Af9d96d440', type: 'vcStatusRegistry2019' }), '@context': ['https://schema.org/givenName'] } before(() => { chai.should() chai.use(sinonChai) chai.use(chaiAsPromised) }) describe('Verifiable Credential repository', function () { const dataStorage = new DataStorageMock() const vcRepoDataKey = 'verifiable_credential' const sut = new VerifiableCredentialRepository(dataStorage) afterEach(() => { sinon.restore() }) it('should return the correct items for findByContext', () => { // Arranging and fake data to be returned from stub const firstCredential = new VerifiableCredential(testCredParams) const secondCredentialParams = Object.assign({}, testCredParams) secondCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error secondCredentialParams.proof.nonce = '4ccbcbc5-84aa-4d6a-a80b-7bb42dd7e5dc' secondCredentialParams['@context'] = ['https://schema.org/familyName', 'https://schema.org/address'] const secondCredential = new VerifiableCredential(secondCredentialParams) const thirdCredentialParams = Object.assign({}, testCredParams) thirdCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error thirdCredentialParams.proof.nonce = '19167bb6-879a-4a50-8d4e-84df59cf823e' thirdCredentialParams['@context'] = undefined const thirdCredential = new VerifiableCredential(thirdCredentialParams) // Arranging stub & calls const dataStubGet = sinon.stub(dataStorage, 'get') .onCall(0).resolves([ testProof.nonce, secondCredential.proof.nonce, thirdCredential.proof.nonce ]) .onCall(1).resolves(firstCredential.toJSON()) .onCall(2).resolves(secondCredential.toJSON()) .onCall(3).resolves(thirdCredential.toJSON()) // Act return sut.findByContext(/schema\.org\/givenname/i).then((value) => { // Assert const expectedFirstCredential = new VerifiableCredential(firstCredential.toJSON() as IVerifiableCredential) return value.should.deep.equal([expectedFirstCredential]) && dataStubGet.getCalls().length.should.be.equal(4) && dataStubGet.getCalls()[0].should.have.been.calledWithExactly(vcRepoDataKey) && dataStubGet.getCalls()[1].should.have.been.calledWithExactly(testProof.nonce) && dataStubGet.getCalls()[2].should.have.been.calledWithExactly(secondCredential.proof.nonce) && dataStubGet.getCalls()[3].should.have.been.calledWithExactly(thirdCredential.proof.nonce) }) }) it('should return the correct items for findByCredentialSubject', () => { // Arranging and fake data to be returned from stub const firstCredential = new VerifiableCredential(testCredParams) const secondCredentialParams = Object.assign({}, testCredParams) secondCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error secondCredentialParams.proof.nonce = '4ccbcbc5-84aa-4d6a-a80b-7bb42dd7e5dc' secondCredentialParams.credentialSubject = { 'https://schema.org/familyName': '', 'https://schema.org/address': '' } const secondCredential = new VerifiableCredential(secondCredentialParams) const thirdCredentialParams = Object.assign({}, testCredParams) thirdCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error thirdCredentialParams.proof.nonce = '19167bb6-879a-4a50-8d4e-84df59cf823e' thirdCredentialParams.credentialSubject = {} const thirdCredential = new VerifiableCredential(thirdCredentialParams) // Arranging stub & calls const dataStubGet = sinon.stub(dataStorage, 'get') .onCall(0).resolves([ testProof.nonce, secondCredential.proof.nonce, thirdCredential.proof.nonce ]) .onCall(1).resolves(firstCredential.toJSON()) .onCall(2).resolves(secondCredential.toJSON()) .onCall(3).resolves(thirdCredential.toJSON()) // Act return sut.findByCredentialSubject(/schema\.org\/givenname/i).then((value) => { // Assert const expectedFirstCredential = new VerifiableCredential(firstCredential.toJSON() as IVerifiableCredential) return value.should.deep.equal([expectedFirstCredential]) && dataStubGet.getCalls().length.should.be.equal(4) && dataStubGet.getCalls()[0].should.have.been.calledWithExactly(vcRepoDataKey) && dataStubGet.getCalls()[1].should.have.been.calledWithExactly(testProof.nonce) && dataStubGet.getCalls()[2].should.have.been.calledWithExactly(secondCredential.proof.nonce) && dataStubGet.getCalls()[3].should.have.been.calledWithExactly(thirdCredential.proof.nonce) }) }) it('should return the correct items for findByIssuer', () => { // Arranging and fake data to be returned from stub const firstCredential = new VerifiableCredential(testCredParams) const secondCredentialParams = Object.assign({}, testCredParams) secondCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error secondCredentialParams.proof.nonce = '4ccbcbc5-84aa-4d6a-a80b-7bb42dd7e5dc' secondCredentialParams.issuer = 'issuerTwo' const secondCredential = new VerifiableCredential(secondCredentialParams) const thirdCredentialParams = Object.assign({}, testCredParams) thirdCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error thirdCredentialParams.proof.nonce = '19167bb6-879a-4a50-8d4e-84df59cf823e' secondCredentialParams.issuer = 'issuerThree' const thirdCredential = new VerifiableCredential(thirdCredentialParams) // Arranging stub & calls const dataStubGet = sinon.stub(dataStorage, 'get') .onCall(0).resolves([ testProof.nonce, secondCredential.proof.nonce, thirdCredential.proof.nonce ]) .onCall(1).resolves(firstCredential.toJSON()) .onCall(2).resolves(secondCredential.toJSON()) .onCall(3).resolves(thirdCredential.toJSON()) // Act return sut.findByIssuer('issuerTwo').then((value) => { // Assert const expectedSecondCredential = new VerifiableCredential(secondCredential.toJSON() as IVerifiableCredential) return value.should.deep.equal([expectedSecondCredential]) && dataStubGet.getCalls().length.should.be.equal(4) && dataStubGet.getCalls()[0].should.have.been.calledWithExactly(vcRepoDataKey) && dataStubGet.getCalls()[1].should.have.been.calledWithExactly(testProof.nonce) && dataStubGet.getCalls()[2].should.have.been.calledWithExactly(secondCredential.proof.nonce) && dataStubGet.getCalls()[3].should.have.been.calledWithExactly(thirdCredential.proof.nonce) }) }) it('should return the correct array for findAll', () => { // Arranging and fake data to be returned from stub const firstCredential = new VerifiableCredential(testCredParams) const secondCredentialParams = Object.assign({}, testCredParams) secondCredentialParams.proof = Object.assign({}, testProof) // To prevent TS2532 error secondCredentialParams.proof.nonce = '4ccbcbc5-84aa-4d6a-a80b-7bb42dd7e5dc' const secondCredential = new VerifiableCredential(secondCredentialParams) const dataResult = [firstCredential, secondCredential] // Arranging stub & calls const dataStubGet = sinon.stub(dataStorage, 'get') .onFirstCall().resolves([testProof.nonce, secondCredential.proof.nonce]) .onSecondCall().resolves(dataResult[0].toJSON()) .onThirdCall().resolves(dataResult[1].toJSON()) // Act return sut.findAll().then((value) => { // Assert const expectedDataResult = dataResult.map(cred => { return new VerifiableCredential(cred.toJSON() as IVerifiableCredential) }) return value.should.deep.equal(expectedDataResult) && dataStubGet.getCalls().length.should.be.equal(3) && dataStubGet.getCalls()[0].should.have.been.calledWithExactly(vcRepoDataKey) && dataStubGet.getCalls()[1].should.have.been.calledWithExactly(testProof.nonce) && dataStubGet.getCalls()[2].should.have.been.calledWithExactly(secondCredential.proof.nonce) }) }) it('should return an empty array for findAll when storage is not initialized', () => { const dataStubGet = sinon.stub(dataStorage, 'get').resolves(undefined) // Undefined storage return sut.findAll().then((value) => { return value.should.deep.equal([]) && dataStubGet.should.have.been.calledOnceWithExactly(vcRepoDataKey) }) }) it('should throw when trying to find a single VC by a non-existing uuid', () => { const dataStubGet = sinon.stub(dataStorage, 'get').resolves(undefined) // Unknown item const nonce = '177c9547-1db5-4188-b98c-fdac93bd51ca' const findAction = sut.findOneByNonce(nonce) dataStubGet.should.have.been.calledOnceWithExactly(nonce) return findAction.should.have.been.rejectedWith('No verifiable credential found') }) it('should overwrite one verifiable credential properly', () => { const vc = new VerifiableCredential(testCredParams) const dataStubSet = sinon.stub(dataStorage, 'set') const dataStubGet = sinon.stub(dataStorage, 'get').resolves([testProof.nonce]) return sut.saveOne(vc).then(() => { return dataStubGet.should.have.been.calledOnceWithExactly(vcRepoDataKey) && dataStubSet.should.have.been.calledOnceWithExactly(testProof.nonce, vc.toJSON()) }) }) it('should save one verifiable credential properly', () => { const vc = new VerifiableCredential(testCredParams) const dataStubSet = sinon.stub(dataStorage, 'set') const dataStubGet = sinon.stub(dataStorage, 'get').resolves([]) return sut.saveOne(vc).then(() => { return dataStubGet.should.have.been.calledOnceWithExactly(vcRepoDataKey) && dataStubSet.getCalls().length.should.be.equal(2) && dataStubSet.getCalls()[0].should.have.been.calledWithExactly(testProof.nonce, vc.toJSON()) && dataStubSet.getCalls()[1].should.have.been.calledWithExactly(vcRepoDataKey, [testProof.nonce]) }) }) it('should clear all verifiable credentials properly', () => { const nonce1 = '4f73efa2-8849-4cd4-9b2c-7e2796c8f08f' const nonce2 = 'b2577f61-b358-44d0-a1c2-951d7d5f7f03' const dataStubGet = sinon.stub(dataStorage, 'get').resolves([nonce1, nonce2]) const dataStubRemove = sinon.stub(dataStorage, 'remove') return sut.clearAll().then(() => { sinon.assert.calledWithExactly(dataStubRemove.getCall(0), nonce1) sinon.assert.calledWithExactly(dataStubRemove.getCall(1), nonce2) sinon.assert.calledWithExactly(dataStubRemove.getCall(2), vcRepoDataKey) return dataStubGet.should.have.been.calledOnceWithExactly(vcRepoDataKey) && dataStubRemove.callCount.should.be.equal(3) }) }) it('should save multiple verifiable credential properly', () => { const credsToSave = [new VerifiableCredential(testCredParams), new VerifiableCredential(testCredParams)] const dataStubSet = sinon.stub(dataStorage, 'set') const dataStubGet = sinon.stub(dataStorage, 'get') .onFirstCall().resolves([]) .onSecondCall().resolves([]) return sut.saveMultiple(credsToSave).then(() => { return dataStubGet.should.have.been.calledWithExactly(vcRepoDataKey) && dataStubGet.getCalls().length.should.be.equal(2) && dataStubSet.getCalls().length.should.be.equal(4) && dataStubSet.getCalls()[0].should.have.been.calledWithExactly(testProof.nonce, credsToSave[0].toJSON()) && dataStubSet.getCalls()[1].should.have.been.calledWithExactly(vcRepoDataKey, [testProof.nonce]) && dataStubSet.getCalls()[2].should.have.been.calledWithExactly(testProof.nonce, credsToSave[1].toJSON()) && dataStubSet.getCalls()[1].should.have.been.calledWithExactly(vcRepoDataKey, [testProof.nonce]) }) }) it('should throw when saving a VC without a proof', () => { let incorrectVc = JSON.parse(JSON.stringify(new VerifiableCredential(testCredParams))) incorrectVc.proof = undefined return sut.saveOne(incorrectVc).should.be.rejectedWith(Error, 'Verifiable credential does not contain a proof') }) })