Skip to content

Commit

Permalink
[Security Solution][Trusted Apps] New ArtifactEntryCard and refacto…
Browse files Browse the repository at this point in the history
…r of Trusted Apps list to use it (elastic#111051) (elastic#111811)

* New `ArtifactEntryCard` component
* Refactored ContextMenuItemNavByRouter and moved it to top-level components + new ActionsContextMenu component + add context menu to card
* Refactor Trusted App grid to use new ArtifactEntryCard
* new Trusted Apps generator + refactor existing of TA script to use it
* policy details support for custom back link
* bug fix: paginated content should not trigger a change to adjust paging settings unless loading is done

Co-authored-by: Paul Tavares <[email protected]>
  • Loading branch information
kibanamachine and paul-tavares authored Sep 10, 2021
1 parent 9b6629a commit 0ad55ec
Show file tree
Hide file tree
Showing 48 changed files with 11,634 additions and 8,481 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,61 @@ const OS_FAMILY = ['windows', 'macos', 'linux'];
/** Array of 14 day offsets */
const DAY_OFFSETS = Array.from({ length: 14 }, (_, i) => 8.64e7 * (i + 1));

const USERS = [
'elastic',
'shay',
'Damian',
'Sarai',
'Deirdre',
'Shawana',
'Treena',
'Ellamae',
'Myriam',
'Roberto',
'Cordell',
'Demetrice',
'Audrea',
'Shanel',
'Gail',
'Hermila',
'Mara',
'Elden',
'Malisa',
'Derick',
'Teddy',
'Dovie',
'Betty',
'Kay',
'Sharice',
'Evalyn',
'Teressa',
'Teisha',
'Marianne',
'Cherelle',
'Tabitha',
'Deneen',
'Leo',
'Tess',
'Clair',
'Marty',
'Dexter',
'Candis',
'Dina',
'Bennett',
'Vesta',
'Trinity',
'Drusilla',
'Bree',
'Bryon',
'Johnson',
'Justa',
'Jada',
'Armand',
'Raeann',
'Yolande',
'Genevieve',
];

/**
* A generic base class to assist in creating domain specific data generators. It includes
* several general purpose random data generators for use within the class and exposes one
Expand All @@ -36,6 +91,10 @@ export class BaseDataGenerator<GeneratedDoc extends {} = {}> {
throw new Error('method not implemented!');
}

public randomUser(): string {
return this.randomChoice(USERS);
}

/** Returns a future ISO date string */
protected randomFutureDate(from?: Date): string {
const now = from ? from.getTime() : Date.now();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { DeepPartial } from 'utility-types';
import { merge } from 'lodash';
import { BaseDataGenerator } from './base_data_generator';
import { ConditionEntryField, EffectScope, NewTrustedApp, TrustedApp } from '../types';

const TRUSTED_APP_NAMES = [
'Symantec Endpoint Security',
'Bitdefender GravityZone',
'Malwarebytes',
'Sophos Intercept X',
'Webroot Business Endpoint Protection',
'ESET Endpoint Security',
'FortiClient',
'Kaspersky Endpoint Security',
'Trend Micro Apex One',
'CylancePROTECT',
'VIPRE',
'Norton',
'McAfee Endpoint Security',
'AVG AntiVirus',
'CrowdStrike Falcon',
'Avast Business Antivirus',
'Avira Antivirus',
'Cisco AMP for Endpoints',
'Eset Endpoint Antivirus',
'VMware Carbon Black',
'Palo Alto Networks Traps',
'Trend Micro',
'SentinelOne',
'Panda Security for Desktops',
'Microsoft Defender ATP',
];

const EFFECT_SCOPE_TYPES = ['policy', 'global'];

export class TrustedAppGenerator extends BaseDataGenerator<TrustedApp> {
generate(overrides: DeepPartial<TrustedApp> = {}): TrustedApp {
return merge(
this.generateTrustedAppForCreate(),
{
id: this.randomUUID(),
version: this.randomString(5),
created_at: this.randomPastDate(),
updated_at: new Date().toISOString(),
created_by: this.randomUser(),
updated_by: this.randomUser(),
},
overrides
);
}

generateTrustedAppForCreate({
effectScope: effectiveScopeOverride,
...overrides
}: DeepPartial<NewTrustedApp> = {}): NewTrustedApp {
const name = this.randomChoice(TRUSTED_APP_NAMES);
const scopeType = this.randomChoice(EFFECT_SCOPE_TYPES);
const effectScope = (effectiveScopeOverride ?? {
type: scopeType,
...(scopeType === 'policy' ? { policies: this.randomArray(5, () => this.randomUUID()) } : {}),
}) as EffectScope;

// TODO: remove ts-ignore. TS types are conditional when it comes to the combination of OS and ENTRIES
// @ts-ignore
return merge(
{
description: `Generator says we trust ${name}`,
name,
os: this.randomOSFamily(),
effectScope,
entries: [
{
field: ConditionEntryField.HASH,
operator: 'included',
type: 'match',
value: '1234234659af249ddf3e40864e9fb241',
},
{
field: ConditionEntryField.PATH,
operator: 'included',
type: 'match',
value: '/one/two/three',
},
],
},
overrides
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ import {
} from '../../../../fleet/common';
import { EndpointDataLoadingError, wrapErrorAndRejectPromise } from './utils';

export interface SetupFleetForEndpointResponse {
endpointPackage: BulkInstallPackageInfo;
}

/**
* Calls the fleet setup APIs and then installs the latest Endpoint package
* @param kbnClient
*/
export const setupFleetForEndpoint = async (kbnClient: KbnClient) => {
export const setupFleetForEndpoint = async (
kbnClient: KbnClient
): Promise<SetupFleetForEndpointResponse> => {
// We try to use the kbnClient **private** logger, bug if unable to access it, then just use console
// @ts-ignore
const log = kbnClient.log ? kbnClient.log : console;
Expand Down Expand Up @@ -65,20 +71,26 @@ export const setupFleetForEndpoint = async (kbnClient: KbnClient) => {
}

// Install/upgrade the endpoint package
let endpointPackage: BulkInstallPackageInfo;

try {
await installOrUpgradeEndpointFleetPackage(kbnClient);
endpointPackage = await installOrUpgradeEndpointFleetPackage(kbnClient);
} catch (error) {
log.error(error);
throw error;
}

return { endpointPackage };
};

/**
* Installs the Endpoint package (or upgrades it) in Fleet to the latest available in the registry
*
* @param kbnClient
*/
export const installOrUpgradeEndpointFleetPackage = async (kbnClient: KbnClient): Promise<void> => {
export const installOrUpgradeEndpointFleetPackage = async (
kbnClient: KbnClient
): Promise<BulkInstallPackageInfo> => {
const installEndpointPackageResp = (await kbnClient
.request({
path: EPM_API_ROUTES.BULK_INSTALL_PATTERN,
Expand Down Expand Up @@ -108,6 +120,8 @@ export const installOrUpgradeEndpointFleetPackage = async (kbnClient: KbnClient)

throw new EndpointDataLoadingError(bulkResp[0].error, bulkResp);
}

return bulkResp[0] as BulkInstallPackageInfo;
};

function isFleetBulkInstallError(
Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/security_solution/common/endpoint/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ export * from './trusted_apps';
* Supported React-Router state for the Policy Details page
*/
export interface PolicyDetailsRouteState {
/**
* Override the "back link" displayed at the top-left corner of page with custom routing
*/
backLink?: {
/** link label text */
label: string;
navigateTo: Parameters<ApplicationStart['navigateToApp']>;
href?: string;
};

/**
* Where the user should be redirected to when the `Save` button is clicked and the update was successful
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import React from 'react';
import { FormattedDate, FormattedTime, FormattedRelative } from '@kbn/i18n/react';

/**
* @deprecated consider using `FormattedDate` from `x-pack/plugins/security_solution/public/common/components/formatted_date/index.tsx:95`
*/
export const FormattedDateAndTime: React.FC<{ date: Date }> = ({ date }) => {
// If date is greater than or equal to 1h (ago), then show it as a date
// else, show it as relative to "now"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,36 +114,51 @@ export const FormattedDate = React.memo<{

FormattedDate.displayName = 'FormattedDate';

export interface FormattedRelativePreferenceDateProps {
value?: string | number | null;
/**
* Set dateFormat if wanting to override the Kibana system default for when displaying the non-relative date.
* For a list of tokens that can be used to create a date format
* @see https://momentjs.com/docs/#/displaying/format/
*/
dateFormat?: string;
}
/**
* Renders the specified date value according to under/over one hour
* Under an hour = relative format
* Over an hour = in a format determined by the user's preferences,
* Over an hour = in a format determined by the user's preferences (can be overridden via prop),
* with a tooltip that renders:
* - the name of the field
* - a humanized relative date (e.g. 16 minutes ago)
* - a long representation of the date that includes the day of the week (e.g. Thursday, March 21, 2019 6:47pm)
* - the raw date value (e.g. 2019-03-22T00:47:46Z)
*/

export const FormattedRelativePreferenceDate = ({ value }: { value?: string | number | null }) => {
if (value == null) {
return getOrEmptyTagFromValue(value);
}
const maybeDate = getMaybeDate(value);
if (!maybeDate.isValid()) {
return getOrEmptyTagFromValue(value);
export const FormattedRelativePreferenceDate = React.memo<FormattedRelativePreferenceDateProps>(
({ value, dateFormat }) => {
if (value == null) {
return getOrEmptyTagFromValue(value);
}
const maybeDate = getMaybeDate(value);
if (!maybeDate.isValid()) {
return getOrEmptyTagFromValue(value);
}
const date = maybeDate.toDate();
return (
<LocalizedDateTooltip date={date}>
{moment(date).add(1, 'hours').isBefore(new Date()) ? (
<PreferenceFormattedDate
data-test-subj="preference-time"
value={date}
dateFormat={dateFormat}
/>
) : (
<FormattedRelative data-test-subj="relative-time" value={date} />
)}
</LocalizedDateTooltip>
);
}
const date = maybeDate.toDate();
return (
<LocalizedDateTooltip date={date}>
{moment(date).add(1, 'hours').isBefore(new Date()) ? (
<PreferenceFormattedDate data-test-subj="preference-time" value={date} />
) : (
<FormattedRelative data-test-subj="relative-time" value={date} />
)}
</LocalizedDateTooltip>
);
};
);
FormattedRelativePreferenceDate.displayName = 'FormattedRelativePreferenceDate';

/**
* Renders a preceding label according to under/over one hour
Expand Down
Loading

0 comments on commit 0ad55ec

Please sign in to comment.