Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Uptime] Certificates page #64059

Merged
merged 58 commits into from
May 1, 2020
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3cdf756
WIP
shahzad31 Apr 7, 2020
abdfd3d
Merge branch 'master' into certificate-page
shahzad31 Apr 7, 2020
7103860
Updated Code
shahzad31 Apr 8, 2020
c8c785b
WIP
shahzad31 Apr 9, 2020
aadfe22
Merge branch 'master' into certificate-page
shahzad31 Apr 13, 2020
f2983b3
update
shahzad31 Apr 13, 2020
9a85cf2
Merge branch 'master' into certificate-page
shahzad31 Apr 15, 2020
9d29367
update settings
shahzad31 Apr 15, 2020
853baa7
added cert form
shahzad31 Apr 15, 2020
6b438ae
update settings
shahzad31 Apr 15, 2020
9c9ada4
Merge branch 'master' into certificate-page
shahzad31 Apr 16, 2020
ab518f1
Merge branch 'master' into certificate-page
shahzad31 Apr 17, 2020
ec0ed82
cert column
shahzad31 Apr 17, 2020
6078c1c
Merge branch 'master' into certificate-page
shahzad31 Apr 20, 2020
95498df
add pagination
shahzad31 Apr 21, 2020
82c5f63
added in monitor list tls info
shahzad31 Apr 21, 2020
4660ac7
added in monitor list tls info
shahzad31 Apr 21, 2020
6c300ea
fixed types
shahzad31 Apr 22, 2020
cdecb48
fixed types
shahzad31 Apr 22, 2020
8c329b8
updated
shahzad31 Apr 22, 2020
3645e02
update
shahzad31 Apr 23, 2020
b5c789b
update types
shahzad31 Apr 23, 2020
b890f34
update types
shahzad31 Apr 23, 2020
9773832
fixed test
shahzad31 Apr 23, 2020
68c722c
update snap
shahzad31 Apr 23, 2020
a5b49e5
update test
shahzad31 Apr 23, 2020
1e0c4ae
update feedback
shahzad31 Apr 23, 2020
2bf99d1
update snap
shahzad31 Apr 23, 2020
40676d0
update snap
shahzad31 Apr 23, 2020
e5167e9
Merge branch 'master' into certificate-page
shahzad31 Apr 23, 2020
2ede60a
update snap
shahzad31 Apr 23, 2020
4bd50b0
Merge branch 'master' into certificate-page
shahzad31 Apr 24, 2020
bc6b2c6
fix types
shahzad31 Apr 24, 2020
c0e524f
revert
shahzad31 Apr 24, 2020
5c7f0d9
fix type
shahzad31 Apr 24, 2020
524bce3
update snaps
shahzad31 Apr 24, 2020
67d5971
update tets
shahzad31 Apr 24, 2020
9f73c2f
Merge branch 'master' into certificate-page
shahzad31 Apr 27, 2020
4f3eaa6
update PR
shahzad31 Apr 27, 2020
74fd71e
update PR
shahzad31 Apr 27, 2020
3acb211
Merge branch 'master' into certificate-page
shahzad31 Apr 27, 2020
6b4549d
update query
shahzad31 Apr 27, 2020
5b9df04
Merge branch 'master' into certificate-page
shahzad31 Apr 29, 2020
134df07
added sorting on issuer and common name
shahzad31 Apr 29, 2020
68fd60e
added sorting
shahzad31 Apr 29, 2020
a7245ae
Merge branch 'master' into certificate-page
shahzad31 Apr 29, 2020
7ac98c7
updated tests
shahzad31 Apr 29, 2020
9aab27b
fix type
shahzad31 Apr 29, 2020
8f43c47
update exist field
shahzad31 Apr 29, 2020
e40d236
update margins
shahzad31 Apr 29, 2020
eff36cf
Merge branch 'master' into certificate-page
shahzad31 Apr 29, 2020
04ec35b
update cols
shahzad31 Apr 29, 2020
18e7f1c
added age info
shahzad31 Apr 30, 2020
bba5e5e
Merge branch 'master' into certificate-page
shahzad31 Apr 30, 2020
9abd565
update mapping
shahzad31 Apr 30, 2020
b8ea75c
PR feedback
shahzad31 Apr 30, 2020
98d1289
inline vars
shahzad31 May 1, 2020
b2adcda
var renmae
shahzad31 May 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/uptime/common/constants/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
25 changes: 17 additions & 8 deletions x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,28 @@ 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<typeof GetCertsParamsType>;

export const CertMonitorType = t.partial({
name: t.string,
id: 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({
Expand All @@ -39,4 +41,11 @@ export const CertType = t.intersection([
}),
]);

export const CertResultType = t.type({
certs: t.array(CertType),
total: t.number,
});

export type Cert = t.TypeOf<typeof CertType>;
export type CertMonitor = t.TypeOf<typeof CertMonitorType>;
export type CertResult = t.TypeOf<typeof CertResultType>;
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,10 @@ export const CertificatesStatesThresholdType = t.interface({
errorState: t.number,
});

export const DynamicSettingsType = t.intersection([
t.type({
heartbeatIndices: t.string,
}),
t.partial({
certificatesThresholds: CertificatesStatesThresholdType,
}),
]);
export const DynamicSettingsType = t.type({
heartbeatIndices: t.string,
certificatesThresholds: CertificatesStatesThresholdType,
});

export const DynamicSettingsSaveType = t.intersection([
t.type({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 { CertMonitor } from '../../../common/runtime_types';
import { MonitorPageLink } from '../common/monitor_page_link';

interface Props {
monitors: CertMonitor[];
}

export const CertMonitors: React.FC<Props> = ({ monitors }) => {
return (
<span>
{monitors.map((mon: CertMonitor, ind: number) => (
<>
{ind > 0 && ', '}
<MonitorPageLink key={mon.id} monitorId={mon.id!} linkParameters={''}>
{mon.name || mon.id}
</MonitorPageLink>
</>
))}
</span>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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 { CERT_STATUS, useCertStatus } from '../../hooks';
import * as labels from './translations';

interface Props {
cert: Cert;
}

export const CertStatus: React.FC<Props> = ({ cert }) => {
const certStatus = useCertStatus(cert?.certificate_not_valid_after);

const isExpiringSoon = certStatus === CERT_STATUS.EXPIRING_SOON;

const isExpired = certStatus === CERT_STATUS.EXPIRED;

if (isExpiringSoon) {
return (
<EuiHealth color="#E9AA3C">
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
<span>{labels.EXPIRES_SOON}</span>
</EuiHealth>
);
}
if (isExpired) {
return (
<EuiHealth color="danger">
<span>{labels.EXPIRED}</span>
</EuiHealth>
);
}

return (
<EuiHealth color="success">
<span>{labels.OK}</span>
</EuiHealth>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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<Props> = ({ setSearch }) => {
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value);
};

return (
<WrapFieldSearch
placeholder={labels.SEARCH_CERTS}
onChange={onChange}
isClearable={true}
aria-label={labels.SEARCH_CERTS}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* 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, EuiCopy, EuiIcon, EuiLink, EuiToolTip } 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';

interface Page {
index: number;
size: number;
}

export type CertFields =
| 'sha256'
| 'sha1'
| 'issuer'
| 'common_name'
| 'monitors'
| 'certificate_not_valid_after'
| 'certificate_not_valid_before';

export interface CertSort {
field: CertFields;
direction: Direction;
}

interface Props {
page: Page;
sort: CertSort;
onChange: (page: Page, sort: CertSort) => void;
}

const columns = [
{
field: 'tls.certificate_not_valid_after',
name: labels.STATUS_COL,
sortable: true,
render: (val: string, item: Cert) => {
return <CertStatus cert={item} />;
},
},
{
name: labels.COMMON_NAME_COL,
field: 'common_name',
},
{
name: labels.MONITORS_COL,
field: 'monitors',
render: (monitors: CertMonitor[]) => <CertMonitors monitors={monitors} />,
},
{
name: labels.ISSUED_BY_COL,
field: 'issuer',
},
{
name: labels.EXP_DATE_COL,
field: 'certificate_not_valid_after',
sortable: true,
render: (value: string) => {
return moment(value).format('L LT');
},
},
{
name: (
<EuiToolTip
content="Certificate fingerprint using the SHA256 digest of DER-encoded version
of certificate offered by the client."
>
<span>
SHA256
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
),
width: '100px',
actions: [
{
render: (item: Cert) => {
return (
<EuiCopy textToCopy={item.sha256?.toUpperCase()}>
{copy => (
<EuiLink onClick={copy}>
<EuiIcon type="copy" title="Click to Copy SHA 256 Value" />
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
</EuiLink>
)}
</EuiCopy>
);
},
},
],
},
];

export const CertificateList: React.FC<Props> = ({ page, sort, onChange }) => {
const certificates = useSelector(certificatesSelector);

const onTableChange = (newVal: Partial<Props>) => {
onChange(newVal.page as Page, newVal.sort as CertSort);
};

const pagination = {
pageIndex: page.index,
pageSize: page.size,
totalItemCount: certificates?.total ?? 0,
pageSizeOptions: [5, 10, 15, 20],
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
hidePerPageOptions: false,
};

return (
<EuiBasicTable
columns={columns}
items={certificates?.certs ?? []}
pagination={pagination}
onChange={onTableChange}
sorting={{
sort: {
field: sort.field,
direction: sort.direction,
},
}}
/>
);
};
Original file line number Diff line number Diff line change
@@ -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 { 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',
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
});

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 COMMON_NAME_COL = i18n.translate('xpack.uptime.certs.list.commonName', {
defaultMessage: 'Common Name',
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
});

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',
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
});

export const EXP_DATE_COL = i18n.translate('xpack.uptime.certs.list.expirationDate', {
defaultMessage: 'Expiration Date',
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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';

describe('MonitorStatusBar component', () => {
let monitorTls: Tls;
Expand All @@ -23,6 +24,12 @@ describe('MonitorStatusBar component', () => {
monitorTls = {
certificate_not_valid_after: dateInTwoMonths,
};

const spy = jest.spyOn(redux, 'useDispatch');
spy.mockReturnValue(jest.fn());

const spy1 = jest.spyOn(redux, 'useSelector');
spy1.mockReturnValue(true);
});

it('renders', () => {
Expand Down
Loading