chore: designated survivor test suite (#2540)
* chore: designated survivor test suite * add more tests * fix: tests exclusivness * fix removing account from shared vaults test
This commit is contained in:
@@ -1,59 +1,63 @@
|
||||
export const BaseTests = [
|
||||
'memory.test.js',
|
||||
'protocol.test.js',
|
||||
'utils.test.js',
|
||||
'000.test.js',
|
||||
'001.test.js',
|
||||
'002.test.js',
|
||||
'003.test.js',
|
||||
'004.test.js',
|
||||
'username.test.js',
|
||||
'app-group.test.js',
|
||||
'application.test.js',
|
||||
'payload.test.js',
|
||||
'payload_encryption.test.js',
|
||||
'item.test.js',
|
||||
'item_manager.test.js',
|
||||
'features.test.js',
|
||||
'settings.test.js',
|
||||
'mfa_service.test.js',
|
||||
'mutator.test.js',
|
||||
'mutator_service.test.js',
|
||||
'payload_manager.test.js',
|
||||
'collections.test.js',
|
||||
'note_display_criteria.test.js',
|
||||
'keys.test.js',
|
||||
'key_params.test.js',
|
||||
'key_recovery_service.test.js',
|
||||
'backups.test.js',
|
||||
'upgrading.test.js',
|
||||
'model_tests/importing.test.js',
|
||||
'model_tests/appmodels.test.js',
|
||||
'model_tests/items.test.js',
|
||||
'model_tests/mapping.test.js',
|
||||
'model_tests/notes_smart_tags.test.js',
|
||||
'model_tests/notes_tags.test.js',
|
||||
'model_tests/notes_tags_folders.test.js',
|
||||
'model_tests/performance.test.js',
|
||||
'sync_tests/offline.test.js',
|
||||
'sync_tests/notes_tags.test.js',
|
||||
'sync_tests/online.test.js',
|
||||
'sync_tests/conflicting.test.js',
|
||||
'sync_tests/integrity.test.js',
|
||||
'auth-fringe-cases.test.js',
|
||||
'auth.test.js',
|
||||
'device_auth.test.js',
|
||||
'storage.test.js',
|
||||
'protection.test.js',
|
||||
'singletons.test.js',
|
||||
'migrations/migration.test.js',
|
||||
'migrations/tags-to-folders.test.js',
|
||||
'history.test.js',
|
||||
'actions.test.js',
|
||||
'preferences.test.js',
|
||||
'files.test.js',
|
||||
'session.test.js',
|
||||
'session-invalidation.test.js',
|
||||
'subscriptions.test.js',
|
||||
'recovery.test.js',
|
||||
]
|
||||
export const BaseTests = {
|
||||
enabled: true,
|
||||
exclusive: false,
|
||||
files: [
|
||||
'memory.test.js',
|
||||
'protocol.test.js',
|
||||
'utils.test.js',
|
||||
'000.test.js',
|
||||
'001.test.js',
|
||||
'002.test.js',
|
||||
'003.test.js',
|
||||
'004.test.js',
|
||||
'username.test.js',
|
||||
'app-group.test.js',
|
||||
'application.test.js',
|
||||
'payload.test.js',
|
||||
'payload_encryption.test.js',
|
||||
'item.test.js',
|
||||
'item_manager.test.js',
|
||||
'features.test.js',
|
||||
'settings.test.js',
|
||||
'mfa_service.test.js',
|
||||
'mutator.test.js',
|
||||
'mutator_service.test.js',
|
||||
'payload_manager.test.js',
|
||||
'collections.test.js',
|
||||
'note_display_criteria.test.js',
|
||||
'keys.test.js',
|
||||
'key_params.test.js',
|
||||
'key_recovery_service.test.js',
|
||||
'backups.test.js',
|
||||
'upgrading.test.js',
|
||||
'model_tests/importing.test.js',
|
||||
'model_tests/appmodels.test.js',
|
||||
'model_tests/items.test.js',
|
||||
'model_tests/mapping.test.js',
|
||||
'model_tests/notes_smart_tags.test.js',
|
||||
'model_tests/notes_tags.test.js',
|
||||
'model_tests/notes_tags_folders.test.js',
|
||||
'model_tests/performance.test.js',
|
||||
'sync_tests/offline.test.js',
|
||||
'sync_tests/notes_tags.test.js',
|
||||
'sync_tests/online.test.js',
|
||||
'sync_tests/conflicting.test.js',
|
||||
'sync_tests/integrity.test.js',
|
||||
'auth-fringe-cases.test.js',
|
||||
'auth.test.js',
|
||||
'device_auth.test.js',
|
||||
'storage.test.js',
|
||||
'protection.test.js',
|
||||
'singletons.test.js',
|
||||
'migrations/migration.test.js',
|
||||
'migrations/tags-to-folders.test.js',
|
||||
'history.test.js',
|
||||
'actions.test.js',
|
||||
'preferences.test.js',
|
||||
'files.test.js',
|
||||
'session.test.js',
|
||||
'session-invalidation.test.js',
|
||||
'subscriptions.test.js',
|
||||
'recovery.test.js',
|
||||
]
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@ export const VaultTests = {
|
||||
'vaults/files.test.js',
|
||||
'vaults/limits.test.js',
|
||||
'vaults/quota.test.js',
|
||||
'vaults/surviving.test.js',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export const acceptAllInvites = async (context) => {
|
||||
}
|
||||
}
|
||||
|
||||
const inviteContext = async (context, contactContext, sharedVault, contact, permission) => {
|
||||
export const inviteContext = async (context, contactContext, sharedVault, contact, permission) => {
|
||||
contactContext.lockSyncing()
|
||||
|
||||
const inviteOrError = await context.vaultInvites.inviteContactToSharedVault(sharedVault, contact, permission)
|
||||
@@ -207,3 +207,12 @@ export const moveItemToVault = async (context, sharedVault, item) => {
|
||||
|
||||
return result.getValue()
|
||||
}
|
||||
|
||||
export const designateSharedVaultSurvior = async (context, sharedVault, survivorUuid) => {
|
||||
const result = await context.vaultUsers.designateSurvivor(sharedVault, survivorUuid)
|
||||
if (result.isFailed()) {
|
||||
throw new Error(result.getError())
|
||||
}
|
||||
|
||||
return result.getValue()
|
||||
}
|
||||
|
||||
@@ -38,6 +38,14 @@
|
||||
<script type="module">
|
||||
import MainRegistry from './TestRegistry/MainRegistry.js'
|
||||
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
const testSuite = urlSearchParams.get('suite');
|
||||
if (testSuite === 'vaults') {
|
||||
MainRegistry.VaultTests.exclusive = true;
|
||||
} else if (testSuite === 'base') {
|
||||
MainRegistry.BaseTests.exclusive = true;
|
||||
}
|
||||
|
||||
const loadTest = (fileName) => {
|
||||
return new Promise((resolve) => {
|
||||
const script = document.createElement('script');
|
||||
@@ -56,18 +64,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (MainRegistry.VaultTests.enabled) {
|
||||
InternalFeatureService.get().enableFeature(InternalFeature.Vaults);
|
||||
if (MainRegistry.VaultTests.exclusive) {
|
||||
await loadTests(MainRegistry.VaultTests.files);
|
||||
} else {
|
||||
await loadTests([
|
||||
...MainRegistry.BaseTests,
|
||||
...MainRegistry.VaultTests.files
|
||||
]);
|
||||
}
|
||||
InternalFeatureService.get().enableFeature(InternalFeature.Vaults);
|
||||
|
||||
if (MainRegistry.VaultTests.exclusive) {
|
||||
await loadTests(MainRegistry.VaultTests.files);
|
||||
} else if (MainRegistry.BaseTests.exclusive) {
|
||||
await loadTests(MainRegistry.BaseTests.files);
|
||||
} else {
|
||||
await loadTests(MainRegistry.BaseTests);
|
||||
await loadTests([
|
||||
...MainRegistry.BaseTests.files,
|
||||
...MainRegistry.VaultTests.files
|
||||
]);
|
||||
}
|
||||
|
||||
mocha.run()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Utils from '../lib/Utils.js'
|
||||
import * as Collaboration from '../lib/Collaboration.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
@@ -167,4 +168,47 @@ describe('shared vault deletion', function () {
|
||||
|
||||
await deinitContactContext()
|
||||
})
|
||||
|
||||
it('should remove a user from all shared vaults upon account removal', async () => {
|
||||
const secondContext = await Factory.createVaultsContextWithRealCrypto()
|
||||
await secondContext.launch()
|
||||
await secondContext.register()
|
||||
|
||||
const thirdContext = await Factory.createVaultsContextWithRealCrypto()
|
||||
await thirdContext.launch()
|
||||
await thirdContext.register()
|
||||
|
||||
const firstVault = await Collaboration.createSharedVault(context)
|
||||
const secondVault = await Collaboration.createSharedVault(thirdContext)
|
||||
|
||||
const firstToSecondContact = await Collaboration.createTrustedContactForUserOfContext(context, secondContext)
|
||||
await Collaboration.createTrustedContactForUserOfContext(secondContext, context)
|
||||
|
||||
const thirdToSecondContact = await Collaboration.createTrustedContactForUserOfContext(thirdContext, secondContext)
|
||||
await Collaboration.createTrustedContactForUserOfContext(thirdContext, context)
|
||||
|
||||
await Collaboration.inviteContext(context, secondContext, firstVault, firstToSecondContact, SharedVaultUserPermission.PERMISSIONS.Write)
|
||||
await Collaboration.inviteContext(thirdContext, secondContext, secondVault, thirdToSecondContact, SharedVaultUserPermission.PERMISSIONS.Write)
|
||||
|
||||
const promise = secondContext.awaitNextSyncSharedVaultFromScratchEvent()
|
||||
|
||||
await Collaboration.acceptAllInvites(secondContext)
|
||||
|
||||
await Utils.awaitPromiseOrThrow(promise, 2.0, 'Waiting for vault to sync')
|
||||
|
||||
Factory.handlePasswordChallenges(secondContext.application, secondContext.password)
|
||||
await secondContext.application.user.deleteAccount()
|
||||
|
||||
await context.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedVaultUsersInFirstVault = await context.vaultUsers.getSharedVaultUsersFromServer(firstVault)
|
||||
expect(sharedVaultUsersInFirstVault.length).to.equal(1)
|
||||
|
||||
const sharedVaultUsersInSecondVault = await thirdContext.vaultUsers.getSharedVaultUsersFromServer(secondVault)
|
||||
expect(sharedVaultUsersInSecondVault.length).to.equal(1)
|
||||
|
||||
await secondContext.deinit()
|
||||
await thirdContext.deinit()
|
||||
})
|
||||
})
|
||||
|
||||
363
packages/snjs/mocha/vaults/surviving.test.js
Normal file
363
packages/snjs/mocha/vaults/surviving.test.js
Normal file
@@ -0,0 +1,363 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Files from '../lib/Files.js'
|
||||
import * as Collaboration from '../lib/Collaboration.js'
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('designated survival', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let context
|
||||
let secondContext
|
||||
let thirdContext
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
|
||||
context = await Factory.createVaultsContextWithRealCrypto()
|
||||
|
||||
await context.launch()
|
||||
await context.register()
|
||||
})
|
||||
|
||||
afterEach(async function () {
|
||||
await context.deinit()
|
||||
localStorage.clear()
|
||||
sinon.restore()
|
||||
context = undefined
|
||||
if (secondContext) {
|
||||
await secondContext.deinit()
|
||||
secondContext = undefined
|
||||
}
|
||||
if (thirdContext) {
|
||||
await thirdContext.deinit()
|
||||
thirdContext = undefined
|
||||
}
|
||||
})
|
||||
|
||||
it('should indicate that a vault has a designated survivor', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
let vault = context.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(vault.sharing.designatedSurvivor).to.be.null
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
await context.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
vault = context.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(vault.sharing.designatedSurvivor).to.equal(contactContext.userUuid)
|
||||
})
|
||||
|
||||
describe('owner of a shared vault with a designated survivor removing the vault', () => {
|
||||
it('should not remove all users from the vault upon shared vault removal', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||
|
||||
await context.syncAndAwaitNotificationsProcessing()
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||
expect(sharedVaultUsers.length).to.equal(2)
|
||||
|
||||
expect(context.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(context.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(context.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
expect(secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||
expect(secondContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||
expect(secondContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||
|
||||
expect(thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||
expect(thirdContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||
expect(thirdContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||
})
|
||||
|
||||
it('should transition items of the owner in the vault to the designated survivor', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
const note = await context.createSyncedNote('foo', 'bar')
|
||||
await Collaboration.moveItemToVault(context, sharedVault, note)
|
||||
|
||||
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||
expect(sharedVaultUsers.length).to.equal(2)
|
||||
|
||||
const contactNote = secondContext.items.findItem(note.uuid)
|
||||
expect(contactNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||
expect(contactNote.user_uuid).to.equal(secondContext.userUuid)
|
||||
|
||||
const thirdPartyNote = thirdContext.items.findItem(note.uuid)
|
||||
expect(thirdPartyNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||
expect(thirdPartyNote.user_uuid).to.equal(secondContext.userUuid)
|
||||
})
|
||||
|
||||
it('should still allow to download files of the owner in the vault', async () => {
|
||||
await context.activatePaidSubscriptionForUser()
|
||||
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
const response = await fetch('/mocha/assets/small_file.md')
|
||||
const buffer = new Uint8Array(await response.arrayBuffer())
|
||||
const uploadedFile = await Files.uploadFile(context.files, buffer, 'my-file', 'md', 1000, sharedVault)
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedFileBefore = secondContext.items.findItem(uploadedFile.uuid)
|
||||
expect(sharedFileBefore).to.not.be.undefined
|
||||
expect(sharedFileBefore.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||
|
||||
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedFileAfter = secondContext.items.findItem(uploadedFile.uuid)
|
||||
expect(sharedFileAfter).to.not.be.undefined
|
||||
expect(sharedFileAfter.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||
|
||||
const downloadedBytes = await Files.downloadFile(secondContext.files, sharedFileAfter)
|
||||
expect(downloadedBytes).to.eql(buffer)
|
||||
})
|
||||
|
||||
it('should transition vault ownership to the designated survivor', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const contactVault = secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(contactVault.sharing.ownerUserUuid).to.not.equal(context.userUuid)
|
||||
expect(contactVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||
|
||||
const thirdPartyVault = thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(thirdPartyVault.sharing.ownerUserUuid).to.not.equal(context.userUuid)
|
||||
expect(thirdPartyVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||
})
|
||||
})
|
||||
|
||||
describe('owner of a shared vault with a designated survivor deleting their account', () => {
|
||||
it('should not remove all users from the vault upon account removal', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
Factory.handlePasswordChallenges(context.application, context.password)
|
||||
await context.application.user.deleteAccount()
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||
expect(sharedVaultUsers.length).to.equal(2)
|
||||
|
||||
expect(secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||
expect(secondContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||
expect(secondContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||
|
||||
expect(thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||
expect(thirdContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||
expect(thirdContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||
})
|
||||
|
||||
it('should transition items of the owner in the vault to the designated survivor', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
const note = await context.createSyncedNote('foo', 'bar')
|
||||
await Collaboration.moveItemToVault(context, sharedVault, note)
|
||||
|
||||
Factory.handlePasswordChallenges(context.application, context.password)
|
||||
await context.application.user.deleteAccount()
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||
expect(sharedVaultUsers.length).to.equal(2)
|
||||
|
||||
const contactNote = secondContext.items.findItem(note.uuid)
|
||||
expect(contactNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||
expect(contactNote.user_uuid).to.equal(secondContext.userUuid)
|
||||
|
||||
const thirdPartyNote = thirdContext.items.findItem(note.uuid)
|
||||
expect(thirdPartyNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||
expect(thirdPartyNote.user_uuid).to.equal(secondContext.userUuid)
|
||||
})
|
||||
|
||||
it('should still allow to download files of the owner in the vault', async () => {
|
||||
await context.activatePaidSubscriptionForUser()
|
||||
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
const response = await fetch('/mocha/assets/small_file.md')
|
||||
const buffer = new Uint8Array(await response.arrayBuffer())
|
||||
const uploadedFile = await Files.uploadFile(context.files, buffer, 'my-file', 'md', 1000, sharedVault)
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedFileBefore = secondContext.items.findItem(uploadedFile.uuid)
|
||||
expect(sharedFileBefore).to.not.be.undefined
|
||||
expect(sharedFileBefore.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||
|
||||
Factory.handlePasswordChallenges(context.application, context.password)
|
||||
await context.application.user.deleteAccount()
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const sharedFileAfter = secondContext.items.findItem(uploadedFile.uuid)
|
||||
expect(sharedFileAfter).to.not.be.undefined
|
||||
expect(sharedFileAfter.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||
|
||||
const downloadedBytes = await Files.downloadFile(secondContext.files, sharedFileAfter)
|
||||
expect(downloadedBytes).to.eql(buffer)
|
||||
})
|
||||
|
||||
it('should transition vault ownership to the designated survivor', async () => {
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||
|
||||
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||
context,
|
||||
sharedVault,
|
||||
)
|
||||
thirdContext = thirdPartyContext
|
||||
|
||||
await Collaboration.acceptAllInvites(thirdContext)
|
||||
|
||||
Factory.handlePasswordChallenges(context.application, context.password)
|
||||
await context.application.user.deleteAccount()
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
const contactVault = secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(contactVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||
|
||||
const thirdPartyVault = thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||
expect(thirdPartyVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||
})
|
||||
})
|
||||
|
||||
describe('owner of a shared vault without a designated survivor deleting their account', () => {
|
||||
it('should remove all users from all shared vaults upon account removal', async () => {
|
||||
await context.activatePaidSubscriptionForUser()
|
||||
|
||||
const { sharedVault, contactContext } =
|
||||
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
secondContext = contactContext
|
||||
|
||||
const result = await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||
thirdContext = result.contactContext
|
||||
const secondSharedVault = result.sharedVault
|
||||
|
||||
Factory.handlePasswordChallenges(context.application, context.password)
|
||||
await context.application.user.deleteAccount()
|
||||
|
||||
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||
|
||||
expect(secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(secondContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(secondContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||
|
||||
expect(thirdContext.vaults.getVault({ keySystemIdentifier: secondSharedVault.systemIdentifier })).to.be.undefined
|
||||
expect(thirdContext.keys.getPrimaryKeySystemRootKey(secondSharedVault.systemIdentifier)).to.be.undefined
|
||||
expect(thirdContext.keys.getKeySystemItemsKeys(secondSharedVault.systemIdentifier)).to.be.empty
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -37,7 +37,7 @@
|
||||
"@babel/preset-env": "*",
|
||||
"@standardnotes/api": "workspace:*",
|
||||
"@standardnotes/common": "^1.50.0",
|
||||
"@standardnotes/domain-core": "^1.33.1",
|
||||
"@standardnotes/domain-core": "^1.34.1",
|
||||
"@standardnotes/domain-events": "^2.122.0",
|
||||
"@standardnotes/encryption": "workspace:*",
|
||||
"@standardnotes/features": "workspace:*",
|
||||
|
||||
Reference in New Issue
Block a user