tests: vaults-2 (#2368)

This commit is contained in:
Mo
2023-07-26 04:55:58 -05:00
committed by GitHub
parent 6ad5d028af
commit 7222ca7fd0
47 changed files with 900 additions and 310 deletions

View File

@@ -11,7 +11,7 @@ export const VaultTests = {
'vaults/signatures.test.js',
'vaults/shared_vaults.test.js',
'vaults/invites.test.js',
'vaults/locking.test.js',
'vaults/key-management.test.js',
'vaults/items.test.js',
'vaults/conflicts.test.js',
'vaults/deletion.test.js',

View File

@@ -449,7 +449,7 @@ describe('basic auth', function () {
}
const mutatorSpy = sinon.spy(this.application.mutator, 'setItemToBeDeleted')
const removeItemsSpy = sinon.spy(this.application.items, 'removeItemsLocally')
const removeItemsSpy = sinon.spy(this.application.items, 'removeItemsFromMemory')
const deletePayloadsSpy = sinon.spy(this.application.storage, 'deletePayloadsWithUuids')
await this.context.changePassword('new-password')

View File

@@ -201,7 +201,7 @@ describe('item manager', function () {
observed.push({ changed, inserted, removed, ignored })
})
const note = await createNote()
await application.items.removeItemLocally(note)
await application.items.removeItemFromMemory(note)
expect(observed.length).to.equal(1)
expect(application.items.findItem(note.uuid)).to.not.be.ok

View File

@@ -190,7 +190,7 @@ describe('keys', function () {
const itemsKey = this.application.encryption.itemsKeyForEncryptedPayload(encryptedPayload)
await this.application.items.removeItemLocally(itemsKey)
await this.application.items.removeItemFromMemory(itemsKey)
const erroredPayload = await this.application.encryption.decryptSplitSingle({
usesItemsKeyWithKeyLookup: {

View File

@@ -63,6 +63,16 @@ export default class WebDeviceInterface {
return models
}
async getDatabaseEntries(identifier, ids) {
const models = []
for (const id of ids) {
const key = this._keyForPayloadId(id, identifier)
const model = JSON.parse(localStorage[key])
models.push(model)
}
return models
}
async getDatabaseLoadChunks(options, identifier) {
const entries = await this.getAllDatabaseEntries(identifier)
const {

View File

@@ -53,7 +53,7 @@ describe('sync integrity', () => {
const didEnterOutOfSync = awaitSyncEventPromise(this.application, SyncEvent.EnterOutOfSync)
await this.application.sync.sync({ checkIntegrity: true })
await this.application.items.removeItemLocally(item)
await this.application.items.removeItemFromMemory(item)
await this.application.sync.sync({ checkIntegrity: true, awaitAll: true })
await didEnterOutOfSync
@@ -70,7 +70,7 @@ describe('sync integrity', () => {
const didExitOutOfSync = awaitSyncEventPromise(this.application, SyncEvent.ExitOutOfSync)
await this.application.sync.sync({ checkIntegrity: true })
await this.application.items.removeItemLocally(item)
await this.application.items.removeItemFromMemory(item)
await this.application.sync.sync({ checkIntegrity: true, awaitAll: true })
await Promise.all([didEnterOutOfSync, didExitOutOfSync])

View File

@@ -0,0 +1,398 @@
import * as Factory from '../lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('vault key management', 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()
})
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,
})
await context.vaultLocks.lockNonPersistentVault(vault)
expect(context.vaultLocks.isVaultLocked(vault)).to.be.true
})
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 Factory.expectThrowsAsync(
() => context.vaultLocks.lockNonPersistentVault(vault),
'Vault uses synced key storage and cannot be locked',
)
})
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.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', () => {
it('rotating ephemeral vault should not persist keys', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Ephemeral,
})
await context.vaults.rotateVaultRootKey(vault, 'test password')
const syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(0)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.be.undefined
})
it('rotating local vault should not sync keys', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Local,
})
await context.vaults.rotateVaultRootKey(vault, 'test password')
const syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(0)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.not.be.undefined
})
it('rotating synced vault should sync new key', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Synced,
})
await context.vaults.rotateVaultRootKey(vault, 'test password')
const syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(2)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.be.undefined
})
})
describe('memory management', () => {
it('locking a vault should clear decrypted items keys from memory', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Ephemeral,
})
const itemsKeys = context.keys.getKeySystemItemsKeys(vault.systemIdentifier)
expect(itemsKeys.length).to.equal(1)
await context.vaultLocks.lockNonPersistentVault(vault)
const itemsKeysAfterLock = context.keys.getKeySystemItemsKeys(vault.systemIdentifier)
expect(itemsKeysAfterLock.length).to.equal(0)
})
it('locking then unlocking a vault should bring items keys back into memory', 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 context.vaultLocks.unlockNonPersistentVault(vault, 'test password')
const itemsKeys = context.keys.getKeySystemItemsKeys(vault.systemIdentifier)
expect(itemsKeys.length).to.equal(1)
const rootKeys = context.keys.getAllKeySystemRootKeysForVault(vault.systemIdentifier)
expect(rootKeys.length).to.equal(1)
})
})
describe('changeVaultOptions', () => {
describe('change storage type', () => {
it('should not be able to change randomized vault from synced to local', async () => {
const vault = await context.vaults.createRandomizedVault({
name: 'test vault',
description: 'test vault description',
})
const result = await context.vaults.changeVaultOptions({
vault,
newStorageMode: KeySystemRootKeyStorageMode.Local,
})
expect(result.isFailed()).to.be.true
expect(result.getError()).to.equal('Vault uses randomized password and cannot change its storage preference')
})
it('should not be able to change randomized vault from synced to ephemeral', async () => {
const vault = await context.vaults.createRandomizedVault({
name: 'test vault',
description: 'test vault description',
})
const result = await context.vaults.changeVaultOptions({
vault,
newStorageMode: KeySystemRootKeyStorageMode.Local,
})
expect(result.isFailed()).to.be.true
expect(result.getError()).to.equal('Vault uses randomized password and cannot change its storage preference')
})
it('should change user password vault from synced to local', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Synced,
})
let syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
const result = await context.vaults.changeVaultOptions({
vault,
newStorageMode: KeySystemRootKeyStorageMode.Local,
})
expect(result.isFailed()).to.be.false
syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(0)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.not.be.undefined
})
it('should change user password vault from synced to ephemeral', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Synced,
})
let syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
const result = await context.vaults.changeVaultOptions({
vault,
newStorageMode: KeySystemRootKeyStorageMode.Ephemeral,
})
expect(result.isFailed()).to.be.false
syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(0)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.be.undefined
const memKeys = context.keys.getAllKeySystemRootKeysForVault(vault.systemIdentifier)
expect(memKeys.length).to.equal(1)
})
it('should change user password vault from local to synced', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Local,
})
let syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
const result = await context.vaults.changeVaultOptions({
vault,
newStorageMode: KeySystemRootKeyStorageMode.Synced,
})
expect(result.isFailed()).to.be.false
syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(1)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.be.undefined
const memKeys = context.keys.getAllKeySystemRootKeysForVault(vault.systemIdentifier)
expect(memKeys.length).to.equal(1)
})
it('should change user password vault from local to ephemeral', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Local,
})
let syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
const result = await context.vaults.changeVaultOptions({
vault,
newStorageMode: KeySystemRootKeyStorageMode.Ephemeral,
})
expect(result.isFailed()).to.be.false
syncedKeys = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(syncedKeys.length).to.equal(0)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.be.undefined
const memKeys = context.keys.getAllKeySystemRootKeysForVault(vault.systemIdentifier)
expect(memKeys.length).to.equal(1)
})
})
describe('change password type', () => {
it('should fail to change password type from randomized to user inputted if password is not supplied', async () => {
const vault = await context.vaults.createRandomizedVault({
name: 'test vault',
description: 'test vault description',
})
const result = await context.vaults.changeVaultOptions({
vault,
newPasswordType: {
passwordType: KeySystemPasswordType.UserInputted,
},
})
expect(result.isFailed()).to.be.true
})
it('should change password type from randomized to user inputted', async () => {
const vault = await context.vaults.createRandomizedVault({
name: 'test vault',
description: 'test vault description',
})
const rootKeysBeforeChange = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(rootKeysBeforeChange.length).to.equal(1)
const result = await context.vaults.changeVaultOptions({
vault,
newPasswordType: {
passwordType: KeySystemPasswordType.UserInputted,
userInputtedPassword: 'test password',
},
})
expect(result.isFailed()).to.be.false
const rootKeysAfterChange = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(rootKeysAfterChange.length).to.equal(2)
expect(rootKeysAfterChange[0].itemsKey).to.not.equal(rootKeysAfterChange[1].itemsKey)
})
it('should change password type from user inputted to randomized', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Local,
})
const result = await context.vaults.changeVaultOptions({
vault,
newPasswordType: {
passwordType: KeySystemPasswordType.Randomized,
},
})
expect(result.isFailed()).to.be.false
const rootKeysAfterChange = context.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
expect(rootKeysAfterChange.length).to.equal(1)
const storedKey = context.keys.getRootKeyFromStorageForVault(vault.systemIdentifier)
expect(storedKey).to.be.undefined
const updatedVault = context.vaults.getVault({ keySystemIdentifier: vault.systemIdentifier })
expect(updatedVault.keyStorageMode).to.equal(KeySystemRootKeyStorageMode.Synced)
})
it('should fail to change password type from user inputted to randomized if storage mode is not synced', async () => {
const vault = await context.vaults.createUserInputtedPasswordVault({
name: 'test vault',
description: 'test vault description',
userInputtedPassword: 'test password',
storagePreference: KeySystemRootKeyStorageMode.Local,
})
const result = await context.vaults.changeVaultOptions({
vault,
newPasswordType: {
passwordType: KeySystemPasswordType.Randomized,
},
newStorageMode: KeySystemRootKeyStorageMode.Local,
})
expect(result.isFailed()).to.be.true
expect(result.getError()).to.equal('Vault uses randomized password and cannot change its storage preference')
})
})
})
})

View File

@@ -29,7 +29,7 @@ describe('shared vault key rotation', function () {
contactContext.lockSyncing()
const spy = sinon.spy(context.keys, 'reencryptKeySystemItemsKeysForVault')
const spy = sinon.spy(context.keys, 'queueVaultItemsKeysForReencryption')
const promise = context.resolveWhenSharedVaultKeyRotationInvitesGetSent(sharedVault)
await context.vaults.rotateVaultRootKey(sharedVault)

View File

@@ -1,108 +0,0 @@
import * as Factory from '../lib/factory.js'
import * as Collaboration from '../lib/Collaboration.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('vault locking', 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('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,
})
context.vaultLocks.lockNonPersistentVault(vault)
expect(context.vaultLocks.isVaultLocked(vault)).to.be.true
})
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,
})
expect(() => context.vaultLocks.lockNonPersistentVault(vault)).to.throw(
Error,
'Vault uses synced key storage and cannot be locked',
)
})
it('should not be able to lock randomized vault', async () => {
const vault = await context.vaults.createRandomizedVault({
name: 'test vault',
description: 'test vault description',
})
expect(() => context.vaultLocks.lockNonPersistentVault(vault)).to.throw(
Error,
'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,
})
context.vaultLocks.lockNonPersistentVault(vault)
await Factory.expectThrowsAsync(
() => context.vaults.changeVaultOptions({ vault }),
'Attempting to change vault options on a locked vault',
)
})
it('should respect storage preference when rotating key system root key', async () => {
console.error('TODO: implement')
})
it('should change storage preference from synced to local', async () => {
console.error('TODO: implement')
})
it('should change storage preference from local to synced', async () => {
console.error('TODO: implement')
})
it('should resync key system items key if it is encrypted with noncurrent key system root key', async () => {
console.error('TODO: implement')
})
it('should change password type from user inputted to randomized', async () => {
console.error('TODO: implement')
})
it('should change password type from randomized to user inputted', async () => {
console.error('TODO: implement')
})
it('should not be able to change storage mode of third party vault', async () => {
console.error('TODO: implement')
})
})