Skip to content

Commit

Permalink
[Security Solution] add ability for network map to be toggable, preve…
Browse files Browse the repository at this point in the history
…nt map from displaying without permissions (#123336)

* add ability for network map to be toggable, prevent map from displaying without permissions

* PR & test additions

* Found rogue semicolon

Co-authored-by: Kristof-Pierre Cummings <kristofpierre.cummings@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 25, 2022
1 parent 607feec commit 57d507c
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 156 deletions.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ jest.mock('../../../common/lib/kibana');
jest.mock('./embedded_map_helpers', () => ({
createEmbeddable: jest.fn(),
}));

const mockGetStorage = jest.fn();
const mockSetStorage = jest.fn();

jest.mock('../../../common/lib/kibana', () => {
return {
useKibana: jest.fn().mockReturnValue({
useKibana: () => ({
services: {
embeddable: {
EmbeddablePanel: jest.fn(() => <div data-test-subj="EmbeddablePanel" />),
Expand All @@ -38,6 +42,10 @@ jest.mock('../../../common/lib/kibana', () => {
siem: { networkMap: '' },
},
},
storage: {
get: mockGetStorage,
set: mockSetStorage,
},
},
}),
};
Expand Down Expand Up @@ -101,6 +109,11 @@ describe('EmbeddedMapComponent', () => {

beforeEach(() => {
setQuery.mockClear();
mockGetStorage.mockReturnValue(false);
});

afterEach(() => {
jest.clearAllMocks();
});

test('renders correctly against snapshot', () => {
Expand Down Expand Up @@ -175,4 +188,38 @@ describe('EmbeddedMapComponent', () => {
expect(wrapper.find('[data-test-subj="loading-panel"]').exists()).toEqual(true);
});
});

test('map hidden on close', async () => {
const wrapper = mount(
<TestProviders>
<EmbeddedMapComponent {...testProps} />
</TestProviders>
);

const container = wrapper.find('[data-test-subj="false-toggle-network-map"]').at(0);
container.simulate('click');

await waitFor(() => {
wrapper.update();
expect(mockSetStorage).toHaveBeenNthCalledWith(1, 'network_map_visbile', true);
});
});

test('map visible on open', async () => {
mockGetStorage.mockReturnValue(true);

const wrapper = mount(
<TestProviders>
<EmbeddedMapComponent {...testProps} />
</TestProviders>
);

const container = wrapper.find('[data-test-subj="true-toggle-network-map"]').at(0);
container.simulate('click');

await waitFor(() => {
wrapper.update();
expect(mockSetStorage).toHaveBeenNthCalledWith(1, 'network_map_visbile', false);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* 2.0.
*/

import { EuiLink, EuiText } from '@elastic/eui';
import { EuiAccordion, EuiLink, EuiText } from '@elastic/eui';
import deepEqual from 'fast-deep-equal';
import React, { useEffect, useState, useMemo } from 'react';
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import { createPortalNode, InPortal } from 'react-reverse-portal';
import styled, { css } from 'styled-components';

Expand All @@ -20,7 +20,6 @@ import { Loader } from '../../../common/components/loader';
import { displayErrorToast, useStateToaster } from '../../../common/components/toasters';
import { GlobalTimeArgs } from '../../../common/containers/use_global_time';
import { Embeddable } from './embeddable';
import { EmbeddableHeader } from './embeddable_header';
import { createEmbeddable } from './embedded_map_helpers';
import { IndexPatternsMissingPrompt } from './index_patterns_missing_prompt';
import { MapToolTip } from './map_tool_tip/map_tool_tip';
Expand All @@ -34,6 +33,8 @@ import { SourcererScopeName } from '../../../common/store/sourcerer/model';
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
import { useSourcererDataView } from '../../../common/containers/sourcerer';

export const NETWORK_MAP_VISIBLE = 'network_map_visbile';

interface EmbeddableMapProps {
maintainRatio?: boolean;
}
Expand Down Expand Up @@ -73,6 +74,17 @@ const EmbeddableMap = styled.div.attrs(() => ({
}
`}
`;

const StyledEuiText = styled(EuiText)`
margin-right: 16px;
`;

const StyledEuiAccordion = styled(EuiAccordion)`
& .euiAccordion__triggerWrapper {
padding: 16px;
}
`;

EmbeddableMap.displayName = 'EmbeddableMap';

export interface EmbeddedMapProps {
Expand All @@ -93,8 +105,13 @@ export const EmbeddedMapComponent = ({
const [embeddable, setEmbeddable] = React.useState<MapEmbeddable | undefined | ErrorEmbeddable>(
undefined
);

const { services } = useKibana();
const { storage } = services;

const [isError, setIsError] = useState(false);
const [isIndexError, setIsIndexError] = useState(false);
const [storageValue, setStorageValue] = useState(storage.get(NETWORK_MAP_VISIBLE) ?? true);

const [, dispatchToaster] = useStateToaster();

Expand All @@ -115,8 +132,6 @@ export const EmbeddedMapComponent = ({
// Search InPortal/OutPortal for implementation touch points
const portalNode = React.useMemo(() => createPortalNode(), []);

const { services } = useKibana();

useEffect(() => {
setMapIndexPatterns((prevMapIndexPatterns) => {
const newIndexPatterns = kibanaDataViews.filter((dataView) =>
Expand Down Expand Up @@ -222,30 +237,50 @@ export const EmbeddedMapComponent = ({
}
}, [embeddable, startDate, endDate]);

const setDefaultMapVisibility = useCallback(
(isOpen: boolean) => {
storage.set(NETWORK_MAP_VISIBLE, isOpen);
setStorageValue(isOpen);
},
[storage]
);

return isError ? null : (
<Embeddable>
<EmbeddableHeader title={i18n.EMBEDDABLE_HEADER_TITLE}>
<EuiText size="xs">
<StyledEuiAccordion
onToggle={setDefaultMapVisibility}
id={'network-map'}
arrowDisplay="right"
arrowProps={{
color: 'primary',
'data-test-subj': `${storageValue}-toggle-network-map`,
}}
buttonContent={<strong>{i18n.EMBEDDABLE_HEADER_TITLE}</strong>}
extraAction={
<StyledEuiText size="xs">
<EuiLink href={`${services.docLinks.links.siem.networkMap}`} target="_blank">
{i18n.EMBEDDABLE_HEADER_HELP}
</EuiLink>
</EuiText>
</EmbeddableHeader>

<InPortal node={portalNode}>
<MapToolTip />
</InPortal>

<EmbeddableMap maintainRatio={!isIndexError}>
{isIndexError ? (
<IndexPatternsMissingPrompt data-test-subj="missing-prompt" />
) : embeddable != null ? (
<services.embeddable.EmbeddablePanel embeddable={embeddable} />
) : (
<Loader data-test-subj="loading-panel" overlay size="xl" />
)}
</EmbeddableMap>
</Embeddable>
</StyledEuiText>
}
paddingSize="none"
initialIsOpen={storageValue}
>
<Embeddable>
<InPortal node={portalNode}>
<MapToolTip />
</InPortal>

<EmbeddableMap maintainRatio={!isIndexError}>
{isIndexError ? (
<IndexPatternsMissingPrompt data-test-subj="missing-prompt" />
) : embeddable != null ? (
<services.embeddable.EmbeddablePanel embeddable={embeddable} />
) : (
<Loader data-test-subj="loading-panel" overlay size="xl" />
)}
</EmbeddableMap>
</Embeddable>
</StyledEuiAccordion>
);
};

Expand Down
Loading

0 comments on commit 57d507c

Please sign in to comment.