283 lines
10 KiB
JavaScript
283 lines
10 KiB
JavaScript
import * as Factory from './lib/factory.js'
|
|
|
|
chai.use(chaiAsPromised)
|
|
const expect = chai.expect
|
|
|
|
describe('upgrading', () => {
|
|
let application
|
|
let context
|
|
let email
|
|
let password
|
|
let passcode
|
|
let receiveChallenge
|
|
let receiveChallengeWithApp
|
|
|
|
beforeEach(async function () {
|
|
localStorage.clear()
|
|
|
|
context = await Factory.createAppContext()
|
|
await context.launch()
|
|
|
|
application = context.application
|
|
email = UuidGenerator.GenerateUuid()
|
|
password = UuidGenerator.GenerateUuid()
|
|
passcode = '1234'
|
|
|
|
const promptValueReply = (prompts) => {
|
|
const values = []
|
|
for (const prompt of prompts) {
|
|
if (prompt.validation === ChallengeValidation.LocalPasscode) {
|
|
values.push(CreateChallengeValue(prompt, passcode))
|
|
} else {
|
|
values.push(CreateChallengeValue(prompt, password))
|
|
}
|
|
}
|
|
return values
|
|
}
|
|
|
|
receiveChallenge = (challenge) => {
|
|
void receiveChallengeWithApp(application, challenge)
|
|
}
|
|
|
|
receiveChallengeWithApp = (application, challenge) => {
|
|
application.addChallengeObserver(challenge, {
|
|
onInvalidValue: (value) => {
|
|
const values = promptValueReply([value.prompt])
|
|
application.submitValuesForChallenge(challenge, values)
|
|
},
|
|
})
|
|
const initialValues = promptValueReply(challenge.prompts)
|
|
application.submitValuesForChallenge(challenge, initialValues)
|
|
}
|
|
})
|
|
|
|
afterEach(async function () {
|
|
await Factory.safeDeinit(application)
|
|
localStorage.clear()
|
|
})
|
|
|
|
it('upgrade should be available when account only', async function () {
|
|
const oldVersion = ProtocolVersion.V003
|
|
/** Register with 003 version */
|
|
await Factory.registerOldUser({
|
|
application: application,
|
|
email: email,
|
|
password: password,
|
|
version: oldVersion,
|
|
})
|
|
|
|
expect(await application.protocolUpgradeAvailable()).to.equal(true)
|
|
})
|
|
|
|
it('upgrade should be available when passcode only', async function () {
|
|
const oldVersion = ProtocolVersion.V003
|
|
await Factory.setOldVersionPasscode({
|
|
application: application,
|
|
passcode: passcode,
|
|
version: oldVersion,
|
|
})
|
|
|
|
expect(await application.protocolUpgradeAvailable()).to.equal(true)
|
|
})
|
|
|
|
it('upgrades application protocol from 003 to 004', async function () {
|
|
const oldVersion = ProtocolVersion.V003
|
|
const newVersion = ProtocolVersion.V004
|
|
|
|
await Factory.createMappedNote(application)
|
|
|
|
/** Register with 003 version */
|
|
await Factory.registerOldUser({
|
|
application: application,
|
|
email: email,
|
|
password: password,
|
|
version: oldVersion,
|
|
})
|
|
|
|
await Factory.setOldVersionPasscode({
|
|
application: application,
|
|
passcode: passcode,
|
|
version: oldVersion,
|
|
})
|
|
|
|
expect((await application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(oldVersion)
|
|
expect((await application.encryption.getRootKeyParams()).version).to.equal(oldVersion)
|
|
expect((await application.encryption.getRootKey()).keyVersion).to.equal(oldVersion)
|
|
|
|
application.setLaunchCallback({
|
|
receiveChallenge: receiveChallenge,
|
|
})
|
|
const result = await application.upgradeProtocolVersion()
|
|
expect(result).to.deep.equal({ success: true })
|
|
|
|
const wrappedRootKey = await application.encryption.rootKeyManager.getWrappedRootKey()
|
|
const payload = new EncryptedPayload(wrappedRootKey)
|
|
expect(payload.version).to.equal(newVersion)
|
|
|
|
expect((await application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(newVersion)
|
|
expect((await application.encryption.getRootKeyParams()).version).to.equal(newVersion)
|
|
expect((await application.encryption.getRootKey()).keyVersion).to.equal(newVersion)
|
|
|
|
/**
|
|
* Immediately logging out ensures we don't rely on subsequent
|
|
* sync events to complete the upgrade
|
|
*/
|
|
application = await Factory.signOutApplicationAndReturnNew(application)
|
|
await application.signIn(email, password, undefined, undefined, undefined, true)
|
|
expect(application.items.getDisplayableNotes().length).to.equal(1)
|
|
expect(application.payloads.invalidPayloads).to.be.empty
|
|
}).timeout(15000)
|
|
|
|
it('upgrading from 003 to 004 with passcode only then reiniting app should create valid state', async function () {
|
|
/**
|
|
* There was an issue where having the old app set up with passcode,
|
|
* then refreshing with new app, performing upgrade, then refreshing the app
|
|
* resulted in note data being errored.
|
|
*/
|
|
const oldVersion = ProtocolVersion.V003
|
|
|
|
await Factory.setOldVersionPasscode({
|
|
application: application,
|
|
passcode: passcode,
|
|
version: oldVersion,
|
|
})
|
|
await Factory.createSyncedNote(application)
|
|
|
|
application.setLaunchCallback({
|
|
receiveChallenge: receiveChallenge,
|
|
})
|
|
|
|
const identifier = application.identifier
|
|
|
|
/** Recreate the app once */
|
|
const appFirst = Factory.createApplicationWithFakeCrypto(identifier)
|
|
await appFirst.prepareForLaunch({
|
|
receiveChallenge: (challenge) => {
|
|
receiveChallengeWithApp(appFirst, challenge)
|
|
},
|
|
})
|
|
await appFirst.launch(true)
|
|
const result = await appFirst.upgradeProtocolVersion()
|
|
expect(result).to.deep.equal({ success: true })
|
|
expect(appFirst.payloads.invalidPayloads).to.be.empty
|
|
await Factory.safeDeinit(appFirst)
|
|
|
|
/** Recreate the once more */
|
|
const appSecond = Factory.createApplicationWithFakeCrypto(identifier)
|
|
await appSecond.prepareForLaunch({
|
|
receiveChallenge: (challenge) => {
|
|
receiveChallengeWithApp(appSecond, challenge)
|
|
},
|
|
})
|
|
await appSecond.launch(true)
|
|
expect(appSecond.payloads.invalidPayloads).to.be.empty
|
|
await Factory.safeDeinit(appSecond)
|
|
}).timeout(15000)
|
|
|
|
it('protocol version should be upgraded on password change', async function () {
|
|
/** Delete default items key that is created on launch */
|
|
const itemsKey = await application.encryption.getSureDefaultItemsKey()
|
|
await application.mutator.setItemToBeDeleted(itemsKey)
|
|
expect(Uuids(application.items.getDisplayableItemsKeys()).includes(itemsKey.uuid)).to.equal(false)
|
|
|
|
Factory.createMappedNote(application)
|
|
|
|
/** Register with 003 version */
|
|
await Factory.registerOldUser({
|
|
application: application,
|
|
email: email,
|
|
password: password,
|
|
version: ProtocolVersion.V003,
|
|
})
|
|
|
|
expect(application.items.getDisplayableItemsKeys().length).to.equal(1)
|
|
|
|
expect((await application.encryption.getRootKeyParams()).version).to.equal(ProtocolVersion.V003)
|
|
expect((await application.encryption.getRootKey()).keyVersion).to.equal(ProtocolVersion.V003)
|
|
|
|
/** Ensure note is encrypted with 003 */
|
|
const notePayloads = await Factory.getStoragePayloadsOfType(application, ContentType.TYPES.Note)
|
|
expect(notePayloads.length).to.equal(1)
|
|
expect(notePayloads[0].version).to.equal(ProtocolVersion.V003)
|
|
|
|
const { error } = await application.changePassword(password, 'foobarfoo')
|
|
expect(error).to.not.exist
|
|
|
|
const latestVersion = application.encryption.getLatestVersion()
|
|
expect((await application.encryption.getRootKeyParams()).version).to.equal(latestVersion)
|
|
expect((await application.encryption.getRootKey()).keyVersion).to.equal(latestVersion)
|
|
|
|
const defaultItemsKey = await application.encryption.getSureDefaultItemsKey()
|
|
expect(defaultItemsKey.keyVersion).to.equal(latestVersion)
|
|
|
|
/** After change, note should now be encrypted with latest protocol version */
|
|
|
|
const note = application.items.getDisplayableNotes()[0]
|
|
await Factory.markDirtyAndSyncItem(application, note)
|
|
|
|
const refreshedNotePayloads = await Factory.getStoragePayloadsOfType(application, ContentType.TYPES.Note)
|
|
const refreshedNotePayload = refreshedNotePayloads[0]
|
|
expect(refreshedNotePayload.version).to.equal(latestVersion)
|
|
}).timeout(5000)
|
|
|
|
describe('upgrade failure', function () {
|
|
this.timeout(30000)
|
|
const oldVersion = ProtocolVersion.V003
|
|
|
|
beforeEach(async function () {
|
|
await Factory.createMappedNote(application)
|
|
|
|
/** Register with 003 version */
|
|
await Factory.registerOldUser({
|
|
application: application,
|
|
email: email,
|
|
password: password,
|
|
version: oldVersion,
|
|
})
|
|
|
|
await Factory.setOldVersionPasscode({
|
|
application: application,
|
|
passcode: passcode,
|
|
version: oldVersion,
|
|
})
|
|
})
|
|
|
|
afterEach(function () {
|
|
sinon.restore()
|
|
})
|
|
|
|
it('rolls back the local protocol upgrade if syncing fails', async function () {
|
|
sinon.replace(application.sync, 'sync', sinon.fake())
|
|
application.setLaunchCallback({
|
|
receiveChallenge: receiveChallenge,
|
|
})
|
|
expect((await application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(oldVersion)
|
|
const errors = await application.upgradeProtocolVersion()
|
|
expect(errors).to.not.be.empty
|
|
|
|
/** Ensure we're still on 003 */
|
|
expect((await application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(oldVersion)
|
|
expect((await application.encryption.getRootKeyParams()).version).to.equal(oldVersion)
|
|
expect((await application.encryption.getRootKey()).keyVersion).to.equal(oldVersion)
|
|
expect((await application.encryption.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
|
})
|
|
|
|
it('rolls back the local protocol upgrade if the server responds with an error', async function () {
|
|
sinon.replace(application.sessions, 'changeCredentials', () => [Error()])
|
|
|
|
application.setLaunchCallback({
|
|
receiveChallenge: receiveChallenge,
|
|
})
|
|
expect((await application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(oldVersion)
|
|
const errors = await application.upgradeProtocolVersion()
|
|
expect(errors).to.not.be.empty
|
|
|
|
/** Ensure we're still on 003 */
|
|
expect((await application.encryption.rootKeyManager.getRootKeyWrapperKeyParams()).version).to.equal(oldVersion)
|
|
expect((await application.encryption.getRootKeyParams()).version).to.equal(oldVersion)
|
|
expect((await application.encryption.getRootKey()).keyVersion).to.equal(oldVersion)
|
|
expect((await application.encryption.getSureDefaultItemsKey()).keyVersion).to.equal(oldVersion)
|
|
})
|
|
})
|
|
})
|