Skip to content

Commit

Permalink
use the new entry type
Browse files Browse the repository at this point in the history
  • Loading branch information
ashokaditya committed Apr 26, 2021
1 parent f9cb7ed commit b3f5dc4
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { schema } from '@kbn/config-schema';
import { ConditionEntry, ConditionEntryField, OperatingSystem, OperatorEntryField } from '../types';
import { ConditionEntry, ConditionEntryField, OperatingSystem } from '../types';
import { getDuplicateFields, isValidHash } from '../service/trusted_apps/validations';

export const DeleteTrustedAppsRequestSchema = {
Expand All @@ -29,17 +29,13 @@ export const GetTrustedAppsRequestSchema = {
}),
};

const ConditionEntryTypeSchema = schema.literal('match');
// when field === PATH -> operator in ('included', 'wildcard_caseless') else operator === 'included'
const ConditionEntryOperatorSchema = schema.conditional(
const ConditionEntryTypeSchema = schema.conditional(
schema.siblingRef('field'),
ConditionEntryField.PATH,
schema.oneOf([
schema.literal(OperatorEntryField.included),
schema.literal(OperatorEntryField.wildcard_caseless),
]),
schema.literal(OperatorEntryField.included)
schema.oneOf([schema.literal('match'), schema.literal('wildcard')]),
schema.literal('match')
);
const ConditionEntryOperatorSchema = schema.literal('included' as ConditionEntry['operator']);

/*
* A generic Entry schema to be used for a specific entry schema depending on the OS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import { TypeOf } from '@kbn/config-schema';
import { ApplicationStart } from 'kibana/public';

import { Entry } from '../../../../lists/common/schemas/types/entries';
import {
DeleteTrustedAppsRequestSchema,
GetOneTrustedAppRequestSchema,
Expand Down Expand Up @@ -69,14 +71,15 @@ export enum ConditionEntryField {
SIGNER = 'process.Ext.code_signature',
}

export enum OperatorEntryField {
included = 'included',
wildcard_caseless = 'wildcard_caseless',
export enum OperatorFieldIds {
is = 'is',
matches = 'matches',
}

export interface ConditionEntry<T extends ConditionEntryField = ConditionEntryField> {
field: T;
type: 'match';
operator: keyof typeof OperatorEntryField;
type: Entry['type'];
operator: 'included';
value: string;
}

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/security_solution/common/shared_imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export {
EntryExists,
EntryMatch,
EntryMatchAny,
EntriesMatchWildcardCaseless,
EntryNested,
EntryList,
EntriesArray,
Expand All @@ -38,6 +39,7 @@ export {
nestedEntryItem,
entriesMatch,
entriesMatchAny,
entriesMatchWildcardCaseless,
entriesExists,
entriesList,
namespaceType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Entry,
EntryMatch,
EntryMatchAny,
EntriesMatchWildcardCaseless,
EntryExists,
ExceptionListItemSchema,
CreateExceptionListItemSchema,
Expand Down Expand Up @@ -92,6 +93,7 @@ export interface EmptyNestedEntry {
type: OperatorTypeEnum.NESTED;
entries: Array<
| (EntryMatch & { id?: string })
| (EntriesMatchWildcardCaseless & { id?: string })
| (EntryMatchAny & { id?: string })
| (EntryExists & { id?: string })
>;
Expand All @@ -108,6 +110,7 @@ export type BuilderEntryNested = Omit<EntryNested, 'entries'> & {
id?: string;
entries: Array<
| (EntryMatch & { id?: string })
| (EntriesMatchWildcardCaseless & { id?: string })
| (EntryMatchAny & { id?: string })
| (EntryExists & { id?: string })
>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import {
ConditionEntry,
ConditionEntryField,
OperatorEntryField,
OperatorFieldIds,
OperatingSystem,
} from '../../../../../../../common/endpoint/types';

Expand Down Expand Up @@ -79,10 +79,10 @@ const InputItem = styled.div`
vertical-align: baseline;
`;

const operatorOptions = (Object.keys(OperatorEntryField) as OperatorEntryField[]).map((value) => ({
const operatorOptions = (Object.keys(OperatorFieldIds) as OperatorFieldIds[]).map((value) => ({
dropdownDisplay: OPERATOR_TITLES[value],
inputDisplay: OPERATOR_TITLES[value],
value,
value: value === 'matches' ? 'wildcard' : 'match',
}));

export const ConditionEntryInput = memo<ConditionEntryInputProps>(
Expand Down Expand Up @@ -144,7 +144,7 @@ export const ConditionEntryInput = memo<ConditionEntryInputProps>(
);

const handleOperatorUpdate = useCallback(
(newOperator) => onChange({ ...entry, operator: newOperator }, entry),
(newOperator) => onChange({ ...entry, type: newOperator }, entry),
[entry, onChange]
);

Expand Down Expand Up @@ -174,13 +174,13 @@ export const ConditionEntryInput = memo<ConditionEntryInputProps>(
<EuiSuperSelect
options={operatorOptions}
onChange={handleOperatorUpdate}
valueOfSelected={entry.operator}
valueOfSelected={entry.type}
data-test-subj={getTestId('operator')}
/>
) : (
<EuiFieldText
name="operator"
value={OPERATOR_TITLES.included}
value={OPERATOR_TITLES.is}
data-test-subj={getTestId('operator')}
readOnly
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const getEntriesColumnDefinitions = (): Array<EuiTableFieldDataColumnType<Entry>
truncateText: true,
textOnly: true,
width: '30%',
render(field: Entry['field'], entry: Entry) {
render(field: Entry['field'], _entry: Entry) {
return CONDITION_FIELD_TITLE[field];
},
},
Expand All @@ -55,8 +55,8 @@ const getEntriesColumnDefinitions = (): Array<EuiTableFieldDataColumnType<Entry>
sortable: false,
truncateText: true,
width: '20%',
render(field: Entry['operator'], entry: Entry) {
return OPERATOR_TITLES[field];
render(_field: Entry['operator'], entry: Entry) {
return entry.type === 'wildcard' ? OPERATOR_TITLES.matches : OPERATOR_TITLES.is;
},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
MacosLinuxConditionEntry,
WindowsConditionEntry,
ConditionEntryField,
OperatorEntryField,
OperatorFieldIds,
} from '../../../../../common/endpoint/types';

export { OS_TITLES } from '../../../common/translations';
Expand Down Expand Up @@ -52,19 +52,13 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in ConditionEntryField]: string }
),
};

export const OPERATOR_TITLES: { [K in OperatorEntryField]: string } = {
[OperatorEntryField.included]: i18n.translate(
'xpack.securitySolution.trustedapps.card.operator.is',
{
defaultMessage: 'is',
}
),
[OperatorEntryField.wildcard_caseless]: i18n.translate(
'xpack.securitySolution.trustedapps.card.operator.matches',
{
defaultMessage: 'matches',
}
),
export const OPERATOR_TITLES: { [K in OperatorFieldIds]: string } = {
is: i18n.translate('xpack.securitySolution.trustedapps.card.operator.is', {
defaultMessage: 'is',
}),
matches: i18n.translate('xpack.securitySolution.trustedapps.card.operator.matches', {
defaultMessage: 'matches',
}),
};

export const PROPERTY_TITLES: Readonly<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import uuid from 'uuid';

import { OsType } from '../../../../../lists/common/schemas';
import {
Entry,
EntriesArray,
EntryMatch,
EntriesMatchWildcardCaseless,
EntryNested,
ExceptionListItemSchema,
NestedEntriesArray,
Operator,
} from '../../../../../lists/common';
import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants';
import {
Expand All @@ -27,7 +28,6 @@ import {
EffectScope,
NewTrustedApp,
OperatingSystem,
OperatorEntryField,
TrustedApp,
UpdateTrustedApp,
} from '../../../../common/endpoint/types';
Expand All @@ -48,17 +48,18 @@ const OPERATING_SYSTEM_TO_OS_TYPE: Mapping<OperatingSystem, OsType> = {
};

const POLICY_REFERENCE_PREFIX = 'policy:';
const OPERATOR_VALUE = 'included';

const filterUndefined = <T>(list: Array<T | undefined>): T[] => {
return list.filter((item: T | undefined): item is T => item !== undefined);
};

export const createConditionEntry = <T extends ConditionEntryField, O extends OperatorEntryField>(
export const createConditionEntry = <T extends ConditionEntryField>(
field: T,
operator: O,
type: Entry['type'],
value: string
): ConditionEntry<T> => {
return { field, value, type: 'match', operator };
return { field, value, type, operator: OPERATOR_VALUE };
};

export const tagsToEffectScope = (tags: string[]): EffectScope => {
Expand All @@ -76,46 +77,26 @@ export const tagsToEffectScope = (tags: string[]): EffectScope => {
}
};

type TrustedAppsEntriesArray = Omit<EntriesArray, 'operator'> & {
operator: Operator | 'wildcard_caseless';
};

export const entriesToConditionEntriesMap = (
entries: TrustedAppsEntriesArray
): ConditionEntriesMap => {
export const entriesToConditionEntriesMap = (entries: EntriesArray): ConditionEntriesMap => {
return entries.reduce((result, entry) => {
if (entry.field.startsWith('process.hash') && entry.type === 'match') {
return {
...result,
[ConditionEntryField.HASH]: createConditionEntry(
ConditionEntryField.HASH,
OperatorEntryField.included,
entry.value
),
};
} else if (
entry.field === 'process.executable.caseless' &&
entry.type === 'match' &&
entry.operator === OperatorEntryField.wildcard_caseless
) {
return {
...result,
[ConditionEntryField.PATH]: createConditionEntry(
ConditionEntryField.PATH,
OperatorEntryField.wildcard_caseless,
entry.type,
entry.value
),
};
} else if (
entry.field === 'process.executable.caseless' &&
entry.type === 'match' &&
entry.operator === OperatorEntryField.included
(entry.type === 'match' || entry.type === 'wildcard')
) {
return {
...result,
[ConditionEntryField.PATH]: createConditionEntry(
ConditionEntryField.PATH,
OperatorEntryField.included,
entry.type,
entry.value
),
};
Expand All @@ -129,7 +110,7 @@ export const entriesToConditionEntriesMap = (
...result,
[ConditionEntryField.SIGNER]: createConditionEntry(
ConditionEntryField.SIGNER,
OperatorEntryField.included,
entry.type,
subjectNameCondition.value
),
};
Expand Down Expand Up @@ -200,12 +181,15 @@ const hashType = (hash: string): 'md5' | 'sha256' | 'sha1' | undefined => {
}
};

export const createEntryMatch = (
export const createEntryMatch = (field: string, value: string): EntryMatch => {
return { field, value, type: 'match', operator: OPERATOR_VALUE };
};

export const createEntryMatchWildcardCaseless = (
field: string,
operator: OperatorEntryField,
value: string
): EntryMatch => {
return { field, value, type: 'match', operator };
): EntriesMatchWildcardCaseless => {
return { field, value, type: 'wildcard', operator: OPERATOR_VALUE };
};

export const createEntryNested = (field: string, entries: NestedEntriesArray): EntryNested => {
Expand All @@ -225,29 +209,20 @@ export const conditionEntriesToEntries = (conditionEntries: ConditionEntry[]): E
if (conditionEntry.field === ConditionEntryField.HASH) {
return createEntryMatch(
`process.hash.${hashType(conditionEntry.value)}`,
OperatorEntryField.included,
conditionEntry.value.toLowerCase()
);
} else if (conditionEntry.field === ConditionEntryField.SIGNER) {
return createEntryNested(`process.Ext.code_signature`, [
createEntryMatch('trusted', OperatorEntryField.included, 'true'),
createEntryMatch('subject_name', OperatorEntryField.included, conditionEntry.value),
createEntryMatch('trusted', 'true'),
createEntryMatch('subject_name', conditionEntry.value),
]);
} else if (
conditionEntry.field === ConditionEntryField.PATH &&
conditionEntry.operator === OperatorEntryField.wildcard_caseless
conditionEntry.type === 'wildcard'
) {
return createEntryMatch(
`process.executable.caseless`,
OperatorEntryField.wildcard_caseless,
conditionEntry.value
);
return createEntryMatchWildcardCaseless(`process.executable.caseless`, conditionEntry.value);
} else {
return createEntryMatch(
`process.executable.caseless`,
OperatorEntryField.included,
conditionEntry.value
);
return createEntryMatch(`process.executable.caseless`, conditionEntry.value);
}
});
};
Expand Down

0 comments on commit b3f5dc4

Please sign in to comment.