diff --git a/x-pack/plugins/uptime/common/constants/ui.ts b/x-pack/plugins/uptime/common/constants/ui.ts index 29e8dabf53f92..3bf3e3cc0a2cc 100644 --- a/x-pack/plugins/uptime/common/constants/ui.ts +++ b/x-pack/plugins/uptime/common/constants/ui.ts @@ -10,6 +10,8 @@ export const OVERVIEW_ROUTE = '/'; export const SETTINGS_ROUTE = '/settings'; +export const CERTIFICATES_ROUTE = '/certificates'; + export enum STATUS { UP = 'up', DOWN = 'down', @@ -41,3 +43,10 @@ export const SHORT_TIMESPAN_LOCALE = { yy: '%d Yr', }, }; + +export enum CERT_STATUS { + OK = 'OK', + EXPIRING_SOON = 'EXPIRING_SOON', + EXPIRED = 'EXPIRED', + TOO_OLD = 'TOO_OLD', +} diff --git a/x-pack/plugins/uptime/common/runtime_types/certs.ts b/x-pack/plugins/uptime/common/runtime_types/certs.ts index e8be67abf3a44..e9071e76b6d75 100644 --- a/x-pack/plugins/uptime/common/runtime_types/certs.ts +++ b/x-pack/plugins/uptime/common/runtime_types/certs.ts @@ -8,35 +8,45 @@ import * as t from 'io-ts'; export const GetCertsParamsType = t.intersection([ t.type({ - from: t.string, - to: t.string, index: t.number, size: t.number, + sortBy: t.string, + direction: t.string, }), t.partial({ search: t.string, + from: t.string, + to: t.string, }), ]); export type GetCertsParams = t.TypeOf; +export const CertMonitorType = t.partial({ + name: t.string, + id: t.string, + url: t.string, +}); + export const CertType = t.intersection([ t.type({ - monitors: t.array( - t.partial({ - name: t.string, - id: t.string, - }) - ), + monitors: t.array(CertMonitorType), sha256: t.string, }), t.partial({ - certificate_not_valid_after: t.string, - certificate_not_valid_before: t.string, + not_after: t.string, + not_before: t.string, common_name: t.string, issuer: t.string, sha1: t.string, }), ]); +export const CertResultType = t.type({ + certs: t.array(CertType), + total: t.number, +}); + export type Cert = t.TypeOf; +export type CertMonitor = t.TypeOf; +export type CertResult = t.TypeOf; diff --git a/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts b/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts index ee14b298f3810..d8dc7fc89d94b 100644 --- a/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts +++ b/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts @@ -17,8 +17,8 @@ export const HttpResponseBodyType = t.partial({ export type HttpResponseBody = t.TypeOf; export const TlsType = t.partial({ - certificate_not_valid_after: t.string, - certificate_not_valid_before: t.string, + not_after: t.string, + not_before: t.string, }); export type Tls = t.TypeOf; diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_monitors.test.tsx.snap b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_monitors.test.tsx.snap new file mode 100644 index 0000000000000..a79fb0f0d3deb --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_monitors.test.tsx.snap @@ -0,0 +1,134 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CertMonitors renders expected elements for valid props 1`] = ` + + + + + + + + , + + + + + + , + + + + + +`; + +exports[`CertMonitors shallow renders expected elements for valid props 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_search.test.tsx.snap b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_search.test.tsx.snap new file mode 100644 index 0000000000000..0706198a099a5 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_search.test.tsx.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CertificatesSearch renders expected elements for valid props 1`] = ` +.c0 { + min-width: 700px; +} + +
+
+ +
+ + +
+
+`; + +exports[`CertificatesSearch shallow renders expected elements for valid props 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_status.test.tsx.snap b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_status.test.tsx.snap new file mode 100644 index 0000000000000..089d272a075c6 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/cert_status.test.tsx.snap @@ -0,0 +1,100 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CertStatus renders expected elements for valid props 1`] = ` +
+
+
+
+
+
+ + OK + +
+
+
+`; + +exports[`CertStatus shallow renders expected elements for valid props 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/certificates_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/certificates_list.test.tsx.snap new file mode 100644 index 0000000000000..fd90db793b26e --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/certificates_list.test.tsx.snap @@ -0,0 +1,70 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CertificateList shallow renders expected elements for valid props 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/fingerprint_col.test.tsx.snap b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/fingerprint_col.test.tsx.snap new file mode 100644 index 0000000000000..c9b17db5532f4 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/__snapshots__/fingerprint_col.test.tsx.snap @@ -0,0 +1,171 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FingerprintCol renders expected elements for valid props 1`] = ` +Array [ + .c1 .euiButtonEmpty__content { + padding-right: 0px; +} + +.c0 { + margin-right: 8px; +} + + + + + + + + + , + .c1 .euiButtonEmpty__content { + padding-right: 0px; +} + +.c0 { + margin-right: 8px; +} + + + + + + + + + , +] +`; + +exports[`FingerprintCol shallow renders expected elements for valid props 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_monitors.test.tsx b/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_monitors.test.tsx new file mode 100644 index 0000000000000..bc4c770d5cd24 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_monitors.test.tsx @@ -0,0 +1,24 @@ +/* + * 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. + */ + +import React from 'react'; +import { CertMonitors } from '../cert_monitors'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; + +describe('CertMonitors', () => { + const certMons = [ + { name: '', id: 'bad-ssl-dashboard', url: 'https://badssl.com/dashboard/' }, + { name: 'elastic', id: 'elastic-co', url: 'https://www.elastic.co/' }, + { name: '', id: 'extended-validation', url: 'https://extended-validation.badssl.com/' }, + ]; + it('shallow renders expected elements for valid props', () => { + expect(shallowWithRouter()).toMatchSnapshot(); + }); + + it('renders expected elements for valid props', () => { + expect(renderWithRouter()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_search.test.tsx b/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_search.test.tsx new file mode 100644 index 0000000000000..27d3bb18f17c2 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_search.test.tsx @@ -0,0 +1,18 @@ +/* + * 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. + */ + +import React from 'react'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; +import { CertificateSearch } from '../cert_search'; + +describe('CertificatesSearch', () => { + it('shallow renders expected elements for valid props', () => { + expect(shallowWithRouter()).toMatchSnapshot(); + }); + it('renders expected elements for valid props', () => { + expect(renderWithRouter()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_status.test.tsx b/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_status.test.tsx new file mode 100644 index 0000000000000..6f91994fb89c4 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/cert_status.test.tsx @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import React from 'react'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; +import { CertStatus } from '../cert_status'; +import * as redux from 'react-redux'; +import moment from 'moment'; + +describe('CertStatus', () => { + beforeEach(() => { + const spy = jest.spyOn(redux, 'useDispatch'); + spy.mockReturnValue(jest.fn()); + + const spy1 = jest.spyOn(redux, 'useSelector'); + spy1.mockReturnValue(true); + }); + + const cert = { + monitors: [{ name: '', id: 'github', url: 'https://github.com/' }], + not_after: '2020-05-08T00:00:00.000Z', + not_before: '2018-05-08T00:00:00.000Z', + issuer: 'DigiCert SHA2 Extended Validation Server CA', + sha1: 'ca06f56b258b7a0d4f2b05470939478651151984', + sha256: '3111500c4a66012cdae333ec3fca1c9dde45c954440e7ee413716bff3663c074', + common_name: 'github.com', + }; + + it('shallow renders expected elements for valid props', () => { + expect(shallowWithRouter()).toMatchSnapshot(); + }); + + it('renders expected elements for valid props', () => { + cert.not_after = moment() + .add('4', 'months') + .toISOString(); + expect(renderWithRouter()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/certificates_list.test.tsx b/x-pack/plugins/uptime/public/components/certificates/__tests__/certificates_list.test.tsx new file mode 100644 index 0000000000000..a8b60900ec65c --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/certificates_list.test.tsx @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import React from 'react'; +import { shallowWithRouter } from '../../../lib'; +import { CertificateList, CertSort } from '../certificates_list'; + +describe('CertificateList', () => { + it('shallow renders expected elements for valid props', () => { + const page = { + index: 0, + size: 10, + }; + const sort: CertSort = { + field: 'not_after', + direction: 'asc', + }; + + expect( + shallowWithRouter() + ).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/certificates/__tests__/fingerprint_col.test.tsx b/x-pack/plugins/uptime/public/components/certificates/__tests__/fingerprint_col.test.tsx new file mode 100644 index 0000000000000..609b876e24849 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/__tests__/fingerprint_col.test.tsx @@ -0,0 +1,34 @@ +/* + * 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. + */ + +import React from 'react'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; +import { FingerprintCol } from '../fingerprint_col'; +import moment from 'moment'; + +describe('FingerprintCol', () => { + const cert = { + monitors: [{ name: '', id: 'github', url: 'https://github.com/' }], + not_after: '2020-05-08T00:00:00.000Z', + not_before: '2018-05-08T00:00:00.000Z', + issuer: 'DigiCert SHA2 Extended Validation Server CA', + sha1: 'ca06f56b258b7a0d4f2b05470939478651151984', + sha256: '3111500c4a66012cdae333ec3fca1c9dde45c954440e7ee413716bff3663c074', + common_name: 'github.com', + }; + + it('shallow renders expected elements for valid props', () => { + expect(shallowWithRouter()).toMatchSnapshot(); + }); + + it('renders expected elements for valid props', () => { + cert.not_after = moment() + .add('4', 'months') + .toISOString(); + + expect(renderWithRouter()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/certificates/cert_monitors.tsx b/x-pack/plugins/uptime/public/components/certificates/cert_monitors.tsx new file mode 100644 index 0000000000000..bfd309e59d013 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/cert_monitors.tsx @@ -0,0 +1,31 @@ +/* + * 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. + */ + +import React from 'react'; +import { EuiToolTip } from '@elastic/eui'; +import { CertMonitor } from '../../../common/runtime_types'; +import { MonitorPageLink } from '../common/monitor_page_link'; + +interface Props { + monitors: CertMonitor[]; +} + +export const CertMonitors: React.FC = ({ monitors }) => { + return ( + + {monitors.map((mon: CertMonitor, ind: number) => ( + + {ind > 0 && ', '} + + + {mon.name || mon.id} + + + + ))} + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/certificates/cert_search.tsx b/x-pack/plugins/uptime/public/components/certificates/cert_search.tsx new file mode 100644 index 0000000000000..282b623f0f662 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/cert_search.tsx @@ -0,0 +1,34 @@ +/* + * 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. + */ + +import React, { ChangeEvent } from 'react'; +import { EuiFieldSearch } from '@elastic/eui'; +import styled from 'styled-components'; +import * as labels from './translations'; + +const WrapFieldSearch = styled(EuiFieldSearch)` + min-width: 700px; +`; + +interface Props { + setSearch: (val: string) => void; +} + +export const CertificateSearch: React.FC = ({ setSearch }) => { + const onChange = (e: ChangeEvent) => { + setSearch(e.target.value); + }; + + return ( + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/certificates/cert_status.tsx b/x-pack/plugins/uptime/public/components/certificates/cert_status.tsx new file mode 100644 index 0000000000000..e7a86ce98fa3c --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/cert_status.tsx @@ -0,0 +1,49 @@ +/* + * 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. + */ + +import React from 'react'; +import { EuiHealth } from '@elastic/eui'; +import { Cert } from '../../../common/runtime_types'; +import { useCertStatus } from '../../hooks'; +import * as labels from './translations'; +import { CERT_STATUS } from '../../../common/constants'; + +interface Props { + cert: Cert; +} + +export const CertStatus: React.FC = ({ cert }) => { + const certStatus = useCertStatus(cert?.not_after, cert?.not_before); + + if (certStatus === CERT_STATUS.EXPIRING_SOON) { + return ( + + {labels.EXPIRES_SOON} + + ); + } + if (certStatus === CERT_STATUS.EXPIRED) { + return ( + + {labels.EXPIRED} + + ); + } + + if (certStatus === CERT_STATUS.TOO_OLD) { + return ( + + {labels.TOO_OLD} + + ); + } + + return ( + + {labels.OK} + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/certificates/certificates_list.tsx b/x-pack/plugins/uptime/public/components/certificates/certificates_list.tsx new file mode 100644 index 0000000000000..595aa03c99c73 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/certificates_list.tsx @@ -0,0 +1,113 @@ +/* + * 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. + */ + +import React from 'react'; +import moment from 'moment'; +import { useSelector } from 'react-redux'; +import { Direction, EuiBasicTable } from '@elastic/eui'; +import { certificatesSelector } from '../../state/certificates/certificates'; +import { CertStatus } from './cert_status'; +import { CertMonitors } from './cert_monitors'; +import * as labels from './translations'; +import { Cert, CertMonitor } from '../../../common/runtime_types'; +import { FingerprintCol } from './fingerprint_col'; + +interface Page { + index: number; + size: number; +} + +export type CertFields = + | 'sha256' + | 'sha1' + | 'issuer' + | 'common_name' + | 'monitors' + | 'not_after' + | 'not_before'; + +export interface CertSort { + field: CertFields; + direction: Direction; +} + +interface Props { + page: Page; + sort: CertSort; + onChange: (page: Page, sort: CertSort) => void; +} + +export const CertificateList: React.FC = ({ page, sort, onChange }) => { + const certificates = useSelector(certificatesSelector); + + const onTableChange = (newVal: Partial) => { + onChange(newVal.page as Page, newVal.sort as CertSort); + }; + + const pagination = { + pageIndex: page.index, + pageSize: page.size, + totalItemCount: certificates?.total ?? 0, + pageSizeOptions: [10, 25, 50, 100], + hidePerPageOptions: false, + }; + + const columns = [ + { + field: 'not_after', + name: labels.STATUS_COL, + sortable: true, + render: (val: string, item: Cert) => , + }, + { + name: labels.COMMON_NAME_COL, + field: 'common_name', + sortable: true, + }, + { + name: labels.MONITORS_COL, + field: 'monitors', + render: (monitors: CertMonitor[]) => , + }, + { + name: labels.ISSUED_BY_COL, + field: 'issuer', + sortable: true, + }, + { + name: labels.VALID_UNTIL_COL, + field: 'not_after', + sortable: true, + render: (value: string) => moment(value).format('L LT'), + }, + { + name: labels.AGE_COL, + field: 'not_before', + sortable: true, + render: (value: string) => moment().diff(moment(value), 'days') + ' ' + labels.DAYS, + }, + { + name: labels.FINGERPRINTS_COL, + field: 'sha256', + render: (val: string, item: Cert) => , + }, + ]; + + return ( + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.tsx b/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.tsx new file mode 100644 index 0000000000000..4101573907924 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.tsx @@ -0,0 +1,46 @@ +/* + * 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. + */ + +import React from 'react'; +import { EuiButtonEmpty, EuiButtonIcon, EuiCopy, EuiToolTip } from '@elastic/eui'; +import styled from 'styled-components'; +import { Cert } from '../../../common/runtime_types'; +import { COPY_FINGERPRINT } from './translations'; + +const EmptyButton = styled(EuiButtonEmpty)` + .euiButtonEmpty__content { + padding-right: 0px; + } +`; + +const Span = styled.span` + margin-right: 8px; +`; + +interface Props { + cert: Cert; +} + +export const FingerprintCol: React.FC = ({ cert }) => { + const ShaComponent = ({ text, val }: { text: string; val: string }) => { + return ( + + + {text} + + + {copy => } + + + ); + }; + return ( + <> + + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/certificates/index.ts b/x-pack/plugins/uptime/public/components/certificates/index.ts new file mode 100644 index 0000000000000..82f3f7ab67c91 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/index.ts @@ -0,0 +1,11 @@ +/* + * 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 * from './cert_monitors'; +export * from './cert_search'; +export * from './cert_status'; +export * from './certificates_list'; +export * from './fingerprint_col'; diff --git a/x-pack/plugins/uptime/public/components/certificates/translations.ts b/x-pack/plugins/uptime/public/components/certificates/translations.ts new file mode 100644 index 0000000000000..518eddf1211a4 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/certificates/translations.ts @@ -0,0 +1,63 @@ +/* + * 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. + */ + +import { i18n } from '@kbn/i18n'; + +export const OK = i18n.translate('xpack.uptime.certs.ok', { + defaultMessage: 'OK', +}); + +export const EXPIRED = i18n.translate('xpack.uptime.certs.expired', { + defaultMessage: 'Expired', +}); + +export const EXPIRES_SOON = i18n.translate('xpack.uptime.certs.expireSoon', { + defaultMessage: 'Expires soon', +}); + +export const SEARCH_CERTS = i18n.translate('xpack.uptime.certs.searchCerts', { + defaultMessage: 'Search certificates', +}); + +export const STATUS_COL = i18n.translate('xpack.uptime.certs.list.status', { + defaultMessage: 'Status', +}); + +export const TOO_OLD = i18n.translate('xpack.uptime.certs.list.status.old', { + defaultMessage: 'Too old', +}); + +export const COMMON_NAME_COL = i18n.translate('xpack.uptime.certs.list.commonName', { + defaultMessage: 'Common name', +}); + +export const MONITORS_COL = i18n.translate('xpack.uptime.certs.list.monitors', { + defaultMessage: 'Monitors', +}); + +export const ISSUED_BY_COL = i18n.translate('xpack.uptime.certs.list.issuedBy', { + defaultMessage: 'Issued by', +}); + +export const VALID_UNTIL_COL = i18n.translate('xpack.uptime.certs.list.validUntil', { + defaultMessage: 'Valid until', +}); + +export const AGE_COL = i18n.translate('xpack.uptime.certs.list.ageCol', { + defaultMessage: 'Age', +}); + +export const DAYS = i18n.translate('xpack.uptime.certs.list.days', { + defaultMessage: 'days', +}); + +export const FINGERPRINTS_COL = i18n.translate('xpack.uptime.certs.list.expirationDate', { + defaultMessage: 'Fingerprints', +}); + +export const COPY_FINGERPRINT = i18n.translate('xpack.uptime.certs.list.copyFingerprint', { + defaultMessage: 'Click to copy fingerprint value', +}); diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/__tests__/__snapshots__/monitor_page_link.test.tsx.snap similarity index 100% rename from x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/__tests__/__snapshots__/monitor_page_link.test.tsx.snap diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx b/x-pack/plugins/uptime/public/components/common/__tests__/monitor_page_link.test.tsx similarity index 100% rename from x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx rename to x-pack/plugins/uptime/public/components/common/__tests__/monitor_page_link.test.tsx index dd6e9c66d395b..36ebeb6615648 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/__tests__/monitor_page_link.test.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { MonitorPageLink } from '../monitor_page_link'; describe('MonitorPageLink component', () => { diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx b/x-pack/plugins/uptime/public/components/common/monitor_page_link.tsx similarity index 89% rename from x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx rename to x-pack/plugins/uptime/public/components/common/monitor_page_link.tsx index 803b399810508..77faa8edfc5c8 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx +++ b/x-pack/plugins/uptime/public/components/common/monitor_page_link.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import React, { FC } from 'react'; import { EuiLink } from '@elastic/eui'; import { Link } from 'react-router-dom'; -import React, { FunctionComponent } from 'react'; interface DetailPageLinkProps { /** @@ -19,7 +19,7 @@ interface DetailPageLinkProps { linkParameters: string | undefined; } -export const MonitorPageLink: FunctionComponent = ({ +export const MonitorPageLink: FC = ({ children, monitorId, linkParameters, diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap deleted file mode 100644 index 605fc3cdb6b38..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap +++ /dev/null @@ -1,31 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MonitorStatusBar component renders 1`] = ` -Array [ -
, -
- SSL certificate expires - - - - in 2 months - - - -
, -] -`; - -exports[`MonitorStatusBar component renders null if invalid date 1`] = `null`; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap new file mode 100644 index 0000000000000..2f4473ba54cf9 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap @@ -0,0 +1,119 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SSL Certificate component renders 1`] = ` +Array [ +
+ Certificate +
, +
, +
+
+
+ Expires + + + + in 2 months + + + +
+
+ +
, +] +`; + +exports[`SSL Certificate component renders null if invalid date 1`] = `null`; + +exports[`SSL Certificate component shallow renders 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx index 5fd32c808da42..b39a1cb537583 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { MonitorStatusBarComponent } from '../monitor_status_bar'; import { Ping } from '../../../../../common/runtime_types'; +import * as redux from 'react-redux'; describe('MonitorStatusBar component', () => { let monitorStatus: Ping; @@ -46,6 +47,12 @@ describe('MonitorStatusBar component', () => { }, ], }; + + const spy = jest.spyOn(redux, 'useDispatch'); + spy.mockReturnValue(jest.fn()); + + const spy1 = jest.spyOn(redux, 'useSelector'); + spy1.mockReturnValue(true); }); it('renders duration in ms, not us', () => { diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/ssl_certificate.test.tsx similarity index 55% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/ssl_certificate.test.tsx index 57ed09cc30ef1..70a161a2394ec 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/ssl_certificate.test.tsx @@ -6,13 +6,14 @@ import React from 'react'; import moment from 'moment'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { EuiBadge } from '@elastic/eui'; -import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { Tls } from '../../../../../common/runtime_types'; import { MonitorSSLCertificate } from '../monitor_status_bar'; +import * as redux from 'react-redux'; +import { mountWithRouter, renderWithRouter, shallowWithRouter } from '../../../../lib'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../common/constants'; -describe('MonitorStatusBar component', () => { +describe('SSL Certificate component', () => { let monitorTls: Tls; beforeEach(() => { @@ -21,37 +22,52 @@ describe('MonitorStatusBar component', () => { .toString(); monitorTls = { - certificate_not_valid_after: dateInTwoMonths, + not_after: dateInTwoMonths, }; + + const useDispatchSpy = jest.spyOn(redux, 'useDispatch'); + useDispatchSpy.mockReturnValue(jest.fn()); + + const useSelectorSpy = jest.spyOn(redux, 'useSelector'); + useSelectorSpy.mockReturnValue({ settings: DYNAMIC_SETTINGS_DEFAULTS }); + }); + + it('shallow renders', () => { + const monitorTls1 = { + not_after: '2020-04-24T11:41:38.200Z', + }; + const component = shallowWithRouter(); + expect(component).toMatchSnapshot(); }); it('renders', () => { - const component = renderWithIntl(); + const component = renderWithRouter(); expect(component).toMatchSnapshot(); }); it('renders null if invalid date', () => { monitorTls = { - certificate_not_valid_after: 'i am so invalid date', + not_after: 'i am so invalid date', }; - const component = renderWithIntl(); + const component = renderWithRouter(); expect(component).toMatchSnapshot(); }); - it('renders expiration date with a warning state if ssl expiry date is less than 30 days', () => { - const dateIn15Days = moment() - .add(15, 'day') + it('renders expiration date with a warning state if ssl expiry date is less than 5 days', () => { + const dateIn5Days = moment() + .add(5, 'day') .toString(); monitorTls = { - certificate_not_valid_after: dateIn15Days, + not_after: dateIn5Days, }; - const component = mountWithIntl(); + const component = mountWithRouter(); const badgeComponent = component.find(EuiBadge); + expect(badgeComponent.props().color).toBe('warning'); const badgeComponentText = component.find('.euiBadge__text'); - expect(badgeComponentText.text()).toBe(moment(dateIn15Days).fromNow()); + expect(badgeComponentText.text()).toBe(moment(dateIn5Days).fromNow()); expect(badgeComponent.find('span.euiBadge--warning')).toBeTruthy(); }); @@ -61,9 +77,9 @@ describe('MonitorStatusBar component', () => { .add(40, 'day') .toString(); monitorTls = { - certificate_not_valid_after: dateIn40Days, + not_after: dateIn40Days, }; - const component = mountWithIntl(); + const component = mountWithRouter(); const badgeComponent = component.find(EuiBadge); expect(badgeComponent.props().color).toBe('default'); diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx index d92534aecd175..734a68f00f7de 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx @@ -6,10 +6,13 @@ import React from 'react'; import moment from 'moment'; -import { EuiSpacer, EuiText, EuiBadge } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { Link } from 'react-router-dom'; +import { EuiSpacer, EuiText, EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { Tls } from '../../../../../common/runtime_types'; +import { useCertStatus } from '../../../../hooks'; +import { CERT_STATUS, CERTIFICATES_ROUTE } from '../../../../../common/constants'; interface Props { /** @@ -19,40 +22,79 @@ interface Props { } export const MonitorSSLCertificate = ({ tls }: Props) => { - const certValidityDate = new Date(tls?.certificate_not_valid_after ?? ''); + const certStatus = useCertStatus(tls?.not_after); - const isValidDate = !isNaN(certValidityDate.valueOf()); + const isExpiringSoon = certStatus === CERT_STATUS.EXPIRING_SOON; - const dateIn30Days = moment().add('30', 'days'); + const isExpired = certStatus === CERT_STATUS.EXPIRED; - const isExpiringInMonth = isValidDate && dateIn30Days > moment(certValidityDate); + const relativeDate = moment(tls?.not_after).fromNow(); - return isValidDate ? ( + return certStatus ? ( <> - - - - {moment(certValidityDate).fromNow()} - - ), - }} - /> + + {i18n.translate('xpack.uptime.monitorStatusBar.sslCertificate.title', { + defaultMessage: 'Certificate', + })} + + + + + {isExpired ? ( + {relativeDate}, + }} + /> + ) : ( + + {relativeDate} + + ), + }} + /> + )} + + + + + + {i18n.translate('xpack.uptime.monitorStatusBar.sslCertificate.overview', { + defaultMessage: 'Certificate overview', + })} + + + + ) : null; }; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap index ed5602323d254..0d6638e7070d6 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap @@ -556,13 +556,35 @@ exports[`MonitorList component renders the monitor list 1`] = `
-
- Monitor status -
+
+
+ Monitor status +
+
+ +
+ +
+ + TLS Certificate + +
+ @@ -657,7 +695,7 @@ exports[`MonitorList component renders the monitor list 1`] = `
+ +
+ TLS Certificate +
+
+ + - + +
+ @@ -951,6 +1005,22 @@ exports[`MonitorList component renders the monitor list 1`] = `
+ +
+ TLS Certificate +
+
+ + - + +
+ diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx index 9b1d799a23e37..9dd44f5176664 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx @@ -12,12 +12,19 @@ import { } from '../../../../../common/runtime_types'; import { MonitorListComponent } from '../monitor_list'; import { renderWithRouter, shallowWithRouter } from '../../../../lib'; +import * as redux from 'react-redux'; describe('MonitorList component', () => { let result: MonitorSummaryResult; let localStorageMock: any; beforeEach(() => { + const useDispatchSpy = jest.spyOn(redux, 'useDispatch'); + useDispatchSpy.mockReturnValue(jest.fn()); + + const useSelectorSpy = jest.spyOn(redux, 'useSelector'); + useSelectorSpy.mockReturnValue(true); + localStorageMock = { getItem: jest.fn().mockImplementation(() => '25'), setItem: jest.fn(), diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx new file mode 100644 index 0000000000000..d9380476eaf45 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx @@ -0,0 +1,51 @@ +/* + * 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. + */ + +import React from 'react'; +import moment from 'moment'; +import styled from 'styled-components'; +import { EuiIcon, EuiText, EuiToolTip } from '@elastic/eui'; +import { Cert } from '../../../../common/runtime_types'; +import { useCertStatus } from '../../../hooks'; +import { EXPIRED, EXPIRES_SOON } from '../../certificates/translations'; +import { CERT_STATUS } from '../../../../common/constants'; + +interface Props { + cert: Cert; +} + +const Span = styled.span` + margin-left: 5px; + vertical-align: middle; +`; + +export const CertStatusColumn: React.FC = ({ cert }) => { + const certStatus = useCertStatus(cert?.not_after); + + const relativeDate = moment(cert?.not_after).fromNow(); + + const CertStatus = ({ color, text }: { color: string; text: string }) => { + return ( + + + + + {text} {relativeDate} + + + + ); + }; + + if (certStatus === CERT_STATUS.EXPIRING_SOON) { + return ; + } + if (certStatus === CERT_STATUS.EXPIRED) { + return ; + } + + return certStatus ? : -; +}; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx index 7e9536689470e..616d8fbd76043 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx @@ -18,12 +18,13 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; +import { Link } from 'react-router-dom'; import { HistogramPoint, FetchMonitorStatesQueryArgs } from '../../../../common/runtime_types'; import { MonitorSummary } from '../../../../common/runtime_types'; import { MonitorListStatusColumn } from './monitor_list_status_column'; import { ExpandedRowMap } from './types'; import { MonitorBarSeries } from '../../common/charts'; -import { MonitorPageLink } from './monitor_page_link'; +import { MonitorPageLink } from '../../common/monitor_page_link'; import { OverviewPageLink } from './overview_page_link'; import * as labels from './translations'; import { MonitorListPageSizeSelect } from './monitor_list_page_size_select'; @@ -31,6 +32,8 @@ import { MonitorListDrawer } from './monitor_list_drawer/list_drawer_container'; import { MonitorListProps } from './monitor_list_container'; import { MonitorList } from '../../../state/reducers/monitor_list'; import { useUrlParams } from '../../../hooks'; +import { CERTIFICATES_ROUTE } from '../../../../common/constants'; +import { CertStatusColumn } from './cert_status_column'; interface Props extends MonitorListProps { lastRefresh: number; @@ -143,6 +146,12 @@ export const MonitorListComponent: React.FC = ({ ), }, + { + align: 'center' as const, + field: 'state.tls', + name: labels.TLS_COLUMN_LABEL, + render: (tls: any) => , + }, { align: 'center' as const, field: 'histogram.points', @@ -181,15 +190,32 @@ export const MonitorListComponent: React.FC = ({ return ( - -
- -
-
- + + + +
+ +
+
+
+ + +
+ + + +
+
+
+
+ + { return i18n.translate('xpack.uptime.monitorList.expandDrawerButton.ariaLabel', { defaultMessage: 'Expand row for monitor with ID {id}', diff --git a/x-pack/plugins/uptime/public/hooks/index.ts b/x-pack/plugins/uptime/public/hooks/index.ts index 1f50e995eda49..b92d2d4cf7df5 100644 --- a/x-pack/plugins/uptime/public/hooks/index.ts +++ b/x-pack/plugins/uptime/public/hooks/index.ts @@ -8,3 +8,4 @@ export * from './use_monitor'; export * from './use_url_params'; export * from './use_telemetry'; export * from './update_kuery_string'; +export * from './use_cert_status'; diff --git a/x-pack/plugins/uptime/public/hooks/use_cert_status.ts b/x-pack/plugins/uptime/public/hooks/use_cert_status.ts new file mode 100644 index 0000000000000..cb54b05af9dd1 --- /dev/null +++ b/x-pack/plugins/uptime/public/hooks/use_cert_status.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import moment from 'moment'; +import { useSelector } from 'react-redux'; +import { selectDynamicSettings } from '../state/selectors'; +import { CERT_STATUS } from '../../common/constants'; + +export const useCertStatus = (expiryDate?: string, issueDate?: string) => { + const dss = useSelector(selectDynamicSettings); + + const expiryThreshold = dss.settings?.certThresholds?.expiration; + + const ageThreshold = dss.settings?.certThresholds?.age; + + const certValidityDate = new Date(expiryDate ?? ''); + + const isValidDate = !isNaN(certValidityDate.valueOf()); + + if (!isValidDate) { + return false; + } + + const isExpiringSoon = moment(certValidityDate).diff(moment(), 'days') < expiryThreshold!; + + const isTooOld = moment().diff(moment(issueDate), 'days') > ageThreshold!; + + const isExpired = moment(certValidityDate) < moment(); + + if (isExpired) { + return CERT_STATUS.EXPIRED; + } + + return isExpiringSoon + ? CERT_STATUS.EXPIRING_SOON + : isTooOld + ? CERT_STATUS.TOO_OLD + : CERT_STATUS.OK; +}; diff --git a/x-pack/plugins/uptime/public/hooks/use_telemetry.ts b/x-pack/plugins/uptime/public/hooks/use_telemetry.ts index a2012b8ac5636..9b4a441fe5ade 100644 --- a/x-pack/plugins/uptime/public/hooks/use_telemetry.ts +++ b/x-pack/plugins/uptime/public/hooks/use_telemetry.ts @@ -13,6 +13,7 @@ export enum UptimePage { Overview = 'Overview', Monitor = 'Monitor', Settings = 'Settings', + Certificates = 'Certificates', NotFound = '__not-found__', } diff --git a/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/certificates.test.tsx.snap b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/certificates.test.tsx.snap new file mode 100644 index 0000000000000..53b2ea27864bc --- /dev/null +++ b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/certificates.test.tsx.snap @@ -0,0 +1,56 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CertificatesPage shallow renders expected elements for valid props 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/pages/__tests__/certificates.test.tsx b/x-pack/plugins/uptime/public/pages/__tests__/certificates.test.tsx new file mode 100644 index 0000000000000..8dfb6fba3d6be --- /dev/null +++ b/x-pack/plugins/uptime/public/pages/__tests__/certificates.test.tsx @@ -0,0 +1,15 @@ +/* + * 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. + */ + +import React from 'react'; +import { shallowWithRouter } from '../../lib'; +import { CertificatesPage } from '../certificates'; + +describe('CertificatesPage', () => { + it('shallow renders expected elements for valid props', () => { + expect(shallowWithRouter()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/pages/certificates.tsx b/x-pack/plugins/uptime/public/pages/certificates.tsx new file mode 100644 index 0000000000000..d6c1b8e2b4568 --- /dev/null +++ b/x-pack/plugins/uptime/public/pages/certificates.tsx @@ -0,0 +1,136 @@ +/* + * 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. + */ + +import { useDispatch, useSelector } from 'react-redux'; +import { Link } from 'react-router-dom'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, +} from '@elastic/eui'; +import React, { useContext, useEffect, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useTrackPageview } from '../../../observability/public'; +import { PageHeader } from './page_header'; +import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; +import { OVERVIEW_ROUTE, SETTINGS_ROUTE } from '../../common/constants'; +import { getDynamicSettings } from '../state/actions/dynamic_settings'; +import { UptimeRefreshContext } from '../contexts'; +import * as labels from './translations'; +import { UptimePage, useUptimeTelemetry } from '../hooks'; +import { certificatesSelector, getCertificatesAction } from '../state/certificates/certificates'; +import { CertificateList, CertificateSearch, CertSort } from '../components/certificates'; + +const DEFAULT_PAGE_SIZE = 10; +const LOCAL_STORAGE_KEY = 'xpack.uptime.certList.pageSize'; +const getPageSizeValue = () => { + const value = parseInt(localStorage.getItem(LOCAL_STORAGE_KEY) ?? '', 10); + if (isNaN(value)) { + return DEFAULT_PAGE_SIZE; + } + return value; +}; + +export const CertificatesPage: React.FC = () => { + useUptimeTelemetry(UptimePage.Certificates); + + useTrackPageview({ app: 'uptime', path: 'certificates' }); + useTrackPageview({ app: 'uptime', path: 'certificates', delay: 15000 }); + + useBreadcrumbs([{ text: 'Certificates' }]); + + const [page, setPage] = useState({ index: 0, size: getPageSizeValue() }); + const [sort, setSort] = useState({ + field: 'not_after', + direction: 'asc', + }); + const [search, setSearch] = useState(''); + + const dispatch = useDispatch(); + + const { lastRefresh, refreshApp } = useContext(UptimeRefreshContext); + + useEffect(() => { + dispatch(getDynamicSettings()); + }, [dispatch]); + + useEffect(() => { + dispatch( + getCertificatesAction.get({ + search, + ...page, + sortBy: sort.field, + direction: sort.direction, + }) + ); + }, [dispatch, page, search, sort.direction, sort.field, lastRefresh]); + + const certificates = useSelector(certificatesSelector); + + return ( + <> + + + + + {labels.RETURN_TO_OVERVIEW} + + + + + + + {labels.SETTINGS_ON_CERT} + + + + + { + refreshApp(); + }} + data-test-subj="superDatePickerApplyTimeButton" + > + {labels.REFRESH_CERT} + + + + + + + {certificates?.total ?? 0}, + }} + /> + } + datePicker={false} + /> + + + + { + setPage(pageVal); + setSort(sortVal); + localStorage.setItem(LOCAL_STORAGE_KEY, pageVal.size.toString()); + }} + sort={sort} + /> + + + ); +}; diff --git a/x-pack/plugins/uptime/public/pages/monitor.tsx b/x-pack/plugins/uptime/public/pages/monitor.tsx index 8a309db75acd2..fc796e679a2f6 100644 --- a/x-pack/plugins/uptime/public/pages/monitor.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor.tsx @@ -5,8 +5,8 @@ */ import { EuiSpacer } from '@elastic/eui'; -import React from 'react'; -import { useSelector } from 'react-redux'; +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import { monitorStatusSelector } from '../state/selectors'; import { PageHeader } from './page_header'; import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; @@ -14,8 +14,15 @@ import { useTrackPageview } from '../../../observability/public'; import { useMonitorId, useUptimeTelemetry, UptimePage } from '../hooks'; import { MonitorCharts } from '../components/monitor'; import { MonitorStatusDetails, PingList } from '../components/monitor'; +import { getDynamicSettings } from '../state/actions/dynamic_settings'; export const MonitorPage: React.FC = () => { + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(getDynamicSettings()); + }, [dispatch]); + const monitorId = useMonitorId(); const selectedMonitor = useSelector(monitorStatusSelector); diff --git a/x-pack/plugins/uptime/public/pages/page_header.tsx b/x-pack/plugins/uptime/public/pages/page_header.tsx index b10bc6ba44f8a..b6791e6a93445 100644 --- a/x-pack/plugins/uptime/public/pages/page_header.tsx +++ b/x-pack/plugins/uptime/public/pages/page_header.tsx @@ -13,7 +13,7 @@ import { SETTINGS_ROUTE } from '../../common/constants'; import { ToggleAlertFlyoutButton } from '../components/overview/alerts/alerts_containers'; interface PageHeaderProps { - headingText: string; + headingText: string | JSX.Element; extraLinks?: boolean; datePicker?: boolean; } diff --git a/x-pack/plugins/uptime/public/pages/translations.ts b/x-pack/plugins/uptime/public/pages/translations.ts index 85e4e3f931c46..74fb2eeb1416b 100644 --- a/x-pack/plugins/uptime/public/pages/translations.ts +++ b/x-pack/plugins/uptime/public/pages/translations.ts @@ -6,6 +6,21 @@ import { i18n } from '@kbn/i18n'; +export const SETTINGS_ON_CERT = i18n.translate('xpack.uptime.certificates.settingsLinkLabel', { + defaultMessage: 'Settings', +}); + +export const RETURN_TO_OVERVIEW = i18n.translate( + 'xpack.uptime.certificates.returnToOverviewLinkLabel', + { + defaultMessage: 'Return to overview', + } +); + +export const REFRESH_CERT = i18n.translate('xpack.uptime.certificates.refresh', { + defaultMessage: 'Refresh', +}); + export const settings = { breadcrumbText: i18n.translate('xpack.uptime.settingsBreadcrumbText', { defaultMessage: 'Settings', diff --git a/x-pack/plugins/uptime/public/routes.tsx b/x-pack/plugins/uptime/public/routes.tsx index eb0587c0417a2..ca97858998df7 100644 --- a/x-pack/plugins/uptime/public/routes.tsx +++ b/x-pack/plugins/uptime/public/routes.tsx @@ -8,8 +8,14 @@ import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; import { DataPublicPluginSetup } from '../../../../src/plugins/data/public'; import { OverviewPage } from './components/overview/overview_container'; -import { MONITOR_ROUTE, OVERVIEW_ROUTE, SETTINGS_ROUTE } from '../common/constants'; +import { + CERTIFICATES_ROUTE, + MONITOR_ROUTE, + OVERVIEW_ROUTE, + SETTINGS_ROUTE, +} from '../common/constants'; import { MonitorPage, NotFoundPage, SettingsPage } from './pages'; +import { CertificatesPage } from './pages/certificates'; interface RouterProps { autocomplete: DataPublicPluginSetup['autocomplete']; @@ -27,6 +33,11 @@ export const PageRouter: FC = ({ autocomplete }) => (
+ +
+ +
+
diff --git a/x-pack/plugins/uptime/public/state/api/certificates.ts b/x-pack/plugins/uptime/public/state/api/certificates.ts new file mode 100644 index 0000000000000..78267e659d233 --- /dev/null +++ b/x-pack/plugins/uptime/public/state/api/certificates.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +import { API_URLS } from '../../../common/constants'; +import { apiService } from './utils'; +import { CertResultType, GetCertsParams } from '../../../common/runtime_types'; + +export const fetchCertificates = async (params: GetCertsParams) => { + return await apiService.get(API_URLS.CERTS, params, CertResultType); +}; diff --git a/x-pack/plugins/uptime/public/state/certificates/certificates.ts b/x-pack/plugins/uptime/public/state/certificates/certificates.ts new file mode 100644 index 0000000000000..18cbcf6bcb614 --- /dev/null +++ b/x-pack/plugins/uptime/public/state/certificates/certificates.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +import { handleActions } from 'redux-actions'; +import { takeLatest } from 'redux-saga/effects'; +import { createAsyncAction } from '../actions/utils'; +import { getAsyncInitialState, handleAsyncAction } from '../reducers/utils'; +import { CertResult, GetCertsParams } from '../../../common/runtime_types'; +import { AppState } from '../index'; +import { AsyncInitialState } from '../reducers/types'; +import { fetchEffectFactory } from '../effects/fetch_effect'; +import { fetchCertificates } from '../api/certificates'; + +export const getCertificatesAction = createAsyncAction( + 'GET_CERTIFICATES' +); + +interface CertificatesState { + certs: AsyncInitialState; +} + +const initialState = { + certs: getAsyncInitialState(), +}; + +export const certificatesReducer = handleActions( + { + ...handleAsyncAction('certs', getCertificatesAction), + }, + initialState +); + +export function* fetchCertificatesEffect() { + yield takeLatest( + getCertificatesAction.get, + fetchEffectFactory(fetchCertificates, getCertificatesAction.success, getCertificatesAction.fail) + ); +} + +export const certificatesSelector = ({ certificates }: AppState) => certificates.certs.data; diff --git a/x-pack/plugins/uptime/public/state/effects/index.ts b/x-pack/plugins/uptime/public/state/effects/index.ts index 739179c5bbeae..211067c840d54 100644 --- a/x-pack/plugins/uptime/public/state/effects/index.ts +++ b/x-pack/plugins/uptime/public/state/effects/index.ts @@ -16,6 +16,7 @@ import { fetchPingsEffect, fetchPingHistogramEffect } from './ping'; import { fetchMonitorDurationEffect } from './monitor_duration'; import { fetchMLJobEffect } from './ml_anomaly'; import { fetchIndexStatusEffect } from './index_status'; +import { fetchCertificatesEffect } from '../certificates/certificates'; export function* rootEffect() { yield fork(fetchMonitorDetailsEffect); @@ -31,4 +32,5 @@ export function* rootEffect() { yield fork(fetchMLJobEffect); yield fork(fetchMonitorDurationEffect); yield fork(fetchIndexStatusEffect); + yield fork(fetchCertificatesEffect); } diff --git a/x-pack/plugins/uptime/public/state/reducers/index.ts b/x-pack/plugins/uptime/public/state/reducers/index.ts index 294bde2f277ec..ead7f5b46431b 100644 --- a/x-pack/plugins/uptime/public/state/reducers/index.ts +++ b/x-pack/plugins/uptime/public/state/reducers/index.ts @@ -18,6 +18,7 @@ import { pingListReducer } from './ping_list'; import { monitorDurationReducer } from './monitor_duration'; import { indexStatusReducer } from './index_status'; import { mlJobsReducer } from './ml_anomaly'; +import { certificatesReducer } from '../certificates/certificates'; export const rootReducer = combineReducers({ monitor: monitorReducer, @@ -33,4 +34,5 @@ export const rootReducer = combineReducers({ ml: mlJobsReducer, monitorDuration: monitorDurationReducer, indexStatus: indexStatusReducer, + certificates: certificatesReducer, }); diff --git a/x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts b/x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts index 61e03a9592921..9a4a949ac4ede 100644 --- a/x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts +++ b/x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts @@ -15,7 +15,6 @@ import { getMLCapabilitiesAction, } from '../actions'; import { getAsyncInitialState, handleAsyncAction } from './utils'; -import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; import { AsyncInitialState } from './types'; import { MlCapabilitiesResponse } from '../../../../../plugins/ml/common/types/capabilities'; import { CreateMLJobSuccess, DeleteJobResults } from '../actions/types'; @@ -37,15 +36,13 @@ const initialState: MLJobState = { mlCapabilities: getAsyncInitialState(), }; -type Payload = IHttpFetchError; - export const mlJobsReducer = handleActions( { - ...handleAsyncAction('mlJob', getExistingMLJobAction), - ...handleAsyncAction('mlCapabilities', getMLCapabilitiesAction), - ...handleAsyncAction('createJob', createMLJobAction), - ...handleAsyncAction('deleteJob', deleteMLJobAction), - ...handleAsyncAction('anomalies', getAnomalyRecordsAction), + ...handleAsyncAction('mlJob', getExistingMLJobAction), + ...handleAsyncAction('mlCapabilities', getMLCapabilitiesAction), + ...handleAsyncAction('createJob', createMLJobAction), + ...handleAsyncAction('deleteJob', deleteMLJobAction), + ...handleAsyncAction('anomalies', getAnomalyRecordsAction), ...{ [String(resetMLState)]: state => ({ ...state, diff --git a/x-pack/plugins/uptime/public/state/reducers/monitor_list.ts b/x-pack/plugins/uptime/public/state/reducers/monitor_list.ts index cf895aebeb755..59a794a549d57 100644 --- a/x-pack/plugins/uptime/public/state/reducers/monitor_list.ts +++ b/x-pack/plugins/uptime/public/state/reducers/monitor_list.ts @@ -9,9 +9,9 @@ import { getMonitorList, getMonitorListSuccess, getMonitorListFailure } from '.. import { MonitorSummaryResult } from '../../../common/runtime_types'; export interface MonitorList { - list: MonitorSummaryResult; error?: Error; loading: boolean; + list: MonitorSummaryResult; } export const initialState: MonitorList = { diff --git a/x-pack/plugins/uptime/public/state/reducers/utils.ts b/x-pack/plugins/uptime/public/state/reducers/utils.ts index d7a7f237c1154..15e49e7f6de8b 100644 --- a/x-pack/plugins/uptime/public/state/reducers/utils.ts +++ b/x-pack/plugins/uptime/public/state/reducers/utils.ts @@ -7,7 +7,7 @@ import { Action } from 'redux-actions'; import { AsyncAction } from '../actions/types'; -export function handleAsyncAction( +export function handleAsyncAction( storeKey: string, asyncAction: AsyncAction ) { @@ -24,7 +24,7 @@ export function handleAsyncAction( ...state, [storeKey]: { ...(state as any)[storeKey], - data: action.payload === null ? action.payload : { ...action.payload }, + data: action.payload, loading: false, }, }), diff --git a/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts index ba5e5abf588b8..1c4c12f5f52d2 100644 --- a/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts +++ b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts @@ -101,6 +101,12 @@ describe('state selectors', () => { loading: false, }, }, + certificates: { + certs: { + data: null, + loading: false, + }, + }, }; it('selects base path from state', () => { diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts index 894e2316dc927..4aec376ceadf0 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts @@ -19,9 +19,10 @@ describe('getCerts', () => { _score: 0, _source: { tls: { - certificate_not_valid_before: '2019-08-16T01:40:25.000Z', server: { x509: { + not_before: '2019-08-16T01:40:25.000Z', + not_after: '2020-07-16T03:15:39.000Z', subject: { common_name: 'r2.shared.global.fastly.net', }, @@ -34,12 +35,14 @@ describe('getCerts', () => { sha256: '12b00d04db0db8caa302bfde043e88f95baceb91e86ac143e93830b4bbec726d', }, }, - certificate_not_valid_after: '2020-07-16T03:15:39.000Z', }, monitor: { name: 'Real World Test', id: 'real-world-test', }, + url: { + full: 'https://fullurl.com', + }, }, fields: { 'tls.server.hash.sha256': [ @@ -96,24 +99,30 @@ describe('getCerts', () => { to: 'now+1h', search: 'my_common_name', size: 30, + sortBy: 'not_after', + direction: 'desc', }); expect(result).toMatchInlineSnapshot(` - Array [ - Object { - "certificate_not_valid_after": "2020-07-16T03:15:39.000Z", - "certificate_not_valid_before": "2019-08-16T01:40:25.000Z", - "common_name": "r2.shared.global.fastly.net", - "issuer": "GlobalSign CloudSSL CA - SHA256 - G3", - "monitors": Array [ - Object { - "id": "real-world-test", - "name": "Real World Test", - }, - ], - "sha1": "b7b4b89ef0d0caf39d223736f0fdbb03c7b426f1", - "sha256": "12b00d04db0db8caa302bfde043e88f95baceb91e86ac143e93830b4bbec726d", - }, - ] + Object { + "certs": Array [ + Object { + "common_name": "r2.shared.global.fastly.net", + "issuer": "GlobalSign CloudSSL CA - SHA256 - G3", + "monitors": Array [ + Object { + "id": "real-world-test", + "name": "Real World Test", + "url": undefined, + }, + ], + "not_after": "2020-07-16T03:15:39.000Z", + "not_before": "2019-08-16T01:40:25.000Z", + "sha1": "b7b4b89ef0d0caf39d223736f0fdbb03c7b426f1", + "sha256": "12b00d04db0db8caa302bfde043e88f95baceb91e86ac143e93830b4bbec726d", + }, + ], + "total": 0, + } `); expect(mockCallES.mock.calls).toMatchInlineSnapshot(` Array [ @@ -128,9 +137,16 @@ describe('getCerts', () => { "tls.server.x509.subject.common_name", "tls.server.hash.sha1", "tls.server.hash.sha256", - "tls.certificate_not_valid_before", - "tls.certificate_not_valid_after", + "tls.server.x509.not_after", + "tls.server.x509.not_before", ], + "aggs": Object { + "total": Object { + "cardinality": Object { + "field": "tls.server.hash.sha256", + }, + }, + }, "collapse": Object { "field": "tls.server.hash.sha256", "inner_hits": Object { @@ -138,6 +154,7 @@ describe('getCerts', () => { "includes": Array [ "monitor.id", "monitor.name", + "url.full", ], }, "collapse": Object { @@ -151,13 +168,13 @@ describe('getCerts', () => { ], }, }, - "from": 1, + "from": 30, "query": Object { "bool": Object { "filter": Array [ Object { "exists": Object { - "field": "tls", + "field": "tls.server", }, }, Object { @@ -169,39 +186,32 @@ describe('getCerts', () => { }, }, ], + "minimum_should_match": 1, "should": Array [ Object { - "wildcard": Object { - "tls.server.issuer": Object { - "value": "*my_common_name*", - }, - }, - }, - Object { - "wildcard": Object { - "tls.common_name": Object { - "value": "*my_common_name*", - }, - }, - }, - Object { - "wildcard": Object { - "monitor.id": Object { - "value": "*my_common_name*", - }, - }, - }, - Object { - "wildcard": Object { - "monitor.name": Object { - "value": "*my_common_name*", - }, + "multi_match": Object { + "fields": Array [ + "monitor.id.text", + "monitor.name.text", + "url.full.text", + "tls.server.x509.subject.common_name.text", + "tls.server.x509.issuer.common_name.text", + ], + "query": "my_common_name", + "type": "phrase_prefix", }, }, ], }, }, "size": 30, + "sort": Array [ + Object { + "tls.server.x509.not_after": Object { + "order": "desc", + }, + }, + ], }, "index": "heartbeat*", }, diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts index 75bf5096bd997..f8a335c387f2e 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts @@ -32,7 +32,14 @@ describe('getLatestMonitor', () => { }, }, size: 1, - _source: ['url', 'monitor', 'observer', 'tls', '@timestamp'], + _source: [ + 'url', + 'monitor', + 'observer', + '@timestamp', + 'tls.server.x509.not_after', + 'tls.server.x509.not_before', + ], sort: { '@timestamp': { order: 'desc' }, }, @@ -83,6 +90,10 @@ describe('getLatestMonitor', () => { "type": "http", }, "timestamp": "123456", + "tls": Object { + "not_after": undefined, + "not_before": undefined, + }, } `); expect(result.timestamp).toBe('123456'); diff --git a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts index b427e7cae1a7e..6820cd69376d1 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts @@ -5,9 +5,16 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Cert, GetCertsParams } from '../../../common/runtime_types'; +import { CertResult, GetCertsParams } from '../../../common/runtime_types'; -export const getCerts: UMElasticsearchQueryFn = async ({ +enum SortFields { + 'issuer' = 'tls.server.x509.issuer.common_name', + 'not_after' = 'tls.server.x509.not_after', + 'not_before' = 'tls.server.x509.not_before', + 'common_name' = 'tls.server.x509.subject.common_name', +} + +export const getCerts: UMElasticsearchQueryFn = async ({ callES, dynamicSettings, index, @@ -15,19 +22,29 @@ export const getCerts: UMElasticsearchQueryFn = async ({ to, search, size, + sortBy, + direction, }) => { - const searchWrapper = `*${search}*`; + const sort = SortFields[sortBy as keyof typeof SortFields]; + const params: any = { index: dynamicSettings.heartbeatIndices, body: { - from: index, + from: index * size, size, + sort: [ + { + [sort]: { + order: direction, + }, + }, + ], query: { bool: { filter: [ { exists: { - field: 'tls', + field: 'tls.server', }, }, { @@ -48,14 +65,14 @@ export const getCerts: UMElasticsearchQueryFn = async ({ 'tls.server.x509.subject.common_name', 'tls.server.hash.sha1', 'tls.server.hash.sha256', - 'tls.certificate_not_valid_before', - 'tls.certificate_not_valid_after', + 'tls.server.x509.not_after', + 'tls.server.x509.not_before', ], collapse: { field: 'tls.server.hash.sha256', inner_hits: { _source: { - includes: ['monitor.id', 'monitor.name'], + includes: ['monitor.id', 'monitor.name', 'url.full'], }, collapse: { field: 'monitor.id', @@ -64,72 +81,67 @@ export const getCerts: UMElasticsearchQueryFn = async ({ sort: [{ 'monitor.id': 'asc' }], }, }, + aggs: { + total: { + cardinality: { + field: 'tls.server.hash.sha256', + }, + }, + }, }, }; if (search) { + params.body.query.bool.minimum_should_match = 1; params.body.query.bool.should = [ { - wildcard: { - 'tls.server.issuer': { - value: searchWrapper, - }, - }, - }, - { - wildcard: { - 'tls.common_name': { - value: searchWrapper, - }, - }, - }, - { - wildcard: { - 'monitor.id': { - value: searchWrapper, - }, - }, - }, - { - wildcard: { - 'monitor.name': { - value: searchWrapper, - }, + multi_match: { + query: escape(search), + type: 'phrase_prefix', + fields: [ + 'monitor.id.text', + 'monitor.name.text', + 'url.full.text', + 'tls.server.x509.subject.common_name.text', + 'tls.server.x509.issuer.common_name.text', + ], }, }, ]; } const result = await callES('search', params); - const formatted = (result?.hits?.hits ?? []).map((hit: any) => { + + const certs = (result?.hits?.hits ?? []).map((hit: any) => { const { _source: { - tls: { - server: { - x509: { - issuer: { common_name: issuer }, - subject: { common_name }, - }, - hash: { sha1, sha256 }, - }, - certificate_not_valid_after, - certificate_not_valid_before, - }, + tls: { server }, }, } = hit; + + const notAfter = server?.x509?.not_after; + const notBefore = server?.x509?.not_before; + const issuer = server?.x509?.issuer?.common_name; + const commonName = server?.x509?.subject?.common_name; + const sha1 = server?.hash?.sha1; + const sha256 = server?.hash?.sha256; + const monitors = hit.inner_hits.monitors.hits.hits.map((monitor: any) => ({ name: monitor._source?.monitor.name, id: monitor._source?.monitor.id, + url: monitor._source?.url?.full, })); + return { monitors, - certificate_not_valid_after, - certificate_not_valid_before, issuer, sha1, sha256, - common_name, + not_after: notAfter, + not_before: notBefore, + common_name: commonName, }; }); - return formatted; + const total = result?.aggregations?.total?.value ?? 0; + return { certs, total }; }; diff --git a/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts b/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts index 98ce449002f21..db34de5159213 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts @@ -45,7 +45,14 @@ export const getLatestMonitor: UMElasticsearchQueryFn = UMElasticsearchQueryFn; export interface UptimeRequests { - getCerts: ESQ; + getCerts: ESQ; getFilterBar: ESQ; getIndexPattern: ESQ<{}, {}>; getLatestMonitor: ESQ; diff --git a/x-pack/plugins/uptime/server/rest_api/certs.ts b/x-pack/plugins/uptime/server/rest_api/certs/certs.ts similarity index 63% rename from x-pack/plugins/uptime/server/rest_api/certs.ts rename to x-pack/plugins/uptime/server/rest_api/certs/certs.ts index f2e1700b23e7d..a5ca6e264d299 100644 --- a/x-pack/plugins/uptime/server/rest_api/certs.ts +++ b/x-pack/plugins/uptime/server/rest_api/certs/certs.ts @@ -5,14 +5,16 @@ */ import { schema } from '@kbn/config-schema'; -import { UMServerLibs } from '../lib/lib'; -import { UMRestApiRouteFactory } from '.'; -import { API_URLS } from '../../common/constants'; +import { API_URLS } from '../../../common/constants'; +import { UMServerLibs } from '../../lib/lib'; +import { UMRestApiRouteFactory } from '../types'; const DEFAULT_INDEX = 0; const DEFAULT_SIZE = 25; const DEFAULT_FROM = 'now-1d'; const DEFAULT_TO = 'now'; +const DEFAULT_SORT = 'not_after'; +const DEFAULT_DIRECTION = 'asc'; export const createGetCertsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', @@ -24,30 +26,33 @@ export const createGetCertsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) = search: schema.maybe(schema.string()), index: schema.maybe(schema.number()), size: schema.maybe(schema.number()), + sortBy: schema.maybe(schema.string()), + direction: schema.maybe(schema.string()), }), }, - writeAccess: false, - options: { - tags: ['access:uptime-read'], - }, handler: async ({ callES, dynamicSettings }, _context, request, response): Promise => { const index = request.query?.index ?? DEFAULT_INDEX; const size = request.query?.size ?? DEFAULT_SIZE; const from = request.query?.from ?? DEFAULT_FROM; const to = request.query?.to ?? DEFAULT_TO; + const sortBy = request.query?.sortBy ?? DEFAULT_SORT; + const direction = request.query?.direction ?? DEFAULT_DIRECTION; const { search } = request.query; - + const result = await libs.requests.getCerts({ + callES, + dynamicSettings, + index, + search, + size, + from, + to, + sortBy, + direction, + }); return response.ok({ body: { - certs: await libs.requests.getCerts({ - callES, - dynamicSettings, - index, - search, - size, - from, - to, - }), + certs: result.certs, + total: result.total, }, }); }, diff --git a/x-pack/plugins/uptime/server/rest_api/index.ts b/x-pack/plugins/uptime/server/rest_api/index.ts index a7a63342d11d4..2b598be284e1c 100644 --- a/x-pack/plugins/uptime/server/rest_api/index.ts +++ b/x-pack/plugins/uptime/server/rest_api/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createGetCertsRoute } from './certs'; +import { createGetCertsRoute } from './certs/certs'; import { createGetOverviewFilters } from './overview_filters'; import { createGetPingHistogramRoute, createGetPingsRoute } from './pings'; import { createGetDynamicSettingsRoute, createPostDynamicSettingsRoute } from './dynamic_settings'; @@ -19,6 +19,7 @@ import { } from './monitors'; import { createGetMonitorDurationRoute } from './monitors/monitors_durations'; import { createGetIndexPatternRoute, createGetIndexStatusRoute } from './index_state'; + export * from './types'; export { createRouteWithAuth } from './create_route_with_auth'; export { uptimeRouteWrapper } from './uptime_route_wrapper'; diff --git a/x-pack/test/api_integration/apis/uptime/rest/certs.ts b/x-pack/test/api_integration/apis/uptime/rest/certs.ts index a3a15d8f8b014..4917917fdd6bc 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/certs.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/certs.ts @@ -21,7 +21,7 @@ export default function({ getService }: FtrProviderContext) { describe('empty index', async () => { it('returns empty array for no data', async () => { const apiResponse = await supertest.get(API_URLS.CERTS); - expect(JSON.stringify(apiResponse.body)).to.eql('{"certs":[]}'); + expect(JSON.stringify(apiResponse.body)).to.eql('{"certs":[],"total":0}'); }); }); @@ -39,10 +39,10 @@ export default function({ getService }: FtrProviderContext) { 10000, { tls: { - certificate_not_valid_after: cnva, - certificate_not_valid_before: cnvb, server: { x509: { + not_after: cnva, + not_before: cnvb, issuer: { common_name: 'issuer-common-name', }, @@ -78,9 +78,12 @@ export default function({ getService }: FtrProviderContext) { const cert = body.certs[0]; expect(Array.isArray(cert.monitors)).to.be(true); - expect(cert.monitors[0]).to.eql({ id: monitorId }); - expect(cert.certificate_not_valid_after).to.eql(cnva); - expect(cert.certificate_not_valid_before).to.eql(cnvb); + expect(cert.monitors[0]).to.eql({ + id: monitorId, + url: 'http://localhost:5678/pattern?r=200x5,500x1', + }); + expect(cert.not_after).to.eql(cnva); + expect(cert.not_before).to.eql(cnvb); expect(cert.common_name).to.eql('subject-common-name'); expect(cert.issuer).to.eql('issuer-common-name'); }); diff --git a/x-pack/test/api_integration/apis/uptime/rest/fixtures/monitor_latest_status.json b/x-pack/test/api_integration/apis/uptime/rest/fixtures/monitor_latest_status.json index 9a33be807670e..1baff443bd97f 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/fixtures/monitor_latest_status.json +++ b/x-pack/test/api_integration/apis/uptime/rest/fixtures/monitor_latest_status.json @@ -27,5 +27,6 @@ "full": "http://localhost:5678/pattern?r=200x1" }, "docId": "h5toHm0B0I9WX_CznN_V", - "timestamp": "2019-09-11T03:40:34.371Z" -} \ No newline at end of file + "timestamp": "2019-09-11T03:40:34.371Z", + "tls": {} +} diff --git a/x-pack/test/api_integration/apis/uptime/rest/helper/make_checks.ts b/x-pack/test/api_integration/apis/uptime/rest/helper/make_checks.ts index ae326c8b2aee0..5f62a3c55a2eb 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/helper/make_checks.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/helper/make_checks.ts @@ -6,119 +6,36 @@ import uuid from 'uuid'; import { merge, flattenDeep } from 'lodash'; - -const INDEX_NAME = 'heartbeat-8-generated-test'; - -export const makePing = async ( - es: any, - monitorId: string, - fields: { [key: string]: any }, - mogrify: (doc: any) => any, - refresh: boolean = true -) => { - const baseDoc = { - tcp: { - rtt: { - connect: { - us: 14687, - }, - }, - }, - observer: { - geo: { - name: 'mpls', - location: '37.926868, -78.024902', - }, - hostname: 'avc-x1e', - }, - agent: { - hostname: 'avc-x1e', - id: '10730a1a-4cb7-45ce-8524-80c4820476ab', - type: 'heartbeat', - ephemeral_id: '0d9a8dc6-f604-49e3-86a0-d8f9d6f2cbad', - version: '8.0.0', - }, - '@timestamp': new Date().toISOString(), - resolve: { - rtt: { - us: 350, - }, - ip: '127.0.0.1', - }, - ecs: { - version: '1.1.0', - }, - host: { - name: 'avc-x1e', - }, - http: { - rtt: { - response_header: { - us: 19349, - }, - total: { - us: 48954, - }, - write_request: { - us: 33, - }, - content: { - us: 51, - }, - validate: { - us: 19400, - }, - }, - response: { - status_code: 200, - body: { - bytes: 3, - hash: '27badc983df1780b60c2b3fa9d3a19a00e46aac798451f0febdca52920faaddf', - }, - }, - }, - monitor: { - duration: { - us: 49347, - }, - ip: '127.0.0.1', - id: monitorId, - check_group: uuid.v4(), - type: 'http', - status: 'up', - }, - event: { - dataset: 'uptime', - }, - url: { - path: '/pattern', - scheme: 'http', - port: 5678, - domain: 'localhost', - query: 'r=200x5,500x1', - full: 'http://localhost:5678/pattern?r=200x5,500x1', - }, - }; - - const doc = mogrify(merge(baseDoc, fields)); - - await es.index({ - index: INDEX_NAME, - refresh, - body: doc, - }); - - return doc; +import { makePing } from './make_ping'; +import { TlsProps } from './make_tls'; + +interface CheckProps { + es: any; + monitorId?: string; + numIps?: number; + fields?: { [key: string]: any }; + mogrify?: (doc: any) => any; + refresh?: boolean; + tls?: boolean | TlsProps; +} + +const getRandomMonitorId = () => { + return ( + 'monitor-' + + Math.random() + .toString(36) + .substring(7) + ); }; - -export const makeCheck = async ( - es: any, - monitorId: string, - numIps: number, - fields: { [key: string]: any }, - mogrify: (doc: any) => any, - refresh: boolean = true -) => { +export const makeCheck = async ({ + es, + monitorId = getRandomMonitorId(), + numIps = 1, + fields = {}, + mogrify = d => d, + refresh = true, + tls = false, +}: CheckProps): Promise<{ monitorId: string; docs: any }> => { const cgFields = { monitor: { check_group: uuid.v4(), @@ -139,7 +56,7 @@ export const makeCheck = async ( if (i === numIps - 1) { pingFields.summary = summary; } - const doc = await makePing(es, monitorId, pingFields, mogrify, false); + const doc = await makePing(es, monitorId, pingFields, mogrify, false, tls as any); docs.push(doc); // @ts-ignore summary[doc.monitor.status]++; @@ -149,15 +66,15 @@ export const makeCheck = async ( await es.indices.refresh(); } - return docs; + return { monitorId, docs }; }; export const makeChecks = async ( es: any, monitorId: string, - numChecks: number, - numIps: number, - every: number, // number of millis between checks + numChecks: number = 1, + numIps: number = 1, + every: number = 10000, // number of millis between checks fields: { [key: string]: any } = {}, mogrify: (doc: any) => any = d => d, refresh: boolean = true @@ -177,7 +94,8 @@ export const makeChecks = async ( }, }, }); - checks.push(await makeCheck(es, monitorId, numIps, fields, mogrify, false)); + const { docs } = await makeCheck({ es, monitorId, numIps, fields, mogrify, refresh: false }); + checks.push(docs); } if (refresh) { diff --git a/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts b/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts new file mode 100644 index 0000000000000..908c571e07e06 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/helper/make_ping.ts @@ -0,0 +1,118 @@ +/* + * 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. + */ + +import uuid from 'uuid'; +import { merge } from 'lodash'; +import { makeTls, TlsProps } from './make_tls'; + +const INDEX_NAME = 'heartbeat-8-generated-test'; + +export const makePing = async ( + es: any, + monitorId: string, + fields: { [key: string]: any }, + mogrify: (doc: any) => any, + refresh: boolean = true, + tls: boolean | TlsProps = false +) => { + const baseDoc: any = { + tcp: { + rtt: { + connect: { + us: 14687, + }, + }, + }, + observer: { + geo: { + name: 'mpls', + location: '37.926868, -78.024902', + }, + hostname: 'avc-x1e', + }, + agent: { + hostname: 'avc-x1e', + id: '10730a1a-4cb7-45ce-8524-80c4820476ab', + type: 'heartbeat', + ephemeral_id: '0d9a8dc6-f604-49e3-86a0-d8f9d6f2cbad', + version: '8.0.0', + }, + '@timestamp': new Date().toISOString(), + resolve: { + rtt: { + us: 350, + }, + ip: '127.0.0.1', + }, + ecs: { + version: '1.1.0', + }, + host: { + name: 'avc-x1e', + }, + http: { + rtt: { + response_header: { + us: 19349, + }, + total: { + us: 48954, + }, + write_request: { + us: 33, + }, + content: { + us: 51, + }, + validate: { + us: 19400, + }, + }, + response: { + status_code: 200, + body: { + bytes: 3, + hash: '27badc983df1780b60c2b3fa9d3a19a00e46aac798451f0febdca52920faaddf', + }, + }, + }, + monitor: { + duration: { + us: 49347, + }, + ip: '127.0.0.1', + id: monitorId, + check_group: uuid.v4(), + type: 'http', + status: 'up', + }, + event: { + dataset: 'uptime', + }, + url: { + path: '/pattern', + scheme: 'http', + port: 5678, + domain: 'localhost', + query: 'r=200x5,500x1', + full: 'http://localhost:5678/pattern?r=200x5,500x1', + }, + }; + + if (tls) { + baseDoc.tls = makeTls(tls as any); + } + + const doc = mogrify(merge(baseDoc, fields)); + + await es.index({ + index: INDEX_NAME, + refresh, + body: doc, + }); + + return doc; +}; diff --git a/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts b/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts new file mode 100644 index 0000000000000..3606462522024 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/helper/make_tls.ts @@ -0,0 +1,70 @@ +/* + * 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. + */ + +import moment from 'moment'; +import crypto from 'crypto'; + +export interface TlsProps { + valid?: boolean; + commonName?: string; + expiry?: string; + sha256?: string; +} + +type Props = TlsProps & boolean; + +// Note This is just a mock sha256 value, this doesn't actually generate actually sha 256 val +export const getSha256 = () => { + return crypto + .randomBytes(64) + .toString('hex') + .toUpperCase(); +}; + +export const makeTls = ({ valid = true, commonName = '*.elastic.co', expiry, sha256 }: Props) => { + const expiryDate = + expiry ?? + moment() + .add(valid ? 2 : -2, 'months') + .toISOString(); + + return { + version: '1.3', + cipher: 'TLS-AES-128-GCM-SHA256', + certificate_not_valid_before: '2020-03-01T00:00:00.000Z', + certificate_not_valid_after: expiryDate, + server: { + x509: { + not_before: '2020-03-01T00:00:00.000Z', + not_after: '2020-05-30T12:00:00.000Z', + issuer: { + distinguished_name: + 'CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US', + common_name: 'DigiCert SHA2 High Assurance Server CA', + }, + subject: { + common_name: commonName, + distinguished_name: 'CN=*.facebook.com,O=Facebook Inc.,L=Menlo Park,ST=California,C=US', + }, + serial_number: '10043199409725537507026285099403602396', + signature_algorithm: 'SHA256-RSA', + public_key_algorithm: 'ECDSA', + public_key_curve: 'P-256', + }, + hash: { + sha256: sha256 ?? '1a48f1db13c3bd1482ba1073441e74a1bb1308dc445c88749e0dc4f1889a88a4', + sha1: '23291c758d925b9f4bb3584de3763317e94c6ce9', + }, + }, + established: true, + rtt: { + handshake: { + us: 33103, + }, + }, + version_protocol: 'tls', + }; +}; diff --git a/x-pack/test/functional/apps/uptime/certificates.ts b/x-pack/test/functional/apps/uptime/certificates.ts new file mode 100644 index 0000000000000..05967e0f3acaf --- /dev/null +++ b/x-pack/test/functional/apps/uptime/certificates.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { makeCheck } from '../../../api_integration/apis/uptime/rest/helper/make_checks'; +import { getSha256 } from '../../../api_integration/apis/uptime/rest/helper/make_tls'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const { uptime } = getPageObjects(['uptime']); + const uptimeService = getService('uptime'); + + const es = getService('es'); + + describe('certificate page', function() { + before(async () => { + await uptime.goToRoot(true); + }); + + beforeEach(async () => { + await makeCheck({ es, tls: true }); + await uptimeService.navigation.refreshApp(); + }); + + it('can navigate to cert page', async () => { + await uptimeService.navigation.refreshApp(); + await uptimeService.cert.hasViewCertButton(); + await uptimeService.navigation.goToCertificates(); + }); + + it('displays certificates', async () => { + await uptimeService.cert.hasCertificates(); + }); + + it('displays specific certificates', async () => { + const certId = getSha256(); + const { monitorId } = await makeCheck({ + es, + tls: { + sha256: certId, + }, + }); + + await uptimeService.navigation.refreshApp(); + await uptimeService.cert.certificateExists({ certId, monitorId }); + }); + + it('performs search against monitor id', async () => { + const certId = getSha256(); + const { monitorId } = await makeCheck({ + es, + tls: { + sha256: certId, + }, + }); + await uptimeService.navigation.refreshApp(); + await uptimeService.cert.searchIsWorking(monitorId); + }); + }); +}; diff --git a/x-pack/test/functional/apps/uptime/index.ts b/x-pack/test/functional/apps/uptime/index.ts index f47214dc2ad2f..6ecd39f696312 100644 --- a/x-pack/test/functional/apps/uptime/index.ts +++ b/x-pack/test/functional/apps/uptime/index.ts @@ -53,6 +53,7 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { loadTestFile(require.resolve('./locations')); loadTestFile(require.resolve('./settings')); + loadTestFile(require.resolve('./certificates')); }); describe('with real-world data', () => { before(async () => { diff --git a/x-pack/test/functional/es_archives/uptime/blank/mappings.json b/x-pack/test/functional/es_archives/uptime/blank/mappings.json index fff4ef47bce0c..dd7f5cb9aa778 100644 --- a/x-pack/test/functional/es_archives/uptime/blank/mappings.json +++ b/x-pack/test/functional/es_archives/uptime/blank/mappings.json @@ -1665,6 +1665,13 @@ }, "id": { "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, "ignore_above": 1024 }, "ip": { @@ -1672,6 +1679,13 @@ }, "name": { "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, "ignore_above": 1024 }, "status": { @@ -3079,10 +3093,21 @@ }, "x509": { "properties": { + "alternative_names": { + "type": "keyword", + "ignore_above": 1024 + }, "issuer": { "properties": { "common_name": { "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, "ignore_above": 1024 }, "distinguished_name": { @@ -3092,14 +3117,16 @@ } }, "not_after": { - "type": "keyword", - "ignore_above": 1024 + "type": "date" }, "not_before": { + "type": "date" + }, + "public_key_algorithm": { "type": "keyword", "ignore_above": 1024 }, - "public_key_algorithm": { + "public_key_curve": { "type": "keyword", "ignore_above": 1024 }, @@ -3121,6 +3148,13 @@ "properties": { "common_name": { "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, "ignore_above": 1024 }, "distinguished_name": { @@ -3128,6 +3162,10 @@ "ignore_above": 1024 } } + }, + "version_number": { + "type": "keyword", + "ignore_above": 1024 } } } diff --git a/x-pack/test/functional/es_archives/uptime/full_heartbeat/mappings.json b/x-pack/test/functional/es_archives/uptime/full_heartbeat/mappings.json index 2b6002ddb3fab..97b72510da286 100644 --- a/x-pack/test/functional/es_archives/uptime/full_heartbeat/mappings.json +++ b/x-pack/test/functional/es_archives/uptime/full_heartbeat/mappings.json @@ -12,79 +12,115 @@ "beat": "heartbeat", "version": "8.0.0" }, - "date_detection": false, "dynamic_templates": [ { "labels": { + "path_match": "labels.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" + } } }, { "container.labels": { + "path_match": "container.labels.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" + } } }, { "dns.answers": { + "path_match": "dns.answers.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, + } + } + }, + { + "log.syslog": { + "path_match": "log.syslog.*", "match_mapping_type": "string", - "path_match": "dns.answers.*" + "mapping": { + "type": "keyword" + } } }, { - "fields": { + "network.inner": { + "path_match": "network.inner.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, + } + } + }, + { + "observer.egress": { + "path_match": "observer.egress.*", "match_mapping_type": "string", - "path_match": "fields.*" + "mapping": { + "type": "keyword" + } } }, { - "docker.container.labels": { + "observer.ingress": { + "path_match": "observer.ingress.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, + } + } + }, + { + "fields": { + "path_match": "fields.*", + "match_mapping_type": "string", + "mapping": { + "type": "keyword" + } + } + }, + { + "docker.container.labels": { + "path_match": "docker.container.labels.*", "match_mapping_type": "string", - "path_match": "docker.container.labels.*" + "mapping": { + "type": "keyword" + } } }, { "kubernetes.labels.*": { + "path_match": "kubernetes.labels.*", "mapping": { "type": "keyword" - }, - "path_match": "kubernetes.labels.*" + } } }, { "kubernetes.annotations.*": { + "path_match": "kubernetes.annotations.*", "mapping": { "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" + } } }, { "strings_as_keyword": { + "match_mapping_type": "string", "mapping": { "ignore_above": 1024, "type": "keyword" - }, - "match_mapping_type": "string" + } } } ], + "date_detection": false, "properties": { "@timestamp": { "type": "date" @@ -92,28 +128,28 @@ "agent": { "properties": { "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "hostname": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -125,8 +161,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -135,8 +177,8 @@ "client": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -146,8 +188,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -157,41 +205,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -199,8 +247,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -218,43 +266,67 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -265,76 +337,97 @@ "account": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "availability_zone": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "image": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "instance": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "machine": { "properties": { "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "project": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "provider": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" } } }, "container": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "image": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "tag": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -342,20 +435,20 @@ "type": "object" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "runtime": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "destination": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -365,8 +458,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -376,41 +475,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -418,8 +517,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -437,43 +536,144 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha512": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "path": { + "type": "keyword", + "ignore_above": 1024 + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 } } } @@ -484,55 +684,63 @@ "answers": { "properties": { "class": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "data": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "ttl": { "type": "long" }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "header_flags": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "op_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "question": { "properties": { "class": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "registered_domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "subdomain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -540,12 +748,12 @@ "type": "ip" }, "response_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -563,51 +771,61 @@ "ecs": { "properties": { "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "error": { "properties": { "code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "message": { - "norms": false, - "type": "text" + "type": "text", + "norms": false + }, + "stack_trace": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "event": { "properties": { "action": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "category": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "created": { "type": "date" }, "dataset": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "duration": { "type": "long" @@ -616,32 +834,39 @@ "type": "date" }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "ingested": { + "type": "date" }, "kind": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "module": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "outcome": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "provider": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 }, "risk_score": { "type": "float" @@ -659,12 +884,16 @@ "type": "date" }, "timezone": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "url": { + "type": "keyword", + "ignore_above": 1024 } } }, @@ -676,6 +905,31 @@ "accessed": { "type": "date" }, + "attributes": { + "type": "keyword", + "ignore_above": 1024 + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, "created": { "type": "date" }, @@ -683,254 +937,318 @@ "type": "date" }, "device": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "directory": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "drive_letter": { + "type": "keyword", + "ignore_above": 1 }, "extension": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "gid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "group": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "hash": { "properties": { "md5": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha1": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha256": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha512": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "inode": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "mime_type": { + "type": "keyword", + "ignore_above": 1024 }, "mode": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "mtime": { "type": "date" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "owner": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "size": { "type": "long" }, "target_path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "uid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { "properties": { "md5": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha1": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha256": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha512": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "host": { "properties": { "architecture": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "containerized": { "type": "boolean" }, + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hostname": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "ip": { "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "os": { "properties": { "build": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "codename": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "uptime": { "type": "long" @@ -938,40 +1256,56 @@ "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -987,8 +1321,14 @@ "type": "long" }, "content": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } }, @@ -996,12 +1336,12 @@ "type": "long" }, "method": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "referrer": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1013,18 +1353,28 @@ "type": "long" }, "content": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "bytes": { "type": "long" }, + "redirects": { + "type": "keyword", + "ignore_above": 1024 + }, "status_code": { "type": "long" } @@ -1077,8 +1427,8 @@ } }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1096,17 +1446,33 @@ } } }, + "interface": { + "properties": { + "alias": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, "jolokia": { "properties": { "agent": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1116,22 +1482,22 @@ "server": { "properties": { "product": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "vendor": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "url": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1147,20 +1513,20 @@ "container": { "properties": { "image": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "deployment": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1172,42 +1538,42 @@ } }, "namespace": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "node": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "pod": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "uid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "replicaset": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "statefulset": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } } @@ -1219,28 +1585,76 @@ "log": { "properties": { "level": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "logger": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "function": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } } } }, "message": { - "norms": false, - "type": "text" + "type": "text", + "norms": false }, "monitor": { "properties": { "check_group": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "duration": { "properties": { @@ -1250,238 +1664,683 @@ } }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, + "ignore_above": 1024 }, "ip": { "type": "ip" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, + "ignore_above": 1024 }, "status": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "timespan": { + "type": "date_range" }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "network": { "properties": { "application": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "bytes": { "type": "long" }, "community_id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "direction": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "forwarded_ip": { "type": "ip" }, "iana_number": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "packets": { "type": "long" }, "protocol": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "transport": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } } } }, "observer": { "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "zone": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hostname": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "zone": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "ip": { "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 }, "os": { "properties": { "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, + "product": { + "type": "keyword", + "ignore_above": 1024 + }, "serial_number": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "vendor": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "organization": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } }, "os": { "properties": { "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "package": { + "properties": { + "architecture": { + "type": "keyword", + "ignore_above": 1024 + }, + "build_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "checksum": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "install_scope": { + "type": "keyword", + "ignore_above": 1024 + }, + "installed": { + "type": "date" + }, + "license": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "path": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + }, + "size": { + "type": "long" + }, + "type": { + "type": "keyword", + "ignore_above": 1024 + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 } } }, "process": { "properties": { "args": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, - "executable": { - "ignore_above": 1024, - "type": "keyword" + "args_count": { + "type": "long" }, - "hash": { + "code_signature": { "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" + "exists": { + "type": "boolean" }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" + "status": { + "type": "keyword", + "ignore_above": 1024 }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" + "subject_name": { + "type": "keyword", + "ignore_above": 1024 }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "entity_id": { + "type": "keyword", + "ignore_above": 1024 + }, + "executable": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha512": { + "type": "keyword", + "ignore_above": 1024 } } }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "parent": { + "properties": { + "args": { + "type": "keyword", + "ignore_above": 1024 + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "entity_id": { + "type": "keyword", + "ignore_above": 1024 + }, + "executable": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha512": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "title": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + } + } + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "pgid": { "type": "long" @@ -1501,28 +2360,84 @@ "type": "long" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "title": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "uptime": { "type": "long" }, "working_directory": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "type": "keyword", + "ignore_above": 1024 + }, + "strings": { + "type": "keyword", + "ignore_above": 1024 + }, + "type": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "hive": { + "type": "keyword", + "ignore_above": 1024 + }, + "key": { + "type": "keyword", + "ignore_above": 1024 + }, + "path": { + "type": "keyword", + "ignore_above": 1024 + }, + "value": { + "type": "keyword", + "ignore_above": 1024 } } }, "related": { "properties": { + "hash": { + "type": "keyword", + "ignore_above": 1024 + }, "ip": { "type": "ip" + }, + "user": { + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1540,11 +2455,55 @@ } } }, + "rule": { + "properties": { + "author": { + "type": "keyword", + "ignore_above": 1024 + }, + "category": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "license": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + }, + "ruleset": { + "type": "keyword", + "ignore_above": 1024 + }, + "uuid": { + "type": "keyword", + "ignore_above": 1024 + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, "server": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -1554,8 +2513,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1565,41 +2530,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1607,8 +2572,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -1626,43 +2591,67 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1671,28 +2660,36 @@ "service": { "properties": { "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "node": { + "properties": { + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "state": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1714,8 +2711,8 @@ "source": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -1725,8 +2722,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1736,41 +2739,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1778,8 +2781,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -1797,43 +2800,67 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1850,8 +2877,8 @@ } }, "tags": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "tcp": { "properties": { @@ -1875,11 +2902,57 @@ } } }, + "threat": { + "properties": { + "framework": { + "type": "keyword", + "ignore_above": 1024 + }, + "tactic": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "technique": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } + }, "timeseries": { "properties": { "instance": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1891,6 +2964,78 @@ "certificate_not_valid_before": { "type": "date" }, + "cipher": { + "type": "keyword", + "ignore_above": 1024 + }, + "client": { + "properties": { + "certificate": { + "type": "keyword", + "ignore_above": 1024 + }, + "certificate_chain": { + "type": "keyword", + "ignore_above": 1024 + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "issuer": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja3": { + "type": "keyword", + "ignore_above": 1024 + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject": { + "type": "keyword", + "ignore_above": 1024 + }, + "supported_ciphers": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "curve": { + "type": "keyword", + "ignore_above": 1024 + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "type": "keyword", + "ignore_above": 1024 + }, + "resumed": { + "type": "boolean" + }, "rtt": { "properties": { "handshake": { @@ -1901,6 +3046,138 @@ } } } + }, + "server": { + "properties": { + "certificate": { + "type": "keyword", + "ignore_above": 1024 + }, + "certificate_chain": { + "type": "keyword", + "ignore_above": 1024 + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "issuer": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja3s": { + "type": "keyword", + "ignore_above": 1024 + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "type": "keyword", + "ignore_above": 1024 + }, + "x509": { + "properties": { + "alternative_names": { + "type": "keyword", + "ignore_above": 1024 + }, + "issuer": { + "properties": { + "common_name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, + "ignore_above": 1024 + }, + "distinguished_name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "type": "keyword", + "ignore_above": 1024 + }, + "public_key_curve": { + "type": "keyword", + "ignore_above": 1024 + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "type": "keyword", + "ignore_above": 1024 + }, + "signature_algorithm": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject": { + "properties": { + "common_name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false, + "analyzer": "simple" + } + }, + "ignore_above": 1024 + }, + "distinguished_name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "version_number": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + }, + "version_protocol": { + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1909,16 +3186,16 @@ "trace": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "transaction": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } } @@ -1927,83 +3204,123 @@ "url": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "extension": { + "type": "keyword", + "ignore_above": 1024 }, "fragment": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "password": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "port": { "type": "long" }, "query": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 }, "scheme": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 }, "username": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } }, @@ -2012,50 +3329,147 @@ "device": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "os": { "properties": { "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "vulnerability": { + "properties": { + "category": { + "type": "keyword", + "ignore_above": 1024 + }, + "classification": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "enumeration": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + }, + "report_id": { + "type": "keyword", + "ignore_above": 1024 + }, + "scanner": { + "properties": { + "vendor": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "severity": { + "type": "keyword", + "ignore_above": 1024 } } } diff --git a/x-pack/test/functional/page_objects/uptime_page.ts b/x-pack/test/functional/page_objects/uptime_page.ts index 0ebcb5c87deee..53c89eadeced7 100644 --- a/x-pack/test/functional/page_objects/uptime_page.ts +++ b/x-pack/test/functional/page_objects/uptime_page.ts @@ -13,8 +13,11 @@ export function UptimePageProvider({ getPageObjects, getService }: FtrProviderCo const retry = getService('retry'); return new (class UptimePage { - public async goToRoot() { + public async goToRoot(refresh?: boolean) { await navigation.goToUptime(); + if (refresh) { + await navigation.refreshApp(); + } } public async setDateRange(start: string, end: string) { diff --git a/x-pack/test/functional/services/uptime/certificates.ts b/x-pack/test/functional/services/uptime/certificates.ts new file mode 100644 index 0000000000000..fb7cb6191b0ae --- /dev/null +++ b/x-pack/test/functional/services/uptime/certificates.ts @@ -0,0 +1,50 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function UptimeCertProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + const changeSearchField = async (text: string) => { + const input = await testSubjects.find('uptimeCertSearch'); + await input.clearValueWithKeyboard(); + await input.type(text); + }; + + return { + async hasViewCertButton() { + return retry.tryForTime(15000, async () => { + await testSubjects.existOrFail('uptimeCertificatesLink'); + }); + }, + async certificateExists(cert: { certId: string; monitorId: string }) { + return retry.tryForTime(15000, async () => { + await testSubjects.existOrFail(cert.certId); + await testSubjects.existOrFail('monitor-page-link-' + cert.monitorId); + }); + }, + async hasCertificates(expectedTotal?: number) { + return retry.tryForTime(15000, async () => { + const totalCerts = await testSubjects.getVisibleText('uptimeCertTotal'); + if (expectedTotal) { + expect(Number(totalCerts) === expectedTotal).to.eql(true); + } else { + expect(Number(totalCerts) > 0).to.eql(true); + } + }); + }, + async searchIsWorking(monId: string) { + const self = this; + return retry.tryForTime(15000, async () => { + await changeSearchField(monId); + await self.hasCertificates(1); + }); + }, + }; +} diff --git a/x-pack/test/functional/services/uptime/navigation.ts b/x-pack/test/functional/services/uptime/navigation.ts index 36a5d7c9702f8..c17fa3a5f6339 100644 --- a/x-pack/test/functional/services/uptime/navigation.ts +++ b/x-pack/test/functional/services/uptime/navigation.ts @@ -25,9 +25,13 @@ export function UptimeNavigationProvider({ getService, getPageObjects }: FtrProv }); }; + const refreshApp = async () => { + await testSubjects.click('superDatePickerApplyTimeButton'); + }; + return { async refreshApp() { - await testSubjects.click('superDatePickerApplyTimeButton'); + await refreshApp(); }, async goToUptime() { @@ -60,6 +64,13 @@ export function UptimeNavigationProvider({ getService, getPageObjects }: FtrProv } }, + goToCertificates: async () => { + return retry.tryForTime(30 * 1000, async () => { + await testSubjects.click('uptimeCertificatesLink'); + await testSubjects.existOrFail('uptimeCertificatesPage'); + }); + }, + async loadDataAndGoToMonitorPage(dateStart: string, dateEnd: string, monitorId: string) { await PageObjects.timePicker.setAbsoluteRange(dateStart, dateEnd); await this.goToMonitor(monitorId); diff --git a/x-pack/test/functional/services/uptime/uptime.ts b/x-pack/test/functional/services/uptime/uptime.ts index 601feb6b0646e..8d36ba4bf6cfd 100644 --- a/x-pack/test/functional/services/uptime/uptime.ts +++ b/x-pack/test/functional/services/uptime/uptime.ts @@ -12,6 +12,7 @@ import { UptimeMonitorProvider } from './monitor'; import { UptimeNavigationProvider } from './navigation'; import { UptimeAlertsProvider } from './alerts'; import { UptimeMLAnomalyProvider } from './ml_anomaly'; +import { UptimeCertProvider } from './certificates'; export function UptimeProvider(context: FtrProviderContext) { const common = UptimeCommonProvider(context); @@ -20,6 +21,7 @@ export function UptimeProvider(context: FtrProviderContext) { const navigation = UptimeNavigationProvider(context); const alerts = UptimeAlertsProvider(context); const ml = UptimeMLAnomalyProvider(context); + const cert = UptimeCertProvider(context); return { common, @@ -28,5 +30,6 @@ export function UptimeProvider(context: FtrProviderContext) { navigation, alerts, ml, + cert, }; }