Compare commits

..

2 Commits

11 changed files with 79 additions and 49 deletions

View File

@@ -27,7 +27,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -103,9 +103,10 @@ function K8sClustersList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -28,7 +28,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -105,9 +105,10 @@ function K8sDaemonSetsList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -28,7 +28,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -106,9 +106,10 @@ function K8sDeploymentsList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -28,7 +28,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -101,9 +101,10 @@ function K8sJobsList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -10,6 +10,7 @@ import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteRe
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder'; import { DataSource } from 'types/common/queryBuilder';
import { safeParseJSON } from './commonUtils';
import { INFRA_MONITORING_K8S_PARAMS_KEYS, K8sCategory } from './constants'; import { INFRA_MONITORING_K8S_PARAMS_KEYS, K8sCategory } from './constants';
import K8sFiltersSidePanel from './K8sFiltersSidePanel/K8sFiltersSidePanel'; import K8sFiltersSidePanel from './K8sFiltersSidePanel/K8sFiltersSidePanel';
import { IEntityColumn } from './utils'; import { IEntityColumn } from './utils';
@@ -58,9 +59,10 @@ function K8sHeader({
const urlFilters = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.FILTERS); const urlFilters = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.FILTERS);
let { filters } = currentQuery.builder.queryData[0]; let { filters } = currentQuery.builder.queryData[0];
if (urlFilters) { if (urlFilters) {
const decoded = decodeURIComponent(urlFilters); const parsed = safeParseJSON<IBuilderQuery['filters']>(urlFilters);
const parsed = JSON.parse(decoded); if (parsed) {
filters = parsed; filters = parsed;
}
} }
return { return {
...currentQuery, ...currentQuery,

View File

@@ -27,7 +27,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -104,9 +104,10 @@ function K8sNamespacesList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -27,7 +27,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -99,9 +99,10 @@ function K8sNodesList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -29,7 +29,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -92,9 +92,10 @@ function K8sPodsList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -28,7 +28,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -105,9 +105,10 @@ function K8sStatefulSetsList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -28,7 +28,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features'; import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App'; import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams, safeParseJSON } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute, GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
@@ -105,9 +105,10 @@ function K8sVolumesList({
const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => { const [groupBy, setGroupBy] = useState<IBuilderQuery['groupBy']>(() => {
const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY); const groupBy = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.GROUP_BY);
if (groupBy) { if (groupBy) {
const decoded = decodeURIComponent(groupBy); const parsed = safeParseJSON<IBuilderQuery['groupBy']>(groupBy);
const parsed = JSON.parse(decoded); if (parsed) {
return parsed as IBuilderQuery['groupBy']; return parsed;
}
} }
return []; return [];
}); });

View File

@@ -5,6 +5,7 @@
/* eslint-disable prefer-destructuring */ /* eslint-disable prefer-destructuring */
import { useMemo } from 'react'; import { useMemo } from 'react';
import * as Sentry from '@sentry/react';
import { Color } from '@signozhq/design-tokens'; import { Color } from '@signozhq/design-tokens';
import { Table, Tooltip, Typography } from 'antd'; import { Table, Tooltip, Typography } from 'antd';
import { Progress } from 'antd/lib'; import { Progress } from 'antd/lib';
@@ -260,6 +261,27 @@ export const filterDuplicateFilters = (
return uniqueFilters; return uniqueFilters;
}; };
export const safeParseJSON = <T,>(value: string): T | null => {
if (!value) {
return null;
}
try {
// Attempting to parse potentially untrusted user input from the URL.
// If the user pastes a corrupted link or modifies the URL manually (e.g., ?filters=invalidJSON),
// JSON.parse() will throw a SyntaxError. Without this try/catch block, that unhandled
// exception would bubble up during the React component render cycle and crash.
return JSON.parse(value) as T;
} catch (e) {
// By catching the SyntaxError, we gracefully degrade the user experience.
// Instead of crashing, the app ignores the malformed URL parameter and cleanly
// falls back to the default state (e.g., no filters applied).
console.error('Error parsing JSON from URL parameter:', e);
// TODO: Should we capture this error in Sentry?
return null;
}
};
export const getOrderByFromParams = ( export const getOrderByFromParams = (
searchParams: URLSearchParams, searchParams: URLSearchParams,
returnNullAsDefault = false, returnNullAsDefault = false,
@@ -271,9 +293,12 @@ export const getOrderByFromParams = (
INFRA_MONITORING_K8S_PARAMS_KEYS.ORDER_BY, INFRA_MONITORING_K8S_PARAMS_KEYS.ORDER_BY,
); );
if (orderByFromParams) { if (orderByFromParams) {
const decoded = decodeURIComponent(orderByFromParams); const parsed = safeParseJSON<{ columnName: string; order: 'asc' | 'desc' }>(
const parsed = JSON.parse(decoded); orderByFromParams,
return parsed as { columnName: string; order: 'asc' | 'desc' }; );
if (parsed) {
return parsed;
}
} }
if (returnNullAsDefault) { if (returnNullAsDefault) {
return null; return null;
@@ -287,13 +312,7 @@ export const getFiltersFromParams = (
): IBuilderQuery['filters'] | null => { ): IBuilderQuery['filters'] | null => {
const filtersFromParams = searchParams.get(queryKey); const filtersFromParams = searchParams.get(queryKey);
if (filtersFromParams) { if (filtersFromParams) {
try { return safeParseJSON<IBuilderQuery['filters']>(filtersFromParams);
const decoded = decodeURIComponent(filtersFromParams);
const parsed = JSON.parse(decoded);
return parsed as IBuilderQuery['filters'];
} catch (error) {
return null;
}
} }
return null; return null;
}; };