Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task/mac-eventing-form #62999

Merged
merged 12 commits into from
Apr 10, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export const generatePolicy = (): PolicyConfig => {
mac: {
events: {
process: true,
// TODO, is this right?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhhh gotta take away these TODOs

file: true,
// TODO, is this right?
network: true,
},
malware: {
mode: ProtectionModes.detect,
Expand All @@ -67,6 +71,10 @@ export const generatePolicy = (): PolicyConfig => {
linux: {
events: {
process: true,
// TODO, is this right?
file: true,
// TODO, is this right?
network: true,
},
logging: {
stdout: 'debug',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,33 @@ export function clone(policyDetailsConfig: UIPolicyConfig): UIPolicyConfig {
*/
return clonedConfig as UIPolicyConfig;
}

/**
* Returns value from `configuration`
*/
export const getIn = (a: UIPolicyConfig) => <Key extends keyof UIPolicyConfig>(key: Key) => <
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this works to keep us type compliant when we have different combinations of keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this was to make sure the types were still getting passed through correctly

subKey extends keyof UIPolicyConfig[Key]
>(
subKey: subKey
) => <LeafKey extends keyof UIPolicyConfig[Key][subKey]>(
leafKey: LeafKey
): UIPolicyConfig[Key][subKey][LeafKey] => {
return a[key][subKey][leafKey];
};

/**
* Returns cloned `configuration` with `value` set by the `keyPath`.
*/
export const setIn = (a: UIPolicyConfig) => <Key extends keyof UIPolicyConfig>(key: Key) => <
subKey extends keyof UIPolicyConfig[Key]
>(
subKey: subKey
) => <LeafKey extends keyof UIPolicyConfig[Key][subKey]>(leafKey: LeafKey) => <
V extends UIPolicyConfig[Key][subKey][LeafKey]
>(
v: V
): UIPolicyConfig => {
const c = clone(a);
c[key][subKey][leafKey] = v;
return c;
};
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const policyDetailsReducer: Reducer<PolicyDetailsState, AppAction> = (

if (action.type === 'userChangedPolicyConfig') {
const newState = { ...state, policyItem: { ...(state.policyItem as PolicyData) } };
const newPolicy = (newState.policyItem.inputs[0].config.policy.value = {
const newPolicy: any = (newState.policyItem.inputs[0].config.policy.value = {
...fullPolicy(state),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,32 @@ export const selectedWindowsEventing = (state: PolicyDetailsState): number => {
return 0;
};

/** Returns an object of all the mac eventing configurations */
export const macEventing = (state: PolicyDetailsState) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probs going to remove this guy.

const config = policyConfig(state);
return config && config.mac.events;
};

/** Returns the total number of possible mac eventing configurations */
export const totalMacEventing = (state: PolicyDetailsState): number => {
const config = policyConfig(state);
if (config) {
return Object.keys(config.mac.events).length;
}
return 0;
};

/** Returns the number of selected mac eventing configurations */
export const selectedMacEventing = (state: PolicyDetailsState): number => {
const config = policyConfig(state);
if (config) {
return Object.values(config.mac.events).reduce((count, event) => {
return event === true ? count + 1 : count;
}, 0);
}
return 0;
};

/** is there an api call in flight */
export const isLoading = (state: PolicyDetailsState) => state.isLoading;

Expand Down
74 changes: 36 additions & 38 deletions x-pack/plugins/endpoint/public/applications/endpoint/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export interface PolicyListState {
/**
* Policy details store state
*/
export interface PolicyDetailsState {
export type PolicyDetailsState = Immutable<{
/** A single policy item */
policyItem?: PolicyData;
/** API error if loading data failed */
Expand All @@ -112,40 +112,27 @@ export interface PolicyDetailsState {
success: boolean;
error?: ServerApiError;
};
}
}>;

/**
* Endpoint Policy configuration
*/
export interface PolicyConfig {
windows: {
events: {
process: boolean;
network: boolean;
};
/** malware mode can be off, detect, prevent or prevent and notify user */
malware: MalwareFields;
windows: UIPolicyConfig['windows'] & {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious to know why this was needed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying random stuff. Don't think the change is needed

logging: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see you use this same format 3 times here, could be a candidate to abstract

{
  logging: {
     stdout: string;
     file: string;
  }
  advanced: PolicyConfigAdvancedOptions;
}

stdout: string;
file: string;
};
advanced: PolicyConfigAdvancedOptions;
};
mac: {
events: {
process: boolean;
};
malware: MalwareFields;
mac: UIPolicyConfig['mac'] & {
logging: {
stdout: string;
file: string;
};
advanced: PolicyConfigAdvancedOptions;
};
linux: {
events: {
process: boolean;
};
linux: UIPolicyConfig['linux'] & {
logging: {
stdout: string;
file: string;
Expand All @@ -168,29 +155,39 @@ interface PolicyConfigAdvancedOptions {
};
}

/**
* Windows-specific policy configuration that is supported via the UI
*/
type WindowsPolicyConfig = Pick<PolicyConfig['windows'], 'events' | 'malware'>;

/**
* Mac-specific policy configuration that is supported via the UI
*/
type MacPolicyConfig = Pick<PolicyConfig['mac'], 'malware' | 'events'>;

/**
* Linux-specific policy configuration that is supported via the UI
*/
type LinuxPolicyConfig = Pick<PolicyConfig['linux'], 'events'>;

/**
* The set of Policy configuration settings that are show/edited via the UI
*/
export interface UIPolicyConfig {
windows: WindowsPolicyConfig;
mac: MacPolicyConfig;
linux: LinuxPolicyConfig;
}
/* eslint-disable @typescript-eslint/consistent-type-definitions */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why disable this here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed. was just trying random stuff because typescript was beating us up

export type UIPolicyConfig = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you ever use these fields all together and not just selecting one type from the UIPolicyConfig (e.g. UIPolicyConfig['linux'])? What's the benefit of doing it this way as opposed to just having 3 separate types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes as of now, there is one form that changes malware protections for both windows and mac. so it grabs the entire policyconfig and returns back the changed malware protection for both mac and windows. There will probably be other protections like this in the future

windows: {
events: {
process: boolean;
network: boolean;
};
/** malware mode can be off, detect, prevent or prevent and notify user */
malware: MalwareFields;
};
mac: {
events: {
file: boolean;
process: boolean;
network: boolean;
};
malware: MalwareFields;
};

/**
* Linux-specific policy configuration that is supported via the UI
*/
linux: {
events: {
file: boolean;
process: boolean;
network: boolean;
};
};
};

/** OS used in Policy */
export enum OS {
Expand All @@ -203,6 +200,7 @@ export enum OS {
export enum EventingFields {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is used anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i believe you are right!

process = 'process',
network = 'network',
file = 'file',
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ import {
isLoading,
apiError,
} from '../../store/policy_details/selectors';
import { WindowsEventing } from './policy_forms/eventing/windows';
import { PageView, PageViewHeaderTitle } from '../../components/page_view';
import { AppAction } from '../../types';
import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
import { AgentsSummary } from './agents_summary';
import { VerticalDivider } from './vertical_divider';
import { WindowsEventing, MacEventing } from './policy_forms/eventing';
import { MalwareProtections } from './policy_forms/protections/malware';

export const PolicyDetails = React.memo(() => {
Expand Down Expand Up @@ -207,6 +207,8 @@ export const PolicyDetails = React.memo(() => {
</EuiText>
<EuiSpacer size="xs" />
<WindowsEventing />
<EuiSpacer size="l" />
<MacEventing />
</PageView>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,46 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { EuiCheckbox } from '@elastic/eui';
import { useDispatch } from 'react-redux';
import { htmlIdGenerator } from '@elastic/eui';
import { usePolicyDetailsSelector } from '../../policy_hooks';
import { policyConfig, windowsEventing } from '../../../../store/policy_details/selectors';
import { policyConfig } from '../../../../store/policy_details/selectors';
import { PolicyDetailsAction } from '../../../../store/policy_details';
import { OS, EventingFields } from '../../../../types';
import { clone } from '../../../../models/policy_details_config';
import { UIPolicyConfig } from '../../../../types';

export const EventingCheckbox: React.FC<{
id: string;
export const EventingCheckbox = React.memo(function({
name,
setter,
getter,
}: {
name: string;
os: OS;
protectionField: EventingFields;
}> = React.memo(({ id, name, os, protectionField }) => {
setter: (config: UIPolicyConfig, checked: boolean) => UIPolicyConfig;
getter: (config: UIPolicyConfig) => boolean;
}) {
const policyDetailsConfig = usePolicyDetailsSelector(policyConfig);
const eventing = usePolicyDetailsSelector(windowsEventing);
const selected = getter(policyDetailsConfig);
const dispatch = useDispatch<(action: PolicyDetailsAction) => void>();

const handleRadioChange = useCallback(
const handleCheckboxChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
if (policyDetailsConfig) {
const newPayload = clone(policyDetailsConfig);
if (os === OS.linux || os === OS.mac) {
newPayload[os].events.process = event.target.checked;
} else {
newPayload[os].events[protectionField] = event.target.checked;
}

dispatch({
type: 'userChangedPolicyConfig',
payload: { policyConfig: newPayload },
payload: { policyConfig: setter(policyDetailsConfig, event.target.checked) },
});
}
},
[dispatch, os, policyDetailsConfig, protectionField]
[dispatch, policyDetailsConfig, setter]
);

return (
<EuiCheckbox
id={id}
id={useMemo(() => htmlIdGenerator()(), [])}
label={name}
checked={eventing && eventing[protectionField]}
onChange={handleRadioChange}
checked={selected}
onChange={handleCheckboxChange}
/>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export { WindowsEventing } from './windows';
export { MacEventing } from './mac';
Loading