refactor: application dependency management (#2363)

This commit is contained in:
Mo
2023-07-23 15:54:31 -05:00
committed by GitHub
parent e698b1c990
commit a77535456c
299 changed files with 7415 additions and 4890 deletions

View File

@@ -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()
})
})

View File

@@ -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')
})
})

View File

@@ -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')
})
})
})

View File

@@ -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 () => {

View File

@@ -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)

View 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')
})
})

View File

@@ -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()
})

View File

@@ -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()

View 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')
})
})