From 3e3551fd85c95f416057ad328eca1ead3af9adb6 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Wed, 3 Apr 2024 17:59:02 +0200 Subject: [PATCH 01/18] Add setting to disable update check service in dashboard (#6560) * Add setting and segregate columns * Disable api table updater features * Change wazuh-core constants * Connect root updater component to redux configuration * Make the current version column conditional * Fix getApisAvailableUpdates bind * Fix checkApi function bind --- plugins/main/common/constants.ts | 26 ++ plugins/main/public/app.js | 5 +- .../components/common/permissions/button.tsx | 123 ++++-- .../settings/api/api-table-columns.tsx | 301 ++++++++++++++ .../components/settings/api/api-table.js | 369 +++--------------- .../settings/api/check-updates-button.tsx | 35 ++ .../wz-updates-notification/index.tsx | 9 +- .../wz-updates-notification.tsx | 34 ++ plugins/wazuh-core/common/constants.ts | 26 ++ 9 files changed, 552 insertions(+), 376 deletions(-) create mode 100644 plugins/main/public/components/settings/api/api-table-columns.tsx create mode 100644 plugins/main/public/components/settings/api/check-updates-button.tsx create mode 100644 plugins/main/public/components/wz-updates-notification/wz-updates-notification.tsx diff --git a/plugins/main/common/constants.ts b/plugins/main/common/constants.ts index 11b1d6adba..752f902046 100644 --- a/plugins/main/common/constants.ts +++ b/plugins/main/common/constants.ts @@ -1740,6 +1740,32 @@ export const PLUGIN_SETTINGS: { [key: string]: TPluginSetting } = { return schema.number({ validate: this.validate.bind(this) }); }, }, + 'wazuh.updates.disabled': { + title: 'Check updates', + description: 'Define if the check updates service is active.', + category: SettingCategory.GENERAL, + type: EpluginSettingType.switch, + defaultValue: false, + isConfigurableFromFile: false, + isConfigurableFromUI: false, + options: { + switch: { + values: { + disabled: { label: 'false', value: false }, + enabled: { label: 'true', value: true }, + }, + }, + }, + uiFormTransformChangedInputValue: function ( + value: boolean | string, + ): boolean { + return Boolean(value); + }, + validate: SettingsValidator.isBoolean, + validateBackend: function (schema) { + return schema.boolean(); + }, + }, 'vulnerabilities.pattern': { title: 'Index pattern', description: 'Default index pattern to use for vulnerabilities.', diff --git a/plugins/main/public/app.js b/plugins/main/public/app.js index f8e23658ea..bf41808e98 100644 --- a/plugins/main/public/app.js +++ b/plugins/main/public/app.js @@ -77,7 +77,7 @@ app.run([ .then(item => { store.dispatch(updateCurrentPlatform(item)); }) - .catch(() => { }); + .catch(() => {}); // Init the process of refreshing the user's token when app start. checkPluginVersion().finally(WzAuthentication.refresh); @@ -98,10 +98,9 @@ app.run(function ($rootElement) { - + `); - // Bind deleteExistentToken on Log out component. $('.euiHeaderSectionItem__button, .euiHeaderSectionItemButton').on( 'mouseleave', diff --git a/plugins/main/public/components/common/permissions/button.tsx b/plugins/main/public/components/common/permissions/button.tsx index 8bfa0b34c6..b2b5d5d241 100644 --- a/plugins/main/public/components/common/permissions/button.tsx +++ b/plugins/main/public/components/common/permissions/button.tsx @@ -21,37 +21,65 @@ import { EuiButtonIcon, EuiLink, EuiToolTip, - EuiSpacer + EuiSpacer, } from '@elastic/eui'; import { WzPermissionsFormatted } from './format'; -export interface IUserPermissionsObject{action: string, resource: string}; -export type TUserPermissionsFunction = (props : any) => TUserPermissions; +export interface IUserPermissionsObject { + action: string; + resource: string; +} +export type TUserPermissionsFunction = (props: any) => TUserPermissions; export type TUserPermissions = (string | IUserPermissionsObject)[] | null; export type TUserRoles = string[] | null; -export type TUserRolesFunction = (props : any) => TUserRoles; +export type TUserRolesFunction = (props: any) => TUserRoles; -interface IWzButtonPermissionsProps{ - permissions?: TUserPermissions | TUserPermissionsFunction - roles?: TUserRoles | TUserRolesFunction - buttonType?: 'default' | 'empty' | 'icon' | 'link' | 'switch' - tooltip?: any - rest?: any -}; +interface IWzButtonPermissionsProps { + permissions?: TUserPermissions | TUserPermissionsFunction; + roles?: TUserRoles | TUserRolesFunction; + buttonType?: 'default' | 'empty' | 'icon' | 'link' | 'switch'; + iconType?: string; + tooltip?: any; + rest?: any; +} -export const WzButtonPermissions = ({permissions = null, roles = null, buttonType = 'default', tooltip, ...rest} : IWzButtonPermissionsProps) => { - const [userPermissionRequirements, userPermissions] = useUserPermissionsRequirements(typeof permissions === 'function' ? permissions(rest) : permissions); - const [userRolesRequirements, userRoles] = useUserRolesRequirements(typeof roles === 'function' ? roles(rest) : roles); +export const WzButtonPermissions = ({ + permissions = null, + roles = null, + buttonType = 'default', + tooltip, + ...rest +}: IWzButtonPermissionsProps) => { + const [userPermissionRequirements, userPermissions] = + useUserPermissionsRequirements( + typeof permissions === 'function' ? permissions(rest) : permissions, + ); + const [userRolesRequirements, userRoles] = useUserRolesRequirements( + typeof roles === 'function' ? roles(rest) : roles, + ); - const Button = buttonType === 'default' ? EuiButton - : buttonType === 'empty' ? EuiButtonEmpty - : buttonType === 'icon' ? EuiButtonIcon - : buttonType === 'link' ? EuiLink - : buttonType === 'switch' ? EuiSwitch - : null - const disabled = Boolean(userRolesRequirements || userPermissionRequirements || rest.isDisabled || rest.disabled); - const disabledProp = !['link', 'switch'].includes(buttonType) ? { isDisabled: disabled } : { disabled }; + const Button = + buttonType === 'default' + ? EuiButton + : buttonType === 'empty' + ? EuiButtonEmpty + : buttonType === 'icon' + ? EuiButtonIcon + : buttonType === 'link' + ? EuiLink + : buttonType === 'switch' + ? EuiSwitch + : null; + const disabled = Boolean( + userRolesRequirements || + userPermissionRequirements || + rest.isDisabled || + rest.disabled, + ); + const disabledProp = !['link', 'switch'].includes(buttonType) + ? { isDisabled: disabled } + : { disabled }; const onClick = disabled || !rest.onClick ? undefined : rest.onClick; const onChange = disabled || !rest.onChange ? undefined : rest.onChange; const customProps = { ...rest, onChange, onClick }; @@ -59,34 +87,45 @@ export const WzButtonPermissions = ({permissions = null, roles = null, buttonTyp if (buttonType == 'switch') delete customProps.onClick; const button = - -

+ +
+

+ No results +

+ +
+
+ No results were found. +
+ +
+
+ - -
-
-
- -
- -
+ Agents summary + +
+ +
+
- - - - - -

+
+
+ +
+ +
+
+ Rule level 12 to 14 +
+
+
+
+ +
+
+ +
+
+ + + Last 24 hours alerts + + -
diff --git a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-query.ts b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-query.ts index 4c1e524c8b..170a3e6b28 100644 --- a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-query.ts +++ b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-query.ts @@ -2,6 +2,10 @@ export const getLastAlertsQuery = ( currentIndexPattern: string, isClusterEnabled: boolean, clusterValue: string, + ruleLevelRange: { + minRuleLevel: number; + maxRuleLevel?: number; + }, ) => { const clusterField = isClusterEnabled ? 'cluster.name' : 'manager.name'; return { @@ -27,6 +31,14 @@ export const getLastAlertsQuery = ( }, }, }, + { + range: { + 'rule.level': { + gte: ruleLevelRange.minRuleLevel, + lte: ruleLevelRange.maxRuleLevel, + }, + }, + }, { query: { match: { diff --git a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-service.ts b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-service.ts index 7b9a715873..693641ed99 100644 --- a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-service.ts +++ b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-service.ts @@ -17,7 +17,9 @@ interface Last24HoursAlerts { * This fetch the last 24 hours alerts from the selected cluster * TODO: The search function should be moved to a common place */ -export const getLast24HoursAlerts = async (): Promise => { +export const getLast24HoursAlerts = async ( + ruleLevelRange, +): Promise => { try { const currentIndexPattern = await getDataPlugin().indexPatterns.get( AppState.getCurrentPattern() || getSettingDefaultValue('pattern'), @@ -31,6 +33,7 @@ export const getLast24HoursAlerts = async (): Promise => { currentIndexPattern, isCluster, clusterValue, + ruleLevelRange, ); const result = await search(lastAlertsQuery); diff --git a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx index 950e659e15..9cd11c5a94 100644 --- a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx +++ b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx @@ -1,7 +1,13 @@ import React, { useState, useEffect } from 'react'; -import { EuiStat, EuiFlexItem, EuiLink, EuiToolTip } from '@elastic/eui'; +import { + EuiStat, + EuiFlexItem, + EuiLink, + EuiToolTip, + EuiText, +} from '@elastic/eui'; import { getLast24HoursAlerts } from './last-alerts-service'; -import { UI_COLOR_AGENT_STATUS } from '../../../../../common/constants'; +import { UI_COLOR_STATUS } from '../../../../../common/constants'; import { getCore } from '../../../../kibana-services'; import { RedirectAppLinks } from '../../../../../../../src/plugins/opensearch_dashboards_react/public'; import { @@ -10,22 +16,87 @@ import { HttpError, } from '../../../../react-services/error-management'; -export function LastAlertsStat() { +export function LastAlertsStat({ severity }: { severity: string }) { const [countLastAlerts, setCountLastAlerts] = useState(null); const [discoverLocation, setDiscoverLocation] = useState(''); + const severityLabel = { + low: { + label: 'Low', + color: UI_COLOR_STATUS.success, + ruleLevelRange: { + minRuleLevel: 0, + maxRuleLevel: 6, + }, + }, + medium: { + label: 'Medium', + color: UI_COLOR_STATUS.info, + ruleLevelRange: { + minRuleLevel: 7, + maxRuleLevel: 11, + }, + }, + high: { + label: 'High', + color: UI_COLOR_STATUS.warning, + ruleLevelRange: { + minRuleLevel: 12, + maxRuleLevel: 14, + }, + }, + critical: { + label: 'Critical', + color: UI_COLOR_STATUS.danger, + ruleLevelRange: { + minRuleLevel: 15, + }, + }, + }; useEffect(() => { const getCountLastAlerts = async () => { try { - const { indexPatternName, cluster, count } = - await getLast24HoursAlerts(); + const { indexPatternName, cluster, count } = await getLast24HoursAlerts( + severityLabel[severity].ruleLevelRange, + ); setCountLastAlerts(count); + const core = getCore(); + + // Check if the new discover is enabled to build the URL + const v2Enabled = await core.uiSettings.get('discover:v2'); + + let discoverLocation = { + app: 'data-explorer', + basePath: 'discover', + }; + + if (!v2Enabled) { + discoverLocation = { + app: 'discoverLegacy', + basePath: '', + }; + } // TODO: find a better way to get the query discover URL - const destURL = getCore().application.getUrlForApp('data-explorer', { - path: `discover#?_a=(discover:(columns:!(_source),isDirty:!f,sort:!()),metadata:(indexPattern:'${indexPatternName}',view:discover))&_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,index:'${indexPatternName}',key:${cluster.field},negate:!f,params:(query:${cluster.name}),type:phrase),query:(match_phrase:(${cluster.field}:${cluster.name})))),refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_q=(filters:!(),query:(language:kuery,query:''))`, + const destURL = core.application.getUrlForApp(discoverLocation.app, { + path: `${ + discoverLocation.basePath + }#?_a=(discover:(columns:!(_source),isDirty:!f,sort:!()),metadata:(indexPattern:'${indexPatternName}',view:discover))&_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,index:'${indexPatternName}',key:${ + cluster.field + },negate:!f,params:(query:${ + cluster.name + }),type:phrase),query:(match_phrase:(${cluster.field}:${ + cluster.name + }))),('$state':(store:globalState),meta:(alias:!n,disabled:!f,index:'wazuh-alerts-*',key:rule.level,negate:!f,params:(gte:${ + severityLabel[severity].ruleLevelRange.minRuleLevel + },lte:${ + severityLabel[severity].ruleLevelRange.maxRuleLevel || '!n' + }),type:range),range:(rule.level:(gte:${ + severityLabel[severity].ruleLevelRange.minRuleLevel + },lte:${ + severityLabel[severity].ruleLevelRange.maxRuleLevel || '!n' + })))),refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_q=(filters:!(),query:(language:kuery,query:''))`, }); - setDiscoverLocation(destURL); } catch (error) { const searchError = ErrorFactory.create(HttpError, { @@ -43,12 +114,23 @@ export function LastAlertsStat() { + @@ -56,10 +138,18 @@ export function LastAlertsStat() { } - description={`Last 24 hours alerts`} - titleColor={UI_COLOR_AGENT_STATUS.active} + description={`${severityLabel[severity].label} severity`} + descriptionElement='h2' + titleColor={severityLabel[severity].color} textAlign='center' /> + + {'Rule level ' + + severityLabel[severity].ruleLevelRange.minRuleLevel + + (severityLabel[severity].ruleLevelRange.maxRuleLevel + ? ' to ' + severityLabel[severity].ruleLevelRange.maxRuleLevel + : ' or higher')} + ); diff --git a/plugins/main/public/controllers/overview/components/stats.js b/plugins/main/public/controllers/overview/components/stats.js index 6701993a02..e0f08ae4ad 100644 --- a/plugins/main/public/controllers/overview/components/stats.js +++ b/plugins/main/public/controllers/overview/components/stats.js @@ -13,12 +13,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { - EuiStat, + EuiCard, EuiFlexItem, EuiFlexGroup, EuiPage, EuiToolTip, - EuiLink, } from '@elastic/eui'; import { withErrorBoundary } from '../../../components/common/hocs'; import { API_NAME_AGENT_STATUS } from '../../../../common/constants'; @@ -29,13 +28,22 @@ import { import { getCore } from '../../../kibana-services'; import { endpointSummary } from '../../../utils/applications'; import { LastAlertsStat } from './last-alerts-stat'; - +import { VisualizationBasic } from '../../../components/common/charts/visualizations/basic'; +import './stats.scss'; export const Stats = withErrorBoundary( class Stats extends Component { constructor(props) { super(props); - this.state = {}; + this.state = { + agentStatusSummary: { + active: '-', + disconnected: '-', + total: '-', + pending: '-', + never_connected: '-', + }, + }; this.agentStatus = [ API_NAME_AGENT_STATUS.ACTIVE, API_NAME_AGENT_STATUS.DISCONNECTED, @@ -70,39 +78,50 @@ export const Stats = withErrorBoundary( } render() { + const hasResults = this.agentStatus.some( + ({ status }) => this.props[status], + ); return ( - + <> - - {this.agentStatus.map(({ status, label, onClick, color }) => ( - - - - {typeof this.props[status] !== 'undefined' - ? this.props[status] - : '-'} - - + + + ({ + onClick, + label, + value: + typeof this.props[status] !== 'undefined' + ? this.props[status] + : 0, + color, + }), + ) } - description={`${label} agents`} - titleColor={color} - textAlign='center' + noDataTitle='No results' + noDataMessage='No results were found.' /> - - ))} - - + + + + + + + + + + + + - + ); } }, diff --git a/plugins/main/public/controllers/overview/components/stats.scss b/plugins/main/public/controllers/overview/components/stats.scss new file mode 100644 index 0000000000..8e8bfcf937 --- /dev/null +++ b/plugins/main/public/controllers/overview/components/stats.scss @@ -0,0 +1,3 @@ +.vulnerabilites-summary-card { + padding-top: 2vh; +} diff --git a/plugins/main/public/controllers/overview/components/stats.test.tsx b/plugins/main/public/controllers/overview/components/stats.test.tsx index 4e4a777b63..1b794f8842 100644 --- a/plugins/main/public/controllers/overview/components/stats.test.tsx +++ b/plugins/main/public/controllers/overview/components/stats.test.tsx @@ -17,7 +17,14 @@ import { render, act } from '@testing-library/react'; import '@testing-library/jest-dom'; import { Stats } from './stats'; -jest.mock('react-use/lib/useObservable', () => () => {}); +jest.mock( + '../../../../../../node_modules/@elastic/eui/lib/services/accessibility/html_id_generator', + () => ({ + htmlIdGenerator: () => () => 'htmlId', + }), +); + +jest.mock('react-use/lib/useObservable', () => () => { }); jest.mock('./last-alerts-stat/last-alerts-service', () => ({ getLast24HoursAlerts: jest.fn().mockReturnValue({ count: 100, @@ -35,12 +42,15 @@ jest.mock('../../../kibana-services', () => ({ navigateToApp: () => 'http://url', getUrlForApp: () => 'http://url', }, + uiSettings: { + get: () => true + } }), })); jest.mock('../../../react-services/common-services', () => ({ getErrorOrchestrator: () => ({ - handleError: options => {}, + handleError: options => { }, }), })); diff --git a/plugins/main/server/lib/generate-alerts/generate-alerts-script.js b/plugins/main/server/lib/generate-alerts/generate-alerts-script.js index f718d55e47..7d2ac02222 100644 --- a/plugins/main/server/lib/generate-alerts/generate-alerts-script.js +++ b/plugins/main/server/lib/generate-alerts/generate-alerts-script.js @@ -22,7 +22,14 @@ import { randomElements, randomArrayItem, } from './sample-data/common'; -import { PCI_DSS, GDPR, HIPAA, GPG13, NIST_800_53, tsc } from './sample-data/regulatory-compliance'; +import { + PCI_DSS, + GDPR, + HIPAA, + GPG13, + NIST_800_53, + tsc, +} from './sample-data/regulatory-compliance'; import * as Audit from './sample-data/audit'; import * as Authentication from './sample-data/authentication'; @@ -54,7 +61,7 @@ const ruleDescription = [ 'Sample alert 4', 'Sample alert 5', ]; -const ruleMaxLevel = 14; +const ruleMaxLevel = 15; /** * Generate a alert @@ -143,7 +150,9 @@ function generateAlert(params) { 'iamPolicyGrantGlobal', ]); - const beforeDate = new Date(new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000); + const beforeDate = new Date( + new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000, + ); switch (randomType) { case 'guarddutyPortProbe': { const typeAlert = AWS.guarddutyPortProbe; @@ -151,29 +160,39 @@ function generateAlert(params) { alert.data = { ...typeAlert.data }; alert.data.integration = 'aws'; alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.resource.instanceDetails = { ...randomArrayItem(AWS.instanceDetails) }; - alert.data.aws.resource.instanceDetails.iamInstanceProfile.arn = interpolateAlertProps( - typeAlert.data.aws.resource.instanceDetails.iamInstanceProfile.arn, - alert + alert.data.aws.resource.instanceDetails = { + ...randomArrayItem(AWS.instanceDetails), + }; + alert.data.aws.resource.instanceDetails.iamInstanceProfile.arn = + interpolateAlertProps( + typeAlert.data.aws.resource.instanceDetails.iamInstanceProfile.arn, + alert, + ); + alert.data.aws.title = interpolateAlertProps( + alert.data.aws.title, + alert, ); - alert.data.aws.title = interpolateAlertProps(alert.data.aws.title, alert); alert.data.aws.accountId = randomArrayItem(AWS.accountId); - alert.data.aws.service.eventFirstSeen = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.service.eventFirstSeen = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); alert.data.aws.service.eventLastSeen = formatDate( new Date(alert.timestamp), - 'Y-M-DTh:m:s.lZ' + 'Y-M-DTh:m:s.lZ', ); - alert.data.aws.service.action.portProbeAction.portProbeDetails.remoteIpDetails = { - ...randomArrayItem(AWS.remoteIpDetails), - }; + alert.data.aws.service.action.portProbeAction.portProbeDetails.remoteIpDetails = + { + ...randomArrayItem(AWS.remoteIpDetails), + }; alert.data.aws.log_info = { s3bucket: randomArrayItem(AWS.buckets), log_file: `guardduty/${formatDate( new Date(alert.timestamp), - 'Y/M/D/h' + 'Y/M/D/h', )}/firehose_guardduty-1-${formatDate( new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' + 'Y-M-D-h-m-s-l', )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, }; alert.data.aws.service.count = `${randomIntervalInteger(400, 4000)}`; @@ -181,7 +200,10 @@ function generateAlert(params) { alert.rule = { ...typeAlert.rule }; alert.rule.firedtimes = randomIntervalInteger(1, 50); - alert.rule.description = interpolateAlertProps(typeAlert.rule.description, alert); + alert.rule.description = interpolateAlertProps( + typeAlert.rule.description, + alert, + ); alert.decoder = { ...typeAlert.decoder }; alert.location = typeAlert.location; @@ -193,36 +215,49 @@ function generateAlert(params) { alert.data = { ...typeAlert.data }; alert.data.integration = 'aws'; alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.resource.accessKeyDetails.userName = randomArrayItem(Users); + alert.data.aws.resource.accessKeyDetails.userName = + randomArrayItem(Users); alert.data.aws.log_info = { s3bucket: randomArrayItem(AWS.buckets), log_file: `guardduty/${formatDate( new Date(alert.timestamp), - 'Y/M/D/h' + 'Y/M/D/h', )}/firehose_guardduty-1-${formatDate( new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' + 'Y-M-D-h-m-s-l', )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, }; alert.data.aws.accountId = randomArrayItem(AWS.accountId); alert.data.aws.service.action.awsApiCallAction.remoteIpDetails = { ...randomArrayItem(AWS.remoteIpDetails), }; - alert.data.aws.service.eventFirstSeen = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.service.eventFirstSeen = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); alert.data.aws.service.eventLastSeen = formatDate( new Date(alert.timestamp), - 'Y-M-DTh:m:s.lZ' + 'Y-M-DTh:m:s.lZ', ); alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.title = interpolateAlertProps(alert.data.aws.title, alert); - alert.data.aws.description = interpolateAlertProps(alert.data.aws.description, alert); + alert.data.aws.title = interpolateAlertProps( + alert.data.aws.title, + alert, + ); + alert.data.aws.description = interpolateAlertProps( + alert.data.aws.description, + alert, + ); const count = `${randomIntervalInteger(400, 4000)}`; alert.data.aws.service.additionalInfo.recentApiCalls.count = count; alert.data.aws.service.count = count; alert.rule = { ...typeAlert.rule }; alert.rule.firedtimes = randomIntervalInteger(1, 50); - alert.rule.description = interpolateAlertProps(typeAlert.rule.description, alert); + alert.rule.description = interpolateAlertProps( + typeAlert.rule.description, + alert, + ); alert.decoder = { ...typeAlert.decoder }; alert.location = typeAlert.location; @@ -234,28 +269,40 @@ function generateAlert(params) { alert.data = { ...typeAlert.data }; alert.data.integration = 'aws'; alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.resource.instanceDetails = { ...randomArrayItem(AWS.instanceDetails) }; + alert.data.aws.resource.instanceDetails = { + ...randomArrayItem(AWS.instanceDetails), + }; alert.data.aws.log_info = { s3bucket: randomArrayItem(AWS.buckets), log_file: `guardduty/${formatDate( new Date(alert.timestamp), - 'Y/M/D/h' + 'Y/M/D/h', )}/firehose_guardduty-1-${formatDate( new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' + 'Y-M-D-h-m-s-l', )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, }; - alert.data.aws.description = interpolateAlertProps(alert.data.aws.description, alert); - alert.data.aws.title = interpolateAlertProps(alert.data.aws.title, alert); + alert.data.aws.description = interpolateAlertProps( + alert.data.aws.description, + alert, + ); + alert.data.aws.title = interpolateAlertProps( + alert.data.aws.title, + alert, + ); alert.data.aws.accountId = randomArrayItem(AWS.accountId); alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.service.action.networkConnectionAction.remoteIpDetails = { - ...randomArrayItem(AWS.remoteIpDetails), - }; - alert.data.aws.service.eventFirstSeen = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.service.action.networkConnectionAction.remoteIpDetails = + { + ...randomArrayItem(AWS.remoteIpDetails), + }; + alert.data.aws.service.eventFirstSeen = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); alert.data.aws.service.eventLastSeen = formatDate( new Date(alert.timestamp), - 'Y-M-DTh:m:s.lZ' + 'Y-M-DTh:m:s.lZ', ); alert.data.aws.service.additionalInfo = { localPort: `${randomArrayItem(Ports)}`, @@ -266,10 +313,16 @@ function generateAlert(params) { alert.data.aws.service.count = `${randomIntervalInteger(400, 4000)}`; alert.data.aws.service.action.networkConnectionAction.localIpDetails.ipAddressV4 = alert.data.aws.resource.instanceDetails.networkInterfaces.privateIpAddress; - alert.data.aws.arn = interpolateAlertProps(typeAlert.data.aws.arn, alert); + alert.data.aws.arn = interpolateAlertProps( + typeAlert.data.aws.arn, + alert, + ); alert.rule = { ...typeAlert.rule }; alert.rule.firedtimes = randomIntervalInteger(1, 50); - alert.rule.description = interpolateAlertProps(typeAlert.rule.description, alert); + alert.rule.description = interpolateAlertProps( + typeAlert.rule.description, + alert, + ); alert.decoder = { ...typeAlert.decoder }; alert.location = typeAlert.location; @@ -281,23 +334,32 @@ function generateAlert(params) { alert.data = { ...typeAlert.data }; alert.data.integration = 'aws'; alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.summary.Timestamps = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.summary.Timestamps = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); alert.data.aws.log_info = { s3bucket: randomArrayItem(AWS.buckets), log_file: `macie/${formatDate( new Date(alert.timestamp), - 'Y/M/D/h' + 'Y/M/D/h', )}/firehose_macie-1-${formatDate( new Date(alert.timestamp), - 'Y-M-D-h-m-s' + 'Y-M-D-h-m-s', )}-0b1ede94-f399-4e54-8815-1c6587eee3b1//firehose_guardduty-1-${formatDate( new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' + 'Y-M-D-h-m-s-l', )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, }; alert.data.aws['created-at'] = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.url = interpolateAlertProps(typeAlert.data.aws.url, alert); - alert.data.aws['alert-arn'] = interpolateAlertProps(typeAlert.data.aws['alert-arn'], alert); + alert.data.aws.url = interpolateAlertProps( + typeAlert.data.aws.url, + alert, + ); + alert.data.aws['alert-arn'] = interpolateAlertProps( + typeAlert.data.aws['alert-arn'], + alert, + ); alert.rule = { ...typeAlert.rule }; alert.rule.firedtimes = randomIntervalInteger(1, 50); @@ -317,25 +379,31 @@ function generateAlert(params) { alert.agent = { id: '000', ip: alert.agent.ip, - name: alert.agent.name + name: alert.agent.name, }; if (params.manager && params.manager.name) { alert.agent.name = params.manager.name; - }; + } - const beforeDate = new Date(new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000); + const beforeDate = new Date( + new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000, + ); const IntraID = randomArrayItem(Office.arrayUuidOffice); const OrgID = randomArrayItem(Office.arrayUuidOffice); const objID = randomArrayItem(Office.arrayUuidOffice); const userKey = randomArrayItem(Office.arrayUuidOffice); const userID = randomArrayItem(Office.arrayUserId); const userType = randomArrayItem([0, 2, 4]); - const resultStatus = randomArrayItem(['Succeeded', 'PartiallySucceeded', 'Failed']); + const resultStatus = randomArrayItem([ + 'Succeeded', + 'PartiallySucceeded', + 'Failed', + ]); const log = randomArrayItem(Office.arrayLogs); const ruleData = Office.officeRules[log.RecordType]; - alert.agent.id = '000' + alert.agent.id = '000'; alert.rule = ruleData.rule; alert.decoder = randomArrayItem(Office.arrayDecoderOffice); alert.GeoLocation = randomArrayItem(GeoLocation); @@ -362,13 +430,30 @@ function generateAlert(params) { alert.data.gcp = { insertId: 'uk1zpe23xcj', jsonPayload: { - authAnswer: GCP.arrayAuthAnswer[Math.floor(GCP.arrayAuthAnswer.length * Math.random())], - protocol: GCP.arrayProtocol[Math.floor(GCP.arrayProtocol.length * Math.random())], - queryName: GCP.arrayQueryName[Math.floor(GCP.arrayQueryName.length * Math.random())], - queryType: GCP.arrayQueryType[Math.floor(GCP.arrayQueryType.length * Math.random())], + authAnswer: + GCP.arrayAuthAnswer[ + Math.floor(GCP.arrayAuthAnswer.length * Math.random()) + ], + protocol: + GCP.arrayProtocol[ + Math.floor(GCP.arrayProtocol.length * Math.random()) + ], + queryName: + GCP.arrayQueryName[ + Math.floor(GCP.arrayQueryName.length * Math.random()) + ], + queryType: + GCP.arrayQueryType[ + Math.floor(GCP.arrayQueryType.length * Math.random()) + ], responseCode: - GCP.arrayResponseCode[Math.floor(GCP.arrayResponseCode.length * Math.random())], - sourceIP: GCP.arraySourceIP[Math.floor(GCP.arraySourceIP.length * Math.random())], + GCP.arrayResponseCode[ + Math.floor(GCP.arrayResponseCode.length * Math.random()) + ], + sourceIP: + GCP.arraySourceIP[ + Math.floor(GCP.arraySourceIP.length * Math.random()) + ], vmInstanceId: '4980113928800839680.000000', vmInstanceName: '531339229531.instance-1', }, @@ -376,14 +461,24 @@ function generateAlert(params) { receiveTimestamp: '2019-11-11T02:42:05.05853152Z', resource: { labels: { - location: GCP.arrayLocation[Math.floor(GCP.arrayLocation.length * Math.random())], - project_id: GCP.arrayProject[Math.floor(GCP.arrayProject.length * Math.random())], - source_type: GCP.arraySourceType[Math.floor(GCP.arraySourceType.length * Math.random())], + location: + GCP.arrayLocation[ + Math.floor(GCP.arrayLocation.length * Math.random()) + ], + project_id: + GCP.arrayProject[ + Math.floor(GCP.arrayProject.length * Math.random()) + ], + source_type: + GCP.arraySourceType[ + Math.floor(GCP.arraySourceType.length * Math.random()) + ], target_type: 'external', }, type: GCP.arrayType[Math.floor(GCP.arrayType.length * Math.random())], }, - severity: GCP.arraySeverity[Math.floor(GCP.arraySeverity.length * Math.random())], + severity: + GCP.arraySeverity[Math.floor(GCP.arraySeverity.length * Math.random())], timestamp: '2019-11-11T02:42:04.34921449Z', }; @@ -459,13 +554,21 @@ function generateAlert(params) { switch (alertCategory) { case 'Rootkit': { - const rootkitCategory = randomArrayItem(Object.keys(PolicyMonitoring.rootkits)); - const rootkit = randomArrayItem(PolicyMonitoring.rootkits[rootkitCategory]); + const rootkitCategory = randomArrayItem( + Object.keys(PolicyMonitoring.rootkits), + ); + const rootkit = randomArrayItem( + PolicyMonitoring.rootkits[rootkitCategory], + ); alert.data = { - title: interpolateAlertProps(PolicyMonitoring.rootkitsData.data.title, alert, { - _rootkit_category: rootkitCategory, - _rootkit_file: rootkit, - }), + title: interpolateAlertProps( + PolicyMonitoring.rootkitsData.data.title, + alert, + { + _rootkit_category: rootkitCategory, + _rootkit_file: rootkit, + }, + ), }; alert.rule = { ...PolicyMonitoring.rootkitsData.rule }; alert.rule.firedtimes = randomIntervalInteger(1, 10); @@ -480,9 +583,13 @@ function generateAlert(params) { }; alert.rule = { ...PolicyMonitoring.trojansData.rule }; alert.rule.firedtimes = randomIntervalInteger(1, 10); - alert.full_log = interpolateAlertProps(PolicyMonitoring.trojansData.full_log, alert, { - _trojan_signature: trojan.signature, - }); + alert.full_log = interpolateAlertProps( + PolicyMonitoring.trojansData.full_log, + alert, + { + _trojan_signature: trojan.signature, + }, + ); break; } default: { @@ -497,7 +604,7 @@ function generateAlert(params) { alert.syscheck.path = randomArrayItem( alert.agent.name === 'Windows' ? IntegrityMonitoring.pathsWindows - : IntegrityMonitoring.pathsLinux + : IntegrityMonitoring.pathsLinux, ); alert.syscheck.uname_after = randomArrayItem(Users); alert.syscheck.gname_after = 'root'; @@ -513,10 +620,14 @@ function generateAlert(params) { break; case 'modified': alert.rule = IntegrityMonitoring.regulatory[1]; - alert.syscheck.mtime_before = new Date(alert.syscheck.mtime_after.getTime() - 1000 * 60); + alert.syscheck.mtime_before = new Date( + alert.syscheck.mtime_after.getTime() - 1000 * 60, + ); alert.syscheck.inode_before = randomIntervalInteger(0, 100000); alert.syscheck.sha1_after = randomElements(40, 'abcdef0123456789'); - alert.syscheck.changed_attributes = [randomArrayItem(IntegrityMonitoring.attributes)]; + alert.syscheck.changed_attributes = [ + randomArrayItem(IntegrityMonitoring.attributes), + ]; alert.syscheck.md5_after = randomElements(32, 'abcdef0123456789'); alert.syscheck.sha256_after = randomElements(60, 'abcdef0123456789'); break; @@ -560,7 +671,10 @@ function generateAlert(params) { alert.data.virustotal.source = { sha1: randomElements(40, 'abcdef0123456789'), file: randomArrayItem(Virustotal.sourceFile), - alert_id: `${randomElements(10, '0123456789')}.${randomElements(7, '0123456789')}`, + alert_id: `${randomElements(10, '0123456789')}.${randomElements( + 7, + '0123456789', + )}`, md5: randomElements(32, 'abcdef0123456789'), }; @@ -571,10 +685,13 @@ function generateAlert(params) { alert.data.virustotal.malicious + alert.data.virustotal.positives; alert.rule.description = `VirusTotal: Alert - ${alert.data.virustotal.source.file} - ${alert.data.virustotal.positives} engines detected this file`; alert.data.virustotal.permalink = randomArrayItem(Virustotal.permalink); - alert.data.virustotal.scan_date = new Date(Date.parse(alert.timestamp) - 4 * 60000); + alert.data.virustotal.scan_date = new Date( + Date.parse(alert.timestamp) - 4 * 60000, + ); } else { alert.data.virustotal.malicious = '0'; - alert.rule.description = 'VirusTotal: Alert - No records in VirusTotal database'; + alert.rule.description = + 'VirusTotal: Alert - No records in VirusTotal database'; } } @@ -605,7 +722,9 @@ function generateAlert(params) { alert.data.osquery = dataOsquery.osquery; alert.data.osquery.calendarTime = alert.timestamp; alert.rule.description = dataOsquery.rule.description; - randomIntervalInteger(0, 99) === 0 ? (alert.data.osquery.action = 'removed') : null; + randomIntervalInteger(0, 99) === 0 + ? (alert.data.osquery.action = 'removed') + : null; } } @@ -687,39 +806,56 @@ function generateAlert(params) { case 'invalidLoginPassword': { alert.location = Authentication.invalidLoginPassword.location; alert.rule = { ...Authentication.invalidLoginPassword.rule }; - alert.rule.groups = [...Authentication.invalidLoginPassword.rule.groups]; - alert.full_log = interpolateAlertProps(Authentication.invalidLoginPassword.full_log, alert); + alert.rule.groups = [ + ...Authentication.invalidLoginPassword.rule.groups, + ]; + alert.full_log = interpolateAlertProps( + Authentication.invalidLoginPassword.full_log, + alert, + ); break; } case 'invalidLoginUser': { alert.location = Authentication.invalidLoginUser.location; alert.rule = { ...Authentication.invalidLoginUser.rule }; alert.rule.groups = [...Authentication.invalidLoginUser.rule.groups]; - alert.full_log = interpolateAlertProps(Authentication.invalidLoginUser.full_log, alert); + alert.full_log = interpolateAlertProps( + Authentication.invalidLoginUser.full_log, + alert, + ); break; } case 'multipleAuthenticationFailures': { alert.location = Authentication.multipleAuthenticationFailures.location; alert.rule = { ...Authentication.multipleAuthenticationFailures.rule }; - alert.rule.groups = [...Authentication.multipleAuthenticationFailures.rule.groups]; + alert.rule.groups = [ + ...Authentication.multipleAuthenticationFailures.rule.groups, + ]; alert.rule.frequency = randomIntervalInteger(5, 50); alert.full_log = interpolateAlertProps( Authentication.multipleAuthenticationFailures.full_log, - alert + alert, ); break; } case 'windowsInvalidLoginPassword': { alert.location = Authentication.windowsInvalidLoginPassword.location; alert.rule = { ...Authentication.windowsInvalidLoginPassword.rule }; - alert.rule.groups = [...Authentication.windowsInvalidLoginPassword.rule.groups]; + alert.rule.groups = [ + ...Authentication.windowsInvalidLoginPassword.rule.groups, + ]; alert.rule.frequency = randomIntervalInteger(5, 50); - alert.data.win = { ...Authentication.windowsInvalidLoginPassword.data_win }; + alert.data.win = { + ...Authentication.windowsInvalidLoginPassword.data_win, + }; alert.data.win.eventdata.ipAddress = randomArrayItem(IPs); alert.data.win.eventdata.ipPort = randomArrayItem(Ports); alert.data.win.system.computer = randomArrayItem(Win_Hostnames); alert.data.win.system.eventID = `${randomIntervalInteger(1, 600)}`; - alert.data.win.system.eventRecordID = `${randomIntervalInteger(10000, 50000)}`; + alert.data.win.system.eventRecordID = `${randomIntervalInteger( + 10000, + 50000, + )}`; alert.data.win.system.processID = `${randomIntervalInteger(1, 1200)}`; alert.data.win.system.systemTime = alert.timestamp; alert.data.win.system.processID = `${randomIntervalInteger(1, 1200)}`; @@ -727,7 +863,7 @@ function generateAlert(params) { alert.data.win.system.threadID = `${randomIntervalInteger(1, 500)}`; alert.full_log = interpolateAlertProps( Authentication.windowsInvalidLoginPassword.full_log, - alert + alert, ); break; } @@ -743,7 +879,10 @@ function generateAlert(params) { tty: 'ssh', }; alert.decoder = { ...Authentication.userLoginFailed.decoder }; - alert.full_log = interpolateAlertProps(Authentication.userLoginFailed.full_log, alert); + alert.full_log = interpolateAlertProps( + Authentication.userLoginFailed.full_log, + alert, + ); break; } case 'passwordCheckFailed': { @@ -755,23 +894,31 @@ function generateAlert(params) { }; alert.predecoder.program_name = 'unix_chkpwd'; alert.decoder = { ...Authentication.passwordCheckFailed.decoder }; - alert.full_log = interpolateAlertProps(Authentication.passwordCheckFailed.full_log, alert); + alert.full_log = interpolateAlertProps( + Authentication.passwordCheckFailed.full_log, + alert, + ); break; } case 'nonExistentUser': { alert.location = Authentication.nonExistentUser.location; alert.rule = { ...Authentication.nonExistentUser.rule }; alert.rule.groups = [...Authentication.nonExistentUser.rule.groups]; - alert.full_log = interpolateAlertProps(Authentication.nonExistentUser.full_log, alert); + alert.full_log = interpolateAlertProps( + Authentication.nonExistentUser.full_log, + alert, + ); break; } case 'bruteForceTryingAccessSystem': { alert.location = Authentication.bruteForceTryingAccessSystem.location; alert.rule = { ...Authentication.bruteForceTryingAccessSystem.rule }; - alert.rule.groups = [...Authentication.bruteForceTryingAccessSystem.rule.groups]; + alert.rule.groups = [ + ...Authentication.bruteForceTryingAccessSystem.rule.groups, + ]; alert.full_log = interpolateAlertProps( Authentication.bruteForceTryingAccessSystem.full_log, - alert + alert, ); break; } @@ -782,25 +929,32 @@ function generateAlert(params) { alert.data = { srcip: randomArrayItem(IPs), }; - alert.full_log = interpolateAlertProps(Authentication.reverseLoockupError.full_log, alert); + alert.full_log = interpolateAlertProps( + Authentication.reverseLoockupError.full_log, + alert, + ); } case 'insecureConnectionAttempt': { alert.location = Authentication.insecureConnectionAttempt.location; alert.rule = { ...Authentication.insecureConnectionAttempt.rule }; - alert.rule.groups = [...Authentication.insecureConnectionAttempt.rule.groups]; + alert.rule.groups = [ + ...Authentication.insecureConnectionAttempt.rule.groups, + ]; alert.data = { srcip: randomArrayItem(IPs), srcport: randomArrayItem(Ports), }; alert.full_log = interpolateAlertProps( Authentication.insecureConnectionAttempt.full_log, - alert + alert, ); } case 'authenticationSuccess': { alert.location = Authentication.authenticationSuccess.location; alert.rule = { ...Authentication.authenticationSuccess.rule }; - alert.rule.groups = [...Authentication.authenticationSuccess.rule.groups]; + alert.rule.groups = [ + ...Authentication.authenticationSuccess.rule.groups, + ]; alert.data = { srcip: randomArrayItem(IPs), srcport: randomArrayItem(Ports), @@ -808,13 +962,18 @@ function generateAlert(params) { }; alert.full_log = interpolateAlertProps( Authentication.authenticationSuccess.full_log, - alert + alert, ); } case 'maximumAuthenticationAttemptsExceeded': { - alert.location = Authentication.maximumAuthenticationAttemptsExceeded.location; - alert.rule = { ...Authentication.maximumAuthenticationAttemptsExceeded.rule }; - alert.rule.groups = [...Authentication.maximumAuthenticationAttemptsExceeded.rule.groups]; + alert.location = + Authentication.maximumAuthenticationAttemptsExceeded.location; + alert.rule = { + ...Authentication.maximumAuthenticationAttemptsExceeded.rule, + }; + alert.rule.groups = [ + ...Authentication.maximumAuthenticationAttemptsExceeded.rule.groups, + ]; alert.data = { srcip: randomArrayItem(IPs), srcport: randomArrayItem(Ports), @@ -822,7 +981,7 @@ function generateAlert(params) { }; alert.full_log = interpolateAlertProps( Authentication.maximumAuthenticationAttemptsExceeded.full_log, - alert + alert, ); } default: { @@ -915,7 +1074,10 @@ function generateAlert(params) { alert.decoder = { ...Apache.decoder }; alert.full_log = interpolateAlertProps(typeAlert.full_log, alert, { - _timestamp_apache: formatDate(new Date(alert.timestamp), 'E N D h:m:s.l Y'), + _timestamp_apache: formatDate( + new Date(alert.timestamp), + 'E N D h:m:s.l Y', + ), _pi_id: randomIntervalInteger(10000, 30000), }); } @@ -951,35 +1113,49 @@ function generateAlert(params) { interpolateAlertProps(typeAlert.full_log, alert, { _user_agent: userAgent, _date: formatDate(new Date(beforeDate), 'D/N/Y:h:m:s +0000'), - }) + }), ); } alert.previous_output = previousOutput.join('\n'); } } - if (params.github){ + if (params.github) { alert.location = GitHub.LOCATION; alert.decoder = GitHub.DECODER; const alertType = randomArrayItem(GitHub.ALERT_TYPES); const actor = randomArrayItem(GitHub.ACTORS); alert.data = { - github : { ...alertType.data.github } + github: { ...alertType.data.github }, }; alert.data.github.org = randomArrayItem(GitHub.ORGANIZATION_NAMES); - alert.data.github.repo && (alert.data.github.repo = `${alert.data.github.org}/${randomArrayItem(GitHub.REPOSITORY_NAMES)}`); - alert.data.github.repository && (alert.data.github.repository = `${alert.data.github.org}/${randomArrayItem(GitHub.REPOSITORY_NAMES)}`); + alert.data.github.repo && + (alert.data.github.repo = `${alert.data.github.org}/${randomArrayItem( + GitHub.REPOSITORY_NAMES, + )}`); + alert.data.github.repository && + (alert.data.github.repository = `${ + alert.data.github.org + }/${randomArrayItem(GitHub.REPOSITORY_NAMES)}`); alert.data.github.actor = actor.name; - alert.data.github.actor_location && alert.data.github.actor_location.country_code && (alert.data.github.actor_location.country_code = actor.country_code); - alert.data.github.user && (alert.data.github.user = randomArrayItem(GitHub.USER_NAMES)); - alert.data.github.config && alert.data.github.config.url && (alert.data.github.config.url = randomArrayItem(GitHub.SERVER_ADDRESS_WEBHOOK)); + alert.data.github.actor_location && + alert.data.github.actor_location.country_code && + (alert.data.github.actor_location.country_code = actor.country_code); + alert.data.github.user && + (alert.data.github.user = randomArrayItem(GitHub.USER_NAMES)); + alert.data.github.config && + alert.data.github.config.url && + (alert.data.github.config.url = randomArrayItem( + GitHub.SERVER_ADDRESS_WEBHOOK, + )); alert.data.github['@timestamp'] = alert.timestamp; - alert.data.github.created_at && (alert.data.github.created_at = alert.timestamp); + alert.data.github.created_at && + (alert.data.github.created_at = alert.timestamp); alert.rule = { - ...alertType.rule + ...alertType.rule, }; } - + return alert; } @@ -1037,7 +1213,8 @@ function randomDate(inf, sup) { return formatDate(lastWeek, 'Y-M-DTh:m:s.l+0000'); } -const formatterNumber = (number, zeros = 0) => ('0'.repeat(zeros) + `${number}`).slice(-zeros); +const formatterNumber = (number, zeros = 0) => + ('0'.repeat(zeros) + `${number}`).slice(-zeros); const monthNames = { long: [ 'January', @@ -1053,28 +1230,49 @@ const monthNames = { 'November', 'December', ], - short: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + short: [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], }; const dayNames = { - long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + long: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ], short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], }; function formatDate(date, format) { // It could use "moment" library to format strings too const tokens = { - D: (d) => formatterNumber(d.getDate(), 2), // 01-31 - A: (d) => dayNames.long[d.getDay()], // 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' - E: (d) => dayNames.short[d.getDay()], // 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' - M: (d) => formatterNumber(d.getMonth() + 1, 2), // 01-12 - J: (d) => monthNames.long[d.getMonth()], // 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' - N: (d) => monthNames.short[d.getMonth()], // 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' - Y: (d) => d.getFullYear(), // 2020 - h: (d) => formatterNumber(d.getHours(), 2), // 00-23 - m: (d) => formatterNumber(d.getMinutes(), 2), // 00-59 - s: (d) => formatterNumber(d.getSeconds(), 2), // 00-59 - l: (d) => formatterNumber(d.getMilliseconds(), 3), // 000-999 + D: d => formatterNumber(d.getDate(), 2), // 01-31 + A: d => dayNames.long[d.getDay()], // 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' + E: d => dayNames.short[d.getDay()], // 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' + M: d => formatterNumber(d.getMonth() + 1, 2), // 01-12 + J: d => monthNames.long[d.getMonth()], // 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' + N: d => monthNames.short[d.getMonth()], // 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + Y: d => d.getFullYear(), // 2020 + h: d => formatterNumber(d.getHours(), 2), // 00-23 + m: d => formatterNumber(d.getMinutes(), 2), // 00-59 + s: d => formatterNumber(d.getSeconds(), 2), // 00-59 + l: d => formatterNumber(d.getMilliseconds(), 3), // 000-999 }; return format.split('').reduce((accum, token) => { @@ -1098,7 +1296,9 @@ function interpolateAlertProps(str, alert, extra = {}) { matches.reduce((accum, cur) => { const match = cur.match(/{([\w\._]+)}/); const items = match[1].split('.'); - const value = items.reduce((a, c) => (a && a[c]) || extra[c] || undefined, alert) || cur; + const value = + items.reduce((a, c) => (a && a[c]) || extra[c] || undefined, alert) || + cur; return accum.replace(cur, value); }, str)) || str diff --git a/plugins/wazuh-core/common/constants.ts b/plugins/wazuh-core/common/constants.ts index ff88f204ed..1e3e214864 100644 --- a/plugins/wazuh-core/common/constants.ts +++ b/plugins/wazuh-core/common/constants.ts @@ -333,6 +333,15 @@ export const PLUGIN_PLATFORM_REQUEST_HEADERS = { export const PLUGIN_APP_NAME = 'Wazuh dashboard'; // UI +export const UI_COLOR_STATUS = { + success: '#007871', + danger: '#BD271E', + warning: '#FEC514', + disabled: '#646A77', + info: '#6092C0', + default: '#000000', +} as const; + export const API_NAME_AGENT_STATUS = { ACTIVE: 'active', DISCONNECTED: 'disconnected', @@ -341,11 +350,11 @@ export const API_NAME_AGENT_STATUS = { } as const; export const UI_COLOR_AGENT_STATUS = { - [API_NAME_AGENT_STATUS.ACTIVE]: '#007871', - [API_NAME_AGENT_STATUS.DISCONNECTED]: '#BD271E', - [API_NAME_AGENT_STATUS.PENDING]: '#FEC514', - [API_NAME_AGENT_STATUS.NEVER_CONNECTED]: '#646A77', - default: '#000000', + [API_NAME_AGENT_STATUS.ACTIVE]: UI_COLOR_STATUS.success, + [API_NAME_AGENT_STATUS.DISCONNECTED]: UI_COLOR_STATUS.danger, + [API_NAME_AGENT_STATUS.PENDING]: UI_COLOR_STATUS.warning, + [API_NAME_AGENT_STATUS.NEVER_CONNECTED]: UI_COLOR_STATUS.disabled, + default: UI_COLOR_STATUS.default, } as const; export const UI_LABEL_NAME_AGENT_STATUS = { diff --git a/scripts/wazuh-alerts-generator/lib/index.js b/scripts/wazuh-alerts-generator/lib/index.js index 9a9a58b819..9c3a92d5d5 100644 --- a/scripts/wazuh-alerts-generator/lib/index.js +++ b/scripts/wazuh-alerts-generator/lib/index.js @@ -1,49 +1,56 @@ // General const { - IPs, - Users, - Ports, - Paths, - Win_Hostnames, - GeoLocation, - Agents, - randomElements, - randomArrayItem, + IPs, + Users, + Ports, + Paths, + Win_Hostnames, + GeoLocation, + Agents, + randomElements, + randomArrayItem, } = require('./common'); -const { PCI_DSS, GDPR, HIPAA, GPG13, NIST_800_53, tsc } = require('./modules/regulatory-compliance'); +const { + PCI_DSS, + GDPR, + HIPAA, + GPG13, + NIST_800_53, + tsc, +} = require('./modules/regulatory-compliance'); const Audit = require('./modules/audit'); const Authentication = require('./modules/authentication'); -const AWS = require( './modules/aws'); -const IntegrityMonitoring = require( './modules/integrity-monitoring'); -const CISCAT = require( './modules/ciscat'); -const GCP = require( './modules/gcp'); -const Docker = require( './modules/docker'); -const Mitre = require( './modules/mitre'); -const Osquery = require( './modules/osquery'); -const OpenSCAP = require( './modules/openscap'); -const PolicyMonitoring = require( './modules/policy-monitoring'); -const Virustotal = require( './modules/virustotal'); -const Vulnerability = require( './modules/vulnerabilities'); -const SSH = require( './modules/ssh'); -const Apache = require( './modules/apache'); -const Web = require( './modules/web'); -const GitHub = require( './modules/github'); -const Office = require( './modules/office'); +const AWS = require('./modules/aws'); +const IntegrityMonitoring = require('./modules/integrity-monitoring'); +const CISCAT = require('./modules/ciscat'); +const GCP = require('./modules/gcp'); +const Docker = require('./modules/docker'); +const Mitre = require('./modules/mitre'); +const Osquery = require('./modules/osquery'); +const OpenSCAP = require('./modules/openscap'); +const PolicyMonitoring = require('./modules/policy-monitoring'); +const Virustotal = require('./modules/virustotal'); +const Vulnerability = require('./modules/vulnerabilities'); +const SSH = require('./modules/ssh'); +const Apache = require('./modules/apache'); +const Web = require('./modules/web'); +const GitHub = require('./modules/github'); +const Office = require('./modules/office'); //Alert const alertIDMax = 6000; // Rule const ruleDescription = [ - 'Sample alert 1', - 'Sample alert 2', - 'Sample alert 3', - 'Sample alert 4', - 'Sample alert 5', + 'Sample alert 1', + 'Sample alert 2', + 'Sample alert 3', + 'Sample alert 4', + 'Sample alert 5', ]; -const ruleMaxLevel = 14; +const ruleMaxLevel = 15; /** * Generate a alert @@ -76,900 +83,1069 @@ const ruleMaxLevel = 14; * @return {any} - Alert generated */ function generateAlert(params) { - let alert = { - ['@sampledata']: true, - timestamp: '2020-01-27T11:08:47.777+0000', - rule: { - level: 3, - description: 'Sample alert', - id: '5502', - mail: false, - groups: [], - }, - agent: { - id: '000', - name: 'master', - }, - manager: { - name: 'master', - }, - cluster: { - name: 'wazuh', - }, - id: '1580123327.49031', - predecoder: {}, - decoder: {}, - data: {}, - location: '', - }; - alert.agent = randomArrayItem(Agents); - alert.rule.description = randomArrayItem(ruleDescription); - alert.rule.id = `${randomIntervalInteger(1, alertIDMax)}`; - alert.rule.level = randomIntervalInteger(1, ruleMaxLevel); - - alert.timestamp = randomDate(); - - if (params.manager) { - if (params.manager.name) { - alert.manager.name = params.manager.name; - } + let alert = { + ['@sampledata']: true, + timestamp: '2020-01-27T11:08:47.777+0000', + rule: { + level: 3, + description: 'Sample alert', + id: '5502', + mail: false, + groups: [], + }, + agent: { + id: '000', + name: 'master', + }, + manager: { + name: 'master', + }, + cluster: { + name: 'wazuh', + }, + id: '1580123327.49031', + predecoder: {}, + decoder: {}, + data: {}, + location: '', + }; + alert.agent = randomArrayItem(Agents); + alert.rule.description = randomArrayItem(ruleDescription); + alert.rule.id = `${randomIntervalInteger(1, alertIDMax)}`; + alert.rule.level = randomIntervalInteger(1, ruleMaxLevel); + + alert.timestamp = randomDate(); + + if (params.manager) { + if (params.manager.name) { + alert.manager.name = params.manager.name; } + } - if (params.cluster) { - if (params.cluster.name) { - alert.cluster.name = params.cluster.name; - } - if (params.cluster.node) { - alert.cluster.node = params.cluster.node; - } + if (params.cluster) { + if (params.cluster.name) { + alert.cluster.name = params.cluster.name; } - - if (params.aws) { - let randomType = randomArrayItem([ - 'guarddutyPortProbe', - 'apiCall', - 'networkConnection', - 'iamPolicyGrantGlobal', - ]); - - const beforeDate = new Date(new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000); - switch (randomType) { - case 'guarddutyPortProbe': { - const typeAlert = AWS.guarddutyPortProbe; - - alert.data = { ...typeAlert.data }; - alert.data.integration = 'aws'; - alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.resource.instanceDetails = { ...randomArrayItem(AWS.instanceDetails) }; - alert.data.aws.resource.instanceDetails.iamInstanceProfile.arn = interpolateAlertProps( - typeAlert.data.aws.resource.instanceDetails.iamInstanceProfile.arn, - alert - ); - alert.data.aws.title = interpolateAlertProps(alert.data.aws.title, alert); - alert.data.aws.accountId = randomArrayItem(AWS.accountId); - alert.data.aws.service.eventFirstSeen = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.service.eventLastSeen = formatDate( - new Date(alert.timestamp), - 'Y-M-DTh:m:s.lZ' - ); - alert.data.aws.service.action.portProbeAction.portProbeDetails.remoteIpDetails = { - ...randomArrayItem(AWS.remoteIpDetails), - }; - alert.data.aws.log_info = { - s3bucket: randomArrayItem(AWS.buckets), - log_file: `guardduty/${formatDate( - new Date(alert.timestamp), - 'Y/M/D/h' - )}/firehose_guardduty-1-${formatDate( - new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' - )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, - }; - alert.data.aws.service.count = `${randomIntervalInteger(400, 4000)}`; - alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 50); - alert.rule.description = interpolateAlertProps(typeAlert.rule.description, alert); - - alert.decoder = { ...typeAlert.decoder }; - alert.location = typeAlert.location; - break; - } - case 'apiCall': { - const typeAlert = AWS.apiCall; - - alert.data = { ...typeAlert.data }; - alert.data.integration = 'aws'; - alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.resource.accessKeyDetails.userName = randomArrayItem(Users); - alert.data.aws.log_info = { - s3bucket: randomArrayItem(AWS.buckets), - log_file: `guardduty/${formatDate( - new Date(alert.timestamp), - 'Y/M/D/h' - )}/firehose_guardduty-1-${formatDate( - new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' - )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, - }; - alert.data.aws.accountId = randomArrayItem(AWS.accountId); - alert.data.aws.service.action.awsApiCallAction.remoteIpDetails = { - ...randomArrayItem(AWS.remoteIpDetails), - }; - alert.data.aws.service.eventFirstSeen = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.service.eventLastSeen = formatDate( - new Date(alert.timestamp), - 'Y-M-DTh:m:s.lZ' - ); - alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.title = interpolateAlertProps(alert.data.aws.title, alert); - alert.data.aws.description = interpolateAlertProps(alert.data.aws.description, alert); - const count = `${randomIntervalInteger(400, 4000)}`; - alert.data.aws.service.additionalInfo.recentApiCalls.count = count; - alert.data.aws.service.count = count; - - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 50); - alert.rule.description = interpolateAlertProps(typeAlert.rule.description, alert); - - alert.decoder = { ...typeAlert.decoder }; - alert.location = typeAlert.location; - break; - } - case 'networkConnection': { - const typeAlert = AWS.networkConnection; - - alert.data = { ...typeAlert.data }; - alert.data.integration = 'aws'; - alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.resource.instanceDetails = { ...randomArrayItem(AWS.instanceDetails) }; - alert.data.aws.log_info = { - s3bucket: randomArrayItem(AWS.buckets), - log_file: `guardduty/${formatDate( - new Date(alert.timestamp), - 'Y/M/D/h' - )}/firehose_guardduty-1-${formatDate( - new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' - )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, - }; - alert.data.aws.description = interpolateAlertProps(alert.data.aws.description, alert); - alert.data.aws.title = interpolateAlertProps(alert.data.aws.title, alert); - alert.data.aws.accountId = randomArrayItem(AWS.accountId); - alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.service.action.networkConnectionAction.remoteIpDetails = { - ...randomArrayItem(AWS.remoteIpDetails), - }; - alert.data.aws.service.eventFirstSeen = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.service.eventLastSeen = formatDate( - new Date(alert.timestamp), - 'Y-M-DTh:m:s.lZ' - ); - alert.data.aws.service.additionalInfo = { - localPort: `${randomArrayItem(Ports)}`, - outBytes: `${randomIntervalInteger(1000, 3000)}`, - inBytes: `${randomIntervalInteger(1000, 10000)}`, - unusual: `${randomIntervalInteger(1000, 10000)}`, - }; - alert.data.aws.service.count = `${randomIntervalInteger(400, 4000)}`; - alert.data.aws.service.action.networkConnectionAction.localIpDetails.ipAddressV4 = - alert.data.aws.resource.instanceDetails.networkInterfaces.privateIpAddress; - alert.data.aws.arn = interpolateAlertProps(typeAlert.data.aws.arn, alert); - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 50); - alert.rule.description = interpolateAlertProps(typeAlert.rule.description, alert); - - alert.decoder = { ...typeAlert.decoder }; - alert.location = typeAlert.location; - break; - } - case 'iamPolicyGrantGlobal': { - const typeAlert = AWS.iamPolicyGrantGlobal; - - alert.data = { ...typeAlert.data }; - alert.data.integration = 'aws'; - alert.data.aws.region = randomArrayItem(AWS.region); - alert.data.aws.summary.Timestamps = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.log_info = { - s3bucket: randomArrayItem(AWS.buckets), - log_file: `macie/${formatDate( - new Date(alert.timestamp), - 'Y/M/D/h' - )}/firehose_macie-1-${formatDate( - new Date(alert.timestamp), - 'Y-M-D-h-m-s' - )}-0b1ede94-f399-4e54-8815-1c6587eee3b1//firehose_guardduty-1-${formatDate( - new Date(alert.timestamp), - 'Y-M-D-h-m-s-l' - )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, - }; - alert.data.aws['created-at'] = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - alert.data.aws.url = interpolateAlertProps(typeAlert.data.aws.url, alert); - alert.data.aws['alert-arn'] = interpolateAlertProps(typeAlert.data.aws['alert-arn'], alert); - - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 50); - - alert.decoder = { ...typeAlert.decoder }; - alert.location = typeAlert.location; - break; - } - default: { - } - } - alert.input = { type: 'log' }; - alert.GeoLocation = randomArrayItem(GeoLocation); + if (params.cluster.node) { + alert.cluster.node = params.cluster.node; } + } + + if (params.aws) { + let randomType = randomArrayItem([ + 'guarddutyPortProbe', + 'apiCall', + 'networkConnection', + 'iamPolicyGrantGlobal', + ]); + + const beforeDate = new Date( + new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000, + ); + switch (randomType) { + case 'guarddutyPortProbe': { + const typeAlert = AWS.guarddutyPortProbe; - if (params.office) { - alert.agent = { - id: '000', - ip: alert.agent.ip, - name: alert.agent.name + alert.data = { ...typeAlert.data }; + alert.data.integration = 'aws'; + alert.data.aws.region = randomArrayItem(AWS.region); + alert.data.aws.resource.instanceDetails = { + ...randomArrayItem(AWS.instanceDetails), }; - - if (params.manager && params.manager.name) { - alert.agent.name = params.manager.name; + alert.data.aws.resource.instanceDetails.iamInstanceProfile.arn = + interpolateAlertProps( + typeAlert.data.aws.resource.instanceDetails.iamInstanceProfile.arn, + alert, + ); + alert.data.aws.title = interpolateAlertProps( + alert.data.aws.title, + alert, + ); + alert.data.aws.accountId = randomArrayItem(AWS.accountId); + alert.data.aws.service.eventFirstSeen = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.service.eventLastSeen = formatDate( + new Date(alert.timestamp), + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.service.action.portProbeAction.portProbeDetails.remoteIpDetails = + { + ...randomArrayItem(AWS.remoteIpDetails), + }; + alert.data.aws.log_info = { + s3bucket: randomArrayItem(AWS.buckets), + log_file: `guardduty/${formatDate( + new Date(alert.timestamp), + 'Y/M/D/h', + )}/firehose_guardduty-1-${formatDate( + new Date(alert.timestamp), + 'Y-M-D-h-m-s-l', + )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, }; + alert.data.aws.service.count = `${randomIntervalInteger(400, 4000)}`; + alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); - const beforeDate = new Date(new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000); - const IntraID = randomArrayItem(Office.arrayUuidOffice); - const OrgID = randomArrayItem(Office.arrayUuidOffice); - const objID = randomArrayItem(Office.arrayUuidOffice); - const userKey = randomArrayItem(Office.arrayUuidOffice); - const userID = randomArrayItem(Office.arrayUserId); - const userType = randomArrayItem([0, 2, 4]); - const resultStatus = randomArrayItem(['Succeeded', 'PartiallySucceeded', 'Failed']); - const log = randomArrayItem(Office.arrayLogs); - const ruleData = Office.officeRules[log.RecordType]; - - alert.agent.id = '000' - alert.rule = ruleData.rule; - alert.decoder = randomArrayItem(Office.arrayDecoderOffice); - alert.GeoLocation = randomArrayItem(GeoLocation); - alert.data.integration = 'Office365'; - alert.location = Office.arrayLocationOffice; - alert.data.office365 = { - ...log, - ...ruleData.data.office365, - Id: IntraID, - CreationTime: formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'), - OrganizationId: OrgID, - UserType: userType, - UserKey: userKey, - ResultStatus: resultStatus, - ObjectId: objID, - UserId: userID, - ClientIP: randomArrayItem(Office.arrayIp), - }; - } + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 50); + alert.rule.description = interpolateAlertProps( + typeAlert.rule.description, + alert, + ); - if (params.gcp) { - alert.rule = randomArrayItem(GCP.arrayRules); - alert.data.integration = 'gcp'; - alert.data.gcp = { - insertId: 'uk1zpe23xcj', - jsonPayload: { - authAnswer: GCP.arrayAuthAnswer[Math.floor(GCP.arrayAuthAnswer.length * Math.random())], - protocol: GCP.arrayProtocol[Math.floor(GCP.arrayProtocol.length * Math.random())], - queryName: GCP.arrayQueryName[Math.floor(GCP.arrayQueryName.length * Math.random())], - queryType: GCP.arrayQueryType[Math.floor(GCP.arrayQueryType.length * Math.random())], - responseCode: - GCP.arrayResponseCode[Math.floor(GCP.arrayResponseCode.length * Math.random())], - sourceIP: GCP.arraySourceIP[Math.floor(GCP.arraySourceIP.length * Math.random())], - vmInstanceId: '4980113928800839680.000000', - vmInstanceName: '531339229531.instance-1', - }, - logName: 'projects/wazuh-dev/logs/dns.googleapis.com%2Fdns_queries', - receiveTimestamp: '2019-11-11T02:42:05.05853152Z', - resource: { - labels: { - location: GCP.arrayLocation[Math.floor(GCP.arrayLocation.length * Math.random())], - project_id: GCP.arrayProject[Math.floor(GCP.arrayProject.length * Math.random())], - source_type: GCP.arraySourceType[Math.floor(GCP.arraySourceType.length * Math.random())], - target_type: 'external', - }, - type: GCP.arrayType[Math.floor(GCP.arrayType.length * Math.random())], - }, - severity: GCP.arraySeverity[Math.floor(GCP.arraySeverity.length * Math.random())], - timestamp: '2019-11-11T02:42:04.34921449Z', - }; + alert.decoder = { ...typeAlert.decoder }; + alert.location = typeAlert.location; + break; + } + case 'apiCall': { + const typeAlert = AWS.apiCall; - alert.GeoLocation = randomArrayItem(GeoLocation); - } + alert.data = { ...typeAlert.data }; + alert.data.integration = 'aws'; + alert.data.aws.region = randomArrayItem(AWS.region); + alert.data.aws.resource.accessKeyDetails.userName = + randomArrayItem(Users); + alert.data.aws.log_info = { + s3bucket: randomArrayItem(AWS.buckets), + log_file: `guardduty/${formatDate( + new Date(alert.timestamp), + 'Y/M/D/h', + )}/firehose_guardduty-1-${formatDate( + new Date(alert.timestamp), + 'Y-M-D-h-m-s-l', + )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, + }; + alert.data.aws.accountId = randomArrayItem(AWS.accountId); + alert.data.aws.service.action.awsApiCallAction.remoteIpDetails = { + ...randomArrayItem(AWS.remoteIpDetails), + }; + alert.data.aws.service.eventFirstSeen = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.service.eventLastSeen = formatDate( + new Date(alert.timestamp), + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.title = interpolateAlertProps( + alert.data.aws.title, + alert, + ); + alert.data.aws.description = interpolateAlertProps( + alert.data.aws.description, + alert, + ); + const count = `${randomIntervalInteger(400, 4000)}`; + alert.data.aws.service.additionalInfo.recentApiCalls.count = count; + alert.data.aws.service.count = count; - if (params.audit) { - let dataAudit = randomArrayItem(Audit.dataAudit); - alert.data = dataAudit.data; - alert.data.audit.file - ? alert.data.audit.file.name === '' - ? (alert.data.audit.file.name = randomArrayItem(Audit.fileName)) - : null - : null; - alert.rule = dataAudit.rule; - } + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 50); + alert.rule.description = interpolateAlertProps( + typeAlert.rule.description, + alert, + ); - if (params.ciscat) { - alert.rule.groups.push('ciscat'); - alert.data.cis = {}; - - alert.data.cis.group = randomArrayItem(CISCAT.group); - alert.data.cis.fail = randomIntervalInteger(0, 100); - alert.data.cis.rule_title = randomArrayItem(CISCAT.ruleTitle); - alert.data.cis.notchecked = randomIntervalInteger(0, 100); - alert.data.cis.score = randomIntervalInteger(0, 100); - alert.data.cis.pass = randomIntervalInteger(0, 100); - alert.data.cis.timestamp = new Date(randomDate()); - alert.data.cis.error = randomIntervalInteger(0, 1); - alert.data.cis.benchmark = randomArrayItem(CISCAT.benchmark); - alert.data.cis.unknown = randomIntervalInteger(0, 100); - alert.data.cis.notchecked = randomIntervalInteger(0, 5); - alert.data.cis.result = randomArrayItem(CISCAT.result); - } + alert.decoder = { ...typeAlert.decoder }; + alert.location = typeAlert.location; + break; + } + case 'networkConnection': { + const typeAlert = AWS.networkConnection; - if (params.docker) { - const dataDocker = randomArrayItem(Docker.dataDocker); - alert.data = {}; - alert.data = dataDocker.data; - alert.rule = dataDocker.rule; - } + alert.data = { ...typeAlert.data }; + alert.data.integration = 'aws'; + alert.data.aws.region = randomArrayItem(AWS.region); + alert.data.aws.resource.instanceDetails = { + ...randomArrayItem(AWS.instanceDetails), + }; + alert.data.aws.log_info = { + s3bucket: randomArrayItem(AWS.buckets), + log_file: `guardduty/${formatDate( + new Date(alert.timestamp), + 'Y/M/D/h', + )}/firehose_guardduty-1-${formatDate( + new Date(alert.timestamp), + 'Y-M-D-h-m-s-l', + )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, + }; + alert.data.aws.description = interpolateAlertProps( + alert.data.aws.description, + alert, + ); + alert.data.aws.title = interpolateAlertProps( + alert.data.aws.title, + alert, + ); + alert.data.aws.accountId = randomArrayItem(AWS.accountId); + alert.data.aws.createdAt = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.service.action.networkConnectionAction.remoteIpDetails = + { + ...randomArrayItem(AWS.remoteIpDetails), + }; + alert.data.aws.service.eventFirstSeen = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.service.eventLastSeen = formatDate( + new Date(alert.timestamp), + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.service.additionalInfo = { + localPort: `${randomArrayItem(Ports)}`, + outBytes: `${randomIntervalInteger(1000, 3000)}`, + inBytes: `${randomIntervalInteger(1000, 10000)}`, + unusual: `${randomIntervalInteger(1000, 10000)}`, + }; + alert.data.aws.service.count = `${randomIntervalInteger(400, 4000)}`; + alert.data.aws.service.action.networkConnectionAction.localIpDetails.ipAddressV4 = + alert.data.aws.resource.instanceDetails.networkInterfaces.privateIpAddress; + alert.data.aws.arn = interpolateAlertProps( + typeAlert.data.aws.arn, + alert, + ); + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 50); + alert.rule.description = interpolateAlertProps( + typeAlert.rule.description, + alert, + ); - if (params.mitre) { - alert.rule = randomArrayItem(Mitre.arrayMitreRules); - alert.location = randomArrayItem(Mitre.arrayLocation); - } + alert.decoder = { ...typeAlert.decoder }; + alert.location = typeAlert.location; + break; + } + case 'iamPolicyGrantGlobal': { + const typeAlert = AWS.iamPolicyGrantGlobal; - if (params.openscap) { - alert.data = {}; - alert.data.oscap = {}; - const typeAlert = { ...randomArrayItem(OpenSCAP.data) }; alert.data = { ...typeAlert.data }; - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(2, 10); - alert.input = { - type: 'log', + alert.data.integration = 'aws'; + alert.data.aws.region = randomArrayItem(AWS.region); + alert.data.aws.summary.Timestamps = formatDate( + beforeDate, + 'Y-M-DTh:m:s.lZ', + ); + alert.data.aws.log_info = { + s3bucket: randomArrayItem(AWS.buckets), + log_file: `macie/${formatDate( + new Date(alert.timestamp), + 'Y/M/D/h', + )}/firehose_macie-1-${formatDate( + new Date(alert.timestamp), + 'Y-M-D-h-m-s', + )}-0b1ede94-f399-4e54-8815-1c6587eee3b1//firehose_guardduty-1-${formatDate( + new Date(alert.timestamp), + 'Y-M-D-h-m-s-l', + )}b5b9b-ec62-4a07-85d7-b1699b9c031e.zip`, }; - alert.decoder = { ...OpenSCAP.decoder }; - alert.location = OpenSCAP.location; - if (typeAlert.full_log) { - alert.full_log = interpolateAlertProps(typeAlert.full_log, alert); - } - } + alert.data.aws['created-at'] = formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'); + alert.data.aws.url = interpolateAlertProps( + typeAlert.data.aws.url, + alert, + ); + alert.data.aws['alert-arn'] = interpolateAlertProps( + typeAlert.data.aws['alert-arn'], + alert, + ); - if (params.rootcheck) { - alert.location = PolicyMonitoring.location; - alert.decoder = { ...PolicyMonitoring.decoder }; - alert.input = { - type: 'log', - }; + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 50); - const alertCategory = randomArrayItem(['Rootkit', 'Trojan']); - - switch (alertCategory) { - case 'Rootkit': { - const rootkitCategory = randomArrayItem(Object.keys(PolicyMonitoring.rootkits)); - const rootkit = randomArrayItem(PolicyMonitoring.rootkits[rootkitCategory]); - alert.data = { - title: interpolateAlertProps(PolicyMonitoring.rootkitsData.data.title, alert, { - _rootkit_category: rootkitCategory, - _rootkit_file: rootkit, - }), - }; - alert.rule = { ...PolicyMonitoring.rootkitsData.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 10); - alert.full_log = alert.data.title; - break; - } - case 'Trojan': { - const trojan = randomArrayItem(PolicyMonitoring.trojans); - alert.data = { - file: trojan.file, - title: 'Trojaned version of file detected.', - }; - alert.rule = { ...PolicyMonitoring.trojansData.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 10); - alert.full_log = interpolateAlertProps(PolicyMonitoring.trojansData.full_log, alert, { - _trojan_signature: trojan.signature, - }); - break; - } - default: { - } - } + alert.decoder = { ...typeAlert.decoder }; + alert.location = typeAlert.location; + break; + } + default: { + } } + alert.input = { type: 'log' }; + alert.GeoLocation = randomArrayItem(GeoLocation); + } + + if (params.office) { + alert.agent = { + id: '000', + ip: alert.agent.ip, + name: alert.agent.name, + }; - if (params.syscheck) { - alert.rule.groups.push('syscheck'); - alert.syscheck = {}; - alert.syscheck.event = randomArrayItem(IntegrityMonitoring.events); - alert.syscheck.path = randomArrayItem( - alert.agent.name === 'Windows' - ? IntegrityMonitoring.pathsWindows - : IntegrityMonitoring.pathsLinux - ); - alert.syscheck.uname_after = randomArrayItem(Users); - alert.syscheck.gname_after = 'root'; - alert.syscheck.mtime_after = new Date(randomDate()); - alert.syscheck.size_after = randomIntervalInteger(0, 65); - alert.syscheck.uid_after = randomArrayItem(IntegrityMonitoring.uid_after); - alert.syscheck.gid_after = randomArrayItem(IntegrityMonitoring.gid_after); - alert.syscheck.perm_after = 'rw-r--r--'; - alert.syscheck.inode_after = randomIntervalInteger(0, 100000); - switch (alert.syscheck.event) { - case 'added': - alert.rule = IntegrityMonitoring.regulatory[0]; - break; - case 'modified': - alert.rule = IntegrityMonitoring.regulatory[1]; - alert.syscheck.mtime_before = new Date(alert.syscheck.mtime_after.getTime() - 1000 * 60); - alert.syscheck.inode_before = randomIntervalInteger(0, 100000); - alert.syscheck.sha1_after = randomElements(40, 'abcdef0123456789'); - alert.syscheck.changed_attributes = [randomArrayItem(IntegrityMonitoring.attributes)]; - alert.syscheck.md5_after = randomElements(32, 'abcdef0123456789'); - alert.syscheck.sha256_after = randomElements(60, 'abcdef0123456789'); - break; - case 'deleted': - alert.rule = IntegrityMonitoring.regulatory[2]; - alert.syscheck.tags = [randomArrayItem(IntegrityMonitoring.tags)]; - alert.syscheck.sha1_after = randomElements(40, 'abcdef0123456789'); - alert.syscheck.audit = { - process: { - name: randomArrayItem(Paths), - id: randomIntervalInteger(0, 100000), - ppid: randomIntervalInteger(0, 100000), - }, - effective_user: { - name: randomArrayItem(Users), - id: randomIntervalInteger(0, 100), - }, - user: { - name: randomArrayItem(Users), - id: randomIntervalInteger(0, 100), - }, - group: { - name: randomArrayItem(Users), - id: randomIntervalInteger(0, 100), - }, - }; - alert.syscheck.md5_after = randomElements(32, 'abcdef0123456789'); - alert.syscheck.sha256_after = randomElements(60, 'abcdef0123456789'); - break; - default: { - } - } + if (params.manager && params.manager.name) { + alert.agent.name = params.manager.name; } - if (params.virustotal) { - alert.rule.groups.push('virustotal'); - alert.location = 'virustotal'; - alert.data.virustotal = {}; - alert.data.virustotal.found = randomArrayItem(['0', '1', '1', '1']); - - alert.data.virustotal.source = { - sha1: randomElements(40, 'abcdef0123456789'), - file: randomArrayItem(Virustotal.sourceFile), - alert_id: `${randomElements(10, '0123456789')}.${randomElements(7, '0123456789')}`, - md5: randomElements(32, 'abcdef0123456789'), - }; + const beforeDate = new Date( + new Date(alert.timestamp) - 3 * 24 * 60 * 60 * 1000, + ); + const IntraID = randomArrayItem(Office.arrayUuidOffice); + const OrgID = randomArrayItem(Office.arrayUuidOffice); + const objID = randomArrayItem(Office.arrayUuidOffice); + const userKey = randomArrayItem(Office.arrayUuidOffice); + const userID = randomArrayItem(Office.arrayUserId); + const userType = randomArrayItem([0, 2, 4]); + const resultStatus = randomArrayItem([ + 'Succeeded', + 'PartiallySucceeded', + 'Failed', + ]); + const log = randomArrayItem(Office.arrayLogs); + const ruleData = Office.officeRules[log.RecordType]; + + alert.agent.id = '000'; + alert.rule = ruleData.rule; + alert.decoder = randomArrayItem(Office.arrayDecoderOffice); + alert.GeoLocation = randomArrayItem(GeoLocation); + alert.data.integration = 'Office365'; + alert.location = Office.arrayLocationOffice; + alert.data.office365 = { + ...log, + ...ruleData.data.office365, + Id: IntraID, + CreationTime: formatDate(beforeDate, 'Y-M-DTh:m:s.lZ'), + OrganizationId: OrgID, + UserType: userType, + UserKey: userKey, + ResultStatus: resultStatus, + ObjectId: objID, + UserId: userID, + ClientIP: randomArrayItem(Office.arrayIp), + }; + } + + if (params.gcp) { + alert.rule = randomArrayItem(GCP.arrayRules); + alert.data.integration = 'gcp'; + alert.data.gcp = { + insertId: 'uk1zpe23xcj', + jsonPayload: { + authAnswer: + GCP.arrayAuthAnswer[ + Math.floor(GCP.arrayAuthAnswer.length * Math.random()) + ], + protocol: + GCP.arrayProtocol[ + Math.floor(GCP.arrayProtocol.length * Math.random()) + ], + queryName: + GCP.arrayQueryName[ + Math.floor(GCP.arrayQueryName.length * Math.random()) + ], + queryType: + GCP.arrayQueryType[ + Math.floor(GCP.arrayQueryType.length * Math.random()) + ], + responseCode: + GCP.arrayResponseCode[ + Math.floor(GCP.arrayResponseCode.length * Math.random()) + ], + sourceIP: + GCP.arraySourceIP[ + Math.floor(GCP.arraySourceIP.length * Math.random()) + ], + vmInstanceId: '4980113928800839680.000000', + vmInstanceName: '531339229531.instance-1', + }, + logName: 'projects/wazuh-dev/logs/dns.googleapis.com%2Fdns_queries', + receiveTimestamp: '2019-11-11T02:42:05.05853152Z', + resource: { + labels: { + location: + GCP.arrayLocation[ + Math.floor(GCP.arrayLocation.length * Math.random()) + ], + project_id: + GCP.arrayProject[ + Math.floor(GCP.arrayProject.length * Math.random()) + ], + source_type: + GCP.arraySourceType[ + Math.floor(GCP.arraySourceType.length * Math.random()) + ], + target_type: 'external', + }, + type: GCP.arrayType[Math.floor(GCP.arrayType.length * Math.random())], + }, + severity: + GCP.arraySeverity[Math.floor(GCP.arraySeverity.length * Math.random())], + timestamp: '2019-11-11T02:42:04.34921449Z', + }; - if (alert.data.virustotal.found === '1') { - alert.data.virustotal.malicious = randomArrayItem(Virustotal.malicious); - alert.data.virustotal.positives = `${randomIntervalInteger(0, 65)}`; - alert.data.virustotal.total = - alert.data.virustotal.malicious + alert.data.virustotal.positives; - alert.rule.description = `VirusTotal: Alert - ${alert.data.virustotal.source.file} - ${alert.data.virustotal.positives} engines detected this file`; - alert.data.virustotal.permalink = randomArrayItem(Virustotal.permalink); - alert.data.virustotal.scan_date = new Date(Date.parse(alert.timestamp) - 4 * 60000); - } else { - alert.data.virustotal.malicious = '0'; - alert.rule.description = 'VirusTotal: Alert - No records in VirusTotal database'; - } + alert.GeoLocation = randomArrayItem(GeoLocation); + } + + if (params.audit) { + let dataAudit = randomArrayItem(Audit.dataAudit); + alert.data = dataAudit.data; + alert.data.audit.file + ? alert.data.audit.file.name === '' + ? (alert.data.audit.file.name = randomArrayItem(Audit.fileName)) + : null + : null; + alert.rule = dataAudit.rule; + } + + if (params.ciscat) { + alert.rule.groups.push('ciscat'); + alert.data.cis = {}; + + alert.data.cis.group = randomArrayItem(CISCAT.group); + alert.data.cis.fail = randomIntervalInteger(0, 100); + alert.data.cis.rule_title = randomArrayItem(CISCAT.ruleTitle); + alert.data.cis.notchecked = randomIntervalInteger(0, 100); + alert.data.cis.score = randomIntervalInteger(0, 100); + alert.data.cis.pass = randomIntervalInteger(0, 100); + alert.data.cis.timestamp = new Date(randomDate()); + alert.data.cis.error = randomIntervalInteger(0, 1); + alert.data.cis.benchmark = randomArrayItem(CISCAT.benchmark); + alert.data.cis.unknown = randomIntervalInteger(0, 100); + alert.data.cis.notchecked = randomIntervalInteger(0, 5); + alert.data.cis.result = randomArrayItem(CISCAT.result); + } + + if (params.docker) { + const dataDocker = randomArrayItem(Docker.dataDocker); + alert.data = {}; + alert.data = dataDocker.data; + alert.rule = dataDocker.rule; + } + + if (params.mitre) { + alert.rule = randomArrayItem(Mitre.arrayMitreRules); + alert.location = randomArrayItem(Mitre.arrayLocation); + } + + if (params.openscap) { + alert.data = {}; + alert.data.oscap = {}; + const typeAlert = { ...randomArrayItem(OpenSCAP.data) }; + alert.data = { ...typeAlert.data }; + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(2, 10); + alert.input = { + type: 'log', + }; + alert.decoder = { ...OpenSCAP.decoder }; + alert.location = OpenSCAP.location; + if (typeAlert.full_log) { + alert.full_log = interpolateAlertProps(typeAlert.full_log, alert); } + } - if (params.vulnerabilities) { - const dataVulnerability = randomArrayItem(Vulnerability.data); - alert.rule = { - ...dataVulnerability.rule, - mail: false, - groups: ['vulnerability-detector'], - gdpr: ['IV_35.7.d'], - pci_dss: ['11.2.1', '11.2.3'], - tsc: ['CC7.1', 'CC7.2'], + if (params.rootcheck) { + alert.location = PolicyMonitoring.location; + alert.decoder = { ...PolicyMonitoring.decoder }; + alert.input = { + type: 'log', + }; + + const alertCategory = randomArrayItem(['Rootkit', 'Trojan']); + + switch (alertCategory) { + case 'Rootkit': { + const rootkitCategory = randomArrayItem( + Object.keys(PolicyMonitoring.rootkits), + ); + const rootkit = randomArrayItem( + PolicyMonitoring.rootkits[rootkitCategory], + ); + alert.data = { + title: interpolateAlertProps( + PolicyMonitoring.rootkitsData.data.title, + alert, + { + _rootkit_category: rootkitCategory, + _rootkit_file: rootkit, + }, + ), }; - alert.location = 'vulnerability-detector'; - alert.decoder = { name: 'json' }; + alert.rule = { ...PolicyMonitoring.rootkitsData.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 10); + alert.full_log = alert.data.title; + break; + } + case 'Trojan': { + const trojan = randomArrayItem(PolicyMonitoring.trojans); alert.data = { - ...dataVulnerability.data, + file: trojan.file, + title: 'Trojaned version of file detected.', }; + alert.rule = { ...PolicyMonitoring.trojansData.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 10); + alert.full_log = interpolateAlertProps( + PolicyMonitoring.trojansData.full_log, + alert, + { + _trojan_signature: trojan.signature, + }, + ); + break; + } + default: { + } } - - if (params.osquery) { - alert.rule.groups.push('osquery'); - alert.data.osquery = {}; - if (randomIntervalInteger(0, 5) === 0) { - alert.rule.description = 'osquery error message'; - } else { - let dataOsquery = randomArrayItem(Osquery.dataOsquery); - alert.data.osquery = dataOsquery.osquery; - alert.data.osquery.calendarTime = alert.timestamp; - alert.rule.description = dataOsquery.rule.description; - randomIntervalInteger(0, 99) === 0 ? (alert.data.osquery.action = 'removed') : null; - } + } + + if (params.syscheck) { + alert.rule.groups.push('syscheck'); + alert.syscheck = {}; + alert.syscheck.event = randomArrayItem(IntegrityMonitoring.events); + alert.syscheck.path = randomArrayItem( + alert.agent.name === 'Windows' + ? IntegrityMonitoring.pathsWindows + : IntegrityMonitoring.pathsLinux, + ); + alert.syscheck.uname_after = randomArrayItem(Users); + alert.syscheck.gname_after = 'root'; + alert.syscheck.mtime_after = new Date(randomDate()); + alert.syscheck.size_after = randomIntervalInteger(0, 65); + alert.syscheck.uid_after = randomArrayItem(IntegrityMonitoring.uid_after); + alert.syscheck.gid_after = randomArrayItem(IntegrityMonitoring.gid_after); + alert.syscheck.perm_after = 'rw-r--r--'; + alert.syscheck.inode_after = randomIntervalInteger(0, 100000); + switch (alert.syscheck.event) { + case 'added': + alert.rule = IntegrityMonitoring.regulatory[0]; + break; + case 'modified': + alert.rule = IntegrityMonitoring.regulatory[1]; + alert.syscheck.mtime_before = new Date( + alert.syscheck.mtime_after.getTime() - 1000 * 60, + ); + alert.syscheck.inode_before = randomIntervalInteger(0, 100000); + alert.syscheck.sha1_after = randomElements(40, 'abcdef0123456789'); + alert.syscheck.changed_attributes = [ + randomArrayItem(IntegrityMonitoring.attributes), + ]; + alert.syscheck.md5_after = randomElements(32, 'abcdef0123456789'); + alert.syscheck.sha256_after = randomElements(60, 'abcdef0123456789'); + break; + case 'deleted': + alert.rule = IntegrityMonitoring.regulatory[2]; + alert.syscheck.tags = [randomArrayItem(IntegrityMonitoring.tags)]; + alert.syscheck.sha1_after = randomElements(40, 'abcdef0123456789'); + alert.syscheck.audit = { + process: { + name: randomArrayItem(Paths), + id: randomIntervalInteger(0, 100000), + ppid: randomIntervalInteger(0, 100000), + }, + effective_user: { + name: randomArrayItem(Users), + id: randomIntervalInteger(0, 100), + }, + user: { + name: randomArrayItem(Users), + id: randomIntervalInteger(0, 100), + }, + group: { + name: randomArrayItem(Users), + id: randomIntervalInteger(0, 100), + }, + }; + alert.syscheck.md5_after = randomElements(32, 'abcdef0123456789'); + alert.syscheck.sha256_after = randomElements(60, 'abcdef0123456789'); + break; + default: { + } } + } + + if (params.virustotal) { + alert.rule.groups.push('virustotal'); + alert.location = 'virustotal'; + alert.data.virustotal = {}; + alert.data.virustotal.found = randomArrayItem(['0', '1', '1', '1']); + + alert.data.virustotal.source = { + sha1: randomElements(40, 'abcdef0123456789'), + file: randomArrayItem(Virustotal.sourceFile), + alert_id: `${randomElements(10, '0123456789')}.${randomElements( + 7, + '0123456789', + )}`, + md5: randomElements(32, 'abcdef0123456789'), + }; - // Regulatory compliance - if ( - params.pci_dss || - params.regulatory_compliance || - (params.random_probability_regulatory_compliance && - randomProbability(params.random_probability_regulatory_compliance)) - ) { - alert.rule.pci_dss = [randomArrayItem(PCI_DSS)]; - } - if ( - params.gdpr || - params.regulatory_compliance || - (params.random_probability_regulatory_compliance && - randomProbability(params.random_probability_regulatory_compliance)) - ) { - alert.rule.gdpr = [randomArrayItem(GDPR)]; - } - if ( - params.gpg13 || - params.regulatory_compliance || - (params.random_probability_regulatory_compliance && - randomProbability(params.random_probability_regulatory_compliance)) - ) { - alert.rule.gpg13 = [randomArrayItem(GPG13)]; + if (alert.data.virustotal.found === '1') { + alert.data.virustotal.malicious = randomArrayItem(Virustotal.malicious); + alert.data.virustotal.positives = `${randomIntervalInteger(0, 65)}`; + alert.data.virustotal.total = + alert.data.virustotal.malicious + alert.data.virustotal.positives; + alert.rule.description = `VirusTotal: Alert - ${alert.data.virustotal.source.file} - ${alert.data.virustotal.positives} engines detected this file`; + alert.data.virustotal.permalink = randomArrayItem(Virustotal.permalink); + alert.data.virustotal.scan_date = new Date( + Date.parse(alert.timestamp) - 4 * 60000, + ); + } else { + alert.data.virustotal.malicious = '0'; + alert.rule.description = + 'VirusTotal: Alert - No records in VirusTotal database'; } - if ( - params.hipaa || - params.regulatory_compliance || - (params.random_probability_regulatory_compliance && - randomIntervalInteger(params.random_probability_regulatory_compliance)) - ) { - alert.rule.hipaa = [randomArrayItem(HIPAA)]; - } - if ( - params.nist_800_83 || - params.regulatory_compliance || - (params.random_probability_regulatory_compliance && - randomIntervalInteger(params.random_probability_regulatory_compliance)) - ) { - alert.rule.nist_800_53 = [randomArrayItem(NIST_800_53)]; + } + + if (params.vulnerabilities) { + const dataVulnerability = randomArrayItem(Vulnerability.data); + alert.rule = { + ...dataVulnerability.rule, + mail: false, + groups: ['vulnerability-detector'], + gdpr: ['IV_35.7.d'], + pci_dss: ['11.2.1', '11.2.3'], + tsc: ['CC7.1', 'CC7.2'], + }; + alert.location = 'vulnerability-detector'; + alert.decoder = { name: 'json' }; + alert.data = { + ...dataVulnerability.data, + }; + } + + if (params.osquery) { + alert.rule.groups.push('osquery'); + alert.data.osquery = {}; + if (randomIntervalInteger(0, 5) === 0) { + alert.rule.description = 'osquery error message'; + } else { + let dataOsquery = randomArrayItem(Osquery.dataOsquery); + alert.data.osquery = dataOsquery.osquery; + alert.data.osquery.calendarTime = alert.timestamp; + alert.rule.description = dataOsquery.rule.description; + randomIntervalInteger(0, 99) === 0 + ? (alert.data.osquery.action = 'removed') + : null; } - - if (params.authentication) { - alert.data = { - srcip: randomArrayItem(IPs), - srcuser: randomArrayItem(Users), - srcport: randomArrayItem(Ports), - }; - alert.GeoLocation = randomArrayItem(GeoLocation); - alert.decoder = { - name: 'sshd', - parent: 'sshd', - }; - alert.input = { - type: 'log', - }; - alert.predecoder = { - program_name: 'sshd', - timestamp: formatDate(new Date(alert.timestamp), 'N D h:m:s'), - hostname: alert.manager.name, + } + + // Regulatory compliance + if ( + params.pci_dss || + params.regulatory_compliance || + (params.random_probability_regulatory_compliance && + randomProbability(params.random_probability_regulatory_compliance)) + ) { + alert.rule.pci_dss = [randomArrayItem(PCI_DSS)]; + } + if ( + params.gdpr || + params.regulatory_compliance || + (params.random_probability_regulatory_compliance && + randomProbability(params.random_probability_regulatory_compliance)) + ) { + alert.rule.gdpr = [randomArrayItem(GDPR)]; + } + if ( + params.gpg13 || + params.regulatory_compliance || + (params.random_probability_regulatory_compliance && + randomProbability(params.random_probability_regulatory_compliance)) + ) { + alert.rule.gpg13 = [randomArrayItem(GPG13)]; + } + if ( + params.hipaa || + params.regulatory_compliance || + (params.random_probability_regulatory_compliance && + randomIntervalInteger(params.random_probability_regulatory_compliance)) + ) { + alert.rule.hipaa = [randomArrayItem(HIPAA)]; + } + if ( + params.nist_800_83 || + params.regulatory_compliance || + (params.random_probability_regulatory_compliance && + randomIntervalInteger(params.random_probability_regulatory_compliance)) + ) { + alert.rule.nist_800_53 = [randomArrayItem(NIST_800_53)]; + } + + if (params.authentication) { + alert.data = { + srcip: randomArrayItem(IPs), + srcuser: randomArrayItem(Users), + srcport: randomArrayItem(Ports), + }; + alert.GeoLocation = randomArrayItem(GeoLocation); + alert.decoder = { + name: 'sshd', + parent: 'sshd', + }; + alert.input = { + type: 'log', + }; + alert.predecoder = { + program_name: 'sshd', + timestamp: formatDate(new Date(alert.timestamp), 'N D h:m:s'), + hostname: alert.manager.name, + }; + let typeAlert = randomArrayItem([ + 'invalidLoginPassword', + 'invalidLoginUser', + 'multipleAuthenticationFailures', + 'windowsInvalidLoginPassword', + 'userLoginFailed', + 'passwordCheckFailed', + 'nonExistentUser', + 'bruteForceTryingAccessSystem', + 'authenticationSuccess', + 'maximumAuthenticationAttemptsExceeded', + ]); + + switch (typeAlert) { + case 'invalidLoginPassword': { + alert.location = Authentication.invalidLoginPassword.location; + alert.rule = { ...Authentication.invalidLoginPassword.rule }; + alert.rule.groups = [ + ...Authentication.invalidLoginPassword.rule.groups, + ]; + alert.full_log = interpolateAlertProps( + Authentication.invalidLoginPassword.full_log, + alert, + ); + break; + } + case 'invalidLoginUser': { + alert.location = Authentication.invalidLoginUser.location; + alert.rule = { ...Authentication.invalidLoginUser.rule }; + alert.rule.groups = [...Authentication.invalidLoginUser.rule.groups]; + alert.full_log = interpolateAlertProps( + Authentication.invalidLoginUser.full_log, + alert, + ); + break; + } + case 'multipleAuthenticationFailures': { + alert.location = Authentication.multipleAuthenticationFailures.location; + alert.rule = { ...Authentication.multipleAuthenticationFailures.rule }; + alert.rule.groups = [ + ...Authentication.multipleAuthenticationFailures.rule.groups, + ]; + alert.rule.frequency = randomIntervalInteger(5, 50); + alert.full_log = interpolateAlertProps( + Authentication.multipleAuthenticationFailures.full_log, + alert, + ); + break; + } + case 'windowsInvalidLoginPassword': { + alert.location = Authentication.windowsInvalidLoginPassword.location; + alert.rule = { ...Authentication.windowsInvalidLoginPassword.rule }; + alert.rule.groups = [ + ...Authentication.windowsInvalidLoginPassword.rule.groups, + ]; + alert.rule.frequency = randomIntervalInteger(5, 50); + alert.data.win = { + ...Authentication.windowsInvalidLoginPassword.data_win, }; - let typeAlert = randomArrayItem([ - 'invalidLoginPassword', - 'invalidLoginUser', - 'multipleAuthenticationFailures', - 'windowsInvalidLoginPassword', - 'userLoginFailed', - 'passwordCheckFailed', - 'nonExistentUser', - 'bruteForceTryingAccessSystem', - 'authenticationSuccess', - 'maximumAuthenticationAttemptsExceeded', - ]); - - switch (typeAlert) { - case 'invalidLoginPassword': { - alert.location = Authentication.invalidLoginPassword.location; - alert.rule = { ...Authentication.invalidLoginPassword.rule }; - alert.rule.groups = [...Authentication.invalidLoginPassword.rule.groups]; - alert.full_log = interpolateAlertProps(Authentication.invalidLoginPassword.full_log, alert); - break; - } - case 'invalidLoginUser': { - alert.location = Authentication.invalidLoginUser.location; - alert.rule = { ...Authentication.invalidLoginUser.rule }; - alert.rule.groups = [...Authentication.invalidLoginUser.rule.groups]; - alert.full_log = interpolateAlertProps(Authentication.invalidLoginUser.full_log, alert); - break; - } - case 'multipleAuthenticationFailures': { - alert.location = Authentication.multipleAuthenticationFailures.location; - alert.rule = { ...Authentication.multipleAuthenticationFailures.rule }; - alert.rule.groups = [...Authentication.multipleAuthenticationFailures.rule.groups]; - alert.rule.frequency = randomIntervalInteger(5, 50); - alert.full_log = interpolateAlertProps( - Authentication.multipleAuthenticationFailures.full_log, - alert - ); - break; - } - case 'windowsInvalidLoginPassword': { - alert.location = Authentication.windowsInvalidLoginPassword.location; - alert.rule = { ...Authentication.windowsInvalidLoginPassword.rule }; - alert.rule.groups = [...Authentication.windowsInvalidLoginPassword.rule.groups]; - alert.rule.frequency = randomIntervalInteger(5, 50); - alert.data.win = { ...Authentication.windowsInvalidLoginPassword.data_win }; - alert.data.win.eventdata.ipAddress = randomArrayItem(IPs); - alert.data.win.eventdata.ipPort = randomArrayItem(Ports); - alert.data.win.system.computer = randomArrayItem(Win_Hostnames); - alert.data.win.system.eventID = `${randomIntervalInteger(1, 600)}`; - alert.data.win.system.eventRecordID = `${randomIntervalInteger(10000, 50000)}`; - alert.data.win.system.processID = `${randomIntervalInteger(1, 1200)}`; - alert.data.win.system.systemTime = alert.timestamp; - alert.data.win.system.processID = `${randomIntervalInteger(1, 1200)}`; - alert.data.win.system.task = `${randomIntervalInteger(1, 1800)}`; - alert.data.win.system.threadID = `${randomIntervalInteger(1, 500)}`; - alert.full_log = interpolateAlertProps( - Authentication.windowsInvalidLoginPassword.full_log, - alert - ); - break; - } - case 'userLoginFailed': { - alert.location = Authentication.userLoginFailed.location; - alert.rule = { ...Authentication.userLoginFailed.rule }; - alert.rule.groups = [...Authentication.userLoginFailed.rule.groups]; - alert.data = { - srcip: randomArrayItem(IPs), - dstuser: randomArrayItem(Users), - uid: `${randomIntervalInteger(0, 50)}`, - euid: `${randomIntervalInteger(0, 50)}`, - tty: 'ssh', - }; - alert.decoder = { ...Authentication.userLoginFailed.decoder }; - alert.full_log = interpolateAlertProps(Authentication.userLoginFailed.full_log, alert); - break; - } - case 'passwordCheckFailed': { - alert.location = Authentication.passwordCheckFailed.location; - alert.rule = { ...Authentication.passwordCheckFailed.rule }; - alert.rule.groups = [...Authentication.passwordCheckFailed.rule.groups]; - alert.data = { - srcuser: randomArrayItem(Users), - }; - alert.predecoder.program_name = 'unix_chkpwd'; - alert.decoder = { ...Authentication.passwordCheckFailed.decoder }; - alert.full_log = interpolateAlertProps(Authentication.passwordCheckFailed.full_log, alert); - break; - } - case 'nonExistentUser': { - alert.location = Authentication.nonExistentUser.location; - alert.rule = { ...Authentication.nonExistentUser.rule }; - alert.rule.groups = [...Authentication.nonExistentUser.rule.groups]; - alert.full_log = interpolateAlertProps(Authentication.nonExistentUser.full_log, alert); - break; - } - case 'bruteForceTryingAccessSystem': { - alert.location = Authentication.bruteForceTryingAccessSystem.location; - alert.rule = { ...Authentication.bruteForceTryingAccessSystem.rule }; - alert.rule.groups = [...Authentication.bruteForceTryingAccessSystem.rule.groups]; - alert.full_log = interpolateAlertProps( - Authentication.bruteForceTryingAccessSystem.full_log, - alert - ); - break; - } - case 'reverseLoockupError': { - alert.location = Authentication.reverseLoockupError.location; - alert.rule = { ...Authentication.reverseLoockupError.rule }; - alert.rule.groups = [...Authentication.reverseLoockupError.rule.groups]; - alert.data = { - srcip: randomArrayItem(IPs), - }; - alert.full_log = interpolateAlertProps(Authentication.reverseLoockupError.full_log, alert); - } - case 'insecureConnectionAttempt': { - alert.location = Authentication.insecureConnectionAttempt.location; - alert.rule = { ...Authentication.insecureConnectionAttempt.rule }; - alert.rule.groups = [...Authentication.insecureConnectionAttempt.rule.groups]; - alert.data = { - srcip: randomArrayItem(IPs), - srcport: randomArrayItem(Ports), - }; - alert.full_log = interpolateAlertProps( - Authentication.insecureConnectionAttempt.full_log, - alert - ); - } - case 'authenticationSuccess': { - alert.location = Authentication.authenticationSuccess.location; - alert.rule = { ...Authentication.authenticationSuccess.rule }; - alert.rule.groups = [...Authentication.authenticationSuccess.rule.groups]; - alert.data = { - srcip: randomArrayItem(IPs), - srcport: randomArrayItem(Ports), - dstuser: randomArrayItem(Users), - }; - alert.full_log = interpolateAlertProps( - Authentication.authenticationSuccess.full_log, - alert - ); - } - case 'maximumAuthenticationAttemptsExceeded': { - alert.location = Authentication.maximumAuthenticationAttemptsExceeded.location; - alert.rule = { ...Authentication.maximumAuthenticationAttemptsExceeded.rule }; - alert.rule.groups = [...Authentication.maximumAuthenticationAttemptsExceeded.rule.groups]; - alert.data = { - srcip: randomArrayItem(IPs), - srcport: randomArrayItem(Ports), - dstuser: randomArrayItem(Users), - }; - alert.full_log = interpolateAlertProps( - Authentication.maximumAuthenticationAttemptsExceeded.full_log, - alert - ); - } - default: { - } - } - alert.rule.firedtimes = randomIntervalInteger(2, 15); - alert.rule.tsc = [randomArrayItem(tsc)]; - } - - if (params.ssh) { + alert.data.win.eventdata.ipAddress = randomArrayItem(IPs); + alert.data.win.eventdata.ipPort = randomArrayItem(Ports); + alert.data.win.system.computer = randomArrayItem(Win_Hostnames); + alert.data.win.system.eventID = `${randomIntervalInteger(1, 600)}`; + alert.data.win.system.eventRecordID = `${randomIntervalInteger( + 10000, + 50000, + )}`; + alert.data.win.system.processID = `${randomIntervalInteger(1, 1200)}`; + alert.data.win.system.systemTime = alert.timestamp; + alert.data.win.system.processID = `${randomIntervalInteger(1, 1200)}`; + alert.data.win.system.task = `${randomIntervalInteger(1, 1800)}`; + alert.data.win.system.threadID = `${randomIntervalInteger(1, 500)}`; + alert.full_log = interpolateAlertProps( + Authentication.windowsInvalidLoginPassword.full_log, + alert, + ); + break; + } + case 'userLoginFailed': { + alert.location = Authentication.userLoginFailed.location; + alert.rule = { ...Authentication.userLoginFailed.rule }; + alert.rule.groups = [...Authentication.userLoginFailed.rule.groups]; alert.data = { - srcip: randomArrayItem(IPs), - srcuser: randomArrayItem(Users), - srcport: randomArrayItem(Ports), - }; - alert.GeoLocation = randomArrayItem(GeoLocation); - alert.decoder = { - name: 'sshd', - parent: 'sshd', - }; - alert.input = { - type: 'log', + srcip: randomArrayItem(IPs), + dstuser: randomArrayItem(Users), + uid: `${randomIntervalInteger(0, 50)}`, + euid: `${randomIntervalInteger(0, 50)}`, + tty: 'ssh', }; - alert.predecoder = { - program_name: 'sshd', - timestamp: formatDate(new Date(alert.timestamp), 'N D h:m:s'), - hostname: alert.manager.name, - }; - const typeAlert = randomArrayItem(SSH.data); - alert.location = typeAlert.location; - alert.rule = { ...typeAlert.rule }; - alert.rule.groups = [...typeAlert.rule.groups]; - alert.rule.firedtimes = randomIntervalInteger(1, 15); - alert.full_log = interpolateAlertProps(typeAlert.full_log, alert); - } - - if (params.windows) { - alert.rule.groups.push('windows'); - if (params.windows.service_control_manager) { - alert.predecoder = { - program_name: 'WinEvtLog', - timestamp: '2020 Apr 17 05:59:05', - }; - alert.input = { - type: 'log', - }; - alert.data = { - extra_data: 'Service Control Manager', - dstuser: 'SYSTEM', - system_name: randomArrayItem(Win_Hostnames), - id: '7040', - type: 'type', - status: 'INFORMATION', - }; - alert.rule.description = 'Windows: Service startup type was changed.'; - alert.rule.firedtimes = randomIntervalInteger(1, 20); - alert.rule.mail = false; - alert.rule.level = 3; - alert.rule.groups.push('windows', 'policy_changed'); - alert.rule.pci = ['10.6']; - alert.rule.hipaa = ['164.312.b']; - alert.rule.gdpr = ['IV_35.7.d']; - alert.rule.nist_800_53 = ['AU.6']; - alert.rule.info = 'This does not appear to be logged on Windows 2000.'; - alert.location = 'WinEvtLog'; - alert.decoder = { - parent: 'windows', - name: 'windows', - }; - alert.full_log = `2020 Apr 17 05:59:05 WinEvtLog: type: INFORMATION(7040): Service Control Manager: SYSTEM: NT AUTHORITY: ${alert.data.system_name}: Background Intelligent Transfer Service auto start demand start BITS `; //TODO: date - alert.id = 18145; - alert.fields = { - timestamp: alert.timestamp, - }; - } - } - - if (params.apache) { - const typeAlert = { ...Apache.data[0] }; // there is only one type alert in data array at the moment. Randomize if add more type of alerts to data array + alert.decoder = { ...Authentication.userLoginFailed.decoder }; + alert.full_log = interpolateAlertProps( + Authentication.userLoginFailed.full_log, + alert, + ); + break; + } + case 'passwordCheckFailed': { + alert.location = Authentication.passwordCheckFailed.location; + alert.rule = { ...Authentication.passwordCheckFailed.rule }; + alert.rule.groups = [...Authentication.passwordCheckFailed.rule.groups]; alert.data = { - srcip: randomArrayItem(IPs), - srcport: randomArrayItem(Ports), - id: `AH${randomIntervalInteger(10000, 99999)}`, + srcuser: randomArrayItem(Users), }; - alert.GeoLocation = { ...randomArrayItem(GeoLocation) }; - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(2, 10); - alert.input = { type: 'log' }; - alert.location = Apache.location; - alert.decoder = { ...Apache.decoder }; - - alert.full_log = interpolateAlertProps(typeAlert.full_log, alert, { - _timestamp_apache: formatDate(new Date(alert.timestamp), 'E N D h:m:s.l Y'), - _pi_id: randomIntervalInteger(10000, 30000), - }); - } - - if (params.web) { - alert.input = { - type: 'log', + alert.predecoder.program_name = 'unix_chkpwd'; + alert.decoder = { ...Authentication.passwordCheckFailed.decoder }; + alert.full_log = interpolateAlertProps( + Authentication.passwordCheckFailed.full_log, + alert, + ); + break; + } + case 'nonExistentUser': { + alert.location = Authentication.nonExistentUser.location; + alert.rule = { ...Authentication.nonExistentUser.rule }; + alert.rule.groups = [...Authentication.nonExistentUser.rule.groups]; + alert.full_log = interpolateAlertProps( + Authentication.nonExistentUser.full_log, + alert, + ); + break; + } + case 'bruteForceTryingAccessSystem': { + alert.location = Authentication.bruteForceTryingAccessSystem.location; + alert.rule = { ...Authentication.bruteForceTryingAccessSystem.rule }; + alert.rule.groups = [ + ...Authentication.bruteForceTryingAccessSystem.rule.groups, + ]; + alert.full_log = interpolateAlertProps( + Authentication.bruteForceTryingAccessSystem.full_log, + alert, + ); + break; + } + case 'reverseLoockupError': { + alert.location = Authentication.reverseLoockupError.location; + alert.rule = { ...Authentication.reverseLoockupError.rule }; + alert.rule.groups = [...Authentication.reverseLoockupError.rule.groups]; + alert.data = { + srcip: randomArrayItem(IPs), }; + alert.full_log = interpolateAlertProps( + Authentication.reverseLoockupError.full_log, + alert, + ); + } + case 'insecureConnectionAttempt': { + alert.location = Authentication.insecureConnectionAttempt.location; + alert.rule = { ...Authentication.insecureConnectionAttempt.rule }; + alert.rule.groups = [ + ...Authentication.insecureConnectionAttempt.rule.groups, + ]; alert.data = { - protocol: 'GET', - srcip: randomArrayItem(IPs), - id: '404', - url: randomArrayItem(Web.urls), + srcip: randomArrayItem(IPs), + srcport: randomArrayItem(Ports), }; - alert.GeoLocation = { ...randomArrayItem(GeoLocation) }; - - const typeAlert = randomArrayItem(Web.data); - const userAgent = randomArrayItem(Web.userAgents); - alert.rule = { ...typeAlert.rule }; - alert.rule.firedtimes = randomIntervalInteger(1, 10); - alert.decoder = { ...typeAlert.decoder }; - alert.location = typeAlert.location; - alert.full_log = interpolateAlertProps(typeAlert.full_log, alert, { - _user_agent: userAgent, - _date: formatDate(new Date(alert.timestamp), 'D/N/Y:h:m:s +0000'), - }); - if (typeAlert.previous_output) { - const previousOutput = []; - const beforeSeconds = 4; - for (let i = beforeSeconds; i > 0; i--) { - const beforeDate = new Date(new Date(alert.timestamp) - (2 + i) * 1000); - previousOutput.push( - interpolateAlertProps(typeAlert.full_log, alert, { - _user_agent: userAgent, - _date: formatDate(new Date(beforeDate), 'D/N/Y:h:m:s +0000'), - }) - ); - } - alert.previous_output = previousOutput.join('\n'); - } - } - - if (params.github) { - alert.location = GitHub.LOCATION; - alert.decoder = GitHub.DECODER; - const alertType = randomArrayItem(GitHub.ALERT_TYPES); - const actor = randomArrayItem(GitHub.ACTORS); + alert.full_log = interpolateAlertProps( + Authentication.insecureConnectionAttempt.full_log, + alert, + ); + } + case 'authenticationSuccess': { + alert.location = Authentication.authenticationSuccess.location; + alert.rule = { ...Authentication.authenticationSuccess.rule }; + alert.rule.groups = [ + ...Authentication.authenticationSuccess.rule.groups, + ]; alert.data = { - github: { ...alertType.data.github } + srcip: randomArrayItem(IPs), + srcport: randomArrayItem(Ports), + dstuser: randomArrayItem(Users), }; - alert.data.github.org = randomArrayItem(GitHub.ORGANIZATION_NAMES); - alert.data.github.repo && (alert.data.github.repo = `${alert.data.github.org}/${randomArrayItem(GitHub.REPOSITORY_NAMES)}`); - alert.data.github.repository && (alert.data.github.repository = `${alert.data.github.org}/${randomArrayItem(GitHub.REPOSITORY_NAMES)}`); - alert.data.github.actor = actor.name; - alert.data.github.actor_location && alert.data.github.actor_location.country_code && (alert.data.github.actor_location.country_code = actor.country_code); - alert.data.github.user && (alert.data.github.user = randomArrayItem(GitHub.USER_NAMES)); - alert.data.github.config && alert.data.github.config.url && (alert.data.github.config.url = randomArrayItem(GitHub.SERVER_ADDRESS_WEBHOOK)); - alert.data.github['@timestamp'] = alert.timestamp; - alert.data.github.created_at && (alert.data.github.created_at = alert.timestamp); + alert.full_log = interpolateAlertProps( + Authentication.authenticationSuccess.full_log, + alert, + ); + } + case 'maximumAuthenticationAttemptsExceeded': { + alert.location = + Authentication.maximumAuthenticationAttemptsExceeded.location; alert.rule = { - ...alertType.rule + ...Authentication.maximumAuthenticationAttemptsExceeded.rule, }; + alert.rule.groups = [ + ...Authentication.maximumAuthenticationAttemptsExceeded.rule.groups, + ]; + alert.data = { + srcip: randomArrayItem(IPs), + srcport: randomArrayItem(Ports), + dstuser: randomArrayItem(Users), + }; + alert.full_log = interpolateAlertProps( + Authentication.maximumAuthenticationAttemptsExceeded.full_log, + alert, + ); + } + default: { + } } + alert.rule.firedtimes = randomIntervalInteger(2, 15); + alert.rule.tsc = [randomArrayItem(tsc)]; + } + + if (params.ssh) { + alert.data = { + srcip: randomArrayItem(IPs), + srcuser: randomArrayItem(Users), + srcport: randomArrayItem(Ports), + }; + alert.GeoLocation = randomArrayItem(GeoLocation); + alert.decoder = { + name: 'sshd', + parent: 'sshd', + }; + alert.input = { + type: 'log', + }; + alert.predecoder = { + program_name: 'sshd', + timestamp: formatDate(new Date(alert.timestamp), 'N D h:m:s'), + hostname: alert.manager.name, + }; + const typeAlert = randomArrayItem(SSH.data); + alert.location = typeAlert.location; + alert.rule = { ...typeAlert.rule }; + alert.rule.groups = [...typeAlert.rule.groups]; + alert.rule.firedtimes = randomIntervalInteger(1, 15); + alert.full_log = interpolateAlertProps(typeAlert.full_log, alert); + } + + if (params.windows) { + alert.rule.groups.push('windows'); + if (params.windows.service_control_manager) { + alert.predecoder = { + program_name: 'WinEvtLog', + timestamp: '2020 Apr 17 05:59:05', + }; + alert.input = { + type: 'log', + }; + alert.data = { + extra_data: 'Service Control Manager', + dstuser: 'SYSTEM', + system_name: randomArrayItem(Win_Hostnames), + id: '7040', + type: 'type', + status: 'INFORMATION', + }; + alert.rule.description = 'Windows: Service startup type was changed.'; + alert.rule.firedtimes = randomIntervalInteger(1, 20); + alert.rule.mail = false; + alert.rule.level = 3; + alert.rule.groups.push('windows', 'policy_changed'); + alert.rule.pci = ['10.6']; + alert.rule.hipaa = ['164.312.b']; + alert.rule.gdpr = ['IV_35.7.d']; + alert.rule.nist_800_53 = ['AU.6']; + alert.rule.info = 'This does not appear to be logged on Windows 2000.'; + alert.location = 'WinEvtLog'; + alert.decoder = { + parent: 'windows', + name: 'windows', + }; + alert.full_log = `2020 Apr 17 05:59:05 WinEvtLog: type: INFORMATION(7040): Service Control Manager: SYSTEM: NT AUTHORITY: ${alert.data.system_name}: Background Intelligent Transfer Service auto start demand start BITS `; //TODO: date + alert.id = 18145; + alert.fields = { + timestamp: alert.timestamp, + }; + } + } + + if (params.apache) { + const typeAlert = { ...Apache.data[0] }; // there is only one type alert in data array at the moment. Randomize if add more type of alerts to data array + alert.data = { + srcip: randomArrayItem(IPs), + srcport: randomArrayItem(Ports), + id: `AH${randomIntervalInteger(10000, 99999)}`, + }; + alert.GeoLocation = { ...randomArrayItem(GeoLocation) }; + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(2, 10); + alert.input = { type: 'log' }; + alert.location = Apache.location; + alert.decoder = { ...Apache.decoder }; + + alert.full_log = interpolateAlertProps(typeAlert.full_log, alert, { + _timestamp_apache: formatDate( + new Date(alert.timestamp), + 'E N D h:m:s.l Y', + ), + _pi_id: randomIntervalInteger(10000, 30000), + }); + } + + if (params.web) { + alert.input = { + type: 'log', + }; + alert.data = { + protocol: 'GET', + srcip: randomArrayItem(IPs), + id: '404', + url: randomArrayItem(Web.urls), + }; + alert.GeoLocation = { ...randomArrayItem(GeoLocation) }; + + const typeAlert = randomArrayItem(Web.data); + const userAgent = randomArrayItem(Web.userAgents); + alert.rule = { ...typeAlert.rule }; + alert.rule.firedtimes = randomIntervalInteger(1, 10); + alert.decoder = { ...typeAlert.decoder }; + alert.location = typeAlert.location; + alert.full_log = interpolateAlertProps(typeAlert.full_log, alert, { + _user_agent: userAgent, + _date: formatDate(new Date(alert.timestamp), 'D/N/Y:h:m:s +0000'), + }); + if (typeAlert.previous_output) { + const previousOutput = []; + const beforeSeconds = 4; + for (let i = beforeSeconds; i > 0; i--) { + const beforeDate = new Date(new Date(alert.timestamp) - (2 + i) * 1000); + previousOutput.push( + interpolateAlertProps(typeAlert.full_log, alert, { + _user_agent: userAgent, + _date: formatDate(new Date(beforeDate), 'D/N/Y:h:m:s +0000'), + }), + ); + } + alert.previous_output = previousOutput.join('\n'); + } + } + + if (params.github) { + alert.location = GitHub.LOCATION; + alert.decoder = GitHub.DECODER; + const alertType = randomArrayItem(GitHub.ALERT_TYPES); + const actor = randomArrayItem(GitHub.ACTORS); + alert.data = { + github: { ...alertType.data.github }, + }; + alert.data.github.org = randomArrayItem(GitHub.ORGANIZATION_NAMES); + alert.data.github.repo && + (alert.data.github.repo = `${alert.data.github.org}/${randomArrayItem( + GitHub.REPOSITORY_NAMES, + )}`); + alert.data.github.repository && + (alert.data.github.repository = `${ + alert.data.github.org + }/${randomArrayItem(GitHub.REPOSITORY_NAMES)}`); + alert.data.github.actor = actor.name; + alert.data.github.actor_location && + alert.data.github.actor_location.country_code && + (alert.data.github.actor_location.country_code = actor.country_code); + alert.data.github.user && + (alert.data.github.user = randomArrayItem(GitHub.USER_NAMES)); + alert.data.github.config && + alert.data.github.config.url && + (alert.data.github.config.url = randomArrayItem( + GitHub.SERVER_ADDRESS_WEBHOOK, + )); + alert.data.github['@timestamp'] = alert.timestamp; + alert.data.github.created_at && + (alert.data.github.created_at = alert.timestamp); + alert.rule = { + ...alertType.rule, + }; + } - return alert; + return alert; } /** @@ -980,12 +1156,12 @@ function generateAlert(params) { * @return {*} Array with random values extracted of paramater array passed */ function randomUniqueValuesFromArray(array, randomMaxRepetitions = 1, sort) { - const repetitions = randomIntervalInteger(1, randomMaxRepetitions); - const set = new Set(); - for (let i = 0; i < repetitions; i++) { - set.add(array[randomIntervalInteger(0, array.length - 1)]); - } - return sort ? Array.from(set).sort(sort) : Array.from(set); + const repetitions = randomIntervalInteger(1, randomMaxRepetitions); + const set = new Set(); + for (let i = 0; i < repetitions; i++) { + set.add(array[randomIntervalInteger(0, array.length - 1)]); + } + return sort ? Array.from(set).sort(sort) : Array.from(set); } /** @@ -995,7 +1171,7 @@ function randomUniqueValuesFromArray(array, randomMaxRepetitions = 1, sort) { * @returns {number} - Randomized number in interval */ function randomIntervalInteger(min, max) { - return Math.floor(Math.random() * (max - (min - 1))) + min; + return Math.floor(Math.random() * (max - (min - 1))) + min; } /** @@ -1005,11 +1181,11 @@ function randomIntervalInteger(min, max) { * @return {*} - Random generated alerts defined with params */ function generateAlerts(params, numAlerts = 1) { - const alerts = []; - for (let i = 0; i < numAlerts; i++) { - alerts.push(generateAlert(params)); - } - return alerts; + const alerts = []; + for (let i = 0; i < numAlerts; i++) { + alerts.push(generateAlert(params)); + } + return alerts; } /** @@ -1017,61 +1193,83 @@ function generateAlerts(params, numAlerts = 1) { * @returns {date} - Random date in range (7 days ago - now) */ function randomDate(inf, sup) { - const nowTimestamp = Date.now(); - const time = randomIntervalInteger(0, 604800000); // Random 7 days in miliseconds + const nowTimestamp = Date.now(); + const time = randomIntervalInteger(0, 604800000); // Random 7 days in miliseconds - const unix_timestamp = nowTimestamp - time; // Last 7 days = require( now + const unix_timestamp = nowTimestamp - time; // Last 7 days = require( now - const lastWeek = new Date(unix_timestamp); - return formatDate(lastWeek, 'Y-M-DTh:m:s.l+0000'); + const lastWeek = new Date(unix_timestamp); + return formatDate(lastWeek, 'Y-M-DTh:m:s.l+0000'); } -const formatterNumber = (number, zeros = 0) => ('0'.repeat(zeros) + `${number}`).slice(-zeros); +const formatterNumber = (number, zeros = 0) => + ('0'.repeat(zeros) + `${number}`).slice(-zeros); const monthNames = { - long: [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', - ], - short: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + long: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + short: [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], }; const dayNames = { - long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + long: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ], + short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], }; function formatDate(date, format) { - // It could use "moment" library to format strings too - const tokens = { - D: (d) => formatterNumber(d.getDate(), 2), // 01-31 - A: (d) => dayNames.long[d.getDay()], // 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' - E: (d) => dayNames.short[d.getDay()], // 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' - M: (d) => formatterNumber(d.getMonth() + 1, 2), // 01-12 - J: (d) => monthNames.long[d.getMonth()], // 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' - N: (d) => monthNames.short[d.getMonth()], // 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' - Y: (d) => d.getFullYear(), // 2020 - h: (d) => formatterNumber(d.getHours(), 2), // 00-23 - m: (d) => formatterNumber(d.getMinutes(), 2), // 00-59 - s: (d) => formatterNumber(d.getSeconds(), 2), // 00-59 - l: (d) => formatterNumber(d.getMilliseconds(), 3), // 000-999 - }; - - return format.split('').reduce((accum, token) => { - if (tokens[token]) { - return accum + tokens[token](date); - } - return accum + token; - }, ''); + // It could use "moment" library to format strings too + const tokens = { + D: d => formatterNumber(d.getDate(), 2), // 01-31 + A: d => dayNames.long[d.getDay()], // 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' + E: d => dayNames.short[d.getDay()], // 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' + M: d => formatterNumber(d.getMonth() + 1, 2), // 01-12 + J: d => monthNames.long[d.getMonth()], // 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' + N: d => monthNames.short[d.getMonth()], // 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + Y: d => d.getFullYear(), // 2020 + h: d => formatterNumber(d.getHours(), 2), // 00-23 + m: d => formatterNumber(d.getMinutes(), 2), // 00-59 + s: d => formatterNumber(d.getSeconds(), 2), // 00-59 + l: d => formatterNumber(d.getMilliseconds(), 3), // 000-999 + }; + + return format.split('').reduce((accum, token) => { + if (tokens[token]) { + return accum + tokens[token](date); + } + return accum + token; + }, ''); } /** @@ -1081,17 +1279,19 @@ function formatDate(date, format) { * @param {*} extra Extra parameters to interpolate what aren't in alert objet. Only admit one level of depth */ function interpolateAlertProps(str, alert, extra = {}) { - const matches = str.match(/{([\w\._]+)}/g); - return ( - (matches && - matches.reduce((accum, cur) => { - const match = cur.match(/{([\w\._]+)}/); - const items = match[1].split('.'); - const value = items.reduce((a, c) => (a && a[c]) || extra[c] || undefined, alert) || cur; - return accum.replace(cur, value); - }, str)) || - str - ); + const matches = str.match(/{([\w\._]+)}/g); + return ( + (matches && + matches.reduce((accum, cur) => { + const match = cur.match(/{([\w\._]+)}/); + const items = match[1].split('.'); + const value = + items.reduce((a, c) => (a && a[c]) || extra[c] || undefined, alert) || + cur; + return accum.replace(cur, value); + }, str)) || + str + ); } /** @@ -1100,7 +1300,7 @@ function interpolateAlertProps(str, alert, extra = {}) { * @param {number[=100]} maximum */ function randomProbability(probability, maximum = 100) { - return randomIntervalInteger(0, maximum) <= probability; + return randomIntervalInteger(0, maximum) <= probability; } module.exports = { generateAlert, generateAlerts }; From 43babf6111b82116c1aaa22539234063154eef93 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Fri, 5 Apr 2024 12:21:11 +0200 Subject: [PATCH 04/18] Bump revision to 07 (#6576) --- CHANGELOG.md | 2 +- plugins/main/opensearch_dashboards.json | 2 +- plugins/main/package.json | 2 +- plugins/wazuh-check-updates/opensearch_dashboards.json | 2 +- plugins/wazuh-check-updates/package.json | 2 +- plugins/wazuh-core/opensearch_dashboards.json | 2 +- plugins/wazuh-core/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b113ae0b23..2a8a764b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Wazuh app project will be documented in this file. -## Wazuh v4.8.0 - OpenSearch Dashboards 2.10.0 - Revision 06 +## Wazuh v4.8.0 - OpenSearch Dashboards 2.10.0 - Revision 07 ### Added diff --git a/plugins/main/opensearch_dashboards.json b/plugins/main/opensearch_dashboards.json index 72c3d45aad..fc3b0cb9c8 100644 --- a/plugins/main/opensearch_dashboards.json +++ b/plugins/main/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuh", - "version": "4.8.0-06", + "version": "4.8.0-07", "opensearchDashboardsVersion": "opensearchDashboards", "configPath": [ "wazuh" diff --git a/plugins/main/package.json b/plugins/main/package.json index 915a8eaeef..dd4ad72dbc 100644 --- a/plugins/main/package.json +++ b/plugins/main/package.json @@ -1,7 +1,7 @@ { "name": "wazuh", "version": "4.8.0", - "revision": "06", + "revision": "07", "pluginPlatform": { "version": "2.10.0" }, diff --git a/plugins/wazuh-check-updates/opensearch_dashboards.json b/plugins/wazuh-check-updates/opensearch_dashboards.json index 160537e5e5..79f0a4f662 100644 --- a/plugins/wazuh-check-updates/opensearch_dashboards.json +++ b/plugins/wazuh-check-updates/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuhCheckUpdates", - "version": "4.8.0-06", + "version": "4.8.0-07", "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, diff --git a/plugins/wazuh-check-updates/package.json b/plugins/wazuh-check-updates/package.json index 92ad3c44bc..e816e2a255 100644 --- a/plugins/wazuh-check-updates/package.json +++ b/plugins/wazuh-check-updates/package.json @@ -1,7 +1,7 @@ { "name": "wazuh-check-updates", "version": "4.8.0", - "revision": "06", + "revision": "07", "pluginPlatform": { "version": "2.10.0" }, diff --git a/plugins/wazuh-core/opensearch_dashboards.json b/plugins/wazuh-core/opensearch_dashboards.json index e578b6f736..f249d45f01 100644 --- a/plugins/wazuh-core/opensearch_dashboards.json +++ b/plugins/wazuh-core/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuhCore", - "version": "4.8.0-06", + "version": "4.8.0-07", "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, diff --git a/plugins/wazuh-core/package.json b/plugins/wazuh-core/package.json index 261fb2e3d4..5df721e9ad 100644 --- a/plugins/wazuh-core/package.json +++ b/plugins/wazuh-core/package.json @@ -1,7 +1,7 @@ { "name": "wazuh-core", "version": "4.8.0", - "revision": "06", + "revision": "07", "pluginPlatform": { "version": "2.10.0" }, From b988643b121607e61bdfc73eeccebdb075e73faf Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Tue, 9 Apr 2024 14:25:44 +0200 Subject: [PATCH 05/18] Create published vulnerabilities severity visualization (#6583) * Create Published vulnerabilities severity visualization * Adapt vulnerabilities injector script --- .../dashboards/overview/dashboard_panels.ts | 68 ++++++++----------- .../dataInjectScript.py | 8 +-- 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard_panels.ts b/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard_panels.ts index 8ff1084b67..252d60d65a 100644 --- a/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard_panels.ts +++ b/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard_panels.ts @@ -269,11 +269,11 @@ const getVisStateAccumulationMostDetectedVulnerabilities = ( indexPatternId: string, ) => { return { - id: 'accumulation_most_vulnerable_vulnerabilities', - title: 'Accumulation of the most detected vulnerabilities', - type: 'line', + id: 'vulnerabilities_by_year_of_publication', + title: 'Vulnerabilities by year of publication', + type: 'histogram', params: { - type: 'line', + type: 'histogram', grid: { categoryLines: false, }, @@ -304,8 +304,9 @@ const getVisStateAccumulationMostDetectedVulnerabilities = ( show: true, style: {}, scale: { - type: 'linear', + type: 'log', mode: 'normal', + defaultYExtents: true, }, labels: { show: true, @@ -321,16 +322,15 @@ const getVisStateAccumulationMostDetectedVulnerabilities = ( seriesParams: [ { show: true, - type: 'line', - mode: 'normal', + type: 'histogram', + mode: 'stacked', data: { label: 'Count', id: '1', }, valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: false, + drawLinesBetweenPoints: true, lineWidth: 2, - interpolate: 'linear', showCircles: true, }, ], @@ -339,7 +339,9 @@ const getVisStateAccumulationMostDetectedVulnerabilities = ( legendPosition: 'right', times: [], addTimeMarker: false, - labels: {}, + labels: { + show: false, + }, thresholdLine: { show: false, value: 10, @@ -347,7 +349,6 @@ const getVisStateAccumulationMostDetectedVulnerabilities = ( style: 'full', color: '#E7664C', }, - radiusRatio: 20, }, data: { searchSource: { @@ -376,49 +377,38 @@ const getVisStateAccumulationMostDetectedVulnerabilities = ( { id: '2', enabled: true, - type: 'count', - params: {}, - schema: 'radius', - }, - { - id: '4', - enabled: true, - type: 'terms', - params: { - field: 'vulnerability.id', - orderBy: '1', - order: 'desc', - size: 5, - otherBucket: false, - otherBucketLabel: 'Others', - missingBucket: false, - missingBucketLabel: 'Missing', - }, - schema: 'group', - }, - { - id: '3', - enabled: true, type: 'date_histogram', params: { field: 'vulnerability.published_at', - customLabel: 'Published at', timeRange: { from: 'now-24h', to: 'now', }, useNormalizedOpenSearchInterval: true, scaleMetricValues: false, - interval: 'w', - // eslint-disable-next-line camelcase + interval: 'y', drop_partials: false, - // eslint-disable-next-line camelcase min_doc_count: 1, - // eslint-disable-next-line camelcase extended_bounds: {}, }, schema: 'segment', }, + { + id: '3', + enabled: true, + type: 'terms', + params: { + field: 'vulnerability.severity', + orderBy: '1', + order: 'desc', + size: 5, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', + }, + schema: 'group', + }, ], }, }; diff --git a/scripts/vulnerabilities-events-injector/dataInjectScript.py b/scripts/vulnerabilities-events-injector/dataInjectScript.py index cee658ad92..e9f8edb324 100644 --- a/scripts/vulnerabilities-events-injector/dataInjectScript.py +++ b/scripts/vulnerabilities-events-injector/dataInjectScript.py @@ -6,9 +6,9 @@ import warnings warnings.filterwarnings("ignore") -def generateRandomDate(): +def generateRandomDate(days_interval=10): start_date = datetime.now() - end_date = start_date - timedelta(days=10) + end_date = start_date - timedelta(days=days_interval) random_date = start_date + (end_date - start_date) * random.random() return(random_date.strftime("%Y-%m-%dT%H:%M:%S.{}Z".format(random.randint(0, 999)))) @@ -115,8 +115,8 @@ def generateRandomVulnerability(): vulnerability['scanner'] = {'vendor':'vendor-{}'.format(random.randint(0, 9))} vulnerability['score'] = {'base':round(random.uniform(0, 10),1), 'environmental':round(random.uniform(0, 10),1), 'temporal':round(random.uniform(0, 10),1),'version':'{}'.format(round(random.uniform(0, 10),1))} vulnerability['severity'] = random.choice(['Low','Medium','High','Critical']) - vulnerability['published_at'] = generateRandomDate() - vulnerability['detected_at'] = generateRandomDate() + vulnerability['published_at'] = generateRandomDate(2000) + vulnerability['detected_at'] = generateRandomDate(180) return(vulnerability) def generateRandomWazuh(): From 308a2aedca17ad8b4b929f569cc84b106a5f1a75 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Thu, 11 Apr 2024 14:52:05 +0200 Subject: [PATCH 06/18] Remove hardcoded colors and implement OUI styles (#6587) * Remove deprecates css clases and implement OUI styles * Remove deprecated styles * Implement euiThemeVars * Add changelog --- CHANGELOG.md | 1 + .../components/common/modules/main-agent.tsx | 2 + .../components/common/modules/module.scss | 160 +++++++++--------- .../management/ruleset/components/columns.tsx | 3 +- .../management/ruleset/views/rule-info.tsx | 8 +- plugins/main/public/styles/common.scss | 41 ----- plugins/main/public/styles/component.scss | 27 --- plugins/main/public/styles/layout.scss | 133 --------------- .../public/styles/theme/dark/index.dark.scss | 14 -- plugins/main/public/styles/typography.scss | 43 +---- .../templates/management/management.html | 10 +- 11 files changed, 99 insertions(+), 343 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8a764b78..ade5bc5d36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Fixed a error pop-up spawn in MITRE ATT&CK [#6431](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6431) - Fixed minor style issues [#6484](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6484) [#6489](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6489) - Fixed "View alerts of this Rule" link [#6553](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6553) +- Fixed minor color styles [#6587](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6587) ### Removed diff --git a/plugins/main/public/components/common/modules/main-agent.tsx b/plugins/main/public/components/common/modules/main-agent.tsx index 6baa5d2ab9..028d6933d9 100644 --- a/plugins/main/public/components/common/modules/main-agent.tsx +++ b/plugins/main/public/components/common/modules/main-agent.tsx @@ -18,6 +18,7 @@ import { EuiTitle, EuiButtonEmpty, } from '@elastic/eui'; +import { euiThemeVars } from '@osd/ui-shared-deps/theme'; import '../../common/modules/module.scss'; import store from '../../../redux/store'; import { FilterHandler } from '../../../utils/filter-handler'; @@ -107,6 +108,7 @@ export class MainModuleAgent extends Component {

{ window.location.href = `#/agents?agent=${this.props.agent.id}`; this.router.reload(); diff --git a/plugins/main/public/components/common/modules/module.scss b/plugins/main/public/components/common/modules/module.scss index 5c076faf70..fd906406cd 100644 --- a/plugins/main/public/components/common/modules/module.scss +++ b/plugins/main/public/components/common/modules/module.scss @@ -1,130 +1,130 @@ .wz-module { - display: contents; + display: contents; } -.wz-module-header-agent, .wz-module-header-nav{ - background:#fafbfd; +.wz-module-header-agent, +.wz-module-header-nav { + background: #fafbfd; } -.wz-module-header-agent{ - height: 50px; - padding: 16px; +.wz-module-header-agent { + height: 50px; + padding: 16px; } -.wz-module-header-agent .euiHealth svg{ - width: 16px; - height: 24px; +.wz-module-header-agent .euiHealth svg { + width: 16px; + height: 24px; } -.wzApp .euiFlyoutBody .euiFlyoutBody__overflowContent{ - padding:0!important; +.wzApp .euiFlyoutBody .euiFlyoutBody__overflowContent { + padding: 0 !important; } .wz-module-header-nav > .euiFlexGroup { - margin-top: -16px; + margin-top: -16px; } -.wz-module-header-nav > .euiFlexGroup .euiFlexItem{ - margin-top: 0px; +.wz-module-header-nav > .euiFlexGroup .euiFlexItem { + margin-top: 0px; } -.wz-module-header-agent-title{ - margin: 6px 12px!important; +.wz-module-header-agent-title { + margin: 6px 12px !important; } -.wz-module-header-agent-title-badge{ - border: 1px solid #d3dae6; - padding: 0 100px; - border-radius: 100px; +.wz-module-header-agent-title-badge { + border: 1px solid #d3dae6; + padding: 0 100px; + border-radius: 100px; } -.wz-module-header-agent-title-btn{ - cursor: pointer; +.wz-module-header-agent-title-btn { + cursor: pointer; } -.wz-module-header-agent-title-btn > span:hover{ - color: #006BB4; +.wz-font-weight-normal { + font-weight: normal; } - -.wz-module-header-agent h1{ - font-weight: 400; +.wz-module-header-agent h1 { + font-weight: 400; } -.wz-module-header-agent h1 b{ - font-weight: 500; +.wz-module-header-agent h1 b { + font-weight: 500; } -.wz-module-header-nav .euiTabs{ - padding-top: 6px; +.wz-module-header-nav .euiTabs { + padding-top: 6px; } -.wz-module-header-nav .euiTab__content{ - font-size: 16px!important; - font-weight: 400; +.wz-module-header-nav .euiTab__content { + font-size: 16px !important; + font-weight: 400; } .wz-module-body { - padding-top: 105px; + padding-top: 105px; } -.wz-module.wz-module-welcome{ - .wz-module-body{ - padding-top: 109px !important; - } +.wz-module.wz-module-welcome { + .wz-module-body { + padding-top: 109px !important; + } } -.wz-module.wz-module-showing-agent .wz-module-body{ - padding-top: 160px !important; +.wz-module.wz-module-showing-agent .wz-module-body { + padding-top: 160px !important; } -.flyout-body .globalQueryBar{ - padding: 2px 0px 8px 0px!important; +.flyout-body .globalQueryBar { + padding: 2px 0px 8px 0px !important; } -.sidebar-list{ - margin-bottom: 2px; +.sidebar-list { + margin-bottom: 2px; } discover-app-w .sidebar-container { - background-color: transparent!important; -} + background-color: transparent !important; +} + +@media only screen and (max-width: 1360px) { + .wz-module.wz-module-welcome .wz-module-body { + padding-top: 189px !important; + } + @media only screen and (max-width: 767px) { + .wz-module-header-agent { + height: auto; + h1 { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + } + .wz-module-body { + margin-top: -160px; + } + + .wz-module-header-nav { + padding-bottom: 16px; + } + + .wz-module-body-agent-info > .euiFlexGroup > .euiFlexItem { + max-width: unset !important; + } -@media only screen and (max-width: 1360px){ - .wz-module.wz-module-welcome .wz-module-body{ - padding-top: 189px !important; + .wz-module-header-agent-title .euiFlexItem { + align-items: flex-start !important; } - @media only screen and (max-width: 767px){ - .wz-module-header-agent{ - height: auto; - h1{ - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - } - .wz-module-body { - margin-top: -160px; - } - - .wz-module-header-nav { - padding-bottom: 16px; - } - - .wz-module-body-agent-info > .euiFlexGroup > .euiFlexItem { - max-width: unset!important; - } - - .wz-module-header-agent-title .euiFlexItem{ - align-items: flex-start!important; - } - .wz-agent-empty-item.euiFlexItem{ - margin-top: 0px!important; - margin-bottom:0px!important; - } + .wz-agent-empty-item.euiFlexItem { + margin-top: 0px !important; + margin-bottom: 0px !important; } + } } .wz-section-sca-euiFlexGroup { - display: flex; - justify-content: space-between; + display: flex; + justify-content: space-between; } diff --git a/plugins/main/public/controllers/management/components/management/ruleset/components/columns.tsx b/plugins/main/public/controllers/management/components/management/ruleset/components/columns.tsx index 8b0d25e718..f49f0e01d7 100644 --- a/plugins/main/public/controllers/management/components/management/ruleset/components/columns.tsx +++ b/plugins/main/public/controllers/management/components/management/ruleset/components/columns.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { EuiToolTip, EuiBadge } from '@elastic/eui'; +import { euiThemeVars } from '@osd/ui-shared-deps/theme'; import { resourceDictionary, ResourcesHandler, @@ -48,7 +49,7 @@ export default class RulesetColumns { for (const oldValue of result) { let newValue = oldValue.replace( '$(', - ``, + ``, ); newValue = newValue.replace(')', ' '); value = value.replace(oldValue, newValue); 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 f82c713c22..c1d5cdbdef 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 @@ -29,6 +29,7 @@ import { TableWzAPI } from '../../../../../../components/common/tables'; import { getErrorOrchestrator } from '../../../../../../react-services/common-services'; import { getCore } from '../../../../../../kibana-services'; import { threatHunting } from '../../../../../../utils/applications'; +import { euiThemeVars } from '@osd/ui-shared-deps/theme'; export default class WzRuleInfo extends Component { constructor(props) { @@ -105,7 +106,7 @@ export default class WzRuleInfo extends Component { for (const oldValue of result) { let newValue = oldValue.replace( '$(', - ``, + ``, ); newValue = newValue.replace(')', ' '); value = value.replace(oldValue, newValue); @@ -702,7 +703,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); } diff --git a/plugins/main/public/styles/common.scss b/plugins/main/public/styles/common.scss index b806c95086..3b693c810a 100644 --- a/plugins/main/public/styles/common.scss +++ b/plugins/main/public/styles/common.scss @@ -252,30 +252,6 @@ top: 210px !important; } -.btn-as-i { - background: none; - border: 0; - color: #006bb4; - padding: 0; - margin: 0; - font-size: 20px; - box-shadow: none !important; -} - -.btn-as-i:hover, -.btn-as-i:focus { - background: none !important; - color: #006bb4 !important; -} - -/* Custom reporting button styles */ - -.wz-report-button:hover { - background-color: #006bb4 !important; - color: #f5f5f5; - border-radius: 0; -} - .wz-report-refresh-btn { position: absolute !important; right: 0px; @@ -326,23 +302,6 @@ input[type='search'].euiFieldSearch { border: 1px solid #d9d9d9 !important; } -/* Custom input container styles */ - -.wz-input-container label { - font-weight: 700 !important; - color: rgba(0, 0, 0, 0.38) !important; -} - -.wz-input-container label.md-required:after { - color: #006bb4 !important; -} - -.wz-input-container input, -.wz-input-container input.md-input-invalid.md-input, -.wz-input-container input.ng-invalid.ng-touched { - border-color: rgba(0, 0, 0, 0.12) !important; -} - .wz-autocomplete md-autocomplete-wrap { box-shadow: none !important; } diff --git a/plugins/main/public/styles/component.scss b/plugins/main/public/styles/component.scss index 7fa8976546..b4d8f3a0ac 100644 --- a/plugins/main/public/styles/component.scss +++ b/plugins/main/public/styles/component.scss @@ -20,21 +20,10 @@ height: auto !important; } -.wz-nav-item button, .wz-no-padding { padding: 0 5px !important; } -.wz-nav-item button.md-primary { - color: rgb(0, 121, 165) !important; - background: #f5fafb !important; - border-bottom: 2px solid #006bb4; -} - -.wz-nav-item button.md-unselected { - color: rgba(0, 0, 0, 0.87) !important; -} - .wz-nav-bar md-nav-ink-bar { color: rgb(0, 121, 165) !important; background: rgb(0, 121, 165) !important; @@ -58,22 +47,6 @@ margin: 0 !important; } -/* Custom chips styles */ - -.wz-chips .md-chips { - box-shadow: none !important; - padding-bottom: 0; -} - -.wz-chip { - font-size: 12px; - color: white; - background-color: #006bb4; - height: 26px !important; - line-height: 26px !important; - margin: 0 8px 0 0 !important; -} - .sca-chart-widget { margin: 0 auto; //width:350px; diff --git a/plugins/main/public/styles/layout.scss b/plugins/main/public/styles/layout.scss index 2bf6fc5318..bcc08f7681 100644 --- a/plugins/main/public/styles/layout.scss +++ b/plugins/main/public/styles/layout.scss @@ -294,131 +294,6 @@ display: inline; } -md-dialog-actions button { - color: white !important; - transition: none !important; - background-color: rgb(0, 85, 113) !important; -} - -md-backdrop.md-opaque { - opacity: 1 !important; - background-color: rgba(255, 255, 255, 0.8); -} - -md-backdrop.md-opaque.ng-leave { - opacity: 0 !important; - transition: none !important; - transform: none !important; -} - -md-dialog.md-transition-in { - transition: 150ms ease-in !important; - transform: none !important; - animation: 350ms cubic-bezier(0.34, 1.61, 0.7, 1); -} - -md-dialog.md-transition-out { - transition: none !important; - transform: none !important; -} - -.md-dialog-container { - //padding-bottom: 10vh; - z-index: 100 !important; -} - -md-dialog .md-dialog-content { - padding: 0px !important; -} - -md-dialog { - animation: 350ms cubic-bezier(0.34, 1.61, 0.7, 1); - border: 1px solid #d9d9d9; - border-color: #c4cace; - border-top-color: #e2e5e7; - border-bottom-color: #a7b0b6; - min-width: 400px; - max-width: 768px; - padding: 15px; - box-shadow: 0 40px 64px 0 rgba(59, 79, 93, 0.1), - 0 24px 32px 0 rgba(59, 79, 93, 0.1), 0 16px 16px 0 rgba(59, 79, 93, 0.1), - 0 8px 8px 0 rgba(59, 79, 93, 0.1), 0 4px 4px 0 rgba(59, 79, 93, 0.1), - 0 2px 2px 0 rgba(59, 79, 93, 0.1) !important; -} - -.md-cancel-button { - background-color: #ffffff !important; - color: #005571 !important; -} - -.md-title { - color: #1a1a1a; - font-size: 24px; - font-weight: 600; - line-height: 2.5rem; -} - -md-dialog md-dialog-content .md-dialog-content-body { - padding-top: 15px; - margin-bottom: 45px; -} - -md-dialog .md-dialog-content { - padding: 25px 5px 35px 5px; - overflow: hidden !important; - height: auto !important; -} - -md-dialog .md-actions, -md-dialog md-dialog-actions { - border: none !important; -} - -md-dialog .md-button.md-primary:not(.md-cancel-button) { - color: #ffffff; - background-color: #006bb4 !important; - border-color: #006bb4 !important; - border-radius: 4px; -} - -md-dialog .md-button.md-primary:not(.md-cancel-button):hover { - background-color: #005472 !important; - border-color: #004c68 !important; -} - -md-dialog.modalTheme { - animation: none !important; - transition: none !important; - transform: none !important; - bottom: 0; - right: 0; - position: fixed; - width: 350px; -} - -md-dialog.modalTheme .md-button { - margin-bottom: 0; -} - -.md-dialog-body { - top: 0 !important; - width: 100vw !important; -} - -.md-dialog-body { - top: 0 !important; - width: 100vw !important; -} - -.md-dialog-body .md-scroll-mask { - display: none !important; -} - -.md-dialog-body .md-dialog-container { - height: 0 !important; - width: 0 !important; -} - .chrHeaderWrapper--navIsLocked ~ .app-wrapper .fullscreen { width: calc(100vw - 400px) !important; left: 321px !important; @@ -440,10 +315,6 @@ md-dialog.modalTheme .md-button { padding: 5%; } -.filter-bar .filter { - background-color: #0079a5 !important; -} - .columns-bar { margin-top: -17px; margin-left: -16px; @@ -512,7 +383,3 @@ md-dialog.modalTheme .md-button { font-kerning: normal !important; padding: 8px !important; } - -.kbnTableCellFilter { - cursor: pointer; -} diff --git a/plugins/main/public/styles/theme/dark/index.dark.scss b/plugins/main/public/styles/theme/dark/index.dark.scss index 4f037e9dba..0bbe58a1f2 100644 --- a/plugins/main/public/styles/theme/dark/index.dark.scss +++ b/plugins/main/public/styles/theme/dark/index.dark.scss @@ -123,21 +123,11 @@ md-content { color: #fff; } -.wz-nav-item button.md-primary { - color: #0079a5 !important; - background-color: #232635 !important; - border-bottom: 2px solid #006bb4; -} - md-nav-bar.md-default-theme .md-nav-bar, md-nav-bar .md-nav-bar { border-color: rgb(52, 55, 65); } -.wz-nav-item button.md-unselected { - color: #fff !important; -} - .sidebar-container .index-pattern { background-color: #1ba9f5 !important; color: white !important; @@ -239,10 +229,6 @@ table thead > tr { border-left: 1px dashed #343741; } -md-dialog.md-default-theme.md-content-overflow .md-actions, -md-dialog.md-content-overflow .md-actions, -md-dialog.md-default-theme.md-content-overflow md-dialog-actions, -md-dialog.md-content-overflow md-dialog-actions, md-divider.md-default-theme, md-divider { border-top-color: rgb(52, 55, 65); diff --git a/plugins/main/public/styles/typography.scss b/plugins/main/public/styles/typography.scss index 6475feaea7..8534102e97 100644 --- a/plugins/main/public/styles/typography.scss +++ b/plugins/main/public/styles/typography.scss @@ -20,13 +20,13 @@ body, button:not(.fa):not(.fa-times), textarea, input, -select{ +select { //font-size: 14px; } .wz-headline-title:not(.wz-dev-title) { - padding: 8px!important; - justify-content: start!important; + padding: 8px !important; + justify-content: start !important; font-size: 12px; } @@ -39,18 +39,6 @@ select{ color: grey !important; } -.color-f9 { - color: #ff9999; -} - -.wz-color-orange { - color: #f39c12 !important; -} - -.color-pointer { - color: #006bb4 !important; -} - .wz-line-height { line-height: 20px !important; } @@ -142,31 +130,6 @@ select{ color: rgb(0, 166, 155); } -/* Class for linkable text elements */ -.wz-text-link { - cursor: pointer !important; - color: #006bb4 !important; - - &:hover { - text-decoration: underline !important; - } -} - -.wz-text-link-add { - cursor: pointer !important; - color: #006bb4 !important; - - &:hover { - text-decoration: none !important; - } -} - -.wz-text-active { - color: rgb(0, 121, 165); - font-weight: bold; - text-decoration: underline; -} - /* Special fix for text in navbars */ .md-button { diff --git a/plugins/main/public/templates/management/management.html b/plugins/main/public/templates/management/management.html index 8bfc57911f..d0b4c3447e 100644 --- a/plugins/main/public/templates/management/management.html +++ b/plugins/main/public/templates/management/management.html @@ -21,7 +21,7 @@ ng-if="mctrl.tab === 'groups' && mctrl.currentGroup && mctrl.currentGroup.name" > {{ mctrl.tabNames[mctrl.tab] }} @@ -147,13 +147,13 @@ > Nodes {{nodesCount}} Agents {{agentsCount}} Date: Tue, 16 Apr 2024 08:55:05 -0300 Subject: [PATCH 07/18] Add JSON visualization to Vulnerability Detection inventory flyout (#6590) * Create tabbed content component * Replace flyout content with the new component * Update changelog * Rename file to meet the format specifications --- CHANGELOG.md | 2 +- .../document-view-table-and-json.tsx | 40 +++++++++++++++++++ .../dashboards/inventory/inventory.tsx | 10 ++--- 3 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 plugins/main/public/components/overview/vulnerabilities/common/components/document-view-table-and-json.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index ade5bc5d36..54beab43e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Added the ability to check if there are available updates from the UI. [#6093](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6093) [#6256](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6256) [#6328](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6328) - Added remember server address check [#5791](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5791) - Added the ssl_agent_ca configuration to the SSL Settings form [#6083](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6083) -- Added global vulnerabilities dashboards [#5896](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5896) [#6179](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6179) [#6173](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6173) [#6147](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6147) [#6231](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6231) [#6246](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6246) [#6321](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6321) [#6338](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6338) [#6356](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6356) [#6396](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6396) [#6399](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6399) [#6405](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6405) [#6410](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6410) [#6424](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6424) [#6422](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6422) [#6429](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6429) [#6448](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6448) [#6488](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6488) +- Added global vulnerabilities dashboards [#5896](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5896) [#6179](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6179) [#6173](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6173) [#6147](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6147) [#6231](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6231) [#6246](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6246) [#6321](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6321) [#6338](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6338) [#6356](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6356) [#6396](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6396) [#6399](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6399) [#6405](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6405) [#6410](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6410) [#6424](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6424) [#6422](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6422) [#6429](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6429) [#6448](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6448) [#6488](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6488) [#6590](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6590) - Added an agent selector to the IT Hygiene application [#5840](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5840) - Added query results limit when the search exceed 10000 hits [#6106](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6106) - Added a redirection button to Endpoint Summary from IT Hygiene application [#6176](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6176) diff --git a/plugins/main/public/components/overview/vulnerabilities/common/components/document-view-table-and-json.tsx b/plugins/main/public/components/overview/vulnerabilities/common/components/document-view-table-and-json.tsx new file mode 100644 index 0000000000..3ea1c82c1d --- /dev/null +++ b/plugins/main/public/components/overview/vulnerabilities/common/components/document-view-table-and-json.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { EuiFlexItem, EuiCodeBlock, EuiTabbedContent } from '@elastic/eui'; +import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; +import DocViewer from '../../doc_viewer/doc_viewer'; +import { useDocViewer } from '../../doc_viewer/use_doc_viewer'; + +export const DocumentViewTableAndJson = ({ document, indexPattern }) => { + const docViewerProps = useDocViewer({ + doc: document, + indexPattern: indexPattern as IndexPattern, + }); + + return ( + + , + }, + { + id: 'json', + name: 'JSON', + content: ( + + {JSON.stringify(document, null, 2)} + + ), + }, + ]} + /> + + ); +}; diff --git a/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx b/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx index 4d96a4710a..0ed0e71d74 100644 --- a/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx +++ b/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx @@ -9,7 +9,6 @@ import { EuiButtonIcon, EuiDataGridCellValueElementProps, EuiFlexGroup, - EuiFlexItem, EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, @@ -18,7 +17,6 @@ import { } from '@elastic/eui'; import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; import { SearchResponse } from '../../../../../../../../src/core/server'; -import DocViewer from '../../doc_viewer/doc_viewer'; import { DiscoverNoResults } from '../../common/components/no_results'; import { LoadingSpinner } from '../../common/components/loading_spinner'; import { useDataGrid } from '../../data_grid/use_data_grid'; @@ -44,6 +42,7 @@ import { compose } from 'redux'; import { withVulnerabilitiesStateDataSource } from '../../common/hocs/validate-vulnerabilities-states-index-pattern'; import { ModuleEnabledCheck } from '../../common/components/check-module-enabled'; import { DataSourceFilterManagerVulnerabilitiesStates } from '../../../../../react-services/data-sources'; +import { DocumentViewTableAndJson } from '../../common/components/document-view-table-and-json'; const InventoryVulsComponent = () => { const appConfig = useAppConfig(); @@ -241,9 +240,10 @@ const InventoryVulsComponent = () => { - - - + From bca15ab3b2e5da2f788533374753b4143131cff4 Mon Sep 17 00:00:00 2001 From: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com> Date: Wed, 17 Apr 2024 06:33:53 -0300 Subject: [PATCH 08/18] Change getHistory for syncHistoryLocations (#6591) * Change getHistory for syncHistoryLocations * Update changelog * Add comment --------- Co-authored-by: Federico Rodriguez --- CHANGELOG.md | 2 +- .../discover/build_services.ts | 17 ++++++++++++----- .../kibana-integrations/kibana-discover.js | 4 ++-- plugins/main/public/plugin.ts | 5 ----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54beab43e8..a4384ed1c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ All notable changes to the Wazuh app project will be documented in this file. ### Changed -- Moved the plugin menu to platform applications into the side menu [#5840](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5840) [#6226](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6226) [#6244](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6244) [#6176](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6176) [#6423](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6423) [#6510](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6510) +- Moved the plugin menu to platform applications into the side menu [#5840](https://github.com/wazuh/wazuh-dashboard-plugins/pull/5840) [#6226](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6226) [#6244](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6244) [#6176](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6176) [#6423](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6423) [#6510](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6510) [#6591](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6591) - Changed dashboards. [#6035](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6035) - Change the display order of tabs in all modules. [#6067](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6067) - Upgraded the `axios` dependency to `1.6.1` [#6114](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6114) diff --git a/plugins/main/public/kibana-integrations/discover/build_services.ts b/plugins/main/public/kibana-integrations/discover/build_services.ts index 9d7d4dd86b..41a93a99e3 100644 --- a/plugins/main/public/kibana-integrations/discover/build_services.ts +++ b/plugins/main/public/kibana-integrations/discover/build_services.ts @@ -40,11 +40,15 @@ import { VisualizationsStart } from 'src/plugins/visualizations/public'; import { SavedObjectOpenSearchDashboardsServices } from 'src/plugins/saved_objects/public'; //import { createSavedSearchesLoader, SavedSearch } from './saved_searches'; -import { getHistory } from './kibana_services'; +import { syncHistoryLocations } from './kibana_services'; import { OpenSearchDashboardsLegacyStart } from '../../../../../src/plugins/opensearch_dashboards_legacy/public'; import { UrlForwardingStart } from '../../../../../src/plugins/url_forwarding/public'; import { NavigationPublicPluginStart } from '../../../../../src/plugins/navigation/public'; -import { getDataPlugin, getNavigationPlugin, getVisualizationsPlugin } from '../../kibana-services'; +import { + getDataPlugin, + getNavigationPlugin, + getVisualizationsPlugin, +} from '../../kibana-services'; //import { DiscoverStartPlugins, SavedSearch } from '../../../../../src/plugins/discover/public'; export interface DiscoverServices { @@ -77,9 +81,9 @@ export async function buildServices( core: CoreStart, plugins: any, //DiscoverStartPlugins, context: PluginInitializerContext, - getEmbeddableInjector: any + getEmbeddableInjector: any, ): Promise { -/* const services: SavedObjectOpenSearchDashboardsServices = { + /* const services: SavedObjectOpenSearchDashboardsServices = { savedObjectsClient: core.savedObjects.client, indexPatterns: plugins.data.indexPatterns, search: plugins.data.search, @@ -99,7 +103,10 @@ export async function buildServices( getEmbeddableInjector, /* getSavedSearchById: async (id: string) => savedObjectService.get(id), getSavedSearchUrlById: async (id: string) => savedObjectService.urlFor(id), */ - history: getHistory, + /* Discover currently uses two history instances: + one from Opensearch Dashboards Platform and another from history package. + getHistory is replaced by the following function that is used each time the Discover application is loaded to synchronise both instances */ + history: syncHistoryLocations, indexPatterns: getDataPlugin().indexPatterns, inspector: plugins.inspector, metadata: { diff --git a/plugins/main/public/kibana-integrations/kibana-discover.js b/plugins/main/public/kibana-integrations/kibana-discover.js index b0c5404fff..cabfca9a22 100644 --- a/plugins/main/public/kibana-integrations/kibana-discover.js +++ b/plugins/main/public/kibana-integrations/kibana-discover.js @@ -204,7 +204,7 @@ function discoverController( filterManager, timefilter, toastNotifications, - history: getHistory, + history: syncHistoryLocations, uiSettings: config, visualizations, } = getServices(); @@ -218,7 +218,7 @@ function discoverController( : undefined; }; - const history = getHistory(); + const history = syncHistoryLocations(); const { appStateContainer, diff --git a/plugins/main/public/plugin.ts b/plugins/main/public/plugin.ts index 8126e4acc5..de0b53ac26 100644 --- a/plugins/main/public/plugin.ts +++ b/plugins/main/public/plugin.ts @@ -44,7 +44,6 @@ import { unregisterInterceptor, } from './services/request-handler'; import { Applications, Categories } from './utils/applications'; -import { syncHistoryLocations } from './kibana-integrations/discover/kibana_services'; import { euiPaletteColorBlind } from '@elastic/eui'; const innerAngularName = 'app/wazuh'; @@ -149,10 +148,6 @@ export class WazuhPlugin setScopedHistory(params.history); // This allows you to add the selectors to the navbar setHeaderActionMenuMounter(params.setHeaderActionMenu); - // Discover currently uses two history instances: - // one from Kibana Platform and another from history package. - // Below function is used every time Discover app is loaded to synchronize both instances - syncHistoryLocations(); // Load application bundle const { renderApp } = await import('./application'); // Get start services as specified in kibana.json From c9878a8523c9e4566948a7855e164800a4779499 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Thu, 18 Apr 2024 15:19:53 +0200 Subject: [PATCH 09/18] Bump version to 4.7.4 (#6599) --- CHANGELOG.md | 6 ++++++ plugins/main/opensearch_dashboards.json | 2 +- plugins/main/package.json | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18a038a3dd..2ac21b12aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to the Wazuh app project will be documented in this file. +## Wazuh v4.7.4 - OpenSearch Dashboards 2.8.0 - Revision 00 + +### Added + +- Support for Wazuh 4.7.4 + ## Wazuh v4.7.3 - OpenSearch Dashboards 2.8.0 - Revision 02 ### Added diff --git a/plugins/main/opensearch_dashboards.json b/plugins/main/opensearch_dashboards.json index 2b976f93f0..d5c3e5ec9f 100644 --- a/plugins/main/opensearch_dashboards.json +++ b/plugins/main/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuh", - "version": "4.7.3-02", + "version": "4.7.4-00", "opensearchDashboardsVersion": "opensearchDashboards", "configPath": [ "wazuh" diff --git a/plugins/main/package.json b/plugins/main/package.json index 0263ab867d..e4e2f55da3 100644 --- a/plugins/main/package.json +++ b/plugins/main/package.json @@ -1,7 +1,7 @@ { "name": "wazuh", - "version": "4.7.3", - "revision": "02", + "version": "4.7.4", + "revision": "00", "pluginPlatform": { "version": "2.8.0" }, From bf7fdb75f04b9850e20203ff399144e50c4f9823 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Fri, 19 Apr 2024 10:02:32 +0200 Subject: [PATCH 10/18] Bump revision to 08 beta6 (#6604) --- CHANGELOG.md | 2 +- plugins/main/opensearch_dashboards.json | 2 +- plugins/main/package.json | 2 +- plugins/wazuh-check-updates/opensearch_dashboards.json | 2 +- plugins/wazuh-check-updates/package.json | 2 +- plugins/wazuh-core/opensearch_dashboards.json | 2 +- plugins/wazuh-core/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4384ed1c6..94859602fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Wazuh app project will be documented in this file. -## Wazuh v4.8.0 - OpenSearch Dashboards 2.10.0 - Revision 07 +## Wazuh v4.8.0 - OpenSearch Dashboards 2.10.0 - Revision 08 ### Added diff --git a/plugins/main/opensearch_dashboards.json b/plugins/main/opensearch_dashboards.json index fc3b0cb9c8..1962b952bd 100644 --- a/plugins/main/opensearch_dashboards.json +++ b/plugins/main/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuh", - "version": "4.8.0-07", + "version": "4.8.0-08", "opensearchDashboardsVersion": "opensearchDashboards", "configPath": [ "wazuh" diff --git a/plugins/main/package.json b/plugins/main/package.json index dd4ad72dbc..4d5d1a8847 100644 --- a/plugins/main/package.json +++ b/plugins/main/package.json @@ -1,7 +1,7 @@ { "name": "wazuh", "version": "4.8.0", - "revision": "07", + "revision": "08", "pluginPlatform": { "version": "2.10.0" }, diff --git a/plugins/wazuh-check-updates/opensearch_dashboards.json b/plugins/wazuh-check-updates/opensearch_dashboards.json index 79f0a4f662..bcadcb5665 100644 --- a/plugins/wazuh-check-updates/opensearch_dashboards.json +++ b/plugins/wazuh-check-updates/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuhCheckUpdates", - "version": "4.8.0-07", + "version": "4.8.0-08", "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, diff --git a/plugins/wazuh-check-updates/package.json b/plugins/wazuh-check-updates/package.json index e816e2a255..ae6c745a4c 100644 --- a/plugins/wazuh-check-updates/package.json +++ b/plugins/wazuh-check-updates/package.json @@ -1,7 +1,7 @@ { "name": "wazuh-check-updates", "version": "4.8.0", - "revision": "07", + "revision": "08", "pluginPlatform": { "version": "2.10.0" }, diff --git a/plugins/wazuh-core/opensearch_dashboards.json b/plugins/wazuh-core/opensearch_dashboards.json index f249d45f01..044db7e6d3 100644 --- a/plugins/wazuh-core/opensearch_dashboards.json +++ b/plugins/wazuh-core/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuhCore", - "version": "4.8.0-07", + "version": "4.8.0-08", "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, diff --git a/plugins/wazuh-core/package.json b/plugins/wazuh-core/package.json index 5df721e9ad..ce4f841ed5 100644 --- a/plugins/wazuh-core/package.json +++ b/plugins/wazuh-core/package.json @@ -1,7 +1,7 @@ { "name": "wazuh-core", "version": "4.8.0", - "revision": "07", + "revision": "08", "pluginPlatform": { "version": "2.10.0" }, From a46cc8cb0119d0f9a04cf5acbc96f3d5bc802f67 Mon Sep 17 00:00:00 2001 From: Antonio <34042064+Desvelao@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:49:23 +0200 Subject: [PATCH 11/18] Bump revision to 01 for 4.7.4 RC1 (#6611) bump: bump revision to 01 for 4.7.4 --- CHANGELOG.md | 2 +- plugins/main/opensearch_dashboards.json | 2 +- plugins/main/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac21b12aa..01d452c0dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Wazuh app project will be documented in this file. -## Wazuh v4.7.4 - OpenSearch Dashboards 2.8.0 - Revision 00 +## Wazuh v4.7.4 - OpenSearch Dashboards 2.8.0 - Revision 01 ### Added diff --git a/plugins/main/opensearch_dashboards.json b/plugins/main/opensearch_dashboards.json index d5c3e5ec9f..bb9b9b28b6 100644 --- a/plugins/main/opensearch_dashboards.json +++ b/plugins/main/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuh", - "version": "4.7.4-00", + "version": "4.7.4-01", "opensearchDashboardsVersion": "opensearchDashboards", "configPath": [ "wazuh" diff --git a/plugins/main/package.json b/plugins/main/package.json index e4e2f55da3..3c67a5ba45 100644 --- a/plugins/main/package.json +++ b/plugins/main/package.json @@ -1,7 +1,7 @@ { "name": "wazuh", "version": "4.7.4", - "revision": "00", + "revision": "01", "pluginPlatform": { "version": "2.8.0" }, From a297910aad1aff7db79ab930cb6b5ea7935e67ac Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Wed, 24 Apr 2024 17:30:03 +0200 Subject: [PATCH 12/18] Add only active agents guard for configuration (#6617) * Handle log collector and integrity monitoring falsy values * Add changelog * Remove initial assignment * Add not connected agent guard to configuration view --- CHANGELOG.md | 1 + .../configuration/configuration-switch.js | 6 ++-- .../integrity-monitoring.js | 34 +++++++++---------- .../log-collection/log-collection.js | 6 ++-- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94859602fb..5cab59de24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Fixed minor style issues [#6484](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6484) [#6489](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6489) - Fixed "View alerts of this Rule" link [#6553](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6553) - Fixed minor color styles [#6587](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6587) +- Fixed disconnected agent configuration error [#6587](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6617) ### Removed diff --git a/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js b/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js index 9a59dfa8d4..baed3e74ce 100644 --- a/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js +++ b/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js @@ -82,7 +82,7 @@ import { UI_ERROR_SEVERITIES } from '../../../../../react-services/error-orchest import { getErrorOrchestrator } from '../../../../../react-services/common-services'; import { WzConfigurationOffice365 } from './office365/office365'; import { getCore } from '../../../../../kibana-services'; -import { PromptAgentNeverConnected } from '../../../../../components/agents/prompts'; +import { PromptNoActiveAgentWithoutSelect } from '../../../../../components/agents/prompts'; import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; import { endpointGroups } from '../../../../../utils/applications'; @@ -501,8 +501,8 @@ export default compose( ], ]), //TODO: this need cluster:read permission but manager/cluster is managed in WzConfigurationSwitch component withRenderIfOrWrapped( - props => props.agent.status === API_NAME_AGENT_STATUS.NEVER_CONNECTED, - PromptAgentNeverConnected, + props => props.agent.status !== API_NAME_AGENT_STATUS.ACTIVE, + PromptNoActiveAgentWithoutSelect, ), connect(mapStateToProps, mapDispatchToProps), )(WzConfigurationSwitch); diff --git a/plugins/main/public/controllers/management/components/management/configuration/integrity-monitoring/integrity-monitoring.js b/plugins/main/public/controllers/management/components/management/configuration/integrity-monitoring/integrity-monitoring.js index 5450848421..45c18c2d59 100644 --- a/plugins/main/public/controllers/management/components/management/configuration/integrity-monitoring/integrity-monitoring.js +++ b/plugins/main/public/controllers/management/components/management/configuration/integrity-monitoring/integrity-monitoring.js @@ -16,7 +16,7 @@ import withWzConfig from '../util-hocs/wz-config'; import WzNoConfig from '../util-components/no-config'; import { isString } from '../utils/utils'; import WzTabSelector, { - WzTabSelectorTab + WzTabSelectorTab, } from '../util-components/tab-selector'; import helpLinks from './help-links'; @@ -34,15 +34,12 @@ class WzConfigurationIntegrityMonitoring extends Component { super(props); } componentDidMount() { - this.props.currentConfig['syscheck-syscheck'].syscheck.disabled = 'no'; this.props.updateBadge(this.badgeEnabled()); } badgeEnabled() { return ( - this.props.currentConfig['syscheck-syscheck'] && - this.props.currentConfig['syscheck-syscheck'].syscheck && - this.props.currentConfig['syscheck-syscheck'].syscheck.disabled && - this.props.currentConfig['syscheck-syscheck'].syscheck.disabled === 'no' + this.props.currentConfig?.['syscheck-syscheck']?.syscheck?.disabled === + 'no' ); } @@ -61,43 +58,44 @@ class WzConfigurationIntegrityMonitoring extends Component { {currentConfig['syscheck-syscheck'] && !isString(currentConfig['syscheck-syscheck']) && !currentConfig['syscheck-syscheck'].syscheck && ( - + )} {currentConfig['syscheck-syscheck'] && !isString(currentConfig['syscheck-syscheck']) && currentConfig['syscheck-syscheck'].syscheck && ( - + - + - + - + {agentPlatform !== 'windows' && ( - + )} - + - + - { agentPlatform === 'windows' && ( - - + {agentPlatform === 'windows' && ( + + )} - )} diff --git a/plugins/main/public/controllers/management/components/management/configuration/log-collection/log-collection.js b/plugins/main/public/controllers/management/components/management/configuration/log-collection/log-collection.js index 4cdb32b286..d7d6e0220a 100644 --- a/plugins/main/public/controllers/management/components/management/configuration/log-collection/log-collection.js +++ b/plugins/main/public/controllers/management/components/management/configuration/log-collection/log-collection.js @@ -67,7 +67,7 @@ class WzConfigurationLogCollection extends Component { condition: currentConfig[LOGCOLLECTOR_LOCALFILE_PROP] && currentConfig[LOGCOLLECTOR_LOCALFILE_PROP][LOCALFILE_LOGS_PROP] - .length > 0, + ?.length > 0, component: ( 0, + ]?.length > 0, component: ( 0, + ?.length > 0, component: ( Date: Thu, 25 Apr 2024 10:07:35 +0200 Subject: [PATCH 13/18] Bump 4.7.4 revision 02 (#6620) bump: 4.7.4 revision 02 --- CHANGELOG.md | 2 +- plugins/main/opensearch_dashboards.json | 2 +- plugins/main/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01d452c0dc..3294344c4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Wazuh app project will be documented in this file. -## Wazuh v4.7.4 - OpenSearch Dashboards 2.8.0 - Revision 01 +## Wazuh v4.7.4 - OpenSearch Dashboards 2.8.0 - Revision 02 ### Added diff --git a/plugins/main/opensearch_dashboards.json b/plugins/main/opensearch_dashboards.json index bb9b9b28b6..402824ad4d 100644 --- a/plugins/main/opensearch_dashboards.json +++ b/plugins/main/opensearch_dashboards.json @@ -1,6 +1,6 @@ { "id": "wazuh", - "version": "4.7.4-01", + "version": "4.7.4-02", "opensearchDashboardsVersion": "opensearchDashboards", "configPath": [ "wazuh" diff --git a/plugins/main/package.json b/plugins/main/package.json index 3c67a5ba45..3de3879422 100644 --- a/plugins/main/package.json +++ b/plugins/main/package.json @@ -1,7 +1,7 @@ { "name": "wazuh", "version": "4.7.4", - "revision": "01", + "revision": "02", "pluginPlatform": { "version": "2.8.0" }, From 98c64df780a2662229a597d08ae3b0917fbd65df Mon Sep 17 00:00:00 2001 From: Antonio <34042064+Desvelao@users.noreply.github.com> Date: Fri, 26 Apr 2024 19:18:46 +0200 Subject: [PATCH 14/18] Remove management AngularJS controllers (#6555) * feat: remove AngularJS controller of Management - Remove AngularJS controller of Management - Remove deprecated listeners - Remove deprecated methods - Remove logtestProps from some components that were passed from the AngularJS controller - Move some methods to ReactJS - Create router to manage the view to display - Change button to render the Ruleset Test or Decoders Test to use a button that opens a flyout. - Remove the flyout components in the Logtest component * changelog: add entry * feat(logtest): remove showClose prop in favor to onFlyout * remove(logtest): unused components * feat: add comment * fix(logtest): minor fixes --------- Co-authored-by: Federico Rodriguez --- CHANGELOG.md | 1 + .../management/common/file-editor.tsx | 27 +- .../configuration/utils/wz-fetch.js | 2 - .../management/decoders/main-decoders.tsx | 48 +- .../components/management/management-main.js | 57 +- .../management/ruleset/main-ruleset.tsx | 49 +- .../public/controllers/management/index.js | 3 - .../controllers/management/management.js | 502 ------------------ .../wz-logtest/components/logtest.tsx | 201 +++---- .../main/public/services/config-handler.js | 21 +- .../templates/management/management.html | 50 +- 11 files changed, 236 insertions(+), 725 deletions(-) delete mode 100644 plugins/main/public/controllers/management/management.js diff --git a/CHANGELOG.md b/CHANGELOG.md index eb12982b32..e1d9ebe559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Move AngularJS controller and view for manage groups to ReactJS [#6543](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6543) - Move AngularJS controllers and views of Tools and Dev Tools to ReactJS [#6544](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6544) - Move the AngularJS controller and template of blank screen to ReactJS component [#6538](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6538) +- Move AngularJS controller for management to ReactJS component [#6555](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6555) - Moved the registry data to in-memory cache [#6481](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6481) - Enhance the validation for `enrollment.dns` on App Settings application [#6573](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6573) - Remove AngularJS controller for manage groups [#6543](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6543) diff --git a/plugins/main/public/controllers/management/components/management/common/file-editor.tsx b/plugins/main/public/controllers/management/components/management/common/file-editor.tsx index f38df59189..39ba0dd75b 100644 --- a/plugins/main/public/controllers/management/components/management/common/file-editor.tsx +++ b/plugins/main/public/controllers/management/components/management/common/file-editor.tsx @@ -48,6 +48,8 @@ import _ from 'lodash'; import { UI_ERROR_SEVERITIES } from '../../../../../react-services/error-orchestrator/types'; import { UI_LOGGER_LEVELS } from '../../../../../../common/constants'; import { getErrorOrchestrator } from '../../../../../react-services/common-services'; +import { WzButtonPermissionsOpenFlyout } from '../../../../../components/common/buttons/flyout'; +import { Logtest } from '../../../../../directives/wz-logtest/components/logtest'; class WzFileEditor extends Component { _isMounted = false; @@ -236,22 +238,23 @@ class WzFileEditor extends Component { const xmlError = validateXML(content); - const onClickOpenLogtest = () => { - this.props.logtestProps.openCloseFlyout(); - }; - const buildLogtestButton = () => { return ( - ( + + )} + buttonProps={{ + buttonType: 'empty', + permissions: [{ action: 'logtest:run', resource: `*:*:*` }], + color: 'primary', + iconType: 'documentEdit', + style: { margin: '0px 8px', cursor: 'pointer' }, + }} > {isRules} - + ); }; diff --git a/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js b/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js index 3958f81cde..06d0cb45f5 100644 --- a/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js +++ b/plugins/main/public/controllers/management/components/management/configuration/utils/wz-fetch.js @@ -347,11 +347,9 @@ export const restartCluster = async () => { const str = validationError.detail; throw new Error(str); } - // this.performClusterRestart(); // TODO: convert AngularJS to React await WzRequest.apiReq('PUT', `/cluster/restart`, { delay: 15000, }); - // this.$rootScope.$broadcast('removeRestarting', {}); TODO: isRestarting: false? return { data: { data: 'Restarting cluster', diff --git a/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx b/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx index 47f48f3152..57ff2f39c6 100644 --- a/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx +++ b/plugins/main/public/controllers/management/components/management/decoders/main-decoders.tsx @@ -16,8 +16,7 @@ import WzDecodersOverview from './views/decoders-overview'; import WzFileEditor from '../common/file-editor'; import { SECTION_DECODERS_SECTION } from '../common/constants'; -export default function WzDecoder({ logtestProps }) { - +export default function WzDecoder() { const [fileContent, setFileContent] = useState(false); const [addingFile, setAddingFile] = useState(false); const [showingFiles, setShowingFiles] = useState(false); @@ -25,29 +24,34 @@ export default function WzDecoder({ logtestProps }) { const cleanEditState = () => { setFileContent(false); setAddingFile(false); - } + }; return ( - { - ((fileContent || addingFile) && ( - { setFileContent(fileContent) }} - cleanEditState={() => cleanEditState()} - /> - )) || ( - { setFileContent(fileContent) }} - updateAddingFile={(addingFile) => { setAddingFile(addingFile) }} - setShowingFiles={() => { setShowingFiles(!showingFiles) }} - showingFiles={showingFiles} - /> - ) - } + {((fileContent || addingFile) && ( + { + setFileContent(fileContent); + }} + cleanEditState={() => cleanEditState()} + /> + )) || ( + { + setFileContent(fileContent); + }} + updateAddingFile={addingFile => { + setAddingFile(addingFile); + }} + setShowingFiles={() => { + setShowingFiles(!showingFiles); + }} + showingFiles={showingFiles} + /> + )} ); } diff --git a/plugins/main/public/controllers/management/components/management/management-main.js b/plugins/main/public/controllers/management/components/management/management-main.js index 573b88c8c2..45d0a127ab 100644 --- a/plugins/main/public/controllers/management/components/management/management-main.js +++ b/plugins/main/public/controllers/management/components/management/management-main.js @@ -27,13 +27,17 @@ import { SECTION_DECODERS_SECTION, SECTION_RULES_SECTION, } from './common/constants'; +import { getAngularModule } from '../../../../kibana-services'; +import { + withGuardAsync, + withReduxProvider, +} from '../../../../components/common/hocs'; +import { compose } from 'redux'; import { ClusterOverview } from './cluster/cluster-overview'; class WzManagementMain extends Component { constructor(props) { super(props); - this.state = {}; - this.store = store; } render() { @@ -47,20 +51,51 @@ class WzManagementMain extends Component { (section === 'statistics' && ) || (section === 'logs' && ) || (section === 'configuration' && ( - - )) || - (section === SECTION_DECODERS_SECTION && ( - - )) || - (section === SECTION_CDBLIST_SECTION && ( - + )) || + (section === SECTION_DECODERS_SECTION && ) || + (section === SECTION_CDBLIST_SECTION && ) || (['ruleset', SECTION_RULES_SECTION].includes(section) && ( - + ))} ); } } -export default WzManagementMain; +const availableViews = [ + 'groups', + 'status', + 'reporting', + 'statistics', + 'logs', + 'configuration', + 'decoders', + 'lists', + 'ruleset', + 'rules', + 'monitoring', +]; + +export const ManagementRouter = compose( + withReduxProvider, + withGuardAsync( + () => { + // This uses AngularJS to get the tab query parameter + const section = getAngularModule() + .$injector.get('$location') + .search().tab; + if (availableViews.includes(section)) { + return { ok: false, data: { section } }; + } + return { ok: true, data: { section } }; + }, + () => null, + ), +)(({ section }) => ); + +export default ManagementRouter; diff --git a/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx b/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx index 770e383211..e8fe5da73a 100644 --- a/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx +++ b/plugins/main/public/controllers/management/components/management/ruleset/main-ruleset.tsx @@ -15,9 +15,7 @@ import WzRulesetOverview from './views/ruleset-overview'; import WzFileEditor from '../common/file-editor'; import { SECTION_RULES_SECTION } from '../common/constants'; - -export default function WzRuleset({ logtestProps }) { - +export default function WzRuleset() { const [fileContent, setFileContent] = useState(false); const [addingFile, setAddingFile] = useState(false); const [showingFiles, setShowingFiles] = useState(false); @@ -25,29 +23,34 @@ export default function WzRuleset({ logtestProps }) { const cleanEditState = () => { setFileContent(false); setAddingFile(false); - } + }; return ( - { - ((fileContent || addingFile) && ( - { setFileContent(fileContent) }} - cleanEditState={() => cleanEditState()} - /> - )) || ( - { setFileContent(fileContent) }} - updateAddingFile={(addingFile) => { setAddingFile(addingFile) }} - setShowingFiles={() => { setShowingFiles(!showingFiles) }} - showingFiles={showingFiles} - /> - ) - } + {((fileContent || addingFile) && ( + { + setFileContent(fileContent); + }} + cleanEditState={() => cleanEditState()} + /> + )) || ( + { + setFileContent(fileContent); + }} + updateAddingFile={addingFile => { + setAddingFile(addingFile); + }} + setShowingFiles={() => { + setShowingFiles(!showingFiles); + }} + showingFiles={showingFiles} + /> + )} ); } diff --git a/plugins/main/public/controllers/management/index.js b/plugins/main/public/controllers/management/index.js index 79281a2010..f142dd6b2f 100644 --- a/plugins/main/public/controllers/management/index.js +++ b/plugins/main/public/controllers/management/index.js @@ -9,8 +9,6 @@ * * Find more information about this on the LICENSE file. */ - -import { ManagementController } from './management'; import WzManagement from './components/management/management-provider'; import WzManagementConfiguration from './components/management/configuration/configuration-main'; import { getAngularModule } from '../../kibana-services'; @@ -21,6 +19,5 @@ WzManagement.displayName = 'WzManagement'; WzManagementConfiguration.displayName = 'WzManagementConfiguration'; app - .controller('managementController', ManagementController) .value('WzManagement', WzManagement) .value('WzManagementConfiguration', WzManagementConfiguration); diff --git a/plugins/main/public/controllers/management/management.js b/plugins/main/public/controllers/management/management.js deleted file mode 100644 index 5fcbe60d69..0000000000 --- a/plugins/main/public/controllers/management/management.js +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Wazuh app - Management controller - * Copyright (C) 2015-2022 Wazuh, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Find more information about this on the LICENSE file. - */ -import { TabNames } from '../../utils/tab-names'; -import { AppState } from '../../react-services/app-state'; -import { WazuhConfig } from '../../react-services/wazuh-config'; -import { WzRequest } from '../../react-services/wz-request'; -import { ErrorHandler } from '../../react-services/error-handler'; -import { ShareAgent } from '../../factories/share-agent'; -import { - ResourcesHandler, - ResourcesConstants -} from './components/management/common/resources-handler'; - -import { UI_ERROR_SEVERITIES } from '../../react-services/error-orchestrator/types'; -import { UI_LOGGER_LEVELS } from '../../../common/constants'; -import { getErrorOrchestrator } from '../../react-services/common-services'; - -export class ManagementController { - /** - * Class constructor - * @param {*} $scope - * @param {*} $location - */ - constructor($scope, $rootScope, $location, configHandler, errorHandler, $interval) { - this.$scope = $scope; - this.$rootScope = $rootScope; - this.$location = $location; - this.shareAgent = new ShareAgent(); - this.wazuhConfig = new WazuhConfig(); - this.configHandler = configHandler; - this.errorHandler = errorHandler; - this.$interval = $interval; - this.tab = 'welcome'; - this.globalConfigTab = 'overview'; - this.tabNames = TabNames; - this.wazuhManagementTabs = ['ruleset', 'groups', 'configuration']; - this.statusReportsTabs = ['status', 'logs', 'reporting', 'monitoring']; - this.currentGroup = false; - this.logtestOpened = false; - this.uploadOpened = false; - this.rulesetTab = ResourcesConstants.RULES; - - this.$scope.$on('setCurrentGroup', (ev, params) => { - this.currentGroup = (params || {}).currentGroup || false; - }); - - this.$scope.$on('removeCurrentGroup', () => { - this.currentGroup = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentGroup', null); - }); - - this.$scope.$on('setCurrentRule', (ev, params) => { - this.setCurrentRule(params); - }); - - this.$scope.$on('removeCurrentRule', () => { - this.currentRule = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentRule', null); - }); - - this.$scope.$on('setCurrentDecoder', (ev, params) => { - this.currentDecoder = (params || {}).currentDecoder || false; - this.$location.search('currentDecoder', true); - AppState.setNavigation({ status: true }); - }); - - this.$scope.$on('removeCurrentDecoder', () => { - this.currentDecoder = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentDecoder', null); - }); - - this.$scope.$on('setCurrentList', (ev, params) => { - this.currentList = (params || {}).currentList || false; - this.$location.search('currentList', true); - AppState.setNavigation({ status: true }); - this.$scope.$applyAsync(); - }); - - this.$scope.$on('removeCurrentList', () => { - this.currentList = false; - AppState.setNavigation({ status: true }); - this.$location.search('currentList', null); - }); - - this.$scope.$on('setCurrentConfiguration', (ev, params) => { - this.currentConfiguration = (params || {}).currentConfiguration || false; - }); - - this.$scope.$on('removeCurrentConfiguration', () => { - this.currentConfiguration = false; - }); - - this.$scope.$on('viewFileOnly', (ev, params) => { - $scope.$broadcast('viewFileOnlyTable', { - file: params.item, - path: params.path, - }); - }); - - this.$rootScope.$on('setRestarting', () => { - if (this.clusterInfo.status === 'enabled') { - this.blockEditioncounter = 0; - this.blockEdition = true; - this.$interval( - () => { - this.blockEditioncounter++; - if (this.blockEditioncounter == 100) { - this.blockEdition = false; - this.isRestarting = false; - this.$scope.$applyAsync(); - } - }, - 333, - 100 - ); - } - this.isRestarting = true; - this.$scope.$applyAsync(); - }); - - this.$rootScope.$on('removeBlockEdition', () => { - this.blockEdition = false; - this.isRestarting = false; - this.$scope.$applyAsync(); - }); - - this.$scope.$on('removeRestarting', () => { - this.isRestarting = false; - this.$scope.$applyAsync(); - }); - - this.$rootScope.$on('performRestart', (ev) => { - ev.stopPropagation(); - this.clusterInfo.status === 'enabled' ? this.restartCluster() : this.restartManager(); - }); - - this.$rootScope.timeoutIsReady; - this.$rootScope.$watch('resultState', () => { - if (this.$rootScope.timeoutIsReady) { - clearTimeout(this.$rootScope.timeoutIsReady); - } - if (this.$rootScope.resultState === 'ready') { - this.$scope.isReady = true; - } else { - this.$rootScope.timeoutIsReady = setTimeout(() => (this.$scope.isReady = false), 1000); - } - }); - - this.welcomeCardsProps = { - switchTab: (tab, setNav) => this.switchTab(tab, setNav), - }; - - this.managementTabsProps = { - clickAction: (tab) => this.switchTab(tab, true), - selectedTab: this.tab, - tabs: [ - { id: 'status', name: 'Status' }, - { id: 'logs', name: 'Logs' }, - { id: 'monitoring', name: 'Cluster' }, - { id: 'reporting', name: 'Reporting' }, - ], - }; - - this.logtestProps = { - clickAction: (log) => log, - openCloseFlyout: () => this.openCloseFlyout(), - showClose: true, - onFlyout: true, - }; - - this.managementProps = { - switchTab: (section) => this.switchTab(section, true), - section: '', - groupsProps: {}, - configurationProps: { - agent: { - id: '000', - }, // TODO: get dynamically the agent? - updateWazuhNotReadyYet: (status) => { - this.$rootScope.wazuhNotReadyYet = status; - this.$scope.$applyAsync(); - }, - wazuhNotReadyYet: () => this.$rootScope.wazuhNotReadyYet, - }, - logtestProps: this.logtestProps, - }; - } - - /** - * When controller loads - */ - $onInit() { - try { - this.clusterInfo = AppState.getClusterInfo(); - - if (this.shareAgent.getAgent() && this.shareAgent.getSelectedGroup()) { - this.tab = 'groups'; - this.switchTab(this.tab); - return; - } - - const location = this.$location.search(); - - if (location && location.tab) { - this.tab = location.tab; - this.switchTab(this.tab); - } - - this.uploadFilesProps = { - msg: this.$scope.mctrl.rulesetTab, - path: `etc/${this.$scope.mctrl.rulesetTab}`, - upload: (files) => this.uploadFiles(files, this.$scope.mctrl.rulesetTab), - }; - } catch (error) { - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.$onInit`, - error: { - error: error, - message: error?.message || '', - title: 'Error restarting cluster', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } - - /** - * This check if given array of items contais a single given item - * @param {Object} item - * @param {Array} array - */ - inArray(item, array) { - return item && Array.isArray(array) && array.includes(item); - } - - async restartManager() { - try { - if (this.isRestarting) return; - this.isRestarting = true; - await this.configHandler.restartManager(); - this.isRestarting = false; - this.$scope.$applyAsync(); - ErrorHandler.info('Restarting manager.'); - } catch (error) { - this.isRestarting = false; - this.$scope.$applyAsync(); - - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.restartManager`, - error: { - error: error, - message: error?.message || '', - title: 'Error restarting manager', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } - - async restartCluster() { - try { - if (this.isRestarting) return; - this.isRestarting = true; - await this.configHandler.restartCluster(); - this.isRestarting = false; - this.$scope.$applyAsync(); - ErrorHandler.info('Restarting cluster, it will take up to 30 seconds.'); - } catch (error) { - this.isRestarting = false; - this.$scope.$applyAsync(); - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.restartCluster`, - error: { - error: error, - message: error?.message || '', - title: 'Error restarting cluster', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } - - setConfigTab(tab, nav = false) { - this.globalConfigTab = tab; - if (nav) { - AppState.setNavigation({ status: true }); - } else { - this.editionTab = tab; - } - this.$location.search('configSubTab', null); - this.$location.search('editSubTab', tab); - this.$scope.$broadcast('configurationIsReloaded', { - globalConfigTab: this.globalConfigTab, - reloadConfigSubTab: true, - }); - } - - setCurrentRule(params) { - this.currentRule = (params || {}).currentRule || false; - this.$location.search('currentRule', true); - AppState.setNavigation({ status: true }); - } - - /** - * This switch to a selected tab - * @param {String} tab - */ - switchTab(tab, setNav = false) { - this.editTab = ''; - if (setNav) { - AppState.setNavigation({ status: true }); - } else { - if (this.$location.search().editSubTab) { - this.editTab = this.$location.search().editSubTab; - } - } - this.$location.search('editSubTab', null); - this.tab = tab; - - if (this.tab === 'groups') { - this.$scope.$broadcast('groupsIsReloaded'); - } - if (this.tab !== 'groups') { - this.currentGroup = false; - this.$location.search('currentGroup', null); - } - if (this.tab === 'configuration' && !this.editTab) { - this.globalConfigTab = 'overview'; - this.currentConfiguration = false; - this.$scope.$broadcast('configurationIsReloaded'); - } else if (this.tab === 'configuration' && this.editTab) { - this.setConfigTab(this.editTab); - } else { - this.$location.search('configSubTab', null); - } - if (this.tab === 'ruleset') { - this.$scope.$broadcast('rulesetIsReloaded'); - this.globalRuleSet = 'ruleset'; - this.globalRulesetTab = this.rulesetTab; - } else { - this.globalRuleSet = false; - this.globalRulesetTab = false; - this.currentRule = false; - this.currentDecoder = false; - this.currentList = false; - this.managementTabsProps.selectedTab = this.tab; - } - this.managementProps.section = this.tab === 'ruleset' ? this.rulesetTab : this.tab; - this.$location.search('tab', this.tab); - } - - /** - * This set the rules tab - * @param {String} tab - */ - setRulesTab(tab, flag) { - this.openedFileDirect = false; - this.rulesetTab = tab; - this.globalRulesetTab = this.rulesetTab; - this.managingFiles = false; - //this.refreshUploadFileProps(); - if (!flag) { - this.breadCrumbBack(); - } - } - - switchFilesSubTab(flag, showFile) { - this.managingFiles = flag || true; - if (showFile) { - this.showFile = showFile; - this.$scope.$broadcast('editFromTable'); - } else if (!this.openedFileDirect) { - this.$scope.$broadcast('closeRulesetFile'); - } - } - - breadCrumbBack(goRoot = false) { - if (this.currentRule) { - this.$scope.$broadcast('closeRuleView'); - this.$scope.$broadcast('closeRulesetFile'); - this.$scope.$emit('removeCurrentRule'); - } - if (this.currentDecoder) { - this.$scope.$broadcast('closeDecoderView'); - this.$scope.$broadcast('closeRulesetFile'); - this.$scope.$emit('removeCurrentDecoder'); - } - if (this.currentList) { - this.$scope.$broadcast('closeListView'); - } - if (goRoot) { - this.switchTab('ruleset', true); - this.setRulesTab('rules'); - } - this.$scope.$broadcast('closeRulesetFile'); - this.$scope.$applyAsync(); - } - - changeNode(node) { - this.selectedNode = node; - this.$scope.$broadcast('configNodeChanged'); - this.$scope.$applyAsync(); - } - - openCloseFlyout() { - this.logtestOpened = !this.logtestOpened; - this.logtestProps.isRuleset = this.tab; - this.$scope.$applyAsync(); - } - - newFile() { - this.openedFileDirect = true; - this.switchFilesSubTab(); - this.$scope.$applyAsync(); - this.$scope.$broadcast('addNewFile', { type: this.globalRulesetTab }); - } - - openUploadFile() { - this.uploadOpened = !this.uploadOpened; - this.$scope.$applyAsync(); - } - - refreshUploadFileProps() { - this.uploadFilesProps = { - msg: this.rulesetTab, - path: `etc/${this.rulesetTab}`, - upload: (files) => this.uploadFiles(files, this.rulesetTab), - }; - } - - /** - * Uploads the filess - * @param {Array} files - * @param {String} path - */ - async uploadFiles(files, resource) { - try { - this.errors = false; - this.results = []; - const resourcesHandler = new ResourcesHandler(resource); - - for (let idx in files) { - const { file, content } = files[idx]; - try { - await resourcesHandler.updateFile(file, content, true); // True does not overwrite the file - this.results.push({ - index: idx, - uploaded: true, - file: file, - error: 0, - }); - } catch (error) { - this.errors = true; - this.results.push({ - index: idx, - uploaded: false, - file: file, - error: error, - }); - } - } - if (this.errors) throw this.results; - ErrorHandler.info('Upload successful'); - } catch (error) { - if (Array.isArray(error) && error.length) throw error; - - const errorOptions = { - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - context: `${ManagementController.name}.uploadFiles`, - error: { - error: error, - message: error?.message || '', - title: 'Files cannot be loaded', - }, - }; - - getErrorOrchestrator().handleError(errorOptions); - } - } -} diff --git a/plugins/main/public/directives/wz-logtest/components/logtest.tsx b/plugins/main/public/directives/wz-logtest/components/logtest.tsx index eb376f1bbb..f6a5eec19d 100644 --- a/plugins/main/public/directives/wz-logtest/components/logtest.tsx +++ b/plugins/main/public/directives/wz-logtest/components/logtest.tsx @@ -16,16 +16,11 @@ import { EuiCodeBlock, EuiFlexGroup, EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutHeader, - EuiOverlayMask, EuiPage, EuiPanel, EuiSpacer, EuiTextArea, EuiTitle, - EuiOutsideClickDetector, } from '@elastic/eui'; import { WzRequest } from '../../../react-services'; import { @@ -45,29 +40,27 @@ import { } from '../../../react-services/error-orchestrator/types'; import { UI_LOGGER_LEVELS } from '../../../../common/constants'; import { getErrorOrchestrator } from '../../../react-services/common-services'; -import { WzFlyout } from '../../../components/common/flyouts'; import _ from 'lodash'; type LogstestProps = { - openCloseFlyout: () => {}; - showClose: boolean; onFlyout: boolean; - isRuleset: string; }; export const Logtest = compose( withErrorBoundary, withReduxProvider, - withUserAuthorizationPrompt([{ action: 'logtest:run', resource: `*:*:*` }]) + withUserAuthorizationPrompt([{ action: 'logtest:run', resource: '*:*:*' }]), )((props: LogstestProps) => { const [events, setEvents] = useState([]); const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState(''); const dispatch = useDispatch(); - const sessionToken = useSelector((state) => state.appStateReducers.logtestToken); + const sessionToken = useSelector( + state => state.appStateReducers.logtestToken, + ); - const onChange = (e) => { - setEvents(e.target.value.split('\n').filter((item) => item)); + const onChange = e => { + setEvents(e.target.value.split('\n').filter(item => item)); }; // Format the result of the Wazuh API response to an output similar one to the `wazuh-logtest` utility @@ -75,30 +68,39 @@ export const Logtest = compose( // How to the `wazuh-logtest` utility logs the output: // https://github.com/wazuh/wazuh/blob/master/framework/scripts/wazuh-logtest.py#L359-L397 - const logging = []; - + const showFieldInfo = (item, path, label = '') => { - _.has(item, path) && logging.push( - `\t${label || path}: '${Array.isArray(_.get(item, path)) - ? JSON.stringify(_.get(item, path)) - : _.get(item, path)}'` + _.has(item, path) && + logging.push( + `\t${label || path}: '${ + Array.isArray(_.get(item, path)) + ? JSON.stringify(_.get(item, path)) + : _.get(item, path) + }'`, ); }; const showPhaseInfo = (item, showFirst = [], prefix = '') => { - showFirst && showFirst.forEach(field => { - showFieldInfo(item, field, prefix+field); - _.unset(item, field); - }); - typeof item === 'object' && Object.keys(item).sort().forEach((field) => { - if(typeof item[field] === 'object' && !Array.isArray(item[field])){ - showPhaseInfo(item[field],[], prefix + field + '.'); - }else{ - showFieldInfo(item, field, prefix+field); - }; - }); - } + showFirst && + showFirst.forEach(field => { + showFieldInfo(item, field, prefix + field); + _.unset(item, field); + }); + typeof item === 'object' && + Object.keys(item) + .sort() + .forEach(field => { + if ( + typeof item[field] === 'object' && + !Array.isArray(item[field]) + ) { + showPhaseInfo(item[field], [], prefix + field + '.'); + } else { + showFieldInfo(item, field, prefix + field); + } + }); + }; // Output messages if (messages) { @@ -110,25 +112,29 @@ export const Logtest = compose( // Pre-decoding phase logging.push('**Phase 1: Completed pre-decoding.'); // Check in case rule has no_full_log attribute - if(result.full_log){ + if (result.full_log) { showFieldInfo(result, 'full_log', 'full event'); - }; + } - if(result.predecoder){ - showPhaseInfo(result.predecoder, ['timestamp', 'hostname', 'program_name']); + if (result.predecoder) { + showPhaseInfo(result.predecoder, [ + 'timestamp', + 'hostname', + 'program_name', + ]); } // Decoding phase logging.push(''); logging.push('**Phase 2: Completed decoding.'); - if(result.decoder && Object.keys(result.decoder).length > 0){ + if (result.decoder && Object.keys(result.decoder).length > 0) { showPhaseInfo(result.decoder, ['name', 'parent']); - if(result.data){ + if (result.data) { showPhaseInfo(result.data, []); - }; - }else{ - logging.push('\tNo decoder matched.') + } + } else { + logging.push('\tNo decoder matched.'); } // Rule phase @@ -136,24 +142,34 @@ export const Logtest = compose( // Rule debugging // The output has data if the utility is ran in verbose mode: `wazuh-logtest -v`. // At this moment, the Wazuh API doesn't let run in verbose mode. - if(result.rules_debug){ + if (result.rules_debug) { logging.push(''); logging.push('**Rule debugging:'); - result.rules_debug.forEach(debugMessage => logging.push(`${debugMessage[0] === '*' ? '\t\t' : '\t'}${debugMessage}`)); - }; - - if(result.rule){ + result.rules_debug.forEach(debugMessage => + logging.push( + `${debugMessage[0] === '*' ? '\t\t' : '\t'}${debugMessage}`, + ), + ); + } + + if (result.rule) { logging.push(''); logging.push('**Phase 3: Completed filtering (rules).'); - showPhaseInfo(result.rule, ['id', 'level', 'description', 'groups', 'firedtimes']); - }; + showPhaseInfo(result.rule, [ + 'id', + 'level', + 'description', + 'groups', + 'firedtimes', + ]); + } - if(alert){ + if (alert) { logging.push('**Alert to be generated.'); - }; + } return logging.join('\n'); - }; + }; const runAllTests = async () => { setTestResult(''); @@ -172,22 +188,31 @@ export const Logtest = compose( }); token = response.data.data.token; - !sessionToken && !gotToken && token && dispatch(updateLogtestToken(token)); + !sessionToken && + !gotToken && + token && + dispatch(updateLogtestToken(token)); token && (gotToken = true); responses.push(response); } - const testResults = responses.map((response) => { - return response.data.data.output || '' - ? formatResult(response.data.data.output, response.data.data.alert, response.data.data.messages) - : `No result found for: ${response.data.data.output.full_log}`; - }).join('\n\n'); + const testResults = responses + .map(response => { + return response.data.data.output || '' + ? formatResult( + response.data.data.output, + response.data.data.alert, + response.data.data.messages, + ) + : `No result found for: ${response.data.data.output.full_log}`; + }) + .join('\n\n'); setTestResult(testResults); } finally { setTesting(false); } }; - const handleKeyPress = async (event) => { + const handleKeyPress = async event => { if (event.ctrlKey && event.key === 'Enter') { await runAllTests(); } @@ -205,7 +230,9 @@ export const Logtest = compose( severity: UI_ERROR_SEVERITIES.BUSINESS as UIErrorSeverity, error: { error: error, - message: `Error trying to delete logtest token due to: ${error.message || error}`, + message: `Error trying to delete logtest token due to: ${ + error.message || error + }`, title: error.name, }, }; @@ -217,21 +244,21 @@ export const Logtest = compose( return ( - - + + @@ -244,12 +271,12 @@ export const Logtest = compose( tooltip={{ position: 'top', content: 'Clear current session' }} fill isDisabled={sessionToken === '' ? true : false} - aria-label="Clear current session" - iconType="broom" + aria-label='Clear current session' + iconType='broom' onConfirm={async () => { deleteToken(); }} - color="danger" + color='danger' modalTitle={`Do you want to clear current session?`} modalProps={{ buttonColor: 'danger', @@ -261,10 +288,10 @@ export const Logtest = compose( - + - DynamicHeight.dynamicHeightStatic('.euiCodeBlock', props.showClose ? 70 : 100); + DynamicHeight.dynamicHeightStatic( + '.euiCodeBlock', + props.onFlyout ? 70 : 100, + ); dynamicHeight(); @@ -287,40 +317,33 @@ export const Logtest = compose( {(!props.onFlyout && ( - + - + - +

Ruleset Test

- + {buildLogtest()}
)) || ( - props.openCloseFlyout()}> - - - {props.isRuleset.includes('rules') ?

Ruleset Test

:

Decoders Test

} -
-
- - - - - - {buildLogtest()} - -
+ <> + + + + + {buildLogtest()} + )}
); diff --git a/plugins/main/public/services/config-handler.js b/plugins/main/public/services/config-handler.js index e9547e35fe..e87fde2436 100644 --- a/plugins/main/public/services/config-handler.js +++ b/plugins/main/public/services/config-handler.js @@ -24,11 +24,10 @@ export class ConfigHandler { */ async saveManagerConfiguration(content) { try { - const result = await WzRequest.apiReq( - 'PUT', - `/manager/configuration`, - { content, origin: 'xmleditor' } - ); + const result = await WzRequest.apiReq('PUT', `/manager/configuration`, { + content, + origin: 'xmleditor', + }); return result; } catch (error) { return Promise.reject(error); @@ -45,7 +44,7 @@ export class ConfigHandler { const result = await WzRequest.apiReq( 'PUT', `/cluster/${node}/configuration`, - { content, origin: 'xmleditor' } + { content, origin: 'xmleditor' }, ); return result; } catch (error) { @@ -56,9 +55,7 @@ export class ConfigHandler { async performClusterRestart() { try { await WzRequest.apiReq('PUT', `/cluster/restart`, { delay: 15000 }); - this.$rootScope.$broadcast('removeRestarting', {}); } catch (error) { - this.$rootScope.$broadcast('removeRestarting', {}); throw new Error('Error restarting cluster'); } } @@ -71,7 +68,7 @@ export class ConfigHandler { const validationError = await WzRequest.apiReq( 'GET', `/manager/configuration/validation`, - {} + {}, ); const data = ((validationError || {}).data || {}).data || {}; @@ -96,7 +93,7 @@ export class ConfigHandler { const validationError = await WzRequest.apiReq( 'GET', `/cluster/configuration/validation`, - {} + {}, ); const data = ((validationError || {}).data || {}).data || {}; @@ -120,7 +117,7 @@ export class ConfigHandler { const validationError = await WzRequest.apiReq( 'GET', `/cluster/${node}/configuration/validation`, - {} + {}, ); const data = ((validationError || {}).data || {}).data || {}; @@ -132,7 +129,7 @@ export class ConfigHandler { const result = await WzRequest.apiReq( 'PUT', `/cluster/${node}/restart`, - {} + {}, ); return result; } catch (error) { diff --git a/plugins/main/public/templates/management/management.html b/plugins/main/public/templates/management/management.html index 4d69103378..01db1a17d5 100644 --- a/plugins/main/public/templates/management/management.html +++ b/plugins/main/public/templates/management/management.html @@ -1,49 +1 @@ - -
- - -
- -
- -
- -
- {{ mctrl.tabNames[mctrl.tab] }} - / {{ mctrl.currentGroup.name }} -
- -
- - -
- -
- - -
- -
- -
+ From 979db9d9f3b0836f15ea1541a2f381238d55d842 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Mon, 29 Apr 2024 11:00:14 +0200 Subject: [PATCH 15/18] Reduce overview welcome font size (#6627) * Reduce overview welcome font size * Add changelog --- CHANGELOG.md | 1 + .../main/public/components/common/welcome/overview-welcome.js | 2 +- .../overview/components/last-alerts-stat/last-alerts-stat.tsx | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cab59de24..501c31d990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Changed the api configuration title in the Server APIs section. [#6373](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6373) - Changed overview home top KPIs. [#6379](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6379) [#6408](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6408) [#6569](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6569) - Updated the PDF report year number. [#6492](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6492) +- Changed overview home font size [#6627](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6627) ### Fixed diff --git a/plugins/main/public/components/common/welcome/overview-welcome.js b/plugins/main/public/components/common/welcome/overview-welcome.js index 70c40e3741..d64bdba418 100644 --- a/plugins/main/public/components/common/welcome/overview-welcome.js +++ b/plugins/main/public/components/common/welcome/overview-welcome.js @@ -109,7 +109,7 @@ export const OverviewWelcome = compose( render() { return ( - + {this.props.agentsCountTotal === 0 && this.addAgent()} diff --git a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx index 9cd11c5a94..6deceb47f4 100644 --- a/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx +++ b/plugins/main/public/controllers/overview/components/last-alerts-stat/last-alerts-stat.tsx @@ -139,11 +139,11 @@ export function LastAlertsStat({ severity }: { severity: string }) { } description={`${severityLabel[severity].label} severity`} - descriptionElement='h2' + descriptionElement='h3' titleColor={severityLabel[severity].color} textAlign='center' /> - + {'Rule level ' + severityLabel[severity].ruleLevelRange.minRuleLevel + (severityLabel[severity].ruleLevelRange.maxRuleLevel From aee026821f491a9ffe1de7ee0455304a2261a8b9 Mon Sep 17 00:00:00 2001 From: Luciano Gorza <103193307+lucianogorza@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:24:58 -0300 Subject: [PATCH 16/18] Remove agent AngularJS controller (#6618) * Create AgentView component to replace controller * Replace Kibana visualization * Improve Events count evolution chart * Fix Dashboard embeddable * Fix url update when change tab * Move file export-configuration * Fix imports to move file export-configuration * Delete agents angularjs controller * Get agent on change tab * Update CHANGELOG * Remove unused VisFactoryHandler * Improve code and remove unused code --------- Co-authored-by: Federico Rodriguez --- CHANGELOG.md | 2 +- .../components/agents/export-configuration.js | 181 ++++ .../common/charts/visualizations/basic.tsx | 6 +- .../common/welcome/agents-welcome.js | 162 ++-- .../welcome/dashboard/dashboard_panels.ts | 137 +++ .../common/welcome/dashboard/events-count.tsx | 75 ++ .../endpoints-summary/agent/index.tsx | 126 +++ .../endpoints-summary/services/get-agents.tsx | 7 +- .../main/public/controllers/agent/agents.js | 784 ------------------ .../agent/components/export-configuration.js | 172 ---- .../main/public/controllers/agent/index.js | 16 +- .../components/files-group-table.js | 52 +- .../configuration/configuration-overview.js | 2 +- .../configuration/configuration-switch.js | 13 +- .../groups/actions-buttons-agents.js | 2 +- .../groups/actions-buttons-files.js | 2 +- .../public/templates/agents/dashboards.html | 139 +--- .../visualizations/agents/agents-welcome.ts | 192 ++--- 18 files changed, 700 insertions(+), 1370 deletions(-) create mode 100644 plugins/main/public/components/agents/export-configuration.js create mode 100644 plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts create mode 100644 plugins/main/public/components/common/welcome/dashboard/events-count.tsx create mode 100644 plugins/main/public/components/endpoints-summary/agent/index.tsx delete mode 100644 plugins/main/public/controllers/agent/agents.js delete mode 100644 plugins/main/public/controllers/agent/components/export-configuration.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e1d9ebe559..23c0ca5d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,8 @@ All notable changes to the Wazuh app project will be documented in this file. - Move AngularJS controller for management to ReactJS component [#6555](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6555) - Moved the registry data to in-memory cache [#6481](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6481) - Enhance the validation for `enrollment.dns` on App Settings application [#6573](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6573) -- Remove AngularJS controller for manage groups [#6543](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6543) - Remove some branding references across the application. [#6155](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6155) +- Move AngularJS controller for the agent view to ReactJS [#6618](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6618) - Implement new data source feature on MITRE ATT&CK module [#6482](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6482) ### Fixed diff --git a/plugins/main/public/components/agents/export-configuration.js b/plugins/main/public/components/agents/export-configuration.js new file mode 100644 index 0000000000..995a4d23bc --- /dev/null +++ b/plugins/main/public/components/agents/export-configuration.js @@ -0,0 +1,181 @@ +/* + * Wazuh app - React component for exporting the configuration of a group. + * Copyright (C) 2015-2022 Wazuh, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find more information about this on the LICENSE file. + */ +import React, { Component } from 'react'; + +import { + EuiPopover, + EuiButton, + EuiCheckboxGroup, + EuiSpacer, + EuiButtonEmpty, +} from '@elastic/eui'; + +import PropTypes from 'prop-types'; +import { UnsupportedComponents } from '../../utils/components-os-support'; +import { WAZUH_AGENTS_OS_TYPE } from '../../../common/constants'; +import { withErrorBoundary } from '../common/hocs'; + +export const ExportConfiguration = withErrorBoundary( + class ExportConfiguration extends Component { + constructor(props) { + super(props); + + this.state = { + buttonDisabled: false, + isPopoverOpen: false, + }; + + const agentOptions = [ + 'Global configuration', + 'Communication', + 'Anti-flooding settings', + 'Labels', + 'Policy monitoring', + { name: 'oscap', desc: 'OpenSCAP' }, + 'CIS-CAT', + 'Osquery', + 'Inventory data', + 'Active response', + 'Commands', + { name: 'docker', desc: 'Docker listener' }, + 'Log collection', + 'Integrity monitoring', + ]; + const groupOptions = ['Configurations', 'Agents in group']; + + this.options = []; + const list = this.props.type === 'agent' ? agentOptions : groupOptions; + list.forEach((x, idx) => { + if ( + typeof x === 'string' || + (x.name && + !( + UnsupportedComponents[this.props.agentPlatform] || + UnsupportedComponents[WAZUH_AGENTS_OS_TYPE.OTHERS] + ).includes(x.name)) + ) { + this.options.push({ id: `${idx}`, label: x.desc || x }); + } + }); + + let initialChecks = {}; + this.options.forEach(x => { + initialChecks[x.id] = true; + }); + this.state.checkboxIdToSelectedMap = initialChecks; + } + + selectAll(flag) { + let newCheckboxIdToSelectedMap = {}; + for (let i = 0; i < this.options.length; i++) { + newCheckboxIdToSelectedMap[`${this.options[i].id}`] = flag; + } + this.setState({ + checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, + buttonDisabled: !flag, + }); + } + + exportClick() { + this.setState({ + isPopoverOpen: !this.state.isPopoverOpen, + }); + } + + closePopover() { + this.setState({ + isPopoverOpen: false, + }); + } + + onChange = optionId => { + const newCheckboxIdToSelectedMap = { + ...this.state.checkboxIdToSelectedMap, + ...{ + [optionId]: !this.state.checkboxIdToSelectedMap[optionId], + }, + }; + let result = false; + for (let i = 0; i < this.options.length; i++) { + if (newCheckboxIdToSelectedMap[`${this.options[i].id}`] === true) { + result = true; + } + } + this.setState({ + checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, + buttonDisabled: !result, + }); + }; + + render() { + const button = ( + + Export PDF + + ); + return ( + + + + {this.options.length > 3 && ( + <> + this.selectAll(true)}> + Select all + + + this.selectAll(false)}> + Unselect all + + + )} + + { + this.closePopover(); + this.props.exportConfiguration( + this.state.checkboxIdToSelectedMap, + ); + }} + fill + > + Generate PDF report + + + ); + } + }, +); + +ExportConfiguration.propTypes = { + exportConfiguration: PropTypes.func, + type: PropTypes.string, + agentPlatform: PropTypes.string, +}; diff --git a/plugins/main/public/components/common/charts/visualizations/basic.tsx b/plugins/main/public/components/common/charts/visualizations/basic.tsx index 2e48e5e734..eaca2e6270 100644 --- a/plugins/main/public/components/common/charts/visualizations/basic.tsx +++ b/plugins/main/public/components/common/charts/visualizations/basic.tsx @@ -160,7 +160,11 @@ export const VisualizationBasicWidgetSelector = ({ return ( <> - + {title && (

diff --git a/plugins/main/public/components/common/welcome/agents-welcome.js b/plugins/main/public/components/common/welcome/agents-welcome.js index cb4b63fb54..43b19f1556 100644 --- a/plugins/main/public/components/common/welcome/agents-welcome.js +++ b/plugins/main/public/components/common/welcome/agents-welcome.js @@ -22,7 +22,6 @@ import { EuiButtonEmpty, EuiPage, EuiPopover, - EuiLoadingChart, EuiToolTip, EuiButtonIcon, EuiPageBody, @@ -39,20 +38,16 @@ import WzReduxProvider from '../../../redux/wz-redux-provider'; import MenuAgent from './components/menu-agent'; import './welcome.scss'; import { WzDatePicker } from '../../../components/wz-date-picker/wz-date-picker'; -import KibanaVis from '../../../kibana-integrations/kibana-vis'; -import { VisFactoryHandler } from '../../../react-services/vis-factory-handler'; -import { AppState } from '../../../react-services/app-state'; -import { FilterHandler } from '../../../utils/filter-handler'; import { TabVisualizations } from '../../../factories/tab-visualizations'; import { showExploreAgentModalGlobal, updateCurrentAgentData, } from '../../../redux/actions/appStateActions'; import { - getAngularModule, getChrome, getCore, getDataPlugin, + getAngularModule, } from '../../../kibana-services'; import { hasAgentSupportModule } from '../../../react-services/wz-agents'; import { @@ -80,6 +75,7 @@ import { malwareDetection, } from '../../../utils/applications'; import { RedirectAppLinks } from '../../../../../../src/plugins/opensearch_dashboards_react/public'; +import { EventsCount } from './dashboard/events-count'; const mapStateToProps = state => ({ agent: state.appStateReducers.currentAgentData, @@ -105,11 +101,11 @@ export const AgentsWelcome = compose( }, ...(agent?.name ? [ - { - text: `${agent.name}`, - truncate: true, - }, - ] + { + text: `${agent.name}`, + truncate: true, + }, + ] : []), ]; }), @@ -150,6 +146,9 @@ export const AgentsWelcome = compose( this.sidebarSizeDefault = 320; + const $injector = getAngularModule().$injector; + this.location = $injector.get('$location'); + this.state = { lastScans: [], isLoading: true, @@ -200,8 +199,8 @@ export const AgentsWelcome = compose( of duplicating it. It was duplicated due to the differences of requirements in the Explore agent button for the modules and agent welcome */ - async removeAgentsFilter() { - await this.props.setAgent(false); + removeAgentsFilter() { + this.props.setAgent(false); const currentAppliedFilters = getDataPlugin().query.filterManager.filters; const agentFilters = currentAppliedFilters.filter(x => { return x.meta.key !== 'agent.id'; @@ -226,8 +225,7 @@ export const AgentsWelcome = compose( tabVisualizations.assign({ welcome: 8, }); - const filterHandler = new FilterHandler(AppState.getCurrentPattern()); - const $injector = getAngularModule().$injector; + this.drawerLokedSubscribtion = getChrome() .getIsNavDrawerLocked$() .subscribe(isLocked => { @@ -235,15 +233,7 @@ export const AgentsWelcome = compose( this.updateWidth(); }); }); - this.router = $injector.get('$route'); - this.location = $injector.get('$location'); window.addEventListener('resize', this.updateWidth); //eslint-disable-line - await VisFactoryHandler.buildAgentsVisualizations( - filterHandler, - 'welcome', - null, - this.props.agent.id, - ); } componentDidUpdate(prevProps) { @@ -268,13 +258,13 @@ export const AgentsWelcome = compose( ) ? JSON.parse(window.localStorage.getItem('wz-menu-agent-apps-pinned')) : [ - // Default pinned applications - threatHunting.id, - fileIntegrityMonitoring.id, - configurationAssessment.id, - mitreAttack.id, - malwareDetection.id, - ]; + // Default pinned applications + threatHunting.id, + fileIntegrityMonitoring.id, + configurationAssessment.id, + mitreAttack.id, + malwareDetection.id, + ]; } // Ensure the pinned applications are supported @@ -354,7 +344,6 @@ export const AgentsWelcome = compose( closePopover={() => { this.setState({ switchModule: false }); }} - switchTab={module => this.props.switchTab(module)} > @@ -366,7 +355,6 @@ export const AgentsWelcome = compose( } renderTitle() { - const notNeedStatus = true; const thereAreAgentSelected = Boolean(this.props.agent?.id); // Calculate if the header buttons should display the name or only the icon to be responsive @@ -411,7 +399,6 @@ export const AgentsWelcome = compose( closePopover={() => { this.setState({ switchModule: false }); }} - switchTab={module => this.props.switchTab(module)} > @@ -460,9 +447,7 @@ export const AgentsWelcome = compose( - this.props.switchTab('syscollector', notNeedStatus) - } + onClick={() => this.props.switchTab('syscollector')} className='wz-it-hygiene-header-button' tooltip={ this.state.maxModules === null @@ -477,7 +462,7 @@ export const AgentsWelcome = compose( this.props.switchTab('stats', notNeedStatus)} + onClick={() => this.props.switchTab('stats')} className='wz-it-hygiene-header-button' tooltip={ this.state.maxModules === null @@ -492,9 +477,7 @@ export const AgentsWelcome = compose( - this.props.switchTab('configuration', notNeedStatus) - } + onClick={() => this.props.switchTab('configuration')} className='wz-it-hygiene-header-button' tooltip={ this.state.maxModules === null @@ -569,50 +552,13 @@ export const AgentsWelcome = compose( } renderEventCountVisualization() { - return ( - - - - -

- -

Events count evolution

-
-

-
-
- -
- - - -
-
- -
-
-
- ); + return ; } renderSCALastScan() { return ( - + ); } @@ -654,8 +600,8 @@ export const AgentsWelcome = compose( }} > {' '} - {/* DatePicker */} - {}} /> + {/* TODO: Replace with SearchBar and replace implementation to get the time range in AgentView component*/} + { }} /> {(this.state.widthWindow < 1150 && ( @@ -688,33 +634,33 @@ export const AgentsWelcome = compose( )) || ( - - - - - - {this.renderMitrePanel()} - - {this.renderCompliancePanel()} - - - - - - - - {' '} - {/* Events count evolution */} - {this.renderEventCountVisualization()} - - {this.renderSCALastScan()} - - - )} + + + + + + {this.renderMitrePanel()} + + {this.renderCompliancePanel()} + + + + + + + + {' '} + {/* Events count evolution */} + {this.renderEventCountVisualization()} + + {this.renderSCALastScan()} + + + )} diff --git a/plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts b/plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts new file mode 100644 index 0000000000..7d250e7d05 --- /dev/null +++ b/plugins/main/public/components/common/welcome/dashboard/dashboard_panels.ts @@ -0,0 +1,137 @@ +import { DashboardPanelState } from '../../../../../../../src/plugins/dashboard/public/application'; +import { EmbeddableInput } from '../../../../../../../src/plugins/embeddable/public'; + +const getVisStateEventsCountEvolution = (indexPatternId: string) => ({ + id: 'App-Agents-Welcome-Events-Evolution', + title: 'Events count evolution', + type: 'line', + params: { + type: 'line', + grid: { categoryLines: false }, + categoryAxes: [ + { + id: 'CategoryAxis-1', + type: 'category', + position: 'bottom', + show: true, + style: {}, + scale: { type: 'linear' }, + labels: { show: true, filter: true, truncate: 100 }, + title: {}, + }, + ], + valueAxes: [ + { + id: 'ValueAxis-1', + name: 'LeftAxis-1', + type: 'value', + position: 'left', + show: true, + style: {}, + scale: { type: 'linear', mode: 'normal' }, + labels: { show: true, rotate: 0, filter: false, truncate: 100 }, + title: { text: 'Count' }, + }, + ], + seriesParams: [ + { + show: true, + type: 'line', + mode: 'normal', + data: { label: 'Count', id: '1' }, + valueAxis: 'ValueAxis-1', + drawLinesBetweenPoints: true, + lineWidth: 2, + interpolate: 'linear', + showCircles: true, + }, + ], + addTooltip: true, + addLegend: false, + legendPosition: 'right', + times: [], + addTimeMarker: false, + labels: {}, + thresholdLine: { + show: false, + value: 10, + width: 1, + style: 'full', + color: '#E7664C', + }, + dimensions: { + x: null, + y: [ + { + accessor: 0, + format: { id: 'number' }, + params: {}, + label: 'Count', + aggType: 'count', + }, + ], + }, + }, + uiState: { + vis: { params: { sort: { columnIndex: 2, direction: 'desc' } } }, + }, + data: { + searchSource: { + query: { + language: 'kuery', + query: '', + }, + index: indexPatternId, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: indexPatternId, + }, + ], + aggs: [ + { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '2', + enabled: true, + type: 'date_histogram', + schema: 'segment', + params: { + field: 'timestamp', + useNormalizedEsInterval: true, + scaleMetricValues: false, + interval: 'auto', + drop_partials: false, + min_doc_count: 1, + extended_bounds: {}, + }, + }, + ], + }, +}); + +export const getDashboardPanels = ( + indexPatternId: string, +): { + [panelId: string]: DashboardPanelState< + EmbeddableInput & { [k: string]: unknown } + >; +} => { + return { + '1': { + gridData: { + w: 48, + h: 12, + x: 0, + y: 0, + i: '1', + }, + type: 'visualization', + explicitInput: { + id: '1', + savedVis: getVisStateEventsCountEvolution(indexPatternId), + }, + }, + }; +}; diff --git a/plugins/main/public/components/common/welcome/dashboard/events-count.tsx b/plugins/main/public/components/common/welcome/dashboard/events-count.tsx new file mode 100644 index 0000000000..e41f399a5f --- /dev/null +++ b/plugins/main/public/components/common/welcome/dashboard/events-count.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { AlertsDataSource } from '../../data-source/pattern/alerts/alerts-data-source'; +import { AlertsDataSourceRepository } from '../../data-source/pattern/alerts/alerts-data-source-repository'; +import { getPlugins } from '../../../../kibana-services'; +import { getDashboardPanels } from './dashboard_panels'; +import { ViewMode } from '../../../../../../../src/plugins/embeddable/public'; +import { useDataSource } from '../../data-source/hooks'; +import { PatternDataSource, tParsedIndexPattern } from '../../data-source'; +import { + EuiPanel, + EuiFlexItem, + EuiFlexGroup, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { useTimeFilter } from '../../hooks'; +import { LoadingSpinner } from '../../loading-spinner/loading-spinner'; + +const plugins = getPlugins(); +const DashboardByRenderer = plugins.dashboard.DashboardContainerByValueRenderer; + +export const EventsCount = () => { + const { + dataSource, + fetchFilters, + isLoading: isDataSourceLoading, + } = useDataSource({ + DataSource: AlertsDataSource, + repository: new AlertsDataSourceRepository(), + }); + + const { timeFilter } = useTimeFilter(); + + return ( + + + + +

+ +

Events count evolution

+
+

+
+
+ + {!isDataSourceLoading && dataSource ? ( + + ) : ( + + )} +
+
+ ); +}; diff --git a/plugins/main/public/components/endpoints-summary/agent/index.tsx b/plugins/main/public/components/endpoints-summary/agent/index.tsx new file mode 100644 index 0000000000..c7b88c3ad9 --- /dev/null +++ b/plugins/main/public/components/endpoints-summary/agent/index.tsx @@ -0,0 +1,126 @@ +import React, { useState, useEffect } from 'react'; +import { EuiPage, EuiPageBody, EuiProgress } from '@elastic/eui'; +import { useDispatch } from 'react-redux'; +import { getErrorOrchestrator } from '../../../react-services/common-services'; +import { UI_LOGGER_LEVELS } from '../../../../common/constants'; +import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types'; +import { AgentsWelcome } from '../../common/welcome/agents-welcome'; +import { Agent } from '../types'; +import { + getAngularModule, + getCore, + getDataPlugin, +} from '../../../kibana-services'; +import { MainSyscollector } from '../../agents/syscollector/main'; +import { MainAgentStats } from '../../agents/stats'; +import WzManagementConfiguration from '../../../controllers/management/components/management/configuration/configuration-main.js'; +import { getAgentsService } from '../services'; +import { ShareAgent } from '../../../factories/share-agent'; +import { updateCurrentAgentData } from '../../../redux/actions/appStateActions'; +import { endpointSummary } from '../../../utils/applications'; +import { withErrorBoundary, withReduxProvider } from '../../common/hocs'; +import { compose } from 'redux'; + +export const AgentView = compose( + withErrorBoundary, + withReduxProvider, +)(() => { + //TODO: Replace when implement React router + const $injector = getAngularModule().$injector; + const $router = $injector.get('$route'); + const $commonData = $injector.get('commonData'); + + const shareAgent = new ShareAgent(); + + //TODO: Replace with useDatasource and useSearchBar when replace WzDatePicker with SearchBar in AgentsWelcome component + const savedTimefilter = $commonData.getTimefilter(); + if (savedTimefilter) { + getDataPlugin().query.timefilter.timefilter.setTime(savedTimefilter); + $commonData.removeTimefilter(); + } + + const { agent: agentId } = $router.current.params; + + const [agent, setAgent] = useState(); + const [isLoadingAgent, setIsLoadingAgent] = useState(true); + const [tab, setTab] = useState($commonData.checkTabLocation()); + const dispatch = useDispatch(); + + const getAgent = async () => { + try { + setIsLoadingAgent(true); + + const id = $commonData.checkLocationAgentId( + agentId, + shareAgent.getAgent(), + ); + + if (!id) { + return; + } + + const { affected_items } = await getAgentsService({ + agents: [agentId], + }); + if (!affected_items?.length) { + throw 'Not found'; + } + + const agent = affected_items[0]; + setAgent(agent); + dispatch(updateCurrentAgentData(agent)); + } catch (error) { + const options = { + context: `AgentView.getAgent`, + level: UI_LOGGER_LEVELS.ERROR, + severity: UI_ERROR_SEVERITIES.CRITICAL, + store: true, + error: { + error, + message: error.message || error, + title: `Error getting the agent: ${error.message || error}`, + }, + }; + getErrorOrchestrator().handleError(options); + } finally { + setIsLoadingAgent(false); + } + }; + + useEffect(() => { + getAgent(); + }, [tab]); + + const switchTab = (tab: string) => { + setTab(tab); + getCore().application.navigateToApp(endpointSummary.id, { + path: `#/agents?tab=${tab}&agent=${agent?.id}`, + }); + }; + + if (isLoadingAgent) { + return ( + + + + + + ); + } + + if (tab === 'welcome') { + return ; + } + + if (tab === 'syscollector' && agent) { + return ; + } + + if (tab === 'stats' && agent) { + return ; + } + + if (tab === 'configuration' && agent) { + return ; + } +}); diff --git a/plugins/main/public/components/endpoints-summary/services/get-agents.tsx b/plugins/main/public/components/endpoints-summary/services/get-agents.tsx index ebe67f445e..5040a34335 100644 --- a/plugins/main/public/components/endpoints-summary/services/get-agents.tsx +++ b/plugins/main/public/components/endpoints-summary/services/get-agents.tsx @@ -4,11 +4,13 @@ import { Agent } from '../types'; export const getAgentsService = async ({ filters, + agents, limit, offset, pageSize = 1000, }: { - filters: any; + filters?: any; + agents?: string[]; limit?: number; offset?: number; pageSize?: number; @@ -27,7 +29,8 @@ export const getAgentsService = async ({ params: { limit: queryLimit, offset: queryOffset, - q: filters, + ...(agents?.length ? { agents_list: agents?.join(',') } : {}), + ...(filters ? { q: filters } : {}), wait_for_complete: true, }, })) as IApiResponse; diff --git a/plugins/main/public/controllers/agent/agents.js b/plugins/main/public/controllers/agent/agents.js deleted file mode 100644 index db8249dedc..0000000000 --- a/plugins/main/public/controllers/agent/agents.js +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Wazuh app - Agents controller - * Copyright (C) 2015-2022 Wazuh, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Find more information about this on the LICENSE file. - */ -import { FilterHandler } from '../../utils/filter-handler'; -import { TabNames } from '../../utils/tab-names'; -import { visualizations } from '../../templates/agents/visualizations'; - -import { ConfigurationHandler } from '../../utils/config-handler'; -import { AppState } from '../../react-services/app-state'; -import { WazuhConfig } from '../../react-services/wazuh-config'; -import { GenericRequest } from '../../react-services/generic-request'; -import { WzRequest } from '../../react-services/wz-request'; -import { - getToasts, - getDataPlugin, - getWazuhCorePlugin, -} from '../../kibana-services'; -import { ShareAgent } from '../../factories/share-agent'; -import { TabVisualizations } from '../../factories/tab-visualizations'; -import { formatUIDate } from '../../react-services/time-service'; -import { hasAgentSupportModule } from '../../react-services/wz-agents'; -import { UI_LOGGER_LEVELS } from '../../../common/constants'; -import { UI_ERROR_SEVERITIES } from '../../react-services/error-orchestrator/types'; -import { getErrorOrchestrator } from '../../react-services/common-services'; -import { updateCurrentAgentData } from '../../redux/actions/appStateActions'; -import store from '../../redux/store'; - -export class AgentsController { - /** - * Class constructor - * @param {Object} $scope - * @param {Object} $location - * @param {Object} $rootScope - * @param {Object} errorHandler - * @param {Object} commonData - * @param {Object} reportingService - * @param {Object} visFactoryService - * @param {Object} csvReq - */ - constructor( - $scope, - $location, - $rootScope, - errorHandler, - commonData, - reportingService, - visFactoryService, - csvReq, - ) { - this.$scope = $scope; - this.$location = $location; - this.$rootScope = $rootScope; - this.errorHandler = errorHandler; - this.tabVisualizations = new TabVisualizations(); - this.$scope.visualizations = visualizations; - this.shareAgent = new ShareAgent(); - this.commonData = commonData; - this.reportingService = reportingService; - this.visFactoryService = visFactoryService; - this.csvReq = csvReq; - this.wazuhConfig = new WazuhConfig(); - this.genericReq = GenericRequest; - - // Config on-demand - this.$scope.isArray = Array.isArray; - this.configurationHandler = new ConfigurationHandler(errorHandler); - this.$scope.currentConfig = null; - this.$scope.configurationTab = ''; - this.$scope.configurationSubTab = ''; - this.$scope.integrations = {}; - this.$scope.selectedItem = 0; - this.targetLocation = null; - this.ignoredTabs = ['syscollector', 'welcome', 'configuration', 'stats']; - - this.$scope.expandArray = [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - ]; - - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - } - - /** - * On controller loads - */ - async $onInit() { - const savedTimefilter = this.commonData.getTimefilter(); - if (savedTimefilter) { - getDataPlugin().query.timefilter.timefilter.setTime(savedTimefilter); - this.commonData.removeTimefilter(); - } - - this.$rootScope.reportStatus = false; - - this.$location.search('_a', null); - this.filterHandler = new FilterHandler(AppState.getCurrentPattern()); - this.visFactoryService.clearAll(); - - // Getting possible target location - this.targetLocation = this.shareAgent.getTargetLocation(); - - if (this.targetLocation && typeof this.targetLocation === 'object') { - this.$scope.tabView = this.targetLocation.subTab; - this.$scope.tab = this.targetLocation.tab; - } else { - this.$scope.tabView = this.commonData.checkTabViewLocation(); - this.$scope.tab = this.commonData.checkTabLocation(); - } - this.tabHistory = []; - if (!this.ignoredTabs.includes(this.$scope.tab)) - this.tabHistory.push(this.$scope.tab); - - // Tab names - this.$scope.tabNames = TabNames; - - this.tabVisualizations.assign('agents'); - - /** - * This check if given array of items contais a single given item - * @param {Object} item - * @param {Array} array - */ - this.$scope.inArray = (item, array) => - item && Array.isArray(array) && array.includes(item); - - this.$scope.switchSubtab = async ( - subtab, - force = false, - onlyAgent = false, - ) => this.switchSubtab(subtab, force, onlyAgent); - - this.changeAgent = false; - - this.$scope.switchTab = (tab, force = false) => this.switchTab(tab, force); - this.$scope.getAgent = async newAgentId => this.getAgent(newAgentId); - this.$scope.goGroups = (agent, group) => this.goGroups(agent, group); - - this.$scope.search = (term, specificPath) => - this.$scope.$broadcast('wazuhSearch', { - term, - specificPath, - }); - - this.$scope.searchSyscheckFile = (term, specificFilter) => - this.$scope.$broadcast('wazuhSearch', { - term, - specificFilter, - }); - - this.$scope.searchRootcheck = (term, specificFilter) => - this.$scope.$broadcast('wazuhSearch', { - term, - specificFilter, - }); - - this.$scope.shouldShowComponent = component => - this.shouldShowComponent(component); - - this.$scope.$on('$destroy', () => { - this.visFactoryService.clearAll(); - }); - - this.$scope.isArray = Array.isArray; - - this.$scope.goGroup = () => { - this.shareAgent.setAgent(this.$scope.agent); - this.$location.path('/manager/groups'); - }; - - this.$scope.exportConfiguration = enabledComponents => { - this.reportingService.startConfigReport( - this.$scope.agent, - 'agentConfig', - enabledComponents, - ); - }; - - //Load - try { - this.$scope.getAgent(); - } catch (error) { - const options = { - context: `${AgentsController.name}.$onInit`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - store: true, - error: { - error: error, - message: error.message || error, - title: `Error getting the agent: ${error.message || error}`, - }, - }; - getErrorOrchestrator().handleError(options); - } - - // Config on demand - this.$scope.getXML = () => this.configurationHandler.getXML(this.$scope); - this.$scope.getJSON = () => this.configurationHandler.getJSON(this.$scope); - this.$scope.isString = item => typeof item === 'string'; - this.$scope.hasSize = obj => - obj && typeof obj === 'object' && Object.keys(obj).length; - this.$scope.offsetTimestamp = (text, time) => - this.offsetTimestamp(text, time); - this.$scope.switchConfigTab = ( - configurationTab, - sections, - navigate = true, - ) => { - this.$scope.navigate = navigate; - try { - this.$scope.configSubTab = JSON.stringify({ - configurationTab: configurationTab, - sections: sections, - }); - if (!this.$location.search().configSubTab) { - AppState.setSessionStorageItem( - 'configSubTab', - this.$scope.configSubTab, - ); - this.$location.search('configSubTab', true); - } - } catch (error) { - const options = { - context: `${AgentsController.name}.switchConfigTab`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - store: true, - error: { - error: error, - message: error.message || error, - title: `${error.message || error} Set configuration path`, - }, - }; - getErrorOrchestrator().handleError(options); - } - this.configurationHandler.switchConfigTab( - configurationTab, - sections, - this.$scope, - this.$scope.agent.id, - ); - }; - - this.$scope.switchWodle = (wodleName, navigate = true) => { - this.$scope.navigate = navigate; - this.$scope.configWodle = wodleName; - if (!this.$location.search().configWodle) { - this.$location.search('configWodle', this.$scope.configWodle); - } - this.configurationHandler.switchWodle( - wodleName, - this.$scope, - this.$scope.agent.id, - ); - }; - - this.$scope.switchConfigurationTab = (configurationTab, navigate) => { - this.$scope.navigate = navigate; - this.configurationHandler.switchConfigurationTab( - configurationTab, - this.$scope, - ); - if (!this.$scope.navigate) { - const configSubTab = this.$location.search().configSubTab; - if (configSubTab) { - try { - const config = AppState.getSessionStorageItem('configSubTab'); - const configSubTabObj = JSON.parse(config); - this.$scope.switchConfigTab( - configSubTabObj.configurationTab, - configSubTabObj.sections, - false, - ); - } catch (error) { - throw new Error(error); - } - } else { - const configWodle = this.$location.search().configWodle; - if (configWodle) { - this.$scope.switchWodle(configWodle, false); - } - } - } else { - this.$location.search('configSubTab', null); - AppState.removeSessionStorageItem('configSubTab'); - this.$location.search('configWodle', null); - } - }; - this.$scope.switchConfigurationSubTab = configurationSubTab => { - this.configurationHandler.switchConfigurationSubTab( - configurationSubTab, - this.$scope, - ); - if (configurationSubTab === 'pm-sca') { - this.$scope.currentConfig.sca = this.configurationHandler.parseWodle( - this.$scope.currentConfig, - 'sca', - ); - } - }; - this.$scope.updateSelectedItem = i => (this.$scope.selectedItem = i); - this.$scope.getIntegration = list => - this.configurationHandler.getIntegration(list, this.$scope); - - this.$scope.$on('$routeChangeStart', () => { - return AppState.removeSessionStorageItem('configSubTab'); - }); - - this.$scope.expand = i => this.expand(i); - this.setTabs(); - } - - // Switch subtab - async switchSubtab(subtab, force = false, onlyAgent = false) { - try { - if (this.$scope.tabView === subtab && !force) return; - this.tabVisualizations.clearDeadVis(); - this.visFactoryService.clear(onlyAgent); - this.$location.search('tabView', subtab); - if ( - (subtab === 'panels' || - (this.targetLocation && - typeof this.targetLocation === 'object' && - this.targetLocation.subTab === 'discover' && - subtab === 'discover')) && - !this.ignoredTabs.includes(this.$scope.tab) - ) { - await this.visFactoryService.buildAgentsVisualizations( - this.filterHandler, - this.$scope.tab, - subtab, - this.$scope.agent.id, - ); - - this.changeAgent = false; - } else { - this.$scope.$emit('changeTabView', { - tabView: subtab, - tab: this.$scope.tab, - }); - } - this.$scope.tabView = subtab; - } catch (error) { - throw new Error(error); - } - } - - /** - * Switch tab - * @param {*} tab - * @param {*} force - */ - async switchTab(tab, force = false) { - const timefilter = getDataPlugin().query.timefilter.timefilter; - this.tabVisualizations.setTab(tab); - this.$rootScope.rendered = false; - this.$rootScope.$applyAsync(); - this.falseAllExpand(); - if (this.ignoredTabs.includes(tab)) { - this.commonData.setRefreshInterval(timefilter.getRefreshInterval()); - timefilter.setRefreshInterval({ - pause: true, - value: 0, - }); - } else if (this.ignoredTabs.includes(this.$scope.tab)) { - timefilter.setRefreshInterval(this.commonData.getRefreshInterval()); - } - - // Update agent status - if (!force && this.$scope.agent) { - try { - const agentInfo = await WzRequest.apiReq('GET', '/agents', { - params: { - agents_list: this.$scope.agent.id, - select: 'status', - }, - }); - this.$scope.agent.status = - agentInfo?.data?.data?.affected_items?.[0]?.status || - this.$scope.agent.status; - - this.$scope.$applyAsync(); - } catch (error) { - throw new Error(error); - } - } - - try { - if (tab === 'configuration') { - this.$scope.switchConfigurationTab('welcome'); - } else { - this.configurationHandler.reset(this.$scope); - } - - if (!this.ignoredTabs.includes(tab)) this.tabHistory.push(tab); - if (this.tabHistory.length > 2) - this.tabHistory = this.tabHistory.slice(-2); - - if (this.$scope.tab === tab && !force) { - this.$scope.$applyAsync(); - return; - } - - const onlyAgent = this.$scope.tab === tab && force; - const sameTab = this.$scope.tab === tab; - this.$location.search('tab', tab); - const preserveDiscover = - this.tabHistory.length === 2 && - this.tabHistory[0] === this.tabHistory[1] && - !force; - this.$scope.tab = tab; - - const targetSubTab = - this.targetLocation && typeof this.targetLocation === 'object' - ? this.targetLocation.subTab - : 'panels'; - - if (!this.ignoredTabs.includes(this.$scope.tab)) { - this.$scope.switchSubtab( - targetSubTab, - true, - onlyAgent, - sameTab, - preserveDiscover, - ); - } - - this.shareAgent.deleteTargetLocation(); - this.targetLocation = null; - this.$scope.$applyAsync(); - } catch (error) { - const options = { - context: `${AgentsController.name}.switchTab`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.CRITICAL, - store: true, - error: { - error: error, - message: error.message || error, - title: error.message || error, - }, - }; - getErrorOrchestrator().handleError(options); - } - - this.$scope.configurationTabsProps = {}; - this.$scope.buildProps = tabs => { - const cleanTabs = []; - tabs.forEach(x => { - if ( - this.$scope.configurationTab === 'integrity-monitoring' && - x.id === 'fim-whodata' && - x.agent && - x.agent.agentPlatform !== 'linux' - ) - return; - - cleanTabs.push({ - id: x.id, - name: x.name, - }); - }); - this.$scope.configurationTabsProps = { - clickAction: tab => { - this.$scope.switchConfigurationSubTab(tab); - }, - selectedTab: - this.$scope.configurationSubTab || (tabs && tabs.length) - ? tabs[0].id - : '', - tabs: cleanTabs, - }; - }; - - this.setTabs(); - } - - /** - * Filter by Mitre.ID - * @param {*} id - */ - addMitrefilter(id) { - const filter = `{"meta":{"index": ${ - AppState.getCurrentPattern() || - getWazuhCorePlugin().configuration.getSettingValue('pattern') - }},"query":{"match":{"rule.mitre.id":{"query":"${id}","type":"phrase"}}}}`; - this.$rootScope.$emit('addNewKibanaFilter', { - filter: JSON.parse(filter), - }); - } - - /** - * Build the current section tabs - */ - setTabs() { - this.$scope.agentsTabsProps = false; - if (this.$scope.agent) { - this.currentPanel = this.commonData.getCurrentPanel( - this.$scope.tab, - true, - ); - - if (!this.currentPanel) return; - - const tabs = this.commonData.getTabsFromCurrentPanel( - this.currentPanel, - this.$scope.tabNames, - ); - - const cleanTabs = []; - tabs.forEach(x => { - if (!hasAgentSupportModule(this.$scope.agent, x.id)) return; - - cleanTabs.push({ - id: x.id, - name: x.name, - }); - }); - - this.$scope.agentsTabsProps = { - clickAction: tab => { - this.switchTab(tab, true); - }, - selectedTab: - this.$scope.tab || - (this.currentPanel && this.currentPanel.length - ? this.currentPanel[0] - : ''), - tabs: cleanTabs, - }; - this.$scope.$applyAsync(); - } - } - - showToast = (color, title, text, time) => { - getToasts().add({ - color: color, - title: title, - text: text, - toastLifeTimeMs: time, - }); - }; - - // Agent data - - /** - * Checks rootcheck of selected agent - */ - validateRootCheck() { - const result = this.commonData.validateRange(this.$scope.agent.rootcheck); - this.$scope.agent.rootcheck = result; - } - - /** - * Checks syscheck of selected agent - */ - validateSysCheck() { - const result = this.commonData.validateRange(this.$scope.agent.syscheck); - this.$scope.agent.syscheck = result; - } - - /** - * Get the needed data for load syscollector - * @param {*} id - */ - async loadSyscollector(id) { - try { - const syscollectorData = await this.genericReq.request( - 'GET', - `/api/syscollector/${id}`, - ); - this.$scope.syscollector = syscollectorData?.data || {}; - return; - } catch (error) { - throw new Error(error); - } - } - - /** - * Get all data from agent - * @param {*} newAgentId - */ - async getAgent(newAgentId) { - try { - this.$scope.emptyAgent = false; - this.$scope.load = true; - this.changeAgent = true; - - const globalAgent = this.shareAgent.getAgent(); - - const id = this.commonData.checkLocationAgentId(newAgentId, globalAgent); - - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - - if (!id) { - this.$scope.load = false; - // We set some properties used by the rendered component to work and allowing - // to manage when there is not selected agent. - await this.$scope.switchTab(this.$scope.tab, true); - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - this.$scope.$applyAsync(); - return; - } - - const data = await WzRequest.apiReq('GET', `/agents`, { - params: { - agents_list: id, - }, - }); - - const agentInfo = data?.data?.data?.affected_items[0] || false; - // Agent - this.$scope.agent = agentInfo; - - if (!this.$scope.agent) return; - - // Sync the selected agent on Redux store - if ( - store.getState().appStateReducers.currentAgentData.id !== - this.$scope.agent.id - ) { - store.dispatch(updateCurrentAgentData(this.$scope.agent)); - } - - if (agentInfo && this.$scope.agent.os) { - this.$scope.agentOS = - this.$scope.agent.os.name + ' ' + this.$scope.agent.os.version; - const isLinux = this.$scope.agent.os.uname.includes('Linux'); - this.$scope.agent.agentPlatform = isLinux - ? 'linux' - : this.$scope.agent.os.platform; - } else { - this.$scope.agentOS = '-'; - this.$scope.agent.agentPlatform = false; - } - - await this.$scope.switchTab(this.$scope.tab, true); - - this.loadWelcomeCardsProps(); - this.$scope.getWelcomeCardsProps = resultState => { - return { ...this.$scope.welcomeCardsProps, resultState }; - }; - this.$scope.load = false; - this.$scope.$applyAsync(); - return; - } catch (error) { - if (!this.$scope.agent) { - if ((error || {}).status === -1) { - this.$scope.emptyAgent = 'API timeout.'; - } - } - if ( - error && - typeof error === 'string' && - error.includes('Agent does not exist') - ) { - this.$location.search('agent', null); - this.$location.path('/agents-preview'); - } - this.$scope.load = false; - this.$scope.$applyAsync(); - throw new Error(error); - } - } - - shouldShowComponent(component) { - return hasAgentSupportModule(this.$scope.agent, component); - } - - setAgent(agent) { - this.$scope.agent = agent; - } - /** - * Get available welcome cards after getting the agent - */ - loadWelcomeCardsProps() { - this.$scope.welcomeCardsProps = { - switchTab: (tab, force) => this.switchTab(tab, force), - agent: this.$scope.agent, - api: AppState.getCurrentAPI(), - setAgent: agent => this.setAgent(agent), - goGroups: (agent, group) => this.goGroups(agent, group), - }; - } - - /** - * This adds timezone offset to a given date - * @param {String} binding_text - * @param {String} date - */ - offsetTimestamp(text, time) { - try { - return text + formatUIDate(time); - } catch (error) { - const options = { - context: `${AgentsController.name}.offsetTimestamp`, - level: UI_LOGGER_LEVELS.ERROR, - severity: UI_ERROR_SEVERITIES.BUSINESS, - store: false, - error: { - error: error, - message: error.message || error, - title: error.message || error, - }, - }; - getErrorOrchestrator().handleError(options); - return time !== '-' ? `${text}${time} (UTC)` : time; - } - } - - /** - * Navigate to the groups of an agent - * @param {*} agent - * @param {*} group - */ - goGroups(agent, group) { - AppState.setNavigation({ - status: true, - }); - this.visFactoryService.clearAll(); - this.shareAgent.setAgent(agent, group); - this.$location.search('tab', 'groups'); - this.$location.search('navigation', true); - this.$location.path('/manager'); - } - - falseAllExpand() { - this.$scope.expandArray = [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - ]; - } - - expand(i) { - const oldValue = this.$scope.expandArray[i]; - this.falseAllExpand(); - this.$scope.expandArray[i] = !oldValue; - } -} diff --git a/plugins/main/public/controllers/agent/components/export-configuration.js b/plugins/main/public/controllers/agent/components/export-configuration.js deleted file mode 100644 index 0c3ee40f33..0000000000 --- a/plugins/main/public/controllers/agent/components/export-configuration.js +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Wazuh app - React component for exporting the configuration of a group. - * Copyright (C) 2015-2022 Wazuh, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Find more information about this on the LICENSE file. - */ -import React, { Component } from 'react'; - -import { - EuiPopover, - EuiButton, - EuiCheckboxGroup, - EuiSpacer, - EuiButtonEmpty -} from '@elastic/eui'; - -import PropTypes from 'prop-types'; -import { UnsupportedComponents } from '../../../utils/components-os-support'; -import { WAZUH_AGENTS_OS_TYPE } from '../../../../common/constants'; -import { withErrorBoundary } from '../../../components/common/hocs'; - -export const ExportConfiguration = withErrorBoundary (class ExportConfiguration extends Component { - constructor(props) { - super(props); - - this.state = { - buttonDisabled: false, - isPopoverOpen: false - }; - - const agentOptions = [ - 'Global configuration', - 'Communication', - 'Anti-flooding settings', - 'Labels', - 'Policy monitoring', - { name: 'oscap', desc: 'OpenSCAP' }, - 'CIS-CAT', - 'Osquery', - 'Inventory data', - 'Active response', - 'Commands', - { name: 'docker', desc: 'Docker listener' }, - 'Log collection', - 'Integrity monitoring' - ]; - const groupOptions = ['Configurations', 'Agents in group']; - - this.options = []; - const list = this.props.type === 'agent' ? agentOptions : groupOptions; - list.forEach((x, idx) => { - if ( - typeof x === 'string' || - (x.name && - !( - UnsupportedComponents[this.props.agentPlatform] || - UnsupportedComponents[WAZUH_AGENTS_OS_TYPE.OTHERS] - ).includes(x.name)) - ) { - this.options.push({ id: `${idx}`, label: x.desc || x }); - } - }); - - let initialChecks = {}; - this.options.forEach(x => { - initialChecks[x.id] = true; - }); - this.state.checkboxIdToSelectedMap = initialChecks; - } - - selectAll(flag) { - let newCheckboxIdToSelectedMap = {}; - for (let i = 0; i < this.options.length; i++) { - newCheckboxIdToSelectedMap[`${this.options[i].id}`] = flag; - } - this.setState({ - checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, - buttonDisabled: !flag - }); - } - - exportClick() { - this.setState({ - isPopoverOpen: !this.state.isPopoverOpen - }); - } - - closePopover() { - this.setState({ - isPopoverOpen: false - }); - } - - onChange = optionId => { - const newCheckboxIdToSelectedMap = { - ...this.state.checkboxIdToSelectedMap, - ...{ - [optionId]: !this.state.checkboxIdToSelectedMap[optionId] - } - }; - let result = false; - for (let i = 0; i < this.options.length; i++) { - if (newCheckboxIdToSelectedMap[`${this.options[i].id}`] === true) { - result = true; - } - } - this.setState({ - checkboxIdToSelectedMap: newCheckboxIdToSelectedMap, - buttonDisabled: !result - }); - }; - - render() { - const button = ( - - Export PDF - - ); - return ( - - - - {this.options.length > 3 && - <> this.selectAll(true)}> - Select all - this.selectAll(false)}> - Unselect all - } - - { - this.closePopover(); - this.props.exportConfiguration(this.state.checkboxIdToSelectedMap); - }} - fill - > - Generate PDF report - - - ); - } -}); - -ExportConfiguration.propTypes = { - exportConfiguration: PropTypes.func, - type: PropTypes.string, - agentPlatform: PropTypes.string -}; diff --git a/plugins/main/public/controllers/agent/index.js b/plugins/main/public/controllers/agent/index.js index 960ac79295..cb75bf45d0 100644 --- a/plugins/main/public/controllers/agent/index.js +++ b/plugins/main/public/controllers/agent/index.js @@ -9,28 +9,16 @@ * * Find more information about this on the LICENSE file. */ -import { AgentsController } from './agents'; import { RegisterAgent } from '../../components/endpoints-summary/register-agent/containers/register-agent/register-agent'; -import { ExportConfiguration } from './components/export-configuration'; -import { AgentsWelcome } from '../../components/common/welcome/agents-welcome'; -import { Mitre } from '../../components/overview'; -import { AgentsTable } from '../../components/endpoints-summary/table/agents-table'; import { MainModule } from '../../components/common/modules/main'; -import { MainSyscollector } from '../../components/agents/syscollector/main'; -import { MainAgentStats } from '../../components/agents/stats'; import { getAngularModule } from '../../kibana-services'; import { MainEndpointsSummary } from '../../components/endpoints-summary'; +import { AgentView } from '../../components/endpoints-summary/agent'; const app = getAngularModule(); app - .controller('agentsController', AgentsController) .value('RegisterAgent', RegisterAgent) - .value('ExportConfiguration', ExportConfiguration) - .value('AgentsWelcome', AgentsWelcome) - .value('Mitre', Mitre) - .value('AgentsTable', AgentsTable) - .value('MainSyscollector', MainSyscollector) - .value('MainAgentStats', MainAgentStats) + .value('AgentView', AgentView) .value('MainModule', MainModule) .value('MainEndpointsSummary', MainEndpointsSummary); diff --git a/plugins/main/public/controllers/management/components/files-group-table.js b/plugins/main/public/controllers/management/components/files-group-table.js index 5736923a07..61ff65dd56 100644 --- a/plugins/main/public/controllers/management/components/files-group-table.js +++ b/plugins/main/public/controllers/management/components/files-group-table.js @@ -21,10 +21,10 @@ import { EuiTitle, EuiButtonEmpty, EuiText, - EuiToolTip + EuiToolTip, } from '@elastic/eui'; -import { ExportConfiguration } from '../../agent/components/export-configuration'; +import { ExportConfiguration } from '../../../components/agents/export-configuration'; import { ReportingService } from '../../../react-services/reporting'; export class FilesInGroupTable extends Component { @@ -36,7 +36,7 @@ export class FilesInGroupTable extends Component { groupName: this.props.group.name || 'Group', files: [], originalfiles: [], - isLoading: false + isLoading: false, }; this.filters = { name: 'search', value: '' }; @@ -47,7 +47,7 @@ export class FilesInGroupTable extends Component { const files = await this.props.getFilesFromGroup(this.props.group.name); this.setState({ files: files, - originalfiles: files + originalfiles: files, }); } catch (error) { console.error('error mounting the component ', error); @@ -66,7 +66,7 @@ export class FilesInGroupTable extends Component { : this.state.originalfiles; this.setState({ isLoading: false, - files: items + files: items, }); } }; @@ -80,7 +80,7 @@ export class FilesInGroupTable extends Component { const files = await this.props.getFilesFromGroup(this.props.group.name); this.setState({ originalfiles: files, - refreshingFiles: false + refreshingFiles: false, }); } catch (error) { this.setState({ refreshingFiles: false }); @@ -93,45 +93,45 @@ export class FilesInGroupTable extends Component { { field: 'filename', name: 'File', - sortable: true + sortable: true, }, { field: 'hash', name: 'Checksum', - sortable: true + sortable: true, }, { name: 'Actions', render: item => { return ( - + + aria-label='See file content' + onClick={() => this.props.openFileContent( this.state.groupName, - item.filename + item.filename, ) } - iconType="eye" + iconType='eye' /> ); - } - } + }, + }, ]; const search = { onChange: this.onQueryChange, box: { incremental: this.state.incremental, - schema: true - } + schema: true, + }, }; return ( - + @@ -144,8 +144,8 @@ export class FilesInGroupTable extends Component { this.props.editConfig()} > Edit group configuration @@ -157,7 +157,7 @@ export class FilesInGroupTable extends Component { this.reportingService.startConfigReport( this.props.state.itemDetail, 'groupConfig', - enabledComponents + enabledComponents, ) } type='group' @@ -165,7 +165,7 @@ export class FilesInGroupTable extends Component { await this.props.export(this.state.groupName, [this.filters]) } @@ -174,21 +174,21 @@ export class FilesInGroupTable extends Component { - this.refresh()}> + this.refresh()}> Refresh - + From here you can list and see your group files, also, you can edit the group configuration )) || )} @@ -493,12 +492,12 @@ export default compose( props.agent.id === '000' ? { action: 'manager:read', resource: '*:*:*' } : [ - { action: 'agent:read', resource: `agent:id:${props.agent.id}` }, - ...(props.agent.group || []).map(group => ({ - action: 'agent:read', - resource: `agent:group:${group}`, - })), - ], + { action: 'agent:read', resource: `agent:id:${props.agent.id}` }, + ...(props.agent.group || []).map(group => ({ + action: 'agent:read', + resource: `agent:group:${group}`, + })), + ], ]), //TODO: this need cluster:read permission but manager/cluster is managed in WzConfigurationSwitch component withRenderIfOrWrapped( props => props.agent.status === API_NAME_AGENT_STATUS.NEVER_CONNECTED, diff --git a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js index fa3ffc0a7d..4f3d377178 100644 --- a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js +++ b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-agents.js @@ -18,7 +18,7 @@ import { connect } from 'react-redux'; import { updateShowAddAgents } from '../../../../../redux/actions/groupsActions'; import GroupsHandler from './utils/groups-handler'; -import { ExportConfiguration } from '../../../../agent/components/export-configuration'; +import { ExportConfiguration } from '../../../../../components/agents/export-configuration'; import { ReportingService } from '../../../../../react-services/reporting'; class WzGroupsActionButtonsAgents extends Component { diff --git a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js index 32a7bec71c..cfb6defa34 100644 --- a/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js +++ b/plugins/main/public/controllers/management/components/management/groups/actions-buttons-files.js @@ -18,7 +18,7 @@ import { connect } from 'react-redux'; import { updateFileContent } from '../../../../../redux/actions/groupsActions'; import GroupsHandler from './utils/groups-handler'; -import { ExportConfiguration } from '../../../../agent/components/export-configuration'; +import { ExportConfiguration } from '../../../../../components/agents/export-configuration'; import { WzButtonPermissions } from '../../../../../components/common/permissions/button'; import { ReportingService } from '../../../../../react-services/reporting'; diff --git a/plugins/main/public/templates/agents/dashboards.html b/plugins/main/public/templates/agents/dashboards.html index 33fe5c8c5e..93330667b7 100644 --- a/plugins/main/public/templates/agents/dashboards.html +++ b/plugins/main/public/templates/agents/dashboards.html @@ -1,138 +1 @@ - -
-
- -
- - - -
-
-
- -
-
-
- - -
-
- -
-
-
-
- -
-
-
- -
- -
- - -
-
-
- - - - - - -
-
{{loadingStatus}}
-
-
- - -
-
-
- - - - - - -
-
{{reportStatus}}
-
-
-
- -
- -
- - -
-
- -
-
-
- - -
- -
- - -
- -
- - -
+ diff --git a/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts b/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts index 27db0c5f70..20e62748bd 100644 --- a/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts +++ b/plugins/main/server/integration-files/visualizations/agents/agents-welcome.ts @@ -24,7 +24,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -57,7 +62,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -105,7 +116,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -138,7 +154,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -186,7 +208,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -219,7 +246,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -267,7 +300,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -300,7 +338,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -348,7 +392,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -381,7 +430,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -429,7 +484,12 @@ export default [ addLegend: true, legendPosition: 'right', isDonut: true, - labels: { show: false, values: true, last_level: true, truncate: 100 }, + labels: { + show: false, + values: true, + last_level: true, + truncate: 100, + }, dimensions: { metric: { accessor: 1, @@ -462,7 +522,13 @@ export default [ }, }, aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, + { + id: '1', + enabled: true, + type: 'count', + schema: 'metric', + params: {}, + }, { id: '2', enabled: true, @@ -496,106 +562,4 @@ export default [ }, }, }, - { - _id: 'Wazuh-App-Agents-Welcome-Events-Evolution', - _type: 'visualization', - _source: { - title: 'Events evolution', - visState: JSON.stringify({ - title: 'event evolution', - type: 'line', - params: { - type: 'line', - grid: { categoryLines: false }, - categoryAxes: [ - { - id: 'CategoryAxis-1', - type: 'category', - position: 'bottom', - show: true, - style: {}, - scale: { type: 'linear' }, - labels: { show: true, filter: true, truncate: 100 }, - title: {}, - }, - ], - valueAxes: [ - { - id: 'ValueAxis-1', - name: 'LeftAxis-1', - type: 'value', - position: 'left', - show: true, - style: {}, - scale: { type: 'linear', mode: 'normal' }, - labels: { show: true, rotate: 0, filter: false, truncate: 100 }, - title: { text: 'Count' }, - }, - ], - seriesParams: [ - { - show: true, - type: 'line', - mode: 'normal', - data: { label: 'Count', id: '1' }, - valueAxis: 'ValueAxis-1', - drawLinesBetweenPoints: true, - lineWidth: 2, - interpolate: 'linear', - showCircles: true, - }, - ], - addTooltip: true, - addLegend: false, - legendPosition: 'right', - times: [], - addTimeMarker: false, - labels: {}, - thresholdLine: { show: false, value: 10, width: 1, style: 'full', color: '#E7664C' }, - dimensions: { - x: null, - y: [ - { - accessor: 0, - format: { id: 'number' }, - params: {}, - label: 'Count', - aggType: 'count', - }, - ], - }, - }, - aggs: [ - { id: '1', enabled: true, type: 'count', schema: 'metric', params: {} }, - { - id: '2', - enabled: true, - type: 'date_histogram', - schema: 'segment', - params: { - field: 'timestamp', - useNormalizedEsInterval: true, - scaleMetricValues: false, - interval: 'auto', - drop_partials: false, - min_doc_count: 1, - extended_bounds: {}, - }, - }, - ], - }), - uiStateJSON: JSON.stringify({ - vis: { params: { sort: { columnIndex: 2, direction: 'desc' } } }, - }), - description: '', - version: 1, - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - index: 'wazuh-alerts', - query: { query: '', language: 'lucene' }, - filter: [], - }), - }, - }, - }, ]; From 755d7881e1ecbe6275fb03c86c5be2c28b36af25 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Tue, 30 Apr 2024 18:41:15 +0200 Subject: [PATCH 17/18] Update snapshot --- .../__snapshots__/stats.test.tsx.snap | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/plugins/main/public/controllers/overview/components/__snapshots__/stats.test.tsx.snap b/plugins/main/public/controllers/overview/components/__snapshots__/stats.test.tsx.snap index 43ff09536c..6d4b715a74 100644 --- a/plugins/main/public/controllers/overview/components/__snapshots__/stats.test.tsx.snap +++ b/plugins/main/public/controllers/overview/components/__snapshots__/stats.test.tsx.snap @@ -22,6 +22,7 @@ exports[`Stats component renders correctly to match the snapshot 1`] = ` class="euiCard__children" >
+ > + +
@@ -105,11 +110,11 @@ exports[`Stats component renders correctly to match the snapshot 1`] = `
- +
Rule level 15 or higher @@ -150,11 +155,11 @@ exports[`Stats component renders correctly to match the snapshot 1`] = `
- +
Rule level 12 to 14 @@ -195,11 +200,11 @@ exports[`Stats component renders correctly to match the snapshot 1`] = `
- +
Rule level 7 to 11 @@ -240,11 +245,11 @@ exports[`Stats component renders correctly to match the snapshot 1`] = `
- +
Rule level 0 to 6 From d0da634674f57d0818ebf7bd019578312b17f065 Mon Sep 17 00:00:00 2001 From: Federico Rodriguez Date: Tue, 30 Apr 2024 19:30:08 +0200 Subject: [PATCH 18/18] Add agent.id condition to WzConfigurationSwitch HOC --- .../configuration/configuration-switch.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js b/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js index ba4462a1be..fe51c982ff 100644 --- a/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js +++ b/plugins/main/public/controllers/management/components/management/configuration/configuration-switch.js @@ -492,15 +492,17 @@ export default compose( props.agent.id === '000' ? { action: 'manager:read', resource: '*:*:*' } : [ - { action: 'agent:read', resource: `agent:id:${props.agent.id}` }, - ...(props.agent.group || []).map(group => ({ - action: 'agent:read', - resource: `agent:group:${group}`, - })), - ], + { action: 'agent:read', resource: `agent:id:${props.agent.id}` }, + ...(props.agent.group || []).map(group => ({ + action: 'agent:read', + resource: `agent:group:${group}`, + })), + ], ]), //TODO: this need cluster:read permission but manager/cluster is managed in WzConfigurationSwitch component withRenderIfOrWrapped( - props => props.agent.status !== API_NAME_AGENT_STATUS.ACTIVE, + props => + props.agent.id !== '000' && + props.agent.status !== API_NAME_AGENT_STATUS.ACTIVE, PromptNoActiveAgentWithoutSelect, ), connect(mapStateToProps, mapDispatchToProps),