Skip to content

Commit 9caac8c

Browse files
Merge pull request #2747 from shubhamkumar9199/fix/unsafe-json-parse
WEB-(394)-fix: replace all direct JSON.parse usages with safe parsing utilities
2 parents 2389625 + 7a09215 commit 9caac8c

File tree

6 files changed

+47
-11
lines changed

6 files changed

+47
-11
lines changed

src/app/core/utils/json.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export function safeParse<T>(raw: string | null | undefined, defaultValue: T): T {
2+
if (!raw) return defaultValue;
3+
try {
4+
return JSON.parse(raw) as T;
5+
} catch {
6+
return defaultValue;
7+
}
8+
}
9+
10+
export function safeParseObject<T extends object>(raw: string | null | undefined, defaultValue: T): T {
11+
if (!raw) return defaultValue;
12+
try {
13+
const parsed = JSON.parse(raw);
14+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? (parsed as T) : defaultValue;
15+
} catch {
16+
return defaultValue;
17+
}
18+
}
19+
20+
export function safeParseArray<T = unknown>(raw: string | null | undefined, defaultValue: T[] = []): T[] {
21+
if (!raw) return defaultValue;
22+
try {
23+
const parsed = JSON.parse(raw);
24+
return Array.isArray(parsed) ? (parsed as T[]) : defaultValue;
25+
} catch {
26+
return defaultValue;
27+
}
28+
}

src/app/settings/settings.service.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { Injectable } from '@angular/core';
33
import { AlertService } from 'app/core/alert/alert.service';
44
import { Dates } from 'app/core/utils/dates';
5+
import { safeParse, safeParseArray, safeParseObject } from 'app/core/utils/json';
56

67
/** Environment Imports */
78
import { environment } from '../../environments/environment';
@@ -108,8 +109,9 @@ export class SettingsService {
108109
/**
109110
* Returns date format setting.
110111
*/
111-
get dateFormat() {
112-
return JSON.parse(localStorage.getItem('mifosXDateFormat'));
112+
get dateFormat(): string {
113+
const parsed = safeParse<string | null>(localStorage.getItem('mifosXDateFormat'), null);
114+
return typeof parsed === 'string' && parsed.length > 0 ? parsed : 'dd MMMM yyyy';
113115
}
114116

115117
/**
@@ -119,7 +121,10 @@ export class SettingsService {
119121
if (!localStorage.getItem('mifosXLanguage')) {
120122
this.setDefaultLanguage();
121123
}
122-
return JSON.parse(localStorage.getItem('mifosXLanguage'));
124+
return safeParseObject<{ name: string; code: string } | undefined>(
125+
localStorage.getItem('mifosXLanguage'),
126+
undefined
127+
);
123128
}
124129

125130
get languageCode() {
@@ -147,7 +152,7 @@ export class SettingsService {
147152
* Returns list of default server
148153
*/
149154
get servers() {
150-
return JSON.parse(localStorage.getItem('mifosXServers'));
155+
return safeParseArray<string>(localStorage.getItem('mifosXServers'), []);
151156
}
152157

153158
/**
@@ -160,7 +165,7 @@ export class SettingsService {
160165
if (environment.baseApiUrl && environment.baseApiUrl !== '') {
161166
return environment.baseApiUrl;
162167
} else {
163-
return this.servers()[0];
168+
return this.servers[0];
164169
}
165170
}
166171

@@ -217,7 +222,7 @@ export class SettingsService {
217222
* Returns list of Tenant Identifiers
218223
*/
219224
get tenantIdentifiers(): any {
220-
return JSON.parse(localStorage.getItem('mifosXTenantIdentifiers'));
225+
return safeParseArray<string>(localStorage.getItem('mifosXTenantIdentifiers'), []);
221226
}
222227

223228
/**
@@ -260,6 +265,6 @@ export class SettingsService {
260265
}
261266

262267
get themeDarkEnabled(): boolean {
263-
return JSON.parse(localStorage.getItem('mifosXThemeDarkEnabled'));
268+
return safeParse<boolean>(localStorage.getItem('mifosXThemeDarkEnabled'), false);
264269
}
265270
}

src/app/shared/theme-picker/theme-storage.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Injectable, EventEmitter } from '@angular/core';
2+
import { safeParseObject } from 'app/core/utils/json';
23
import { Theme } from './theme.model';
34
import { ThemeManagerService } from './theme-manager.service';
45

@@ -19,7 +20,7 @@ export class ThemeStorageService {
1920
}
2021

2122
getTheme(): Theme {
22-
return JSON.parse(localStorage.getItem(this.themeStorageKey));
23+
return safeParseObject<Theme | null>(localStorage.getItem(this.themeStorageKey), null);
2324
}
2425

2526
clearTheme() {

src/app/system/configurations/business-date-tab/business-date-tab.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class BusinessDateTabComponent implements OnInit {
4646
businessDateData: any;
4747

4848
dateIndex = 0;
49-
userDateFormat: '';
49+
userDateFormat: string = '';
5050
isBusinessDateEnabled = false;
5151
isEditInProgress = false;
5252

src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { MatDivider } from '@angular/material/divider';
1515
import { NgIf, NgFor, KeyValuePipe } from '@angular/common';
1616
import { DateFormatPipe } from '../../pipes/date-format.pipe';
1717
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
18+
import { safeParseObject } from 'app/core/utils/json';
1819

1920
@Component({
2021
selector: 'mifosx-view-checker-inbox',
@@ -52,7 +53,7 @@ export class ViewCheckerInboxComponent {
5253
) {
5354
this.route.data.subscribe((data: { checkerInboxDetail: any }) => {
5455
this.checkerInboxDetail = data.checkerInboxDetail;
55-
this.jsondata = JSON.parse(this.checkerInboxDetail.commandAsJson);
56+
this.jsondata = safeParseObject<any>(this.checkerInboxDetail.commandAsJson, {});
5657
this.displayJSONData = !_.isEmpty(this.jsondata);
5758
});
5859
}

src/app/web-app.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { Dates } from './core/utils/dates';
3131
import { animate, style, transition, trigger } from '@angular/animations';
3232
import { I18nService } from './core/i18n/i18n.service';
3333
import { ThemingService } from './shared/theme-toggle/theming.service';
34+
import { safeParseArray } from 'app/core/utils/json';
3435

3536
import { AuthService } from './zitadel/auth.service';
3637

@@ -195,7 +196,7 @@ export class WebAppComponent implements OnInit, OnDestroy {
195196
// Stores top 100 user activites as local storage object.
196197
let activities: string[] = [];
197198
if (localStorage.getItem('mifosXLocation')) {
198-
const activitiesArray: string[] = JSON.parse(localStorage.getItem('mifosXLocation'));
199+
const activitiesArray = safeParseArray<string>(localStorage.getItem('mifosXLocation'), []);
199200
const length = activitiesArray.length;
200201
activities = length > 100 ? activitiesArray.slice(length - 100) : activitiesArray;
201202
}

0 commit comments

Comments
 (0)