diff --git a/package.json b/package.json index 1499725..fded947 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@godaddy/terminus": "^4.1.0", - "@kiltprotocol/sdk-js": "^0.19.1-d0076cb.0", + "@kiltprotocol/sdk-js": "^0.19.1-affad9d.0", "@nestjs/common": "^5.4.0", "@nestjs/core": "^5.4.0", "@nestjs/mongoose": "^5.2.2", diff --git a/src/contacts/contacts.module.spec.ts b/src/contacts/contacts.module.spec.ts index b3f07e2..08b48c9 100644 --- a/src/contacts/contacts.module.spec.ts +++ b/src/contacts/contacts.module.spec.ts @@ -40,10 +40,8 @@ describe('Contact Module', () => { } const signature = '0x00aad52336444c0263a22c22f2b99bbcdfc3a6912b5d085c11df01de2bb13dae7c9adf89ecb58f9a32dd021c1c0c1ff0ed39ba361a85f350714b58f15cbd617607' - - const signedTestDID: IDidDocumentSigned = { + const unsignedTestDID: IDidDocumentSigned = { id: 'did:kilt:5CKq9ovoHUFb5Qg2q7YmQ2waNhgQm4C22qwb1Wgehnn2eBcb', - signature, '@context': 'https://w3id.org/did/v1', authentication: [ { @@ -75,8 +73,12 @@ describe('Contact Module', () => { serviceEndpoint: 'https://services.devnet.kilt.io:443/messaging', }, ], - } + } as any + const signedTestDID: IDidDocumentSigned = { + ...unsignedTestDID, + signature, + } const contactWithDid: Contact = { ...testContact, did: signedTestDID, @@ -85,7 +87,11 @@ describe('Contact Module', () => { ...testContact, did: { ...signedTestDID, signature: signature.replace('d', 'f') }, } - + const deprecatedDIDFormat: ContactDB & { signature?: string } = { + ...testContact, + signature, + did: unsignedTestDID, + } as any const address = testContact.publicIdentity.address describe('Controller', () => { let contactsController: ContactsController @@ -138,6 +144,7 @@ describe('Contact Module', () => { expect(addSpy).toHaveBeenCalledTimes(1) expect(addSpy).toHaveBeenCalledWith(testContact) }) + it('calls throws Exception on invalid Contact', async () => { const addSpy = jest.spyOn(contactsService, 'add') const noAddressContact: Contact = { @@ -181,6 +188,7 @@ describe('Contact Module', () => { expect(addSpy).toHaveBeenCalledTimes(1) expect(addSpy).toHaveBeenCalledWith(contactWithDid) }) + it('rejects contact with did if signature is missing or invalid', async () => { const addSpy = jest.spyOn(contactsService, 'add') mockedVerifyDidDocumentSignature.mockReturnValue(false) @@ -248,6 +256,9 @@ describe('Contact Module', () => { public static findOne = jest .fn() .mockReturnValue({ exec: async (): Promise => null }) + public static replaceOne = jest + .fn() + .mockReturnValue({ exec: async (): Promise => {} }) public static deleteMany = jest.fn().mockReturnValue({ exec: async () => { return @@ -295,17 +306,42 @@ describe('Contact Module', () => { }) expect(saveSpy).toHaveBeenCalledTimes(1) }) + it('updates a Contact and saves it', async () => { - const saveSpy = jest.spyOn(contactsService['contactModel'], 'save') - const findOneSpy = jest.spyOn( + const findOneSpy = jest + .spyOn(contactsService['contactModel'], 'findOne') + .mockReturnValueOnce({ + exec: async (): Promise => + (({ + ...deprecatedDIDFormat, + _id: 0, + toObject: () => deprecatedDIDFormat, + } as any) as ContactDB), + }) + const replaceOne = jest.spyOn( contactsService['contactModel'], - 'findOne' + 'replaceOne' ) await contactsService.add(contactWithDid) expect(findOneSpy).toHaveBeenCalledWith({ 'publicIdentity.address': testContact.publicIdentity.address, }) - expect(saveSpy).toHaveBeenCalledTimes(1) + expect(replaceOne).toHaveBeenCalledTimes(1) + expect(replaceOne).toHaveBeenCalledWith( + { _id: 0 }, + { + did: deprecatedDIDFormat.signature && { + ...deprecatedDIDFormat.did, + signature: deprecatedDIDFormat.signature, + }, + ...contactWithDid, + publicIdentity: deprecatedDIDFormat.publicIdentity, + metaData: { + ...deprecatedDIDFormat.metaData, + name: contactWithDid.metaData.name, + }, + } + ) }) }) describe('findByAddress', () => { @@ -320,9 +356,11 @@ describe('Contact Module', () => { 'publicIdentity.address': address, }) findOneSpy.mockReturnValue({ - exec: async (): Promise => { - return testContact as ContactDB - }, + exec: async (): Promise => + (({ + ...testContact, + toObject: () => testContact, + } as any) as ContactDB), }) expect(await contactsService.findByAddress(address)).toEqual( Optional.ofNullable(testContact) @@ -330,7 +368,17 @@ describe('Contact Module', () => { expect(findOneSpy).toHaveBeenCalledWith({ 'publicIdentity.address': address, }) - expect(findOneSpy).toHaveBeenCalledTimes(2) + findOneSpy.mockReturnValue({ + exec: async (): Promise => + (({ + ...deprecatedDIDFormat, + toObject: () => deprecatedDIDFormat, + } as any) as ContactDB), + }) + expect(await contactsService.findByAddress(address)).toEqual( + Optional.ofNullable(contactWithDid) + ) + expect(findOneSpy).toHaveBeenCalledTimes(3) findOneSpy.mockRestore() }) }) @@ -340,7 +388,12 @@ describe('Contact Module', () => { .spyOn(contactsService['contactModel'], 'find') .mockReturnValue({ exec: async (): Promise => { - return [testContact as ContactDB] + return [ + ({ + ...testContact, + toObject: () => testContact, + } as any) as ContactDB, + ] }, }) expect(await contactsService.list()).toEqual([testContact]) diff --git a/src/contacts/mongodb-contacts.service.ts b/src/contacts/mongodb-contacts.service.ts index 59a269d..db64419 100644 --- a/src/contacts/mongodb-contacts.service.ts +++ b/src/contacts/mongodb-contacts.service.ts @@ -1,4 +1,5 @@ import { PublicIdentity } from '@kiltprotocol/sdk-js' +import { IDidDocumentSigned } from '@kiltprotocol/sdk-js/build/did/Did' import { Injectable } from '@nestjs/common' import { InjectModel } from '@nestjs/mongoose' import { Model } from 'mongoose' @@ -16,14 +17,31 @@ export class MongoDbMContactsService implements ContactsService { ) {} public async add(contact: Contact): Promise { - const modifiedContact: ContactDB = Optional.ofNullable( + const registeredContact: Optional< + ContactDB & { signature?: string } + > = Optional.ofNullable( await this.contactModel .findOne({ 'publicIdentity.address': contact.publicIdentity.address }) .exec() - ).orElse(new this.contactModel(contact as ContactDB)) - modifiedContact.metaData.name = contact.metaData.name - modifiedContact.did = contact.did - await modifiedContact.save() + ) + if (registeredContact.isPresent) { + const registered = registeredContact.get() + // If the contact was already registered we want to replace the document, as it could exist in outdated format! Signature is still valid. + await this.contactModel.replaceOne({ _id: registered._id }, { + did: registered.signature && { + ...registered.did, + signature: registered.signature, + }, + ...contact, + publicIdentity: registered.publicIdentity, + metaData: { + ...registered.metaData, + name: contact.metaData.name, + }, + } as ContactDB) + } else { + await new this.contactModel(contact as ContactDB).save() + } } public async findByAddress( @@ -48,11 +66,15 @@ export class MongoDbMContactsService implements ContactsService { public async removeAll(): Promise { await this.contactModel.deleteMany({}).exec() } - private convertToContact(contactDB: ContactDB): Contact { - const { metaData, did, publicIdentity } = contactDB + + private convertToContact( + contactDB: ContactDB & { signature?: string } + ): Contact { + // The Old Format had the signature as property in ContactDB, so we check if we have to move it. Signature is still valid. + const { metaData, did, publicIdentity, signature } = contactDB return { metaData, - did, + did: signature && did ? { ...did, signature } : did, publicIdentity, } } diff --git a/src/faucet/faucet.controller.ts b/src/faucet/faucet.controller.ts index a79439b..409486d 100644 --- a/src/faucet/faucet.controller.ts +++ b/src/faucet/faucet.controller.ts @@ -1,4 +1,4 @@ -import { Balance, Blockchain, Identity } from '@kiltprotocol/sdk-js' +import { Balance, Identity } from '@kiltprotocol/sdk-js' import { Controller, Inject, @@ -21,7 +21,10 @@ import { FaucetDropInvalidAddressException, } from './exceptions' import { AuthGuard } from '../auth/auth.guard' -import { IS_IN_BLOCK } from '@kiltprotocol/sdk-js/build/blockchain/Blockchain' +import { + IS_IN_BLOCK, + submitSignedTx, +} from '@kiltprotocol/sdk-js/build/blockchain/Blockchain' const DEFAULT_TOKEN_AMOUNT = 500 @@ -76,9 +79,11 @@ export class FaucetController { new BN(DEFAULT_TOKEN_AMOUNT), 0 ) - const status = await Blockchain.submitSignedTx(tx, { + const status = await submitSignedTx(tx, { resolveOn: IS_IN_BLOCK, }) + console.log(`Status: ${status.isInBlock}`) + return Promise.resolve(status.isInBlock) } catch (e) { console.error(e) diff --git a/src/faucet/faucet.module.spec.ts b/src/faucet/faucet.module.spec.ts index 8e80bd9..8f92229 100644 --- a/src/faucet/faucet.module.spec.ts +++ b/src/faucet/faucet.module.spec.ts @@ -36,13 +36,11 @@ jest.mock('@kiltprotocol/sdk-js/build/balance/Balance.chain', () => { jest.mock('@kiltprotocol/sdk-js/build/blockchain/Blockchain', () => { return { __esModule: true, - default: { - submitSignedTx: jest.fn( - async (): Promise => { - return { isInBlock: true } as SubmittableResult - } - ), - }, + submitSignedTx: jest.fn().mockImplementation( + async (): Promise => { + return { isInBlock: true } as SubmittableResult + } + ), } }) @@ -74,7 +72,7 @@ describe('Faucet Module', () => { .makeTransfer const mockedsubmitSignedTx = require('@kiltprotocol/sdk-js/build/blockchain/Blockchain') - .default.submitSignedTx + .submitSignedTx const fakeFaucetService: FaucetService = { drop: jest.fn(async (): Promise => testFaucetDrop), @@ -202,9 +200,9 @@ describe('Faucet Module', () => { const buildSpy = jest .spyOn(Identity, 'buildFromSeed') .mockResolvedValue(faucetIdentity) - mockedsubmitSignedTx.mockResolvedValue({ - isInBlock: true, - } as SubmittableResult) + mockedsubmitSignedTx.mockResolvedValue({ + isInBlock: true, + } as SubmittableResult) expect( await faucetController['transferTokens'](claimerAddress) ).toEqual(true) diff --git a/test/faucet.e2e-spec.ts b/test/faucet.e2e-spec.ts index d60a6e0..332513a 100644 --- a/test/faucet.e2e-spec.ts +++ b/test/faucet.e2e-spec.ts @@ -16,9 +16,8 @@ jest.mock('@kiltprotocol/sdk-js/build/balance/Balance.chain', () => { jest.mock('@kiltprotocol/sdk-js/build/blockchain/Blockchain', () => { return { __esModules: true, - default: { - submitSignedTx: jest.fn(() => Promise.resolve({ isInBlock: true })), - } + + submitSignedTx: jest.fn(() => Promise.resolve({ isInBlock: true })), } }) @@ -46,11 +45,11 @@ describe('faucet endpoint (e2e)', () => { beforeEach(async () => { await faucetService.reset() - require('@kiltprotocol/sdk-js/build/blockchain/Blockchain').default.submitSignedTx.mockResolvedValue( + require('@kiltprotocol/sdk-js/build/blockchain/Blockchain').submitSignedTx.mockResolvedValue( { isInBlock: true } ) require('@kiltprotocol/sdk-js/build/balance/Balance.chain').makeTransfer.mockResolvedValue( - { } + {} ) }) diff --git a/yarn.lock b/yarn.lock index cb55336..e880bd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -519,10 +519,10 @@ "@polkadot/util" "^3.5.1" "@polkadot/util-crypto" "^3.5.1" -"@kiltprotocol/sdk-js@^0.19.1-d0076cb.0": - version "0.19.1-d0076cb.0" - resolved "https://npm.pkg.github.com/download/@kiltprotocol/sdk-js/0.19.1-d0076cb.0/65c4100d663cb3f26c56a7dadc627e0ed95534e68163016a9943f7e4ed64cedd#18679f21dc1bdbaad7905f569d597a7dd1b5915d" - integrity sha512-C8wVrawG67OoLu3hibEdKgF89T0GTMZi70fTcBJebM2oL74wLue0nG8AdIZ6IUuCxuVDqNvDjwNfTTj6LgbIzQ== +"@kiltprotocol/sdk-js@^0.19.1-affad9d.0": + version "0.19.1-affad9d.0" + resolved "https://npm.pkg.github.com/download/@kiltprotocol/sdk-js/0.19.1-affad9d.0/200b384ed5e5bb5d35e21b3da717463e4aa5f9ca5753bb228c1f761dc41e4fab#8d3cfcfedca9f41fd1ff9080cfed29d79af1d2a1" + integrity sha512-iyY3g1FRNSIleQPLtP9COo/6meu150Z0wTWNMVTFVi9TFRg54V3Tx+/8rc7FI0Qyd0/uAjX8uEBUZ87SDDCIfQ== dependencies: "@kiltprotocol/portablegabi" "^0.4.0" "@polkadot/api" "^2.0.1"