230 lines
9.1 KiB
JavaScript
230 lines
9.1 KiB
JavaScript
import * as Factory from '../lib/factory.js'
|
|
import * as Collaboration from '../lib/Collaboration.js'
|
|
|
|
chai.use(chaiAsPromised)
|
|
const expect = chai.expect
|
|
|
|
describe('shared vault invites', function () {
|
|
this.timeout(Factory.TwentySecondTimeout)
|
|
|
|
let context
|
|
let sharedVaults
|
|
|
|
afterEach(async function () {
|
|
await context.deinit()
|
|
localStorage.clear()
|
|
})
|
|
|
|
beforeEach(async function () {
|
|
localStorage.clear()
|
|
|
|
context = await Factory.createAppContextWithRealCrypto()
|
|
await context.launch()
|
|
await context.register()
|
|
|
|
sharedVaults = context.sharedVaults
|
|
})
|
|
|
|
it('should invite contact to vault', async () => {
|
|
const sharedVault = await Collaboration.createSharedVault(context)
|
|
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
|
const contact = await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
|
|
|
const vaultInvite = await sharedVaults.inviteContactToSharedVault(sharedVault, contact, SharedVaultPermission.Write)
|
|
|
|
expect(vaultInvite).to.not.be.undefined
|
|
expect(vaultInvite.shared_vault_uuid).to.equal(sharedVault.sharing.sharedVaultUuid)
|
|
expect(vaultInvite.user_uuid).to.equal(contact.contactUuid)
|
|
expect(vaultInvite.encrypted_message).to.not.be.undefined
|
|
expect(vaultInvite.permissions).to.equal(SharedVaultPermission.Write)
|
|
expect(vaultInvite.updated_at_timestamp).to.not.be.undefined
|
|
expect(vaultInvite.created_at_timestamp).to.not.be.undefined
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('invites from trusted contact should be pending as trusted', async () => {
|
|
const { contactContext, deinitContactContext } =
|
|
await Collaboration.createSharedVaultWithUnacceptedButTrustedInvite(context)
|
|
|
|
const invites = contactContext.sharedVaults.getCachedPendingInviteRecords()
|
|
|
|
expect(invites[0].trusted).to.be.true
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('invites from untrusted contact should be pending as untrusted', async () => {
|
|
const { contactContext, deinitContactContext } =
|
|
await Collaboration.createSharedVaultWithUnacceptedAndUntrustedInvite(context)
|
|
|
|
const invites = contactContext.sharedVaults.getCachedPendingInviteRecords()
|
|
|
|
expect(invites[0].trusted).to.be.false
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('invite should include delegated trusted contacts', async () => {
|
|
const { sharedVault, contactContext, deinitContactContext } =
|
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
|
|
|
const { thirdPartyContext, deinitThirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
|
context,
|
|
sharedVault,
|
|
)
|
|
|
|
const invites = thirdPartyContext.sharedVaults.getCachedPendingInviteRecords()
|
|
|
|
const message = invites[0].message
|
|
const delegatedContacts = message.data.trustedContacts
|
|
expect(delegatedContacts.length).to.equal(1)
|
|
expect(delegatedContacts[0].contactUuid).to.equal(contactContext.userUuid)
|
|
|
|
await deinitThirdPartyContext()
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('should sync a shared vault from scratch after accepting an invitation', async () => {
|
|
const sharedVault = await Collaboration.createSharedVault(context)
|
|
|
|
const note = await context.createSyncedNote('foo', 'bar')
|
|
await Collaboration.moveItemToVault(context, sharedVault, note)
|
|
|
|
/** Create a mutually trusted contact */
|
|
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
|
const contact = await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
|
await Collaboration.createTrustedContactForUserOfContext(contactContext, context)
|
|
|
|
/** Sync the contact context so that they wouldn't naturally receive changes made before this point */
|
|
await contactContext.sync()
|
|
|
|
await sharedVaults.inviteContactToSharedVault(sharedVault, contact, SharedVaultPermission.Write)
|
|
|
|
/** Contact should now sync and expect to find note */
|
|
const promise = contactContext.awaitNextSyncSharedVaultFromScratchEvent()
|
|
await contactContext.sync()
|
|
await Collaboration.acceptAllInvites(contactContext)
|
|
await promise
|
|
|
|
const receivedNote = contactContext.items.findItem(note.uuid)
|
|
expect(receivedNote).to.not.be.undefined
|
|
expect(receivedNote.title).to.equal('foo')
|
|
expect(receivedNote.text).to.equal(note.text)
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('received invites from untrusted contact should not be trusted', async () => {
|
|
await context.createSyncedNote('foo', 'bar')
|
|
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
|
const sharedVault = await Collaboration.createSharedVault(context)
|
|
|
|
const currentContextContact = await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
|
await sharedVaults.inviteContactToSharedVault(sharedVault, currentContextContact, SharedVaultPermission.Write)
|
|
|
|
await contactContext.sharedVaults.downloadInboundInvites()
|
|
expect(contactContext.sharedVaults.getCachedPendingInviteRecords()[0].trusted).to.be.false
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('received invites from contact who becomes trusted after receipt of invite should be trusted', async () => {
|
|
await context.createSyncedNote('foo', 'bar')
|
|
const { contactContext, deinitContactContext } = await Collaboration.createContactContext()
|
|
const sharedVault = await Collaboration.createSharedVault(context)
|
|
|
|
const currentContextContact = await Collaboration.createTrustedContactForUserOfContext(context, contactContext)
|
|
await sharedVaults.inviteContactToSharedVault(sharedVault, currentContextContact, SharedVaultPermission.Write)
|
|
|
|
await contactContext.sharedVaults.downloadInboundInvites()
|
|
expect(contactContext.sharedVaults.getCachedPendingInviteRecords()[0].trusted).to.be.false
|
|
|
|
await Collaboration.createTrustedContactForUserOfContext(contactContext, context)
|
|
|
|
expect(contactContext.sharedVaults.getCachedPendingInviteRecords()[0].trusted).to.be.true
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('received items should contain the uuid of the contact who sent the item', async () => {
|
|
const { note, contactContext, deinitContactContext } =
|
|
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
|
|
|
const receivedNote = contactContext.items.findItem(note.uuid)
|
|
expect(receivedNote).to.not.be.undefined
|
|
expect(receivedNote.user_uuid).to.equal(context.userUuid)
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('items should contain the uuid of the last person who edited it', async () => {
|
|
const { note, contactContext, deinitContactContext } =
|
|
await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context)
|
|
|
|
const receivedNote = contactContext.items.findItem(note.uuid)
|
|
expect(receivedNote.last_edited_by_uuid).to.not.be.undefined
|
|
expect(receivedNote.last_edited_by_uuid).to.equal(context.userUuid)
|
|
|
|
await contactContext.changeNoteTitleAndSync(receivedNote, 'new title')
|
|
await context.sync()
|
|
|
|
const updatedNote = context.items.findItem(note.uuid)
|
|
expect(updatedNote.last_edited_by_uuid).to.not.be.undefined
|
|
expect(updatedNote.last_edited_by_uuid).to.equal(contactContext.userUuid)
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('canceling an invite should remove it from recipient pending invites', async () => {
|
|
const { invite, contactContext, deinitContactContext } =
|
|
await Collaboration.createSharedVaultWithUnacceptedButTrustedInvite(context)
|
|
|
|
const preInvites = await contactContext.sharedVaults.downloadInboundInvites()
|
|
expect(preInvites.length).to.equal(1)
|
|
|
|
await sharedVaults.deleteInvite(invite)
|
|
|
|
const postInvites = await contactContext.sharedVaults.downloadInboundInvites()
|
|
expect(postInvites.length).to.equal(0)
|
|
|
|
await deinitContactContext()
|
|
})
|
|
|
|
it('when inviter keypair changes, recipient should still be able to trust and decrypt previous invite', async () => {
|
|
console.error('TODO: implement test')
|
|
})
|
|
|
|
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')
|
|
})
|
|
|
|
it('sharing a vault with user inputted and ephemeral password should share the key as synced for the recipient', async () => {
|
|
const privateVault = await context.vaults.createUserInputtedPasswordVault({
|
|
name: 'My Private Vault',
|
|
userInputtedPassword: 'password',
|
|
storagePreference: KeySystemRootKeyStorageMode.Ephemeral,
|
|
})
|
|
|
|
const note = await context.createSyncedNote('foo', 'bar')
|
|
await context.vaults.moveItemToVault(privateVault, note)
|
|
|
|
const sharedVault = await context.sharedVaults.convertVaultToSharedVault(privateVault)
|
|
|
|
const { thirdPartyContext, deinitThirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
|
context,
|
|
sharedVault,
|
|
)
|
|
|
|
await Collaboration.acceptAllInvites(thirdPartyContext)
|
|
|
|
const contextNote = thirdPartyContext.items.findItem(note.uuid)
|
|
expect(contextNote).to.not.be.undefined
|
|
expect(contextNote.title).to.equal('foo')
|
|
expect(contextNote.text).to.equal(note.text)
|
|
|
|
await deinitThirdPartyContext()
|
|
})
|
|
})
|