diff --git a/components/brave_rewards/resources/android_page/storage.ts b/components/brave_rewards/resources/android_page/storage.ts index 76191859ae10..a2c3e8f84e80 100644 --- a/components/brave_rewards/resources/android_page/storage.ts +++ b/components/brave_rewards/resources/android_page/storage.ts @@ -85,19 +85,29 @@ export const defaultState: Rewards.State = { export const load = (): Rewards.State => { const data = window.localStorage.getItem(keyName) - let state: Rewards.State = defaultState - if (data) { - try { - state = JSON.parse(data) - if (!state || state.version !== defaultState.version) { - throw new Error('State versions do not match') - } - state.initializing = true - } catch (e) { - console.error('Could not parse local storage data: ', e) - } + if (!data) { + return defaultState + } + + let parsedData: any + try { + parsedData = JSON.parse(data) + } catch { + parsedData = null + } + + if (!parsedData || typeof parsedData !== 'object') { + console.error('Local storage data is not an object') + return defaultState + } + + if (parsedData.version !== defaultState.version) { + console.error('Local storage state version does not match') + return defaultState } - return state + + parsedData.initializing = true + return parsedData as Rewards.State } export const debouncedSave = debounce((data: Rewards.State) => { diff --git a/components/brave_rewards/resources/page/storage.test.ts b/components/brave_rewards/resources/page/storage.test.ts new file mode 100644 index 000000000000..8aa2d4fe9d9e --- /dev/null +++ b/components/brave_rewards/resources/page/storage.test.ts @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { load, defaultState } from './storage' + +describe('local storage', () => { + describe('loading', () => { + it('returns default state if local storage data is not present', () => { + expect(load()).toEqual(defaultState) + }) + + it('returns default state if local storage is not JSON', () => { + localStorage['rewards-data'] = 'abc' + expect(load()).toEqual(defaultState) + }) + + it('returns default state if local storage is not JSON object', () => { + localStorage['rewards-data'] = '[]' + expect(load()).toEqual(defaultState) + }) + + it('returns default state if local storage is empty JSON object', () => { + localStorage['rewards-data'] = '{}' + expect(load()).toEqual(defaultState) + }) + + it('returns default state if local storage version does not match', () => { + localStorage['rewards-data'] = '{ "version": 0 }' + expect(load()).toEqual(defaultState) + }) + + it('returns loaded state with initializing flag set', () => { + const mockData = { version: defaultState.version } + localStorage['rewards-data'] = JSON.stringify(mockData) + expect(load()).toEqual({ ...mockData, initializing: true }) + }) + }) +}) diff --git a/components/brave_rewards/resources/page/storage.ts b/components/brave_rewards/resources/page/storage.ts index 893d23f09385..37645216682f 100644 --- a/components/brave_rewards/resources/page/storage.ts +++ b/components/brave_rewards/resources/page/storage.ts @@ -85,19 +85,29 @@ export const defaultState: Rewards.State = { export const load = (): Rewards.State => { const data = window.localStorage.getItem(keyName) - let state: Rewards.State = defaultState - if (data) { - try { - state = JSON.parse(data) - if (!state || state.version !== defaultState.version) { - throw new Error('State versions do not match') - } - state.initializing = true - } catch (e) { - console.error('Could not parse local storage data: ', e) - } + if (!data) { + return defaultState + } + + let parsedData: any + try { + parsedData = JSON.parse(data) + } catch { + parsedData = null + } + + if (!parsedData || typeof parsedData !== 'object') { + console.error('Local storage data is not an object') + return defaultState + } + + if (parsedData.version !== defaultState.version) { + console.error('Local storage state version does not match') + return defaultState } - return state + + parsedData.initializing = true + return parsedData as Rewards.State } export const debouncedSave = debounce((data: Rewards.State) => {