From 0696698c358441ad2589d0f6e7faf83dad446fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20David=20Guti=C3=A9rrez?= Date: Wed, 2 Aug 2023 13:09:02 +0200 Subject: [PATCH] fix: fix Management > Rules search bar filters Add id field Fix groups filter in Rule info flyout Remove onFiltersChange handler --- .../ruleset/components/ruleset-suggestions.ts | 16 + .../ruleset/components/ruleset-table.tsx | 1 - .../management/ruleset/views/rule-info.tsx | 328 ++++++++++++------ 3 files changed, 232 insertions(+), 113 deletions(-) diff --git a/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-suggestions.ts b/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-suggestions.ts index 31a64e7de2..b63412b33e 100644 --- a/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-suggestions.ts +++ b/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-suggestions.ts @@ -3,6 +3,7 @@ import { WzRequest } from '../../../../../../react-services/wz-request'; const rulesItems = { field(currentValue) { return [ + { label: 'id', description: 'filter by ID' }, { label: 'filename', description: 'filter by filename' }, { label: 'gdpr', description: 'filter by GDPR requirement' }, { label: 'gpg13', description: 'filter by GPG requirement' }, @@ -20,6 +21,21 @@ const rulesItems = { value: async (currentValue, { field }) => { try { switch (field) { + case 'id': { + const filter = { + distinct: true, + limit: 30, + select: field, + sort: `+${field}`, + ...(currentValue ? { q: `id~${currentValue}` } : {}), + }; + const result = await WzRequest.apiReq('GET', '/rules', { + params: filter, + }); + return result?.data?.data?.affected_items.map(label => ({ + label: label[field], + })); + } case 'status': { return ['enabled', 'disabled'].map(label => ({ label })); } diff --git a/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-table.tsx b/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-table.tsx index df8f432735..2358773423 100644 --- a/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-table.tsx +++ b/plugins/main/public/controllers/management/components/management/ruleset/components/ruleset-table.tsx @@ -139,7 +139,6 @@ const RulesFlyoutTable = ({ downloadCsv={true} showReload={true} filters={filters} - onFiltersChange={updateFilters} tablePageSizeOptions={[10, 25, 50, 100]} /> {isFlyoutVisible && ( diff --git a/plugins/main/public/controllers/management/components/management/ruleset/views/rule-info.tsx b/plugins/main/public/controllers/management/components/management/ruleset/views/rule-info.tsx index 89def62c38..c2c70e3084 100644 --- a/plugins/main/public/controllers/management/components/management/ruleset/views/rule-info.tsx +++ b/plugins/main/public/controllers/management/components/management/ruleset/views/rule-info.tsx @@ -18,7 +18,10 @@ import { import { WzRequest } from '../../../../../../react-services/wz-request'; -import { ResourcesHandler, ResourcesConstants } from '../../common/resources-handler'; +import { + ResourcesHandler, + ResourcesConstants, +} from '../../common/resources-handler'; import WzTextWithTooltipTruncated from '../../../../../../components/common/wz-text-with-tooltip-if-truncated'; import { UI_ERROR_SEVERITIES } from '../../../../../../react-services/error-orchestrator/types'; import { UI_LOGGER_LEVELS } from '../../../../../../../common/constants'; @@ -46,7 +49,7 @@ export default class WzRuleInfo extends Component { mitreRuleId: '', mitreIds: [], currentRuleInfo: {}, - isLoading: true + isLoading: true, }; this.resourcesHandler = new ResourcesHandler(ResourcesConstants.RULES); @@ -95,7 +98,10 @@ export default class WzRuleInfo extends Component { let result = value.match(regex); if (result !== null) { for (const oldValue of result) { - let newValue = oldValue.replace('$(', ``); + let newValue = oldValue.replace( + '$(', + ``, + ); newValue = newValue.replace(')', ' '); value = value.replace(oldValue, newValue); } @@ -133,8 +139,10 @@ export default class WzRuleInfo extends Component { width: '15%', render: (value, item) => { return ( - - handleFileClick(event, item)}>{value} + + handleFileClick(event, item)}> + {value} + ); }, @@ -155,7 +163,7 @@ export default class WzRuleInfo extends Component { async componentDidUpdate(prevProps, prevState) { if (prevState.currentRuleId !== this.state.currentRuleId) - await this.loadRule() + await this.loadRule(); } async loadRule() { @@ -167,7 +175,9 @@ export default class WzRuleInfo extends Component { rule_ids: currentRuleId, }, }); - const currentRule = result?.data?.affected_items?.length ? result.data.affected_items[0] : {}; + const currentRule = result?.data?.affected_items?.length + ? result.data.affected_items[0] + : {}; const compliance = this.buildCompliance(currentRule); if (compliance?.mitre?.length && currentRuleId !== mitreRuleId) { @@ -179,14 +189,14 @@ export default class WzRuleInfo extends Component { mitreIds: [], mitreTactics: [], mitreTechniques: [], - } + }; } this.setState({ currentRuleInfo: currentRule, compliance: compliance, isLoading: false, - ...mitreState + ...mitreState, }); } catch (error) { const options = { @@ -201,7 +211,6 @@ export default class WzRuleInfo extends Component { }; getErrorOrchestrator().handleError(options); } - } /** * Build an object with the compliance info about a rule @@ -209,25 +218,45 @@ export default class WzRuleInfo extends Component { */ buildCompliance(ruleInfo) { const compliance = {}; - const complianceKeys = ['gdpr', 'gpg13', 'hipaa', 'nist-800-53', 'pci', 'tsc', 'mitre']; - Object.keys(ruleInfo).forEach((key) => { - if (complianceKeys.includes(key) && ruleInfo[key].length) compliance[key] = ruleInfo[key]; + const complianceKeys = [ + 'gdpr', + 'gpg13', + 'hipaa', + 'nist-800-53', + 'pci', + 'tsc', + 'mitre', + ]; + Object.keys(ruleInfo).forEach(key => { + if (complianceKeys.includes(key) && ruleInfo[key].length) + compliance[key] = ruleInfo[key]; }); return compliance || {}; } buildComplianceBadges(item) { const badgeList = []; - const fields = ['pci_dss', 'gpg13', 'hipaa', 'gdpr', 'nist_800_53', 'tsc', 'mitre']; - const buildBadge = (field) => { - + const fields = [ + 'pci_dss', + 'gpg13', + 'hipaa', + 'gdpr', + 'nist_800_53', + 'tsc', + 'mitre', + ]; + const buildBadge = field => { return ( - + ev.stopPropagation()} + onClick={ev => ev.stopPropagation()} onClickAriaLabel={field.toUpperCase()} - color="hollow" + color='hollow' style={{ margin: '1px 2px' }} > {field.toUpperCase()} @@ -250,7 +279,7 @@ export default class WzRuleInfo extends Component { error: error, message: error.message || error, title: error.name || error, - } + }, }; getErrorOrchestrator().handleError(options); } @@ -262,9 +291,10 @@ export default class WzRuleInfo extends Component { * Clean the existing filters and sets the new ones and back to the previous section */ setNewFiltersAndBack(filters) { - window.history.pushState("", + window.history.pushState( + '', window.document.title, - window.location.href.replace(new RegExp('&redirectRule=' + '[^&]*'), '') + window.location.href.replace(new RegExp('&redirectRule=' + '[^&]*'), ''), ); this.props.cleanFilters(); this.props.onFiltersChange(filters); @@ -281,37 +311,47 @@ export default class WzRuleInfo extends Component { renderInfo(id = '', level = '', file = '', path = '', groups = []) { return ( - + ID - + this.setNewFiltersAndBack({q: `id=${id}`})} + onClick={async () => + this.setNewFiltersAndBack({ q: `id=${id}` }) + } > {id} - + Level - + this.setNewFiltersAndBack({q: `level=${level}`})} + onClick={async () => + this.setNewFiltersAndBack({ q: `level=${level}` }) + } > {level} - + File - + - this.setNewFiltersAndBack({q: `filename=${file}`}) + this.setNewFiltersAndBack({ q: `filename=${file}` }) } > {file} @@ -319,13 +359,13 @@ export default class WzRuleInfo extends Component { - + Path - + - this.setNewFiltersAndBack({q: `relative_dirname=${path}`}) + this.setNewFiltersAndBack({ q: `relative_dirname=${path}` }) } > {path} @@ -333,11 +373,11 @@ export default class WzRuleInfo extends Component { - + Groups {this.renderGroups(groups)} - + ); } @@ -347,16 +387,16 @@ export default class WzRuleInfo extends Component { let link = ''; let name = ''; - value.forEach((item) => { - if (item.type === 'cve'){ + value.forEach(item => { + if (item.type === 'cve') { name = item.name; } - if (item.type === 'link'){ + if (item.type === 'link') { link = ( {item.name} @@ -369,7 +409,11 @@ export default class WzRuleInfo extends Component { {name}: {link} ); - } else if (value && typeof value === 'object' && value.constructor === Object) { + } else if ( + value && + typeof value === 'object' && + value.constructor === Object + ) { let list = []; Object.keys(value).forEach((key, idx) => { list.push( @@ -378,7 +422,7 @@ export default class WzRuleInfo extends Component { {value[key]} {idx < Object.keys(value).length - 1 && ', '}
- + , ); }); return ( @@ -387,7 +431,11 @@ export default class WzRuleInfo extends Component { ); } else { - return {value}; + return ( + + {value} + + ); } } @@ -400,13 +448,21 @@ export default class WzRuleInfo extends Component { // Exclude group key of details Object.keys(details) - .filter((key) => key !== 'group') - .forEach((key) => { + .filter(key => key !== 'group') + .forEach(key => { detailsToRender.push( - - {key} - {details[key] === '' ? 'true' : this.getFormattedDetails(details[key])} - + + + {key} + + {details[key] === '' + ? 'true' + : this.getFormattedDetails(details[key])} + , ); }); return {detailsToRender}; @@ -422,14 +478,19 @@ export default class WzRuleInfo extends Component { listGroups.push( this.setNewFiltersAndBack({q: `group=${group}`})} + onClick={async () => + this.setNewFiltersAndBack({ q: `groups=${group}` }) + } > - + {group} {index < groups.length - 1 && ', '} - + , ); }); return ( @@ -447,9 +508,10 @@ export default class WzRuleInfo extends Component { tactic_ids: tactics.toString(), }, }); - const formattedData = ((data || {}).data.data || {}).affected_items || [] || {}; + const formattedData = + ((data || {}).data.data || {}).affected_items || [] || {}; formattedData && - formattedData.forEach((item) => { + formattedData.forEach(item => { tacticsObj.push(item.name); }); return tacticsObj; @@ -465,21 +527,23 @@ export default class WzRuleInfo extends Component { const mitreName = []; const mitreIds = []; const mitreTactics = await Promise.all( - compliance.map(async (i) => { + compliance.map(async i => { const data = await WzRequest.apiReq('GET', '/mitre/techniques', { params: { q: `external_id=${i}`, }, }); - const formattedData = (((data || {}).data.data || {}).affected_items || [])[0] || {}; + const formattedData = + (((data || {}).data.data || {}).affected_items || [])[0] || {}; const tactics = this.getTacticsNames(formattedData.tactics) || []; mitreName.push(formattedData.name); mitreIds.push(i); return tactics; - }) + }), ); if (mitreTactics.length) { - let removeDuplicates = (arr) => arr.filter((v, i) => arr.indexOf(v) === i); + let removeDuplicates = arr => + arr.filter((v, i) => arr.indexOf(v) === i); const uniqueTactics = removeDuplicates(mitreTactics.flat()); Object.assign(newMitreState, { mitreRuleId: currentRuleId, @@ -515,8 +579,6 @@ export default class WzRuleInfo extends Component { ? this.state.currentRuleId : this.props.state.ruleInfo.current; - - const listCompliance = []; if (compliance.mitre) delete compliance.mitre; const keys = Object.keys(compliance); @@ -527,9 +589,11 @@ export default class WzRuleInfo extends Component { return ( this.setNewFiltersAndBack({q: `${key}=${element}`})} + onClick={async () => + this.setNewFiltersAndBack({ q: `${key}=${element}` }) + } > - + {element} @@ -539,11 +603,15 @@ export default class WzRuleInfo extends Component { }); listCompliance.push( - + {this.complianceEquivalences[key]}

{values}

- -
+ +
, ); } @@ -553,10 +621,12 @@ export default class WzRuleInfo extends Component { - this.setNewFiltersAndBack({q: `mitre=${this.state.mitreIds[index]}`}) + this.setNewFiltersAndBack({ + q: `mitre=${this.state.mitreIds[index]}`, + }) } > - + {element} @@ -565,21 +635,35 @@ export default class WzRuleInfo extends Component { ); }); listCompliance.push( - - {this.complianceEquivalences['mitreTechniques']} - {(this.state.mitreLoading && ) ||

{values}

} - -
+ + + {this.complianceEquivalences['mitreTechniques']} + + {(this.state.mitreLoading && ) || ( +

{values}

+ )} + +
, ); } if (this.state.mitreTactics && this.state.mitreTactics.length) { listCompliance.push( - - {this.complianceEquivalences['mitreTactics']} + + + {this.complianceEquivalences['mitreTactics']} +

{this.state.mitreTactics.toString()}

- -
+ +
, ); } @@ -598,7 +682,7 @@ export default class WzRuleInfo extends Component { window.location.href = window.location.href.replace( new RegExp('redirectRule=' + '[^&]*'), - `redirectRule=${ruleId}` + `redirectRule=${ruleId}`, ); this.setState({ currentRuleId: ruleId, isLoading: true }); } @@ -621,7 +705,7 @@ export default class WzRuleInfo extends Component { return value; } - onClickRow = (item) => { + onClickRow = item => { return { onClick: () => { this.changeBetweenRules(item.id); @@ -630,38 +714,47 @@ export default class WzRuleInfo extends Component { }; render() { - const { description, details, filename, relative_dirname, level, id, groups } = this.state.currentRuleInfo; + const { + description, + details, + filename, + relative_dirname, + level, + id, + groups, + } = this.state.currentRuleInfo; const compliance = this.buildCompliance(this.state.currentRuleInfo); return ( <> - + - { - description && ( - ) - } + {description && ( + + )} View alerts of this Rule - + - + {/* Cards */} @@ -669,19 +762,25 @@ export default class WzRuleInfo extends Component { {/* General info */} +

Information

} - paddingSize="none" + paddingSize='none' initialIsOpen={true} isLoading={this.state.isLoading} isLoadingMessage={''} > - - {this.renderInfo(id, level, filename, relative_dirname, groups)} + + {this.renderInfo( + id, + level, + filename, + relative_dirname, + groups, + )}
@@ -690,18 +789,20 @@ export default class WzRuleInfo extends Component { +

Details

} - paddingSize="none" + paddingSize='none' initialIsOpen={true} isLoading={this.state.isLoading} isLoadingMessage={''} > - {this.renderDetails(details)} + + {this.renderDetails(details)} +
@@ -710,18 +811,18 @@ export default class WzRuleInfo extends Component { +

Compliance

} - paddingSize="none" + paddingSize='none' initialIsOpen={true} isLoading={this.state.isLoading} isLoadingMessage={''} > - + {this.renderCompliance(compliance)}
@@ -732,29 +833,32 @@ export default class WzRuleInfo extends Component { +

Related rules

} isLoading={this.state.isLoading} isLoadingMessage={''} - paddingSize="none" + paddingSize='none' initialIsOpen={true} > - + - {this.state.currentRuleInfo?.filename && + {this.state.currentRuleInfo?.filename && ( - } + )}