Skip to content

Commit

Permalink
[Security Solution][Endpoint] Prevent event filter list to be created…
Browse files Browse the repository at this point in the history
… twice from policy details page. (#123350)

* Adds new module with service actions to be used in the service class and in the hooks without using the class. Also marks the class as deprecated.

* New service actions to be used in service class and hooks

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
dasansol92 and kibanamachine authored Jan 20, 2022
1 parent b1d7731 commit c5aa390
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,25 @@ import type {
UpdateExceptionListItemSchema,
ExceptionListSummarySchema,
} from '@kbn/securitysolution-io-ts-list-types';
import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '@kbn/securitysolution-list-constants';

import { Immutable } from '../../../../../common/endpoint/types';

import { EVENT_FILTER_LIST, EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '../constants';
import { EventFiltersService } from '../types';

import {
addEventFilters,
getList,
getOne,
updateOne,
deleteOne,
getSummary,
} from './service_actions';

/**
* @deprecated Don't use this class for future implementations, use the service_actions module instead!
*/
export class EventFiltersHttpService implements EventFiltersService {
private listHasBeenCreated: boolean;

constructor(private http: HttpStart) {
this.listHasBeenCreated = false;
}

private async createEndpointEventList() {
try {
await this.http.post<ExceptionListItemSchema>(EXCEPTION_LIST_URL, {
body: JSON.stringify(EVENT_FILTER_LIST),
});
this.listHasBeenCreated = true;
} catch (err) {
// Ignore 409 errors. List already created
if (err.response.status === 409) this.listHasBeenCreated = true;
else throw err;
}
}

private async httpWrapper() {
if (!this.listHasBeenCreated) await this.createEndpointEventList();
return this.http;
this.http = http;
}

async getList({
Expand All @@ -58,87 +47,28 @@ export class EventFiltersHttpService implements EventFiltersService {
sortOrder: string;
filter: string;
}> = {}): Promise<FoundExceptionListItemSchema> {
const http = await this.httpWrapper();
return http.get(`${EXCEPTION_LIST_ITEM_URL}/_find`, {
query: {
page,
per_page: perPage,
sort_field: sortField,
sort_order: sortOrder,
list_id: [ENDPOINT_EVENT_FILTERS_LIST_ID],
namespace_type: ['agnostic'],
filter,
},
});
return getList({ http: this.http, perPage, page, sortField, sortOrder, filter });
}

async addEventFilters(exception: ExceptionListItemSchema | CreateExceptionListItemSchema) {
return (await this.httpWrapper()).post<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
body: JSON.stringify(exception),
});
return addEventFilters(this.http, exception);
}

async getOne(id: string) {
return (await this.httpWrapper()).get<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
query: {
id,
namespace_type: 'agnostic',
},
});
return getOne(this.http, id);
}

async updateOne(
exception: Immutable<UpdateExceptionListItemSchema>
): Promise<ExceptionListItemSchema> {
return (await this.httpWrapper()).put<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
body: JSON.stringify(EventFiltersHttpService.cleanEventFilterToUpdate(exception)),
});
return updateOne(this.http, exception);
}

async deleteOne(id: string): Promise<ExceptionListItemSchema> {
return (await this.httpWrapper()).delete<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
query: {
id,
namespace_type: 'agnostic',
},
});
return deleteOne(this.http, id);
}

async getSummary(): Promise<ExceptionListSummarySchema> {
return (await this.httpWrapper()).get<ExceptionListSummarySchema>(
`${EXCEPTION_LIST_URL}/summary`,
{
query: {
list_id: ENDPOINT_EVENT_FILTERS_LIST_ID,
namespace_type: 'agnostic',
},
}
);
}

static cleanEventFilterToUpdate(
exception: Immutable<UpdateExceptionListItemSchema>
): UpdateExceptionListItemSchema {
const exceptionToUpdateCleaned = { ...exception };
// Clean unnecessary fields for update action
[
'created_at',
'created_by',
'created_at',
'created_by',
'list_id',
'tie_breaker_id',
'updated_at',
'updated_by',
].forEach((field) => {
delete exceptionToUpdateCleaned[field as keyof UpdateExceptionListItemSchema];
});

exceptionToUpdateCleaned.comments = exceptionToUpdateCleaned.comments?.map((comment) => ({
comment: comment.comment,
id: comment.id,
}));

return exceptionToUpdateCleaned as UpdateExceptionListItemSchema;
return getSummary(this.http);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* 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 {
CreateExceptionListItemSchema,
ExceptionListItemSchema,
ExceptionListSummarySchema,
FoundExceptionListItemSchema,
UpdateExceptionListItemSchema,
} from '@kbn/securitysolution-io-ts-list-types';
import { HttpStart } from 'kibana/public';
import {
EXCEPTION_LIST_ITEM_URL,
EXCEPTION_LIST_URL,
EVENT_FILTER_LIST,
ENDPOINT_EVENT_FILTERS_LIST_ID,
} from '../constants';
import { Immutable } from '../../../../../common/endpoint/types';

async function createEventFilterList(http: HttpStart): Promise<void> {
try {
await http.post<ExceptionListItemSchema>(EXCEPTION_LIST_URL, {
body: JSON.stringify(EVENT_FILTER_LIST),
});
} catch (err) {
// Ignore 409 errors. List already created
if (err.response?.status !== 409) {
throw err;
}
}
}

let listExistsPromise: Promise<void>;
export async function ensureEventFiltersListExists(http: HttpStart): Promise<void> {
if (!listExistsPromise) {
listExistsPromise = createEventFilterList(http);
}
await listExistsPromise;
}

export async function getList({
http,
perPage,
page,
sortField,
sortOrder,
filter,
}: {
http: HttpStart;
page?: number;
perPage?: number;
sortField?: string;
sortOrder?: string;
filter?: string;
}): Promise<FoundExceptionListItemSchema> {
await ensureEventFiltersListExists(http);
return http.get(`${EXCEPTION_LIST_ITEM_URL}/_find`, {
query: {
page,
per_page: perPage,
sort_field: sortField,
sort_order: sortOrder,
list_id: [ENDPOINT_EVENT_FILTERS_LIST_ID],
namespace_type: ['agnostic'],
filter,
},
});
}

export async function addEventFilters(
http: HttpStart,
exception: ExceptionListItemSchema | CreateExceptionListItemSchema
) {
await ensureEventFiltersListExists(http);
return http.post<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
body: JSON.stringify(exception),
});
}

export async function getOne(http: HttpStart, id: string) {
await ensureEventFiltersListExists(http);
return http.get<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
query: {
id,
namespace_type: 'agnostic',
},
});
}

export async function updateOne(
http: HttpStart,
exception: Immutable<UpdateExceptionListItemSchema>
): Promise<ExceptionListItemSchema> {
await ensureEventFiltersListExists(http);
return http.put<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
body: JSON.stringify(cleanEventFilterToUpdate(exception)),
});
}

export async function deleteOne(http: HttpStart, id: string): Promise<ExceptionListItemSchema> {
await ensureEventFiltersListExists(http);
return http.delete<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
query: {
id,
namespace_type: 'agnostic',
},
});
}

export async function getSummary(http: HttpStart): Promise<ExceptionListSummarySchema> {
await ensureEventFiltersListExists(http);
return http.get<ExceptionListSummarySchema>(`${EXCEPTION_LIST_URL}/summary`, {
query: {
list_id: ENDPOINT_EVENT_FILTERS_LIST_ID,
namespace_type: 'agnostic',
},
});
}

export function cleanEventFilterToUpdate(
exception: Immutable<UpdateExceptionListItemSchema>
): UpdateExceptionListItemSchema {
const exceptionToUpdateCleaned = { ...exception };
// Clean unnecessary fields for update action
[
'created_at',
'created_by',
'created_at',
'created_by',
'list_id',
'tie_breaker_id',
'updated_at',
'updated_by',
].forEach((field) => {
delete exceptionToUpdateCleaned[field as keyof UpdateExceptionListItemSchema];
});

exceptionToUpdateCleaned.comments = exceptionToUpdateCleaned.comments?.map((comment) => ({
comment: comment.comment,
id: comment.id,
}));

return exceptionToUpdateCleaned as UpdateExceptionListItemSchema;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../../../../../../common/mock/endpoint';
import { PolicyEventFiltersDeleteModal } from './policy_event_filters_delete_modal';
import { eventFiltersListQueryHttpMock } from '../../../../event_filters/test_utils';
import { EventFiltersHttpService } from '../../../../event_filters/service';
import { cleanEventFilterToUpdate } from '../../../../event_filters/service/service_actions';

describe('Policy details event filter delete modal', () => {
let policyId: string;
Expand Down Expand Up @@ -73,7 +73,7 @@ describe('Policy details event filter delete modal', () => {
await waitFor(() => {
expect(mockedApi.responseProvider.eventFiltersUpdateOne).toHaveBeenLastCalledWith({
body: JSON.stringify(
EventFiltersHttpService.cleanEventFilterToUpdate({
cleanEventFilterToUpdate({
...exception,
tags: ['policy:1234', 'policy:4321', 'not-a-policy-tag'],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
FoundExceptionListItemSchema,
UpdateExceptionListItemSchema,
} from '@kbn/securitysolution-io-ts-list-types';
import { EventFiltersHttpService } from '../../../../event_filters/service';
import { cleanEventFilterToUpdate } from '../../../../event_filters/service/service_actions';

const getDefaultQueryParameters = (customFilter: string | undefined = '') => ({
path: '/api/exception_lists/items/_find',
Expand Down Expand Up @@ -56,7 +56,7 @@ const getCleanedExceptionWithNewTags = (
tags: [...testTags, `policy:${policy.id}`],
};

return EventFiltersHttpService.cleanEventFilterToUpdate(exceptionToUpdateWithNewTags);
return cleanEventFilterToUpdate(exceptionToUpdateWithNewTags);
};

describe('Policy details event filters flyout', () => {
Expand Down
Loading

0 comments on commit c5aa390

Please sign in to comment.