refactor: application dependency management (#2363)
This commit is contained in:
@@ -34,10 +34,14 @@ describe('asymmetric messages', function () {
|
||||
const { contactContext, deinitContactContext } = await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
const eventData = {
|
||||
oldKeyPair: context.encryption.getKeyPair(),
|
||||
oldSigningKeyPair: context.encryption.getSigningKeyPair(),
|
||||
newKeyPair: context.encryption.getKeyPair(),
|
||||
newSigningKeyPair: context.encryption.getSigningKeyPair(),
|
||||
current: {
|
||||
encryption: context.encryption.getKeyPair(),
|
||||
signing: context.encryption.getSigningKeyPair(),
|
||||
},
|
||||
previous: {
|
||||
encryption: context.encryption.getKeyPair(),
|
||||
signing: context.encryption.getSigningKeyPair(),
|
||||
},
|
||||
}
|
||||
|
||||
await service.sendOwnContactChangeEventToAllContacts(eventData)
|
||||
@@ -92,6 +96,38 @@ describe('asymmetric messages', function () {
|
||||
await deinitThirdPartyContext()
|
||||
})
|
||||
|
||||
it('should send contact share message when a member is added to a vault', async () => {
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
const handleInitialContactShareMessage = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
|
||||
const { thirdPartyContext, deinitThirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdPartyContext)
|
||||
|
||||
const firstPartySpy = sinon.spy(context.asymmetric, 'handleTrustedContactShareMessage')
|
||||
const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleTrustedContactShareMessage')
|
||||
const thirdPartySpy = sinon.spy(thirdPartyContext.asymmetric, 'handleTrustedContactShareMessage')
|
||||
|
||||
await contactContext.sync()
|
||||
await handleInitialContactShareMessage
|
||||
|
||||
await context.sync()
|
||||
await contactContext.sync()
|
||||
await thirdPartyContext.sync()
|
||||
|
||||
expect(firstPartySpy.callCount).to.equal(0)
|
||||
expect(secondPartySpy.callCount).to.equal(1)
|
||||
expect(thirdPartySpy.callCount).to.equal(0)
|
||||
|
||||
await deinitThirdPartyContext()
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should not send contact share message to self or to contact who is changed', async () => {
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
@@ -100,12 +136,10 @@ describe('asymmetric messages', function () {
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
const handleInitialContactShareMessage = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdPartyContext)
|
||||
|
||||
await contactContext.sync()
|
||||
await handleInitialContactShareMessage
|
||||
|
||||
const sendContactSharePromise = context.resolveWhenSharedVaultServiceSendsContactShareMessage()
|
||||
|
||||
@@ -161,8 +195,8 @@ describe('asymmetric messages', function () {
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
const firstPartySpy = sinon.spy(context.asymmetric, 'handleVaultMetadataChangedMessage')
|
||||
const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleVaultMetadataChangedMessage')
|
||||
const firstPartySpy = sinon.spy(context.asymmetric, 'handleTrustedVaultMetadataChangedMessage')
|
||||
const secondPartySpy = sinon.spy(contactContext.asymmetric, 'handleTrustedVaultMetadataChangedMessage')
|
||||
|
||||
await context.sync()
|
||||
await contactContext.sync()
|
||||
@@ -201,6 +235,61 @@ describe('asymmetric messages', function () {
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should trust and process messages sent after sender keypair changed', async () => {
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
await context.changePassword('new password')
|
||||
|
||||
await context.vaults.changeVaultNameAndDescription(sharedVault, {
|
||||
name: 'New Name',
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
const completedProcessingMessagesPromise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
await contactContext.sync()
|
||||
await completedProcessingMessagesPromise
|
||||
|
||||
const updatedVault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(updatedVault.name).to.equal('New Name')
|
||||
expect(updatedVault.description).to.equal('New Description')
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should not send back a vault change message after receiving a vault change message', async () => {
|
||||
/**
|
||||
* If userA receives a vault change message and mutates their vault locally, this should not create a
|
||||
* chain of vault change messages that then ping-pongs back and forth between the two users.
|
||||
*/
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
await context.changePassword('new password')
|
||||
|
||||
await context.vaults.changeVaultNameAndDescription(sharedVault, {
|
||||
name: 'New Name',
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
context.lockSyncing()
|
||||
|
||||
const completedProcessingMessagesPromise = contactContext.resolveWhenAsymmetricMessageProcessingCompletes()
|
||||
await contactContext.sync()
|
||||
await completedProcessingMessagesPromise
|
||||
|
||||
/**
|
||||
* There's really no good way to await the exact call since
|
||||
* the relevant part fires in the SharedVaultSerivce item observer
|
||||
*/
|
||||
await context.sleep(0.25)
|
||||
|
||||
const messages = await context.asymmetric.getInboundMessages()
|
||||
expect(messages.length).to.equal(0)
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should process sender keypair changed message', async () => {
|
||||
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
||||
await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
||||
@@ -272,6 +361,28 @@ describe('asymmetric messages', function () {
|
||||
|
||||
it('should delete all inbound messages after changing user password', async () => {
|
||||
/** Messages to user are encrypted with old keypair and are no longer decryptable */
|
||||
console.error('TODO: implement test')
|
||||
|
||||
const { sharedVault, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
|
||||
contactContext.lockSyncing()
|
||||
|
||||
await context.vaults.changeVaultNameAndDescription(sharedVault, {
|
||||
name: 'New Name',
|
||||
description: 'New Description',
|
||||
})
|
||||
|
||||
const promise = contactContext.resolveWhenAllInboundAsymmetricMessagesAreDeleted()
|
||||
await contactContext.changePassword('new-password')
|
||||
await promise
|
||||
|
||||
const messages = await contactContext.asymmetric.getInboundMessages()
|
||||
expect(messages.length).to.equal(0)
|
||||
|
||||
const updatedVault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(updatedVault.name).to.not.equal('New Name')
|
||||
expect(updatedVault.description).to.not.equal('New Description')
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -71,6 +71,18 @@ describe('contacts', function () {
|
||||
expect(updatedSelfContact.publicKeySet.signing).to.equal(context.signingPublicKey)
|
||||
})
|
||||
|
||||
it('should update self contact reference when changed', async () => {
|
||||
const selfContact = context.contacts.getSelfContact()
|
||||
|
||||
await context.mutator.changeItem(selfContact, (mutator) => {
|
||||
mutator.name = 'New Name'
|
||||
})
|
||||
|
||||
const updatedSelfContact = context.contacts.getSelfContact()
|
||||
|
||||
expect(updatedSelfContact.name).to.equal('New Name')
|
||||
})
|
||||
|
||||
it('should not be able to delete self contact', async () => {
|
||||
const selfContact = context.contacts.getSelfContact()
|
||||
|
||||
@@ -80,4 +92,8 @@ describe('contacts', function () {
|
||||
it('should not be able to delete a trusted contact if it belongs to a vault I administer', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should be able to refresh a contact using a collaborationID that includes full chain of previouos public keys', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -50,9 +50,10 @@ describe('shared vault crypto', function () {
|
||||
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
||||
|
||||
await contactContext.changeNoteTitleAndSync(note, 'new title')
|
||||
|
||||
await context.sync()
|
||||
|
||||
const rawPayloads = await context.application.diskStorageService.getAllRawPayloads()
|
||||
const rawPayloads = await context.application.storage.getAllRawPayloads()
|
||||
const noteRawPayload = rawPayloads.find((payload) => payload.uuid === note.uuid)
|
||||
|
||||
expect(noteRawPayload.signatureData).to.not.be.undefined
|
||||
@@ -166,11 +167,13 @@ describe('shared vault crypto', function () {
|
||||
const { note, contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
||||
|
||||
expect(context.contacts.isItemAuthenticallySigned(note)).to.equal('not-applicable')
|
||||
expect(context.contacts.isItemAuthenticallySigned(note)).to.equal(ItemSignatureValidationResult.NotApplicable)
|
||||
|
||||
const contactNote = contactContext.items.findItem(note.uuid)
|
||||
|
||||
expect(contactContext.contacts.isItemAuthenticallySigned(contactNote)).to.equal('yes')
|
||||
expect(contactContext.contacts.isItemAuthenticallySigned(contactNote)).to.equal(
|
||||
ItemSignatureValidationResult.Trusted,
|
||||
)
|
||||
|
||||
await contactContext.changeNoteTitleAndSync(contactNote, 'new title')
|
||||
|
||||
@@ -178,27 +181,9 @@ describe('shared vault crypto', function () {
|
||||
|
||||
let updatedNote = context.items.findItem(note.uuid)
|
||||
|
||||
expect(context.contacts.isItemAuthenticallySigned(updatedNote)).to.equal('yes')
|
||||
expect(context.contacts.isItemAuthenticallySigned(updatedNote)).to.equal(ItemSignatureValidationResult.Trusted)
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
})
|
||||
|
||||
describe('keypair revocation', () => {
|
||||
it('should be able to revoke non-current keypair', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
|
||||
it('revoking a keypair should send a keypair revocation event to trusted contacts', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
|
||||
it('should not be able to revoke current key pair', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
|
||||
it('should distrust revoked keypair as contact', async () => {
|
||||
console.error('TODO')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,9 @@ describe('shared vault invites', function () {
|
||||
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
||||
const contact = await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
||||
|
||||
const vaultInvite = await sharedVaults.inviteContactToSharedVault(sharedVault, contact, SharedVaultPermission.Write)
|
||||
const vaultInvite = (
|
||||
await sharedVaults.inviteContactToSharedVault(sharedVault, contact, SharedVaultPermission.Write)
|
||||
).getValue()
|
||||
|
||||
expect(vaultInvite).to.not.be.undefined
|
||||
expect(vaultInvite.shared_vault_uuid).to.equal(sharedVault.sharing.sharedVaultUuid)
|
||||
@@ -78,8 +80,10 @@ describe('shared vault invites', function () {
|
||||
|
||||
const message = invites[0].message
|
||||
const delegatedContacts = message.data.trustedContacts
|
||||
expect(delegatedContacts.length).to.equal(1)
|
||||
expect(delegatedContacts[0].contactUuid).to.equal(contactContext.userUuid)
|
||||
expect(delegatedContacts.length).to.equal(2)
|
||||
|
||||
expect(delegatedContacts.some((contact) => contact.contactUuid === context.userUuid)).to.be.true
|
||||
expect(delegatedContacts.some((contact) => contact.contactUuid === contactContext.userUuid)).to.be.true
|
||||
|
||||
await deinitThirdPartyContext()
|
||||
await deinitContactContext()
|
||||
@@ -197,7 +201,17 @@ describe('shared vault invites', function () {
|
||||
|
||||
it('should delete all inbound invites after changing user password', async () => {
|
||||
/** Invites to user are encrypted with old keypair and are no longer decryptable */
|
||||
console.error('TODO: implement test')
|
||||
const { contactContext, deinitContactContext } =
|
||||
await Collaboration.createSharedVaultWithUnacceptedButTrustedInvite(context)
|
||||
|
||||
const promise = contactContext.resolveWhenAllInboundSharedVaultInvitesAreDeleted()
|
||||
await contactContext.changePassword('new-password')
|
||||
await promise
|
||||
|
||||
const invites = await contactContext.sharedVaults.downloadInboundInvites()
|
||||
expect(invites.length).to.equal(0)
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('sharing a vault with user inputted and ephemeral password should share the key as synced for the recipient', async () => {
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('shared vault key rotation', function () {
|
||||
|
||||
contactContext.lockSyncing()
|
||||
|
||||
const spy = sinon.spy(context.encryption, 'reencryptKeySystemItemsKeysForVault')
|
||||
const spy = sinon.spy(context.keys, 'reencryptKeySystemItemsKeysForVault')
|
||||
|
||||
const promise = context.resolveWhenSharedVaultKeyRotationInvitesGetSent(sharedVault)
|
||||
await vaults.rotateVaultRootKey(sharedVault)
|
||||
|
||||
41
packages/snjs/mocha/vaults/keypair-change.test.js
Normal file
41
packages/snjs/mocha/vaults/keypair-change.test.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Collaboration from '../lib/Collaboration.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('keypair change', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let context
|
||||
|
||||
afterEach(async function () {
|
||||
await context.deinit()
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
|
||||
context = await Factory.createAppContextWithRealCrypto()
|
||||
|
||||
await context.launch()
|
||||
await context.register()
|
||||
})
|
||||
|
||||
it('contacts should be able to handle receiving multiple keypair changed messages and trust them in order', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should not trust messages sent with previous key pair', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should reupload invites after rotating keypair', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('should reupload asymmetric messages after rotating keypair', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
})
|
||||
@@ -43,7 +43,7 @@ describe('shared vault permissions', function () {
|
||||
SharedVaultPermission.Write,
|
||||
)
|
||||
|
||||
expect(isClientDisplayableError(result)).to.be.true
|
||||
expect(result.isFailed()).to.be.true
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
@@ -63,15 +63,15 @@ describe('shared vaults', function () {
|
||||
await promise
|
||||
|
||||
expect(contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(contactContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
const recreatedContext = await Factory.createAppContextWithRealCrypto(contactContext.identifier)
|
||||
await recreatedContext.launch()
|
||||
|
||||
expect(recreatedContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(recreatedContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
await deinitContactContext()
|
||||
await recreatedContext.deinit()
|
||||
@@ -90,15 +90,15 @@ describe('shared vaults', function () {
|
||||
await promise
|
||||
|
||||
expect(contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(contactContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(contactContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
const recreatedContext = await Factory.createAppContextWithRealCrypto(contactContext.identifier)
|
||||
await recreatedContext.launch()
|
||||
|
||||
expect(recreatedContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.encryption.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
expect(recreatedContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(recreatedContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
await deinitContactContext()
|
||||
await recreatedContext.deinit()
|
||||
|
||||
33
packages/snjs/mocha/vaults/signatures.test.js
Normal file
33
packages/snjs/mocha/vaults/signatures.test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Collaboration from '../lib/Collaboration.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('signatures', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let context
|
||||
|
||||
afterEach(async function () {
|
||||
await context.deinit()
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
|
||||
context = await Factory.createAppContextWithRealCrypto()
|
||||
|
||||
await context.launch()
|
||||
await context.register()
|
||||
})
|
||||
|
||||
it('signatures should be marked as of questionable integrity when signed with non root contact public key', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
|
||||
it('items marked with questionable integrity should have option to trust the item which would resync it', async () => {
|
||||
console.error('TODO: implement test')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user