diff --git a/CHANGELOG.md b/CHANGELOG.md index c61a5b03c7..d11dcd927e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to the Wazuh app project will be documented in this file. ### Fixed +- Fixed an issue that caused incorrect visualization of IPv6 addresses ([#4909](https://github.com/wazuh/wazuh-kibana-app/pull/4909)). - Fixed several typos in the code, by @jctello [#4911](https://github.com/wazuh/wazuh-kibana-app/pull/4911) - Fixed references to Elasticsearch in Wazuh-stack plugin [4894](https://github.com/wazuh/wazuh-kibana-app/pull/4894) diff --git a/public/components/common/welcome/agents-info.js b/public/components/common/welcome/agents-info.js index 1a5a04cc26..e34e62c2f2 100644 --- a/public/components/common/welcome/agents-info.js +++ b/public/components/common/welcome/agents-info.js @@ -25,6 +25,7 @@ import WzTextWithTooltipIfTruncated from '../wz-text-with-tooltip-if-truncated'; import { WzStat } from '../../wz-stat'; import { GroupTruncate } from '../util/agent-group-truncate' import { AgentStatus } from '../../agents/agent_status'; +import { compressIPv6 } from '../../../services/ipv6-services'; export class AgentInfo extends Component { constructor(props) { @@ -33,7 +34,7 @@ export class AgentInfo extends Component { this.state = {}; } - + async componentDidMount() { const managerVersion = await WzRequest.apiReq('GET', '/', {}); this.setState({ @@ -73,7 +74,7 @@ export class AgentInfo extends Component { const osName = os_name === '- -' ? '-' : os_name; return ( - + {this.getPlatformIcon(this.props.agent)} {' '}{osName} @@ -99,13 +100,13 @@ export class AgentInfo extends Component { ) } - buildStats(items) { + buildStats(items) { const checkField = field => { return field !== undefined || field ? field : '-'; }; const stats = items.map(item => { // We add tooltipProps, so that the ClusterNode and Operating System fields occupy their space and do not exceed this, overlapping with the one on the right - const tooltipProps = item.description === 'Cluster node' ? { anchorClassName: 'wz-width-100'} : {}; + const tooltipProps = item.description === 'Cluster node' ? { anchorClassName: 'wz-width-100' } : {}; return ( + ) : ( {checkField(item.title)} @@ -157,7 +158,7 @@ export class AgentInfo extends Component { arrayStats = [ { title: agent.id, description: 'ID', style: { minWidth: 30 } }, { title: agent.status, description: 'Status', style: { minWidth: 130 } }, - { title: agent.ip, description: 'IP', style: { minWidth: 80 } }, + { title: compressIPv6(agent.ip), description: 'IP', style: {} }, { title: agent.version, description: 'Version', style: { minWidth: 100 } }, { title: agent.group, description: 'Groups', style: { minWidth: 150 } }, { title: agent.name, description: 'Operating system', style: { minWidth: 150 } }, @@ -173,7 +174,7 @@ export class AgentInfo extends Component { return ( - + {stats} diff --git a/public/controllers/agent/components/agents-table.js b/public/controllers/agent/components/agents-table.js index ee67623e97..05675e1fa9 100644 --- a/public/controllers/agent/components/agents-table.js +++ b/public/controllers/agent/components/agents-table.js @@ -41,6 +41,7 @@ import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/ import { getErrorOrchestrator } from '../../../react-services/common-services'; import { AgentStatus } from '../../../components/agents/agent_status'; import { AgentSynced } from '../../../components/agents/agent-synced'; +import { compressIPv6 } from '../../../services/ipv6-services'; export const AgentsTable = withErrorBoundary( class AgentsTable extends Component { @@ -284,11 +285,10 @@ export const AgentsTable = withErrorBoundary( }; const agentVersion = agent.version !== undefined ? agent.version.split(' ')[1] : '-'; const node_name = agent.node_name && agent.node_name !== 'unknown' ? agent.node_name : '-'; - return { id: agent.id, name: agent.name, - ip: agent.ip, + ip: compressIPv6(agent.ip), status: agent.status, group_config_status: agent.group_config_status, group: checkField(agent.group), @@ -465,7 +465,7 @@ export const AgentsTable = withErrorBoundary( field: 'id', name: 'ID', sortable: true, - width: '6%', + width: '4%', }, { field: 'name', @@ -477,14 +477,14 @@ export const AgentsTable = withErrorBoundary( { field: 'ip', name: 'IP', - width: '8%', + width: '14%', truncateText: true, sortable: true, }, { field: 'group', name: 'Group(s)', - width: '14%', + width: '12%', truncateText: true, sortable: true, render: (groups) => (groups !== '-' ? this.renderGroups(groups) : '-'), @@ -530,7 +530,7 @@ export const AgentsTable = withErrorBoundary( name: 'Status', truncateText: true, sortable: true, - width: '10%', + width: '8%', render: (status) => , }, { @@ -539,7 +539,7 @@ export const AgentsTable = withErrorBoundary( truncateText: true, sortable: true, width: '10%', - render: (synced) => , + render: (synced) => , }, { align: 'right', @@ -671,7 +671,7 @@ export const AgentsTable = withErrorBoundary( return { 'data-test-subj': `row-${id}`, className: 'customRowClass', - onClick: () => {}, + onClick: () => { }, }; }; @@ -700,11 +700,11 @@ export const AgentsTable = withErrorBoundary( const pagination = totalItems > 15 ? { - pageIndex: pageIndex, - pageSize: pageSize, - totalItemCount: totalItems, - pageSizeOptions: [15, 25, 50, 100], - } + pageIndex: pageIndex, + pageSize: pageSize, + totalItemCount: totalItems, + pageSizeOptions: [15, 25, 50, 100], + } : false; const sorting = { sort: { @@ -739,8 +739,8 @@ export const AgentsTable = withErrorBoundary( if (filters.length > 0) { !auxFilters.includes(group) ? this.setState({ - filters: [...filters, { field: 'q', value: `group=${group}` }], - }) + filters: [...filters, { field: 'q', value: `group=${group}` }], + }) : false; } else { this.setState({ diff --git a/public/services/ipv6-services.test.js b/public/services/ipv6-services.test.js new file mode 100644 index 0000000000..9887751b65 --- /dev/null +++ b/public/services/ipv6-services.test.js @@ -0,0 +1,21 @@ +import { compressIPv6 } from "./ipv6-services"; + +describe('[settings] Input validation', () => { + it.each` + value | expectedValidation + ${'192.168.100.1'} | ${'192.168.100.1'} + ${'FE80:1234:2223:A000:2202:B3FF:FE1E:8329'} | ${'FE80:1234:2223:A000:2202:B3FF:FE1E:8329'} + ${'FE80:0034:0223:A000:0002:B3FF:0000:8329'} | ${'FE80:34:223:A000:2:B3FF:0:8329'} + ${'FE80:1234:2223:0000:0000:B3FF:FE1E:8329'} | ${'FE80:1234:2223::B3FF:FE1E:8329'} + ${'FE80:0000:0000:A000:0000:0000:0000:8329'} | ${'FE80:0:0:A000::8329'} + ${'FE80:0000:0000:0000:2202:00FF:0E1E:8329'} | ${'FE80::2202:FF:E1E:8329'} + ${'0000:0000:0000:0000:2202:00FF:0E1E:8329'} | ${'::2202:FF:E1E:8329'} + ${'2202:00FF:0E1E:8329:2202:0000:0000:0000'} | ${'2202:FF:E1E:8329:2202::'} + ${'0000:0000:0000:0000:0000:0000:0000:0000'} | ${'::'} + ${undefined} | ${undefined} + ${234} | ${234} + `('$value | $expectedValidation', ({ value, expectedValidation }) => { + expect( + compressIPv6(value)).toBe(expectedValidation); + }); +}); diff --git a/public/services/ipv6-services.ts b/public/services/ipv6-services.ts new file mode 100644 index 0000000000..ac7fe331c2 --- /dev/null +++ b/public/services/ipv6-services.ts @@ -0,0 +1,21 @@ +export function compressIPv6 (ip: string) { + if (typeof (ip) !== 'string') { + return ip; + } + if (ip?.split(':').length !== 8) { + return ip; + } + + let output = ip.split(':').map(terms => terms.replace(/\b0+/g, '') || '0').join(':'); + const zeros = Array.from(output.matchAll(/\b:?(?:0+:?){2,}/g)); + if (zeros.length > 0) { + let max = ''; + zeros.forEach(item => { + if (item[0].replace(/:/g, '').length > max.replace(/:/g, '').length) { + max = item[0]; + } + }); + output = output.replace(max, '::'); + } + return output; +}