From 7c463b36af3d2bbc5ef34713c629bb421ec02548 Mon Sep 17 00:00:00 2001 From: Mo Date: Wed, 26 Jul 2023 06:43:52 -0500 Subject: [PATCH] tests: vault tests [no ci] --- .../AsymmetricMessageService.ts | 65 +++------ .../UseCase/ResendAllMessages.ts | 4 +- .../src/Domain/Contacts/ContactService.ts | 29 +++- .../UseCase/SendOwnContactChangeMessage.ts | 2 +- .../Contacts/UseCase/ValidateItemSigner.ts | 1 - packages/services/src/Domain/index.ts | 2 +- .../Application/Dependencies/Dependencies.ts | 3 +- packages/snjs/mocha/lib/AppContext.js | 57 +++----- .../mocha/vaults/asymmetric-messages.test.js | 12 +- .../snjs/mocha/vaults/key-management.test.js | 120 ++++++++++------ .../snjs/mocha/vaults/keypair-change.test.js | 129 +++++++++++++++++- packages/snjs/mocha/vaults/vaults.test.js | 14 -- 12 files changed, 279 insertions(+), 159 deletions(-) rename packages/services/src/Domain/{AsymmetricMessage => Contacts}/UseCase/SendOwnContactChangeMessage.ts (96%) diff --git a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts index a28ab8bcf..820b6034b 100644 --- a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts +++ b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts @@ -22,8 +22,6 @@ import { import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage' import { SessionEvent } from '../Session/SessionEvent' import { AsymmetricMessageServer } from '@standardnotes/api' -import { UserKeyPairChangedEventData } from '../Session/UserKeyPairChangedEventData' -import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage' import { GetOutboundMessages } from './UseCase/GetOutboundMessages' import { GetInboundMessages } from './UseCase/GetInboundMessages' import { GetVault } from '../Vault/UseCase/GetVault' @@ -32,7 +30,6 @@ import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload' import { FindContact } from '../Contacts/UseCase/FindContact' import { CreateOrEditContact } from '../Contacts/UseCase/CreateOrEditContact' import { ReplaceContactData } from '../Contacts/UseCase/ReplaceContactData' -import { GetAllContacts } from '../Contacts/UseCase/GetAllContacts' import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface' export class AsymmetricMessageService @@ -46,12 +43,10 @@ export class AsymmetricMessageService private messageServer: AsymmetricMessageServer, private _createOrEditContact: CreateOrEditContact, private _findContact: FindContact, - private _getAllContacts: GetAllContacts, private _replaceContactData: ReplaceContactData, private _getTrustedPayload: GetTrustedPayload, private _getVault: GetVault, private _handleRootKeyChangedMessage: HandleRootKeyChangedMessage, - private _sendOwnContactChangedMessage: SendOwnContactChangeMessage, private _getOutboundMessagesUseCase: GetOutboundMessages, private _getInboundMessagesUseCase: GetInboundMessages, private _getUntrustedPayload: GetUntrustedPayload, @@ -60,11 +55,26 @@ export class AsymmetricMessageService super(eventBus) } + public override deinit(): void { + super.deinit() + ;(this.messageServer as unknown) = undefined + ;(this.encryption as unknown) = undefined + ;(this.mutator as unknown) = undefined + ;(this._createOrEditContact as unknown) = undefined + ;(this._findContact as unknown) = undefined + ;(this._replaceContactData as unknown) = undefined + ;(this._getTrustedPayload as unknown) = undefined + ;(this._getVault as unknown) = undefined + ;(this._handleRootKeyChangedMessage as unknown) = undefined + ;(this._getOutboundMessagesUseCase as unknown) = undefined + ;(this._getInboundMessagesUseCase as unknown) = undefined + ;(this._getUntrustedPayload as unknown) = undefined + } + async handleEvent(event: InternalEventInterface): Promise { switch (event.type) { case SessionEvent.UserKeyPairChanged: void this.messageServer.deleteAllInboundMessages() - void this.sendOwnContactChangeEventToAllContacts(event.payload as UserKeyPairChangedEventData) break case SyncEvent.ReceivedAsymmetricMessages: void this.handleRemoteReceivedAsymmetricMessages(event.payload as SyncEventReceivedAsymmetricMessagesData) @@ -89,31 +99,6 @@ export class AsymmetricMessageService await this.handleRemoteReceivedAsymmetricMessages(messages) } - private async sendOwnContactChangeEventToAllContacts(data: UserKeyPairChangedEventData): Promise { - if (!data.previous) { - return - } - - const contacts = this._getAllContacts.execute() - if (contacts.isFailed()) { - return - } - - for (const contact of contacts.getValue()) { - if (contact.isMe) { - continue - } - - await this._sendOwnContactChangedMessage.execute({ - senderOldKeyPair: data.previous.encryption, - senderOldSigningKeyPair: data.previous.signing, - senderNewKeyPair: data.current.encryption, - senderNewSigningKeyPair: data.current.signing, - contact, - }) - } - } - sortServerMessages(messages: AsymmetricMessageServerHash[]): AsymmetricMessageServerHash[] { const SortedPriorityTypes = [AsymmetricMessagePayloadType.SenderKeypairChanged] @@ -288,22 +273,4 @@ export class AsymmetricMessageService ): Promise { await this._handleRootKeyChangedMessage.execute(trustedPayload) } - - public override deinit(): void { - super.deinit() - ;(this.messageServer as unknown) = undefined - ;(this.encryption as unknown) = undefined - ;(this.mutator as unknown) = undefined - ;(this._createOrEditContact as unknown) = undefined - ;(this._findContact as unknown) = undefined - ;(this._getAllContacts as unknown) = undefined - ;(this._replaceContactData as unknown) = undefined - ;(this._getTrustedPayload as unknown) = undefined - ;(this._getVault as unknown) = undefined - ;(this._handleRootKeyChangedMessage as unknown) = undefined - ;(this._sendOwnContactChangedMessage as unknown) = undefined - ;(this._getOutboundMessagesUseCase as unknown) = undefined - ;(this._getInboundMessagesUseCase as unknown) = undefined - ;(this._getUntrustedPayload as unknown) = undefined - } } diff --git a/packages/services/src/Domain/AsymmetricMessage/UseCase/ResendAllMessages.ts b/packages/services/src/Domain/AsymmetricMessage/UseCase/ResendAllMessages.ts index f1966434b..1ab94f6c9 100644 --- a/packages/services/src/Domain/AsymmetricMessage/UseCase/ResendAllMessages.ts +++ b/packages/services/src/Domain/AsymmetricMessage/UseCase/ResendAllMessages.ts @@ -32,7 +32,7 @@ export class ResendAllMessages implements UseCaseInterface { for (const message of messages.data.messages) { const recipient = this.findContact.execute({ userUuid: message.user_uuid }) - if (recipient) { + if (recipient.isFailed()) { errors.push(`Contact not found for invite ${message.user_uuid}`) continue } @@ -41,7 +41,7 @@ export class ResendAllMessages implements UseCaseInterface { keys: params.keys, previousKeys: params.previousKeys, message: message, - recipient, + recipient: recipient.getValue(), }) await this.messageServer.deleteMessage({ diff --git a/packages/services/src/Domain/Contacts/ContactService.ts b/packages/services/src/Domain/Contacts/ContactService.ts index 9cd69da4f..ef7334f95 100644 --- a/packages/services/src/Domain/Contacts/ContactService.ts +++ b/packages/services/src/Domain/Contacts/ContactService.ts @@ -1,3 +1,4 @@ +import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage' import { DeleteContact } from './UseCase/DeleteContact' import { MutatorClientInterface } from './../Mutator/MutatorClientInterface' import { UserKeyPairChangedEventData } from './../Session/UserKeyPairChangedEventData' @@ -42,6 +43,7 @@ export class ContactService private _createOrEditContact: CreateOrEditContact, private _editContact: EditContact, private _validateItemSigner: ValidateItemSigner, + private _sendOwnContactChangedMessage: SendOwnContactChangeMessage, eventBus: InternalEventBusInterface, ) { super(eventBus) @@ -52,11 +54,36 @@ export class ContactService async handleEvent(event: InternalEventInterface): Promise { if (event.type === SessionEvent.UserKeyPairChanged) { const data = event.payload as UserKeyPairChangedEventData - await this.selfContactManager.updateWithNewPublicKeySet({ encryption: data.current.encryption.publicKey, signing: data.current.signing.publicKey, }) + void this.sendOwnContactChangeEventToAllContacts(event.payload as UserKeyPairChangedEventData) + } + } + + private async sendOwnContactChangeEventToAllContacts(data: UserKeyPairChangedEventData): Promise { + if (!data.previous) { + return + } + + const contacts = this._getAllContacts.execute() + if (contacts.isFailed()) { + return + } + + for (const contact of contacts.getValue()) { + if (contact.isMe) { + continue + } + + await this._sendOwnContactChangedMessage.execute({ + senderOldKeyPair: data.previous.encryption, + senderOldSigningKeyPair: data.previous.signing, + senderNewKeyPair: data.current.encryption, + senderNewSigningKeyPair: data.current.signing, + contact, + }) } } diff --git a/packages/services/src/Domain/AsymmetricMessage/UseCase/SendOwnContactChangeMessage.ts b/packages/services/src/Domain/Contacts/UseCase/SendOwnContactChangeMessage.ts similarity index 96% rename from packages/services/src/Domain/AsymmetricMessage/UseCase/SendOwnContactChangeMessage.ts rename to packages/services/src/Domain/Contacts/UseCase/SendOwnContactChangeMessage.ts index b103414f1..1cb1efcee 100644 --- a/packages/services/src/Domain/AsymmetricMessage/UseCase/SendOwnContactChangeMessage.ts +++ b/packages/services/src/Domain/Contacts/UseCase/SendOwnContactChangeMessage.ts @@ -5,7 +5,7 @@ import { AsymmetricMessageSenderKeypairChanged, } from '@standardnotes/models' import { PkcKeyPair } from '@standardnotes/sncrypto-common' -import { SendMessage } from './SendMessage' +import { SendMessage } from '../../AsymmetricMessage/UseCase/SendMessage' import { EncryptMessage } from '../../Encryption/UseCase/Asymmetric/EncryptMessage' import { Result, UseCaseInterface } from '@standardnotes/domain-core' diff --git a/packages/services/src/Domain/Contacts/UseCase/ValidateItemSigner.ts b/packages/services/src/Domain/Contacts/UseCase/ValidateItemSigner.ts index 3753a9ae2..1a61d157a 100644 --- a/packages/services/src/Domain/Contacts/UseCase/ValidateItemSigner.ts +++ b/packages/services/src/Domain/Contacts/UseCase/ValidateItemSigner.ts @@ -112,7 +112,6 @@ export class ValidateItemSigner { const signerPublicKey = signatureResult.publicKey const trustedContact = this.findContact.execute({ signingPublicKey: signerPublicKey }) - if (trustedContact.isFailed()) { return ItemSignatureValidationResult.NotTrusted } diff --git a/packages/services/src/Domain/index.ts b/packages/services/src/Domain/index.ts index 6d8a9ab0f..2367bdd3e 100644 --- a/packages/services/src/Domain/index.ts +++ b/packages/services/src/Domain/index.ts @@ -21,7 +21,7 @@ export * from './AsymmetricMessage/UseCase/ProcessAcceptedVaultInvite' export * from './AsymmetricMessage/UseCase/ResendAllMessages' export * from './AsymmetricMessage/UseCase/ResendMessage' export * from './AsymmetricMessage/UseCase/SendMessage' -export * from './AsymmetricMessage/UseCase/SendOwnContactChangeMessage' +export * from './Contacts/UseCase/SendOwnContactChangeMessage' export * from './Auth/AuthClientInterface' export * from './Auth/AuthManager' export * from './Authenticator/AuthenticatorClientInterface' diff --git a/packages/snjs/lib/Application/Dependencies/Dependencies.ts b/packages/snjs/lib/Application/Dependencies/Dependencies.ts index ce78e864b..7c6eab793 100644 --- a/packages/snjs/lib/Application/Dependencies/Dependencies.ts +++ b/packages/snjs/lib/Application/Dependencies/Dependencies.ts @@ -702,12 +702,10 @@ export class Dependencies { this.get(TYPES.AsymmetricMessageServer), this.get(TYPES.CreateOrEditContact), this.get(TYPES.FindContact), - this.get(TYPES.GetAllContacts), this.get(TYPES.ReplaceContactData), this.get(TYPES.GetTrustedPayload), this.get(TYPES.GetVault), this.get(TYPES.HandleRootKeyChangedMessage), - this.get(TYPES.SendOwnContactChangeMessage), this.get(TYPES.GetOutboundMessages), this.get(TYPES.GetInboundMessages), this.get(TYPES.GetUntrustedPayload), @@ -791,6 +789,7 @@ export class Dependencies { this.get(TYPES.CreateOrEditContact), this.get(TYPES.EditContact), this.get(TYPES.ValidateItemSigner), + this.get(TYPES.SendOwnContactChangeMessage), this.get(TYPES.InternalEventBus), ) }) diff --git a/packages/snjs/mocha/lib/AppContext.js b/packages/snjs/mocha/lib/AppContext.js index a8dd99d60..d7ba122db 100644 --- a/packages/snjs/mocha/lib/AppContext.js +++ b/packages/snjs/mocha/lib/AppContext.js @@ -358,64 +358,39 @@ export class AppContext { }) } - resolveWhenAsymmetricMessageProcessingCompletes() { + resolveWhenAsyncFunctionCompletes(object, functionName) { return new Promise((resolve) => { - const objectToSpy = this.asymmetric - sinon.stub(objectToSpy, 'handleRemoteReceivedAsymmetricMessages').callsFake(async (messages) => { - objectToSpy.handleRemoteReceivedAsymmetricMessages.restore() - const result = await objectToSpy.handleRemoteReceivedAsymmetricMessages(messages) + sinon.stub(object, functionName).callsFake(async (params) => { + object[functionName].restore() + const result = await object[functionName](params) resolve() return result }) }) } + resolveWhenAsymmetricMessageProcessingCompletes() { + return this.resolveWhenAsyncFunctionCompletes(this.asymmetric, 'handleRemoteReceivedAsymmetricMessages') + } + resolveWhenUserMessagesProcessingCompletes() { - return new Promise((resolve) => { - const objectToSpy = this.application.dependencies.get(TYPES.UserEventService) - sinon.stub(objectToSpy, 'handleReceivedUserEvents').callsFake(async (params) => { - objectToSpy.handleReceivedUserEvents.restore() - const result = await objectToSpy.handleReceivedUserEvents(params) - resolve() - return result - }) - }) + const objectToSpy = this.application.dependencies.get(TYPES.UserEventService) + return this.resolveWhenAsyncFunctionCompletes(objectToSpy, 'handleReceivedUserEvents') } resolveWhenAllInboundAsymmetricMessagesAreDeleted() { - return new Promise((resolve) => { - const objectToSpy = this.application.dependencies.get(TYPES.AsymmetricMessageServer) - sinon.stub(objectToSpy, 'deleteAllInboundMessages').callsFake(async (params) => { - objectToSpy.deleteAllInboundMessages.restore() - const result = await objectToSpy.deleteAllInboundMessages(params) - resolve() - return result - }) - }) + const objectToSpy = this.application.dependencies.get(TYPES.AsymmetricMessageServer) + return this.resolveWhenAsyncFunctionCompletes(objectToSpy, 'deleteAllInboundMessages') } resolveWhenAllInboundSharedVaultInvitesAreDeleted() { - return new Promise((resolve) => { - const objectToSpy = this.application.vaultInvites.invitesServer - sinon.stub(objectToSpy, 'deleteAllInboundInvites').callsFake(async (params) => { - objectToSpy.deleteAllInboundInvites.restore() - const result = await objectToSpy.deleteAllInboundInvites(params) - resolve() - return result - }) - }) + const objectToSpy = this.application.vaultInvites.invitesServer + return this.resolveWhenAsyncFunctionCompletes(objectToSpy, 'deleteAllInboundInvites') } resolveWhenSharedVaultServiceSendsContactShareMessage() { - return new Promise((resolve) => { - const objectToSpy = this.sharedVaults - sinon.stub(objectToSpy, 'shareContactWithVaults').callsFake(async (contact) => { - objectToSpy.shareContactWithVaults.restore() - const result = await objectToSpy.shareContactWithVaults(contact) - resolve() - return result - }) - }) + const objectToSpy = this.sharedVaults + return this.resolveWhenAsyncFunctionCompletes(objectToSpy, 'shareContactWithVaults') } resolveWhenSharedVaultKeyRotationInvitesGetSent(targetVault) { diff --git a/packages/snjs/mocha/vaults/asymmetric-messages.test.js b/packages/snjs/mocha/vaults/asymmetric-messages.test.js index 9044c0d05..933714406 100644 --- a/packages/snjs/mocha/vaults/asymmetric-messages.test.js +++ b/packages/snjs/mocha/vaults/asymmetric-messages.test.js @@ -69,7 +69,7 @@ describe('asymmetric messages', function () { }, } - await service.sendOwnContactChangeEventToAllContacts(eventData) + await context.contacts.sendOwnContactChangeEventToAllContacts(eventData) const deleteFunction = sinon.spy(contactContext.asymmetric, 'deleteMessageAfterProcessing') @@ -239,14 +239,20 @@ describe('asymmetric messages', function () { it('should send sender keypair changed message to trusted contacts', async () => { const { contactContext, deinitContactContext } = await Collaboration.createSharedVaultWithAcceptedInvite(context) + contactContext.lockSyncing() + + const sendPromise = context.resolveWhenAsyncFunctionCompletes( + context.contacts, + 'sendOwnContactChangeEventToAllContacts', + ) await context.changePassword('new password') + await sendPromise const firstPartySpy = sinon.spy(context.asymmetric, 'handleTrustedSenderKeypairChangedMessage') const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleTrustedSenderKeypairChangedMessage') - await context.sync() - const completedProcessingMessagesPromise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes() + contactContext.unlockSyncing() await contactContext.sync() await completedProcessingMessagesPromise diff --git a/packages/snjs/mocha/vaults/key-management.test.js b/packages/snjs/mocha/vaults/key-management.test.js index 3e0fa6dd3..049aab4c1 100644 --- a/packages/snjs/mocha/vaults/key-management.test.js +++ b/packages/snjs/mocha/vaults/key-management.test.js @@ -21,59 +21,99 @@ describe('vault key management', function () { await context.launch() }) - it('should lock non-persistent vault', async () => { - const vault = await context.vaults.createUserInputtedPasswordVault({ - name: 'test vault', - description: 'test vault description', - userInputtedPassword: 'test password', - storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + describe('locking', () => { + it('should throw if attempting to add item to locked vault', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + }) + + await context.vaultLocks.lockNonPersistentVault(vault) + + const item = await context.createSyncedNote('test note', 'test note text') + + await Factory.expectThrowsAsync( + () => context.vaults.moveItemToVault(vault, item), + 'Attempting to add item to locked vault', + ) }) - await context.vaultLocks.lockNonPersistentVault(vault) + it('should throw if attempting to remove item from locked vault', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + }) - expect(context.vaultLocks.isVaultLocked(vault)).to.be.true - }) + const item = await context.createSyncedNote('test note', 'test note text') - it('should not be able to lock user-inputted vault with synced key', async () => { - const vault = await context.vaults.createUserInputtedPasswordVault({ - name: 'test vault', - description: 'test vault description', - userInputtedPassword: 'test password', - storagePreference: KeySystemRootKeyStorageMode.Synced, + await context.vaults.moveItemToVault(vault, item) + + await context.vaultLocks.lockNonPersistentVault(vault) + + await Factory.expectThrowsAsync( + () => context.vaults.removeItemFromVault(item), + 'Attempting to remove item from locked vault', + ) }) - await Factory.expectThrowsAsync( - () => context.vaultLocks.lockNonPersistentVault(vault), - 'Vault uses synced key storage and cannot be locked', - ) - }) + it('should lock non-persistent vault', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + }) - it('should not be able to lock randomized vault', async () => { - const vault = await context.vaults.createRandomizedVault({ - name: 'test vault', - description: 'test vault description', + await context.vaultLocks.lockNonPersistentVault(vault) + + expect(context.vaultLocks.isVaultLocked(vault)).to.be.true }) - await Factory.expectThrowsAsync( - () => context.vaultLocks.lockNonPersistentVault(vault), - 'Vault uses synced key storage and cannot be locked', - ) - }) + it('should not be able to lock user-inputted vault with synced key', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Synced, + }) - it('should throw if attempting to change password of locked vault', async () => { - const vault = await context.vaults.createUserInputtedPasswordVault({ - name: 'test vault', - description: 'test vault description', - userInputtedPassword: 'test password', - storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + await Factory.expectThrowsAsync( + () => context.vaultLocks.lockNonPersistentVault(vault), + 'Vault uses synced key storage and cannot be locked', + ) }) - await context.vaultLocks.lockNonPersistentVault(vault) + it('should not be able to lock randomized vault', async () => { + const vault = await context.vaults.createRandomizedVault({ + name: 'test vault', + description: 'test vault description', + }) - await Factory.expectThrowsAsync( - () => context.vaults.changeVaultOptions({ vault }), - 'Attempting to change vault options on a locked vault', - ) + await Factory.expectThrowsAsync( + () => context.vaultLocks.lockNonPersistentVault(vault), + 'Vault uses synced key storage and cannot be locked', + ) + }) + + it('should throw if attempting to change password of locked vault', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + }) + + await context.vaultLocks.lockNonPersistentVault(vault) + + await Factory.expectThrowsAsync( + () => context.vaults.changeVaultOptions({ vault }), + 'Attempting to change vault options on a locked vault', + ) + }) }) describe('key rotation and persistence', () => { diff --git a/packages/snjs/mocha/vaults/keypair-change.test.js b/packages/snjs/mocha/vaults/keypair-change.test.js index 53d216b9b..c8d623926 100644 --- a/packages/snjs/mocha/vaults/keypair-change.test.js +++ b/packages/snjs/mocha/vaults/keypair-change.test.js @@ -24,18 +24,139 @@ describe('keypair change', function () { }) it('contacts should be able to handle receiving multiple keypair changed messages and trust them in order', async () => { - console.error('TODO: implement test') + const { note, contactContext, deinitContactContext } = + await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context) + + contactContext.lockSyncing() + + const publicKeyChain = [] + const signingPublicKeyChain = [] + + publicKeyChain.push(context.publicKey) + signingPublicKeyChain.push(context.signingPublicKey) + + await context.changePassword('new_password') + publicKeyChain.push(context.publicKey) + signingPublicKeyChain.push(context.signingPublicKey) + + await context.changePassword('new_password-2') + publicKeyChain.push(context.publicKey) + signingPublicKeyChain.push(context.signingPublicKey) + + await context.changePassword('new_password-3') + publicKeyChain.push(context.publicKey) + signingPublicKeyChain.push(context.signingPublicKey) + + await context.changeNoteTitleAndSync(note, 'new title') + + contactContext.unlockSyncing() + const promise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes() + await contactContext.sync() + await promise + + const originatorContact = contactContext.contacts.findContact(context.userUuid) + let currentKeySet = originatorContact.publicKeySet + for (let i = publicKeyChain.length - 1; i >= 0; i--) { + const publicKey = publicKeyChain[i] + const signingPublicKey = signingPublicKeyChain[i] + expect(currentKeySet.encryption).to.equal(publicKey) + expect(currentKeySet.signing).to.equal(signingPublicKey) + currentKeySet = currentKeySet.previousKeySet + } + + const receivedNote = contactContext.items.findItem(note.uuid) + expect(receivedNote.title).to.equal('new title') + expect(receivedNote.signatureData.required).to.be.true + expect(receivedNote.signatureData.result.passes).to.be.true + + await deinitContactContext() }) it('should not trust messages sent with previous key pair', async () => { - console.error('TODO: implement test') + const { sharedVault, contactContext, deinitContactContext } = + await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context) + + contactContext.lockSyncing() + + const previousKeyPair = context.encryption.getKeyPair() + const previousSigningKeyPair = context.encryption.getSigningKeyPair() + + await context.changePassword('new_password') + + sinon.stub(context.encryption, 'getKeyPair').returns(previousKeyPair) + sinon.stub(context.encryption, 'getSigningKeyPair').returns(previousSigningKeyPair) + + await context.vaults.changeVaultNameAndDescription(sharedVault, { + name: 'New Name', + description: 'New Description', + }) + + contactContext.unlockSyncing() + const promise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes() + await contactContext.sync() + await promise + + const updatedVault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier }) + expect(updatedVault.name).to.equal(sharedVault.name) + expect(updatedVault.description).to.equal(sharedVault.description) + expect(updatedVault.name).to.not.equal('New Name') + expect(updatedVault.description).to.not.equal('New Description') + + await deinitContactContext() }) it('should reupload invites after rotating keypair', async () => { - console.error('TODO: implement test') + const { contactContext, deinitContactContext } = + await Collaboration.createSharedVaultWithUnacceptedButTrustedInvite(context) + + contactContext.lockSyncing() + + const invite = (await contactContext.vaultInvites.downloadInboundInvites())[0] + + const promise = context.resolveWhenAsyncFunctionCompletes( + context.application.dependencies.get(TYPES.SendVaultInvite), + 'execute', + ) + await context.changePassword('new_password') + await promise + + const updatedInvite = (await contactContext.vaultInvites.downloadInboundInvites())[0] + expect(updatedInvite.uuid).to.not.equal(invite.uuid) + expect(updatedInvite.created_at_timestamp).to.not.equal(invite.created_at_timestamp) + + await deinitContactContext() }) it('should reupload asymmetric messages after rotating keypair', async () => { - console.error('TODO: implement test') + const { sharedVault, contactContext, deinitContactContext } = + await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context) + + contactContext.lockSyncing() + + await context.vaults.changeVaultNameAndDescription(sharedVault, { + name: 'New Name', + description: 'New Description', + }) + + const originalMessages = await contactContext.asymmetric.getInboundMessages() + expect(originalMessages.length).to.equal(1) + const originalMessage = originalMessages[0] + + const promise = context.resolveWhenAsyncFunctionCompletes( + context.application.dependencies.get(TYPES.HandleKeyPairChange), + 'execute', + ) + await context.changePassword('new_password') + await promise + + const updatedMessages = await contactContext.asymmetric.getInboundMessages() + const expectedMessages = ['keypair-change', 'vault-change'] + expect(updatedMessages.length).to.equal(expectedMessages.length) + + expect(updatedMessages.some((message) => message.uuid === originalMessage.uuid)).to.be.false + expect(updatedMessages.some((message) => message.created_at_timestamp === originalMessage.created_at_timestamp)).to + .be.false + + await deinitContactContext() }) }) diff --git a/packages/snjs/mocha/vaults/vaults.test.js b/packages/snjs/mocha/vaults/vaults.test.js index 2d5973130..d9c8eba41 100644 --- a/packages/snjs/mocha/vaults/vaults.test.js +++ b/packages/snjs/mocha/vaults/vaults.test.js @@ -24,20 +24,6 @@ describe('vaults', function () { vaults = context.vaults }) - describe('locking', () => { - it('should throw if attempting to add item to locked vault', async () => { - console.error('TODO: implement') - }) - - it('should throw if attempting to remove item from locked vault', async () => { - console.error('TODO: implement') - }) - - it('locking vault should remove root key and items keys from memory', async () => { - console.error('TODO: implement') - }) - }) - describe('offline', function () { it('should be able to create an offline vault', async () => { const vault = await vaults.createRandomizedVault({