@@ -65,6 +65,42 @@ export const HDS_THEMING_LOCALSTORAGE_DATA = 'hds-theming-data';
6565export const DEFAULT_THEMING_OPTION_LIGHT_THEME = HdsModesLightValues . CdsG0 ;
6666export const DEFAULT_THEMING_OPTION_DARK_THEME = HdsModesDarkValues . CdsG100 ;
6767
68+ type StoredThemingData = {
69+ theme : HdsThemes | undefined ;
70+ options : HdsThemingOptions ;
71+ } ;
72+
73+ // We use this guard function to check if the data parsed from `localStorage` conforms to the `StoredThemingData` type and so is safe to use.
74+ // This prevents the application from using corrupted, malformed or malicious data, by validating the object structure, theme, and mode values.
75+
76+ function isSafeStoredThemingData ( data : unknown ) : data is StoredThemingData {
77+ if ( typeof data !== 'object' || data === null ) return false ;
78+
79+ const d = data as Record < string , unknown > ;
80+
81+ const isSafeThemeData =
82+ // there is no stored `theme` key in the object (eg. the `default` theme was selected)
83+ ! ( 'theme' in d ) ||
84+ // there is a `theme` value and is one of the valid `HdsThemes`
85+ d [ 'theme' ] === undefined ||
86+ THEMES . includes ( d [ 'theme' ] as HdsThemes ) ;
87+
88+ const options = d [ 'options' ] as Record < string , unknown > | undefined ;
89+
90+ const isSafeOptionsData =
91+ // there is no stored `options` key in the object (eg. it's the first run of the application)
92+ ! ( 'options' in d ) ||
93+ // there is an `options` value and has valid entries
94+ ( typeof options === 'object' &&
95+ options !== null &&
96+ 'lightTheme' in options &&
97+ MODES_LIGHT . includes ( options [ 'lightTheme' ] as HdsModesLight ) &&
98+ 'darkTheme' in options &&
99+ MODES_DARK . includes ( options [ 'darkTheme' ] as HdsModesDark ) ) ;
100+
101+ return isSafeThemeData && isSafeOptionsData ;
102+ }
103+
68104export default class HdsThemingService extends Service {
69105 @tracked _currentTheme : HdsThemes | undefined = undefined ;
70106 @tracked _currentMode : HdsModes | undefined = undefined ;
@@ -77,6 +113,7 @@ export default class HdsThemingService extends Service {
77113 const rawStoredThemingData = localStorage . getItem (
78114 HDS_THEMING_LOCALSTORAGE_DATA
79115 ) ;
116+
80117 if ( rawStoredThemingData !== null ) {
81118 let storedThemingData : unknown ;
82119 try {
@@ -87,16 +124,18 @@ export default class HdsThemingService extends Service {
87124 `Error while reading local storage '${ HDS_THEMING_LOCALSTORAGE_DATA } ' for theming` ,
88125 error
89126 ) ;
90- storedThemingData = undefined ;
91127 }
92- if ( storedThemingData ) {
93- const { theme, options } = storedThemingData as {
94- theme : HdsThemes | undefined ;
95- options : HdsThemingOptions ;
96- } ;
128+
129+ if ( isSafeStoredThemingData ( storedThemingData ) ) {
130+ this . setTheme ( {
131+ theme : storedThemingData . theme ,
132+ options : storedThemingData . options ,
133+ } ) ;
134+ } else {
135+ // if data is not safe or malformed, reset theming to its defaults
97136 this . setTheme ( {
98- theme,
99- options,
137+ theme : undefined ,
138+ options : undefined ,
100139 } ) ;
101140 }
102141 }
0 commit comments