Skip to content

Commit

Permalink
[Wallet] Fix app deprecation check mechanism (#1358)
Browse files Browse the repository at this point in the history
  • Loading branch information
rohit-dua authored and jmrossy committed Nov 12, 2019
1 parent 722945f commit cc69980
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 39 deletions.
23 changes: 4 additions & 19 deletions packages/mobile/src/app/saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
navigateToProperScreen,
waitForRehydrate,
} from 'src/app/saga'
import { waitForFirebaseAuth } from 'src/firebase/saga'
import { isAppVersionDeprecated } from 'src/firebase/firebase'
import { UNLOCK_DURATION } from 'src/geth/consts'
import { NavActions, navigate } from 'src/navigator/NavigationService'
import { Screens, Stacks } from 'src/navigator/Screens'
Expand All @@ -21,12 +21,6 @@ import { zeroSyncSelector } from 'src/web3/selectors'
jest.mock('src/utils/time', () => ({
clockInSync: () => true,
}))
jest.mock('src/firebase/firebase', () => ({
...jest.requireActual('src/firebase/firebase'),
getVersionInfo: jest.fn(async () => ({ deprecated: false })),
}))

const { getVersionInfo } = require('src/firebase/firebase')

const MockedAnalytics = CeloAnalytics as any

Expand All @@ -52,7 +46,7 @@ const navigationSagaTest = (testName: string, state: any, expectedScreen: any) =
})
}

describe('Upload Comment Key Saga', () => {
describe('App saga', () => {
beforeEach(() => {
MockedAnalytics.track = jest.fn()
})
Expand All @@ -61,24 +55,15 @@ describe('Upload Comment Key Saga', () => {
})

it('Version Deprecated', async () => {
getVersionInfo.mockImplementationOnce(async () => ({ deprecated: true }))
await expectSaga(checkAppDeprecation)
.provide([[call(waitForRehydrate), null], [call(waitForFirebaseAuth), null]])
.provide([[call(waitForRehydrate), null], [call(isAppVersionDeprecated), true]])
.run()
expect(navigate).toHaveBeenCalledWith(Screens.UpgradeScreen)
})

it('Version Not Deprecated', async () => {
await expectSaga(checkAppDeprecation)
.provide([[call(waitForRehydrate), null], [call(waitForFirebaseAuth), null]])
.run()
expect(navigate).not.toHaveBeenCalled()
})

it('Version info is not set', async () => {
getVersionInfo.mockImplementationOnce(async () => null)
await expectSaga(checkAppDeprecation)
.provide([[call(waitForRehydrate), null], [call(waitForFirebaseAuth), null]])
.provide([[call(waitForRehydrate), null], [call(isAppVersionDeprecated), false]])
.run()
expect(navigate).not.toHaveBeenCalled()
})
Expand Down
21 changes: 12 additions & 9 deletions packages/mobile/src/app/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import {
} from 'src/app/actions'
import { ErrorMessages } from 'src/app/ErrorMessages'
import { handleDappkitDeepLink } from 'src/dappkit/dappkit'
import { getVersionInfo } from 'src/firebase/firebase'
import { waitForFirebaseAuth } from 'src/firebase/saga'
import { isAppVersionDeprecated } from 'src/firebase/firebase'
import { UNLOCK_DURATION } from 'src/geth/consts'
import { NavActions, navigate } from 'src/navigator/NavigationService'
import { Screens, Stacks } from 'src/navigator/Screens'
Expand Down Expand Up @@ -60,12 +59,12 @@ const mapStateToProps = (state: PersistedRootState): PersistedStateProps | null

export function* checkAppDeprecation() {
yield call(waitForRehydrate)
yield call(waitForFirebaseAuth)
const versionInfo = yield getVersionInfo()
Logger.info(TAG, 'Version Info', JSON.stringify(versionInfo))
if (versionInfo && versionInfo.deprecated) {
Logger.info(TAG, 'this version is deprecated')
const isDeprecated: boolean = yield call(isAppVersionDeprecated)
if (isDeprecated) {
Logger.warn(TAG, 'App version is deprecated')
navigate(Screens.UpgradeScreen)
} else {
Logger.debug(TAG, 'App version is valid')
}
}

Expand Down Expand Up @@ -157,9 +156,13 @@ export function* navigatePinProtected(action: NavigatePinProtected) {
}
}

export function* watchNavigatePinProtected() {
yield takeLatest(Actions.NAVIGATE_PIN_PROTECTED, navigatePinProtected)
}

export function* appSaga() {
yield spawn(checkAppDeprecation)
yield spawn(navigateToProperScreen)
yield spawn(toggleToProperSyncMode)
yield takeLatest(Actions.NAVIGATE_PIN_PROTECTED, navigatePinProtected)
yield spawn(checkAppDeprecation)
yield spawn(watchNavigatePinProtected)
}
6 changes: 2 additions & 4 deletions packages/mobile/src/firebase/db-rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@
}
},
"versions": {
"$verion_string": {
".read": true,
".write": false
}
".read": true,
".write": false
},
"lastBlockNotified": {
".read": false,
Expand Down
16 changes: 15 additions & 1 deletion packages/mobile/src/firebase/firebase.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { expectSaga } from 'redux-saga-test-plan'
import { throwError } from 'redux-saga-test-plan/providers'
import { call, select } from 'redux-saga/effects'
import { currentLanguageSelector } from 'src/app/reducers'
import { initializeCloudMessaging, registerTokenToDb, setUserLanguage } from 'src/firebase/firebase'
import {
initializeCloudMessaging,
isVersionBelowMinimum,
registerTokenToDb,
setUserLanguage,
} from 'src/firebase/firebase'
import { mockAccount2 } from 'test/values'

const hasPermissionMock = jest.fn(() => null)
Expand Down Expand Up @@ -79,3 +84,12 @@ describe(initializeCloudMessaging, () => {
.run()
})
})

describe('Firebase version check', () => {
it('Correctly check if version is deprecated', () => {
expect(isVersionBelowMinimum('1.5.0', '1.4.0')).toBe(false)
expect(isVersionBelowMinimum('1.4.0', '1.5.0')).toBe(true)
expect(isVersionBelowMinimum('1.4.0', '1.4.0')).toBe(false)
expect(isVersionBelowMinimum('1.4.0', '1.4.0.1')).toBe(true)
})
})
42 changes: 37 additions & 5 deletions packages/mobile/src/firebase/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { NotificationReceiveState } from 'src/account'
import { showError } from 'src/alert/actions'
import { ErrorMessages } from 'src/app/ErrorMessages'
import { currentLanguageSelector } from 'src/app/reducers'
import { FIREBASE_ENABLED } from 'src/config'
import { WritePaymentRequest } from 'src/firebase/actions'
import { handleNotification } from 'src/firebase/notifications'
import { navigate } from 'src/navigator/NavigationService'
Expand Down Expand Up @@ -164,14 +165,45 @@ export function* paymentRequestWriter({ paymentInfo }: WritePaymentRequest) {
}
}

export async function getVersionInfo() {
export function isVersionBelowMinimum(version: string, minVersion: string): boolean {
const minVersionArray = minVersion.split('.')
const versionArray = version.split('.')
const minVersionLength = Math.min(minVersionArray.length, version.length)
for (let i = 0; i < minVersionLength; i++) {
if (minVersionArray[i] > versionArray[i]) {
return true
} else if (minVersionArray[i] < versionArray[i]) {
return false
}
}
if (minVersionArray.length > versionArray.length) {
return true
}
return false
}

/*
Get the Version deprecation information.
Firebase DB Format:
(New) Add minVersion child to versions category with a string of the mininum version as string
*/
export async function isAppVersionDeprecated() {
if (!FIREBASE_ENABLED) {
return false
}

Logger.info(TAG, 'Checking version info')
const version = DeviceInfo.getVersion()
const versionFSPath = version.split('.').join('/')
Logger.info(TAG, `Checking version info ${version}`)
return (await firebase

const versionsInfo = (await firebase
.database()
.ref(`versions/${versionFSPath}`)
.ref('versions')
.once('value')).val()
if (!versionsInfo || !versionsInfo.minVersion) {
return false
}
const minVersion: string = versionsInfo.minVersion
return isVersionBelowMinimum(version, minVersion)
}

export async function setUserLanguage(address: string, language: string) {
Expand Down
1 change: 0 additions & 1 deletion packages/mobile/src/firebase/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export function* waitForFirebaseAuth() {

function* initializeFirebase() {
const address = yield call(getAccount)

if (!FIREBASE_ENABLED) {
Logger.info(TAG, 'Firebase disabled')
yield put(showError(ErrorMessages.FIREBASE_DISABLED))
Expand Down

0 comments on commit cc69980

Please sign in to comment.