mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Encrypt telemetry (#33121)
* draft code * finalize solution * encrypted telemetry * update jwks * code review follow up * finalize PR * @elastic/node-crytpo typings * node-crypto typings in x-pack * yarn.lock * add tests * useInternalUser * more tests * unify variable name * update typings * remove root level node-crypto typings * array of encrypted clusters, update endpoint
This commit is contained in:
parent
8df19fef0b
commit
a27cbc1b13
32 changed files with 400 additions and 161 deletions
|
@ -9,7 +9,7 @@ import moment from 'moment';
|
|||
export const name = 'telemetry';
|
||||
export const description = 'Get the clusters stats for the last 1 hour from the Kibana server';
|
||||
export const method = 'POST';
|
||||
export const path = '/api/telemetry/v1/clusters/_stats';
|
||||
export const path = '/api/telemetry/v2/clusters/_stats';
|
||||
|
||||
// Get an object with start and end times for the last 1 hour, ISO format, in UTC
|
||||
function getTimeRange() {
|
||||
|
@ -21,4 +21,4 @@ function getTimeRange() {
|
|||
};
|
||||
}
|
||||
|
||||
export const body = { timeRange: getTimeRange() };
|
||||
export const body = { timeRange: getTimeRange(), unencrypted: true };
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"@elastic/node-crypto": "^1.0.0",
|
||||
"@elastic/nodegit": "0.25.0-alpha.20",
|
||||
"@elastic/numeral": "2.3.3",
|
||||
"@elastic/request-crypto": "^1.0.2",
|
||||
"@kbn/babel-preset": "1.0.0",
|
||||
"@kbn/elastic-idx": "1.0.0",
|
||||
"@kbn/es-query": "1.0.0",
|
||||
|
|
|
@ -18,10 +18,10 @@ import { createTelemetryUsageCollector } from './server/lib/telemetry';
|
|||
import { uiCapabilitiesForFeatures } from './server/lib/ui_capabilities_for_features';
|
||||
import {
|
||||
xpackInfoRoute,
|
||||
telemetryRoute,
|
||||
featuresRoute,
|
||||
settingsRoute,
|
||||
} from './server/routes/api/v1';
|
||||
import { telemetryRoute } from './server/routes/api/v2';
|
||||
import {
|
||||
CONFIG_TELEMETRY,
|
||||
getConfigTelemetryDesc,
|
||||
|
@ -57,8 +57,8 @@ export const xpackMain = (kibana) => {
|
|||
enabled: Joi.boolean().default(true),
|
||||
url: Joi.when('$dev', {
|
||||
is: true,
|
||||
then: Joi.string().default('https://telemetry-staging.elastic.co/xpack/v1/send'),
|
||||
otherwise: Joi.string().default('https://telemetry.elastic.co/xpack/v1/send')
|
||||
then: Joi.string().default('https://telemetry-staging.elastic.co/xpack/v2/send'),
|
||||
otherwise: Joi.string().default('https://telemetry.elastic.co/xpack/v2/send')
|
||||
}),
|
||||
}).default(),
|
||||
xpack_api_polling_frequency_millis: Joi.number().default(XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS),
|
||||
|
|
|
@ -46,16 +46,26 @@ export class OptInExampleFlyout extends Component {
|
|||
this.state = {
|
||||
data: null,
|
||||
isLoading: true,
|
||||
hasPrivilegeToRead: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchTelemetry()
|
||||
.then(response => this.setState({ data: Array.isArray(response.data) ? response.data : null, isLoading: false }))
|
||||
.catch(() => this.setState({ isLoading: false }));
|
||||
.then(response => this.setState({
|
||||
data: Array.isArray(response.data) ? response.data : null,
|
||||
isLoading: false,
|
||||
hasPrivilegeToRead: true,
|
||||
}))
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
hasPrivilegeToRead: err.status !== 403,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderBody({ data, isLoading }) {
|
||||
renderBody({ data, isLoading, hasPrivilegeToRead }) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="spaceAround">
|
||||
|
@ -66,6 +76,24 @@ export class OptInExampleFlyout extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
if (!hasPrivilegeToRead) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={<FormattedMessage
|
||||
id="xpack.main.telemetry.callout.errorUnprivilegedUserTitle"
|
||||
defaultMessage="Error displaying cluster statistics"
|
||||
/>}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.main.telemetry.callout.errorUnprivilegedUserDescription"
|
||||
defaultMessage="You do not have access to see unencrypted cluster statistics."
|
||||
/>
|
||||
</EuiCallOut>
|
||||
);
|
||||
}
|
||||
|
||||
if (data === null) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
|
|
|
@ -73,7 +73,10 @@ export class TelemetryForm extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
{showExample &&
|
||||
<OptInExampleFlyout fetchTelemetry={() => telemetryOptInProvider.fetchExample()} onClose={this.toggleExample} />
|
||||
<OptInExampleFlyout
|
||||
fetchTelemetry={() => telemetryOptInProvider.fetchExample()}
|
||||
onClose={this.toggleExample}
|
||||
/>
|
||||
}
|
||||
<EuiPanel paddingSize="l">
|
||||
<EuiForm>
|
||||
|
|
|
@ -26,7 +26,8 @@ describe('fetch_telemetry', () => {
|
|||
toISOString: () => 'min456'
|
||||
});
|
||||
|
||||
$http.post.withArgs(`fake/api/telemetry/v1/clusters/_stats`, {
|
||||
$http.post.withArgs(`fake/api/telemetry/v2/clusters/_stats`, {
|
||||
unencrypted: true,
|
||||
timeRange: {
|
||||
min: 'min456',
|
||||
max: 'max123'
|
||||
|
@ -34,7 +35,7 @@ describe('fetch_telemetry', () => {
|
|||
})
|
||||
.returns(response);
|
||||
|
||||
expect(fetchTelemetry($http, { basePath, _moment: () => moment })).to.be(response);
|
||||
expect(fetchTelemetry($http, { basePath, _moment: () => moment, unencrypted: true })).to.be(response);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -15,8 +15,9 @@ import moment from 'moment';
|
|||
* @param {Function} _moment moment.js, but injectable for tests
|
||||
* @return {Promise} An array of cluster Telemetry objects.
|
||||
*/
|
||||
export function fetchTelemetry($http, { basePath = uiChrome.getBasePath(), _moment = moment } = { }) {
|
||||
return $http.post(`${basePath}/api/telemetry/v1/clusters/_stats`, {
|
||||
export function fetchTelemetry($http, { basePath = uiChrome.getBasePath(), _moment = moment, unencrypted = false } = { }) {
|
||||
return $http.post(`${basePath}/api/telemetry/v2/clusters/_stats`, {
|
||||
unencrypted,
|
||||
timeRange: {
|
||||
min: _moment().subtract(20, 'minutes').toISOString(),
|
||||
max: _moment().toISOString()
|
||||
|
|
|
@ -65,7 +65,8 @@ export class Telemetry {
|
|||
|
||||
return this._fetchTelemetry()
|
||||
.then(response => {
|
||||
return Promise.all(response.data.map(cluster => {
|
||||
const clusters = [].concat(response.data);
|
||||
return Promise.all(clusters.map(cluster => {
|
||||
const req = {
|
||||
method: 'POST',
|
||||
url: this._telemetryUrl,
|
||||
|
|
|
@ -44,7 +44,7 @@ async function asyncInjectBanner($injector) {
|
|||
if (await shouldShowBanner(telemetryOptInProvider, config)) {
|
||||
const $http = $injector.get('$http');
|
||||
|
||||
renderBanner(telemetryOptInProvider, () => fetchTelemetry($http));
|
||||
renderBanner(telemetryOptInProvider, () => fetchTelemetry($http, { unencrypted: true }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ export function TelemetryOptInProvider($injector, chrome) {
|
|||
let currentOptInStatus = $injector.get('telemetryOptedIn');
|
||||
setCanTrackUiMetrics(currentOptInStatus);
|
||||
|
||||
return {
|
||||
const provider = {
|
||||
getOptIn: () => currentOptInStatus,
|
||||
setOptIn: async (enabled) => {
|
||||
setCanTrackUiMetrics(enabled);
|
||||
|
@ -21,7 +21,7 @@ export function TelemetryOptInProvider($injector, chrome) {
|
|||
const $http = $injector.get('$http');
|
||||
|
||||
try {
|
||||
await $http.post(chrome.addBasePath('/api/telemetry/v1/optIn'), { enabled });
|
||||
await $http.post(chrome.addBasePath('/api/telemetry/v2/optIn'), { enabled });
|
||||
currentOptInStatus = enabled;
|
||||
} catch (error) {
|
||||
notify.error(error);
|
||||
|
@ -32,7 +32,8 @@ export function TelemetryOptInProvider($injector, chrome) {
|
|||
},
|
||||
fetchExample: async () => {
|
||||
const $http = $injector.get('$http');
|
||||
return $http.post(chrome.addBasePath(`/api/telemetry/v1/clusters/_stats`), {
|
||||
return $http.post(chrome.addBasePath(`/api/telemetry/v2/clusters/_stats`), {
|
||||
unencrypted: true,
|
||||
timeRange: {
|
||||
min: moment().subtract(20, 'minutes').toISOString(),
|
||||
max: moment().toISOString()
|
||||
|
@ -40,4 +41,6 @@ export function TelemetryOptInProvider($injector, chrome) {
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ describe('TelemetryOptInProvider', () => {
|
|||
const { provider, mockHttp } = setup({ optedIn: true });
|
||||
await provider.setOptIn(false);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledWith(`/api/telemetry/v1/optIn`, { enabled: false });
|
||||
expect(mockHttp.post).toHaveBeenCalledWith(`/api/telemetry/v2/optIn`, { enabled: false });
|
||||
|
||||
expect(provider.getOptIn()).toEqual(false);
|
||||
});
|
||||
|
@ -72,7 +72,7 @@ describe('TelemetryOptInProvider', () => {
|
|||
const { provider, mockHttp } = setup({ optedIn: false });
|
||||
await provider.setOptIn(true);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledWith(`/api/telemetry/v1/optIn`, { enabled: true });
|
||||
expect(mockHttp.post).toHaveBeenCalledWith(`/api/telemetry/v2/optIn`, { enabled: true });
|
||||
|
||||
expect(provider.getOptIn()).toEqual(true);
|
||||
});
|
||||
|
@ -81,7 +81,7 @@ describe('TelemetryOptInProvider', () => {
|
|||
const { provider, mockHttp } = setup({ optedIn: false, simulatePostError: true });
|
||||
await provider.setOptIn(true);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledWith(`/api/telemetry/v1/optIn`, { enabled: true });
|
||||
expect(mockHttp.post).toHaveBeenCalledWith(`/api/telemetry/v2/optIn`, { enabled: true });
|
||||
|
||||
// opt-in change should not be reflected
|
||||
expect(provider.getOptIn()).toEqual(false);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 { telemetryJWKS } from './telemetry_jwks';
|
||||
import { encryptTelemetry, getKID } from './encrypt';
|
||||
import { createRequestEncryptor } from '@elastic/request-crypto';
|
||||
|
||||
jest.mock('@elastic/request-crypto', () => ({
|
||||
createRequestEncryptor: jest.fn().mockResolvedValue({
|
||||
encrypt: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('getKID', () => {
|
||||
it(`returns 'kibana_dev' kid for development`, async () => {
|
||||
const isProd = false;
|
||||
const kid = getKID(isProd);
|
||||
expect(kid).toBe('kibana_dev');
|
||||
});
|
||||
|
||||
it(`returns 'kibana_prod' kid for development`, async () => {
|
||||
const isProd = true;
|
||||
const kid = getKID(isProd);
|
||||
expect(kid).toBe('kibana');
|
||||
});
|
||||
});
|
||||
|
||||
describe('encryptTelemetry', () => {
|
||||
it('encrypts payload', async () => {
|
||||
const payload = { some: 'value' };
|
||||
await encryptTelemetry(payload, true);
|
||||
expect(createRequestEncryptor).toBeCalledWith(telemetryJWKS);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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 { createRequestEncryptor } from '@elastic/request-crypto';
|
||||
import { telemetryJWKS } from './telemetry_jwks';
|
||||
|
||||
export function getKID(isProd = false): string {
|
||||
return isProd ? 'kibana' : 'kibana_dev';
|
||||
}
|
||||
|
||||
export async function encryptTelemetry(payload: any, isProd = false): Promise<string[]> {
|
||||
const kid = getKID(isProd);
|
||||
const encryptor = await createRequestEncryptor(telemetryJWKS);
|
||||
const clusters = [].concat(payload);
|
||||
return Promise.all(clusters.map((cluster: any) => encryptor.encrypt(kid, cluster)));
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* 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 { encryptTelemetry } from './encrypt';
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { PublicJWKS } from '@elastic/request-crypto';
|
||||
|
||||
export const telemetryJWKS: PublicJWKS = {
|
||||
keys: [
|
||||
{
|
||||
kty: 'RSA',
|
||||
kid: 'kibana',
|
||||
use: 'enc',
|
||||
alg: 'RSA-OAEP',
|
||||
e: 'AQAB',
|
||||
n:
|
||||
'xYYa5XzvENaAzElCxQurloQM2KEQ058YSjZqmOwa-IN-EZMSUaYPY3qfYCG78ioRaKTHq4mgnkyrDKgjY_1pWKytiRD61FG2ZUeOCwzydnqO8Qpz2vFnibEHkZBRsKkLHgm90RgGpcXfz8vwxkz_nu59aWy5Qr7Ct99H0pEV1HoiCvy5Yw3QfWSAeV-3DWmq_0kX49tqk5yZE-vKnUhNMgqM22lMFTE5-vlaeHgv4ZcvCQx_HrOeea8LyZa5YOdqN-9st0g0G-aWp3CNI2-KJlMUTBAfIAtjwmJ-8QlgeIB1aA7OI2Ceh3kd4dNLesGdLvZ0y4f8IMOsO1dsRWSEsQ',
|
||||
},
|
||||
{
|
||||
kty: 'RSA',
|
||||
kid: 'kibana_dev',
|
||||
use: 'enc',
|
||||
alg: 'RSA-OAEP',
|
||||
e: 'AQAB',
|
||||
n:
|
||||
'juVHivsYFznjrDC449oL3xKVTvux_7dEgBGOgJdfzA2R2GspEAOzupT-VkBnqrJnRP_lznM8bQIvvst1f_DNQ1me_Lr9u9cwL5Vq6SWlmw_u9ur_-ewkShU4tBoJDArksOS-ciTaUJoMaxanb7jWexp0pCDlrLrQyAOCnKQL701mD1gdT4rIw7F-jkb5fLUNUVzOGaGyVy6DHAHZx7Tnyw8rswhyRVvuS73imbRp9XcdOFhBDOeSbrSuZGqrVCjoIlWw-UsiW2ueRd8brBoOIHSmTOMIrIMjpPmzMFRKyCvvhnbjrw8j3fQtFII8urhXCVAw8aIHZhiBc5t9ZuwbJw',
|
||||
},
|
||||
],
|
||||
};
|
|
@ -6,4 +6,5 @@
|
|||
|
||||
export { getAllStats } from './monitoring';
|
||||
export { getLocalStats } from './local';
|
||||
export { encryptTelemetry } from './encryption';
|
||||
export { createTelemetryUsageCollector } from './usage';
|
||||
|
|
|
@ -9,7 +9,8 @@ import sinon from 'sinon';
|
|||
|
||||
import { getClusterInfo } from '../get_cluster_info';
|
||||
|
||||
export function mockGetClusterInfo(callCluster, clusterInfo) {
|
||||
export function mockGetClusterInfo(callCluster, clusterInfo, req) {
|
||||
callCluster.withArgs(req, 'info').returns(clusterInfo);
|
||||
callCluster.withArgs('info').returns(clusterInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,12 @@ import sinon from 'sinon';
|
|||
import { TIMEOUT } from '../constants';
|
||||
import { getClusterStats } from '../get_cluster_stats';
|
||||
|
||||
export function mockGetClusterStats(callCluster, clusterStats) {
|
||||
export function mockGetClusterStats(callCluster, clusterStats, req) {
|
||||
callCluster.withArgs(req, 'cluster.stats', {
|
||||
timeout: TIMEOUT
|
||||
})
|
||||
.returns(clusterStats);
|
||||
|
||||
callCluster.withArgs('cluster.stats', {
|
||||
timeout: TIMEOUT
|
||||
})
|
||||
|
|
|
@ -29,10 +29,10 @@ const getMockServer = (getCluster = sinon.stub(), kibanaUsage = {}) => ({
|
|||
},
|
||||
});
|
||||
|
||||
function mockGetLocalStats(callCluster, clusterInfo, clusterStats, license, usage) {
|
||||
mockGetClusterInfo(callCluster, clusterInfo);
|
||||
mockGetClusterStats(callCluster, clusterStats);
|
||||
mockGetXPack(callCluster, license, usage);
|
||||
function mockGetLocalStats(callCluster, clusterInfo, clusterStats, license, usage, req) {
|
||||
mockGetClusterInfo(callCluster, clusterInfo, req);
|
||||
mockGetClusterStats(callCluster, clusterStats, req);
|
||||
mockGetXPack(callCluster, license, usage, req);
|
||||
}
|
||||
|
||||
describe('get_local_stats', () => {
|
||||
|
@ -196,7 +196,29 @@ describe('get_local_stats', () => {
|
|||
Promise.resolve(xpack)
|
||||
);
|
||||
|
||||
const result = await getLocalStats(req);
|
||||
const result = await getLocalStats(req, { useInternalUser: true });
|
||||
expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid);
|
||||
expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name);
|
||||
expect(result.version).to.eql(combinedStatsResult.version);
|
||||
expect(result.cluster_stats).to.eql(combinedStatsResult.cluster_stats);
|
||||
});
|
||||
it('uses callWithRequest from data cluster', async () => {
|
||||
const getCluster = sinon.stub();
|
||||
const req = { server: getMockServer(getCluster) };
|
||||
const callWithRequest = sinon.stub();
|
||||
|
||||
getCluster.withArgs('data').returns({ callWithRequest });
|
||||
|
||||
mockGetLocalStats(
|
||||
callWithRequest,
|
||||
Promise.resolve(clusterInfo),
|
||||
Promise.resolve(clusterStats),
|
||||
Promise.resolve(license),
|
||||
Promise.resolve(xpack),
|
||||
req
|
||||
);
|
||||
|
||||
const result = await getLocalStats(req, { useInternalUser: false });
|
||||
expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid);
|
||||
expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name);
|
||||
expect(result.version).to.eql(combinedStatsResult.version);
|
||||
|
|
|
@ -15,7 +15,16 @@ import {
|
|||
handleXPack,
|
||||
} from '../get_xpack';
|
||||
|
||||
function mockGetXPackLicense(callCluster, license) {
|
||||
function mockGetXPackLicense(callCluster, license, req) {
|
||||
callCluster.withArgs(req, 'transport.request', {
|
||||
method: 'GET',
|
||||
path: '/_license',
|
||||
query: {
|
||||
local: 'true'
|
||||
}
|
||||
})
|
||||
.returns(license.then(response => ({ license: response })));
|
||||
|
||||
callCluster.withArgs('transport.request', {
|
||||
method: 'GET',
|
||||
path: '/_license',
|
||||
|
@ -27,7 +36,16 @@ function mockGetXPackLicense(callCluster, license) {
|
|||
.returns(license.then(response => ({ license: response })));
|
||||
}
|
||||
|
||||
function mockGetXPackUsage(callCluster, usage) {
|
||||
function mockGetXPackUsage(callCluster, usage, req) {
|
||||
callCluster.withArgs(req, 'transport.request', {
|
||||
method: 'GET',
|
||||
path: '/_xpack/usage',
|
||||
query: {
|
||||
master_timeout: TIMEOUT
|
||||
}
|
||||
})
|
||||
.returns(usage);
|
||||
|
||||
callCluster.withArgs('transport.request', {
|
||||
method: 'GET',
|
||||
path: '/_xpack/usage',
|
||||
|
@ -44,10 +62,11 @@ function mockGetXPackUsage(callCluster, usage) {
|
|||
* @param {Function} callCluster Sinon function mock.
|
||||
* @param {Promise} license Promised license response.
|
||||
* @param {Promise} usage Promised usage response.
|
||||
* @param {Object} usage reqeust object.
|
||||
*/
|
||||
export function mockGetXPack(callCluster, license, usage) {
|
||||
mockGetXPackLicense(callCluster, license);
|
||||
mockGetXPackUsage(callCluster, usage);
|
||||
export function mockGetXPack(callCluster, license, usage, req) {
|
||||
mockGetXPackLicense(callCluster, license, req);
|
||||
mockGetXPackUsage(callCluster, usage, req);
|
||||
}
|
||||
|
||||
describe('get_xpack', () => {
|
||||
|
|
|
@ -58,10 +58,13 @@ export function getLocalStatsWithCaller(server, callCluster) {
|
|||
* Get statistics for the connected Elasticsearch cluster.
|
||||
*
|
||||
* @param {Object} req The incoming request
|
||||
* @param {Boolean} useRequestUser callWithRequest, otherwise callWithInternalUser
|
||||
* @return {Promise} The cluster object containing telemetry.
|
||||
*/
|
||||
export function getLocalStats(req) {
|
||||
export function getLocalStats(req, { useInternalUser = false } = {}) {
|
||||
const { server } = req;
|
||||
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('data');
|
||||
return getLocalStatsWithCaller(server, callWithInternalUser);
|
||||
const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster('data');
|
||||
const callCluster = useInternalUser ? callWithInternalUser : (...args) => callWithRequest(req, ...args);
|
||||
|
||||
return getLocalStatsWithCaller(server, callCluster);
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ import { getHighLevelStats } from './get_high_level_stats';
|
|||
* @param {Date} end The ending range to request data
|
||||
* @return {Promise} The array of clusters joined with the Kibana and Logstash instances.
|
||||
*/
|
||||
export function getAllStats(req, start, end) {
|
||||
export function getAllStats(req, start, end, { useInternalUser = false } = {}) {
|
||||
const server = req.server;
|
||||
const { callWithRequest } = server.plugins.elasticsearch.getCluster('monitoring');
|
||||
const callCluster = (...args) => callWithRequest(req, ...args);
|
||||
const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster('monitoring');
|
||||
const callCluster = useInternalUser ? callWithInternalUser : (...args) => callWithRequest(req, ...args);
|
||||
|
||||
return getAllStatsWithCaller(server, callCluster, start, end);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,5 @@
|
|||
*/
|
||||
|
||||
export { xpackInfoRoute } from './xpack_info';
|
||||
export { telemetryRoute } from './telemetry';
|
||||
export { featuresRoute } from './features';
|
||||
export { settingsRoute } from './settings';
|
||||
|
|
|
@ -32,7 +32,7 @@ describe('telemetry', () => {
|
|||
config.get.withArgs('xpack.monitoring.enabled').returns(true);
|
||||
_getAllStats.withArgs(req, start, end).returns(response);
|
||||
|
||||
expect(await getTelemetry(req, config, start, end, { _getAllStats, _getLocalStats })).to.be(response);
|
||||
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.be(response);
|
||||
|
||||
expect(config.get.calledOnce).to.be(true);
|
||||
expect(_getAllStats.calledOnce).to.be(true);
|
||||
|
@ -46,7 +46,7 @@ describe('telemetry', () => {
|
|||
_getAllStats.withArgs(req, start, end).returns([]);
|
||||
_getLocalStats.withArgs(req).returns(response);
|
||||
|
||||
expect(await getTelemetry(req, config, start, end, { _getAllStats, _getLocalStats })).to.eql([ response ]);
|
||||
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.eql([ response ]);
|
||||
|
||||
expect(config.get.calledOnce).to.be(true);
|
||||
expect(_getAllStats.calledOnce).to.be(true);
|
||||
|
@ -60,7 +60,7 @@ describe('telemetry', () => {
|
|||
_getAllStats.withArgs(req, start, end).returns({ not: 'an array' });
|
||||
_getLocalStats.withArgs(req).returns(response);
|
||||
|
||||
expect(await getTelemetry(req, config, start, end, { _getAllStats, _getLocalStats })).to.eql([ response ]);
|
||||
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.eql([ response ]);
|
||||
|
||||
expect(config.get.calledOnce).to.be(true);
|
||||
expect(_getAllStats.calledOnce).to.be(true);
|
||||
|
@ -73,7 +73,7 @@ describe('telemetry', () => {
|
|||
config.get.withArgs('xpack.monitoring.enabled').returns(false);
|
||||
_getLocalStats.withArgs(req).returns(response);
|
||||
|
||||
expect(await getTelemetry(req, config, start, end, { _getAllStats, _getLocalStats })).to.eql([ response ]);
|
||||
expect(await getTelemetry(req, config, start, end, false, { _getAllStats, _getLocalStats })).to.eql([ response ]);
|
||||
|
||||
expect(config.get.calledOnce).to.be(true);
|
||||
expect(_getAllStats.calledOnce).to.be(false);
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* 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 { telemetryRoute } from './telemetry';
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import Joi from 'joi';
|
||||
import { boomify } from 'boom';
|
||||
import { getAllStats, getLocalStats } from '../../../../lib/telemetry';
|
||||
import { getAllStats, getLocalStats, encryptTelemetry } from '../../../../lib/telemetry';
|
||||
|
||||
/**
|
||||
* Get the telemetry data.
|
||||
|
@ -15,15 +15,18 @@ import { getAllStats, getLocalStats } from '../../../../lib/telemetry';
|
|||
* @param {Object} config Kibana config.
|
||||
* @param {String} start The start time of the request (likely 20m ago).
|
||||
* @param {String} end The end time of the request.
|
||||
* @param {Boolean} unencrypted Is the request payload going to be unencrypted.
|
||||
* @return {Promise} An array of telemetry objects.
|
||||
*/
|
||||
export async function getTelemetry(req, config, start, end, { _getAllStats = getAllStats, _getLocalStats = getLocalStats } = {}) {
|
||||
export async function getTelemetry(req, config, start, end, unencrypted, statsGetters = {}) {
|
||||
const { _getAllStats = getAllStats, _getLocalStats = getLocalStats } = statsGetters;
|
||||
let response = [];
|
||||
const useInternalUser = !unencrypted;
|
||||
|
||||
if (config.get('xpack.monitoring.enabled')) {
|
||||
try {
|
||||
// attempt to collect stats from multiple clusters in monitoring data
|
||||
response = await _getAllStats(req, start, end);
|
||||
response = await _getAllStats(req, start, end, { useInternalUser });
|
||||
} catch (err) {
|
||||
// no-op
|
||||
}
|
||||
|
@ -31,7 +34,7 @@ export async function getTelemetry(req, config, start, end, { _getAllStats = get
|
|||
|
||||
if (!Array.isArray(response) || response.length === 0) {
|
||||
// return it as an array for a consistent API response
|
||||
response = [await _getLocalStats(req)];
|
||||
response = [await _getLocalStats(req, { useInternalUser })];
|
||||
}
|
||||
|
||||
return response;
|
||||
|
@ -43,7 +46,7 @@ export function telemetryRoute(server) {
|
|||
*/
|
||||
server.route({
|
||||
method: 'POST',
|
||||
path: '/api/telemetry/v1/optIn',
|
||||
path: '/api/telemetry/v2/optIn',
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.object({
|
||||
|
@ -76,10 +79,11 @@ export function telemetryRoute(server) {
|
|||
*/
|
||||
server.route({
|
||||
method: 'POST',
|
||||
path: '/api/telemetry/v1/clusters/_stats',
|
||||
path: '/api/telemetry/v2/clusters/_stats',
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.object({
|
||||
unencrypted: Joi.bool(),
|
||||
timeRange: Joi.object({
|
||||
min: Joi.date().required(),
|
||||
max: Joi.date().required()
|
||||
|
@ -91,16 +95,21 @@ export function telemetryRoute(server) {
|
|||
const config = req.server.config();
|
||||
const start = req.payload.timeRange.min;
|
||||
const end = req.payload.timeRange.max;
|
||||
const unencrypted = req.payload.unencrypted;
|
||||
const isDev = config.get('env.dev');
|
||||
|
||||
try {
|
||||
return await getTelemetry(req, config, start, end);
|
||||
const usageData = await getTelemetry(req, config, start, end, unencrypted);
|
||||
if (unencrypted) return usageData;
|
||||
return encryptTelemetry(usageData, isDev);
|
||||
} catch (err) {
|
||||
if (config.get('env.dev')) {
|
||||
// don't ignore errors when running in dev mode
|
||||
if (isDev) {
|
||||
// don't ignore errors when running in dev mode
|
||||
return boomify(err, { statusCode: err.status });
|
||||
} else {
|
||||
// ignore errors, return empty set and a 200
|
||||
return h.response([]).code(200);
|
||||
const statusCode = unencrypted && err.status === 403 ? 403 : 200;
|
||||
// ignore errors and return empty set
|
||||
return h.response([]).code(statusCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ export default function featureControlsTests({ getService }: KibanaFunctionalTes
|
|||
const basePath = spaceId ? `/s/${spaceId}` : '';
|
||||
|
||||
return await supertest
|
||||
.post(`${basePath}/api/telemetry/v1/optIn`)
|
||||
.post(`${basePath}/api/telemetry/v2/optIn`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({ enabled: true })
|
||||
|
|
|
@ -12,7 +12,7 @@ export default function ({ getService }) {
|
|||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('/api/telemetry/v1/clusters/_stats', () => {
|
||||
describe('/api/telemetry/v2/clusters/_stats', () => {
|
||||
it('should load multiple trial-license clusters', async () => {
|
||||
const archive = 'monitoring/multicluster';
|
||||
const timeRange = {
|
||||
|
@ -23,9 +23,9 @@ export default function ({ getService }) {
|
|||
await esArchiver.load(archive);
|
||||
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v1/clusters/_stats')
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.send({ timeRange, unencrypted: true })
|
||||
.expect(200);
|
||||
expect(body).to.eql(multiClusterFixture);
|
||||
|
||||
|
@ -43,9 +43,9 @@ export default function ({ getService }) {
|
|||
await esArchiver.load(archive);
|
||||
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v1/clusters/_stats')
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.send({ timeRange, unencrypted: true })
|
||||
.expect(200);
|
||||
expect(body).to.eql(basicClusterFixture);
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export default function ({ getService }) {
|
|||
const supertest = getService('supertest');
|
||||
const esSupertest = getService('esSupertest');
|
||||
|
||||
describe('/api/telemetry/v1/clusters/_stats with monitoring disabled', () => {
|
||||
describe('/api/telemetry/v2/clusters/_stats with monitoring disabled', () => {
|
||||
before('', async () => {
|
||||
await esSupertest.put('/_cluster/settings').send(disableCollection).expect(200);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
|
@ -52,9 +52,9 @@ export default function ({ getService }) {
|
|||
};
|
||||
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v1/clusters/_stats')
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.send({ timeRange, unencrypted: true })
|
||||
.expect(200);
|
||||
|
||||
expect(body.length).to.be(1);
|
||||
|
@ -104,9 +104,9 @@ export default function ({ getService }) {
|
|||
};
|
||||
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v1/clusters/_stats')
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.send({ timeRange, unencrypted: true })
|
||||
.expect(200);
|
||||
|
||||
const stats = body[0];
|
||||
|
|
7
x-pack/typings/elastic__node_crypto.d.ts
vendored
Normal file
7
x-pack/typings/elastic__node_crypto.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
declare module '@elastic/node-crypto';
|
225
yarn.lock
225
yarn.lock
|
@ -1207,14 +1207,6 @@
|
|||
pirates "^4.0.0"
|
||||
source-map-support "^0.5.9"
|
||||
|
||||
"@babel/runtime-corejs2@^7.3.0":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.3.4.tgz#63f8bbc77622da202e9ea6f8f6e3bf28991832d9"
|
||||
integrity sha512-QwPuQE65kNxjsNKk34Rfgen2R5fk0J2So99SD45uXBp34QOfyz11SqVgJ4xvyCpnCIieSQ0X0hSSc9z/ymlJJw==
|
||||
dependencies:
|
||||
core-js "^2.5.7"
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime-corejs2@^7.4.2":
|
||||
version "7.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.4.3.tgz#40271fc260e570fb356da984e42e5990bd275860"
|
||||
|
@ -1326,9 +1318,9 @@
|
|||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@elastic/charts@^3.11.2":
|
||||
version "3.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-3.11.2.tgz#3644eeb7c0d17d6c368cfb380c2d2ef268655d72"
|
||||
integrity sha512-ILU4ijT5GZC4usnbab/IVq1brQ6tFgkfBPwa4ixRtN5TlS+BWjPPVPFfIO3j4K9PijXE6XISfs8L2HkH1IDdtA==
|
||||
version "3.11.4"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-3.11.4.tgz#174004301cf30cff495f9f10aea5dca9441d677b"
|
||||
integrity sha512-9wwMO31M/oD50xDs+m7KIW773h0+Ydq2figtnJ9YRQ1V3S/Yr7OVwUWXYIEGKa3ZbaxEMMc8n8uMvPvPwtjOFg==
|
||||
dependencies:
|
||||
"@types/d3-shape" "^1.3.1"
|
||||
"@types/luxon" "^1.11.1"
|
||||
|
@ -1473,6 +1465,11 @@
|
|||
through2 "^2.0.0"
|
||||
update-notifier "^0.5.0"
|
||||
|
||||
"@elastic/node-crypto@^0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/node-crypto/-/node-crypto-0.1.2.tgz#c18ac282f635e88f041cc1555d806e492ca8f3b1"
|
||||
integrity sha1-wYrCgvY16I8EHMFVXYBuSSyo87E=
|
||||
|
||||
"@elastic/node-crypto@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/node-crypto/-/node-crypto-1.0.0.tgz#4d325df333fe1319556bb4d54214098ada1171d4"
|
||||
|
@ -1499,6 +1496,15 @@
|
|||
resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.3.3.tgz#94d38a35bd315efa7a6918b22695128fc40a885e"
|
||||
integrity sha512-0OyB9oztlYIq8F1LHjcNf+T089PKfYw78tgUY+q2dtox/jmb4xzFKtI9kv1hwAt5tcgBUTtUMK9kszpSh1UZaQ==
|
||||
|
||||
"@elastic/request-crypto@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/request-crypto/-/request-crypto-1.0.2.tgz#bf27bf009227166f3eeb2b5193a108752335ebd3"
|
||||
integrity sha512-8FtGYl7LebhmJmEDWiGn3MorvNiGWSYPqhvgRlKXjNakEuLoPBBe0DHxbwLkj08CMLWczXcO2ixqBPY7fEhJpA==
|
||||
dependencies:
|
||||
"@elastic/node-crypto" "^0.1.2"
|
||||
"@types/node-jose" "1.1.0"
|
||||
node-jose "1.1.0"
|
||||
|
||||
"@elastic/ui-ace@0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/ui-ace/-/ui-ace-0.2.3.tgz#5281aed47a79b7216c55542b0675e435692f20cd"
|
||||
|
@ -3407,9 +3413,9 @@
|
|||
integrity sha512-+UzPmwHSEEyv7aGlNkVpuFxp/BirXgl8NnPGCtmyx2KXIzAapoW3IqSVk87/Z3PUk8vEL8Pe1HXEMJbNBOQgtg==
|
||||
|
||||
"@types/memoize-one@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/memoize-one/-/memoize-one-4.1.0.tgz#62119f26055b3193ae43ca1882c5b29b88b71ece"
|
||||
integrity sha512-cmSgi6JMX/yBwgpVm4GooNWIH+vEeJoa8FAa6ExOhpJbC0Juq32/uYKiKb3VPSqrEA0aOnjvwZanla3O1WZMbw==
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/memoize-one/-/memoize-one-4.1.1.tgz#41dd138a4335b5041f7d8fc038f9d593d88b3369"
|
||||
integrity sha512-+9djKUUn8hOyktLCfCy4hLaIPgDNovaU36fsnZe9trFHr6ddlbIn2q0SEsnkCkNR+pBWEU440Molz/+Mpyf+gQ==
|
||||
|
||||
"@types/mime-db@*":
|
||||
version "1.27.0"
|
||||
|
@ -3483,6 +3489,13 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node-jose@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-jose/-/node-jose-1.1.0.tgz#26e1d234b41a39035482443ef35414bf34ba5d8b"
|
||||
integrity sha512-ws1RJCQmIDww6/OEW1WcLCqDXZmNMWLoGgW5TEIR7pqJDaGrOkgH8hVw96Wx4rmu65r3/ZiDsb9LjpoizAnlww==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@10.12.27", "@types/node@8.5.8", "@types/node@>=6.0.0", "@types/node@^10.12.27":
|
||||
version "10.12.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.27.tgz#eb3843f15d0ba0986cc7e4d734d2ee8b50709ef8"
|
||||
|
@ -3595,9 +3608,9 @@
|
|||
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
|
||||
|
||||
"@types/react-beautiful-dnd@^10.0.1":
|
||||
version "10.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-10.0.3.tgz#baa05ebcb6a95cd0d55c9e92263177c0fcaba9f7"
|
||||
integrity sha512-4h65dOwSC0GrhgmmEGh1p8Fwn6nHtFI3judbDMLDzTkRsPnBx6KwRFveJSMnCULh9gLhPB1ME1bQFEK4j3NgNA==
|
||||
version "10.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-10.1.2.tgz#74069f7b1d0cb67b7af99a2584b30e496e545d8b"
|
||||
integrity sha512-76M5VRbhduUarM9wyMWQm3tLKCVMKTlhG0+W67dteg/HBE+kueIwuyLWzE0m5fmuilvrDXoM5NL890KLnHETZw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
|
@ -4998,20 +5011,20 @@ apollo-link-dedup@^1.0.0:
|
|||
apollo-link "^1.2.2"
|
||||
|
||||
apollo-link-error@^1.1.7:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-1.1.8.tgz#3a957b22b843cf6c307d516709cdc42371c9aafe"
|
||||
integrity sha512-5hbMIBaINWOsZapWgTF8H2X0q3NjrQD/y4HlqDnUeLmT12OqejLasNh+EFE6q37/l28UHQu1/AuyRn15J7gvCA==
|
||||
version "1.1.10"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-1.1.10.tgz#ce57f0793f0923b598655de5bf5e028d4cf4fba6"
|
||||
integrity sha512-itG5UV7mQqaalmRkuRsF0cUS4zW2ja8XCbxkMZnIEeN24X3yoJi5hpJeAaEkXf0KgYNsR0+rmtCQNruWyxDnZQ==
|
||||
dependencies:
|
||||
apollo-link "^1.2.9"
|
||||
apollo-link-http-common "^0.2.11"
|
||||
apollo-link "^1.2.11"
|
||||
apollo-link-http-common "^0.2.13"
|
||||
tslib "^1.9.3"
|
||||
|
||||
apollo-link-http-common@^0.2.11:
|
||||
version "0.2.11"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.11.tgz#d4e494ed1e45ea0e0c0ed60f3df64541d0de682d"
|
||||
integrity sha512-FjtzEDiG6blH/2MR4fpVNoxdZUFmddP0sez34qnoLaYz6ABFbTDlmRE/dVN79nPExM4Spfs/DtW7KRqyjJ3tOg==
|
||||
apollo-link-http-common@^0.2.13:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.13.tgz#c688f6baaffdc7b269b2db7ae89dae7c58b5b350"
|
||||
integrity sha512-Uyg1ECQpTTA691Fwx5e6Rc/6CPSu4TB4pQRTGIpwZ4l5JDOQ+812Wvi/e3IInmzOZpwx5YrrOfXrtN8BrsDXoA==
|
||||
dependencies:
|
||||
apollo-link "^1.2.9"
|
||||
apollo-link "^1.2.11"
|
||||
ts-invariant "^0.3.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
|
@ -5053,15 +5066,15 @@ apollo-link@^1.0.0, apollo-link@^1.2.2, apollo-link@^1.2.3:
|
|||
apollo-utilities "^1.0.0"
|
||||
zen-observable-ts "^0.8.10"
|
||||
|
||||
apollo-link@^1.2.9:
|
||||
version "1.2.9"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.9.tgz#40a8f0b90716ce3fd6beb27b7eae1108b92e0054"
|
||||
integrity sha512-ZLUwthOFZq4lxchQ2jeBfVqS/UDdcVmmh8aUw6Ar9awZH4r+RgkcDeu2ooFLUfodWE3mZr7wIZuYsBas/MaNVA==
|
||||
apollo-link@^1.2.11:
|
||||
version "1.2.11"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.11.tgz#493293b747ad3237114ccd22e9f559e5e24a194d"
|
||||
integrity sha512-PQvRCg13VduLy3X/0L79M6uOpTh5iHdxnxYuo8yL7sJlWybKRJwsv4IcRBJpMFbChOOaHY7Og9wgPo6DLKDKDA==
|
||||
dependencies:
|
||||
apollo-utilities "^1.2.1"
|
||||
ts-invariant "^0.3.2"
|
||||
tslib "^1.9.3"
|
||||
zen-observable-ts "^0.8.16"
|
||||
zen-observable-ts "^0.8.18"
|
||||
|
||||
apollo-server-core@^1.3.6:
|
||||
version "1.3.6"
|
||||
|
@ -6273,6 +6286,11 @@ base64id@1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
|
||||
integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=
|
||||
|
||||
base64url@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
|
||||
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
|
||||
|
||||
base@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
||||
|
@ -6733,16 +6751,7 @@ browserslist@4.4.1, browserslist@^4.0.1, browserslist@^4.3.4:
|
|||
electron-to-chromium "^1.3.103"
|
||||
node-releases "^1.1.3"
|
||||
|
||||
browserslist@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2"
|
||||
integrity sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30000939"
|
||||
electron-to-chromium "^1.3.113"
|
||||
node-releases "^1.1.8"
|
||||
|
||||
browserslist@^4.5.1:
|
||||
browserslist@^4.4.2, browserslist@^4.5.1:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.5.2.tgz#36ad281f040af684555a23c780f5c2081c752df0"
|
||||
integrity sha512-zmJVLiKLrzko0iszd/V4SsjTaomFeoVzQGYYOYgRgsbh7WNh95RgDB0CmBdFWYs/3MyFSt69NypjL/h3iaddKQ==
|
||||
|
@ -7129,11 +7138,6 @@ caniuse-lite@^1.0.30000872, caniuse-lite@^1.0.30000929:
|
|||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz#d01763e9ce77810962ca7391ff827b5949ce4272"
|
||||
integrity sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==
|
||||
|
||||
caniuse-lite@^1.0.30000939:
|
||||
version "1.0.30000943"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000943.tgz#00b25bd5808edc2ed1cfb53533a6a6ff6ca014ee"
|
||||
integrity sha512-nJMjU4UaesbOHTcmz6VS+qaog++Fdepg4KAya5DL/AZrL/aaAZDGOOQ0AECtsJa09r4cJBdHZMive5mw8lnQ5A==
|
||||
|
||||
caniuse-lite@^1.0.30000947, caniuse-lite@^1.0.30000951:
|
||||
version "1.0.30000954"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000954.tgz#227c2743e40f07c71e6683b6ca9491bfd5755b8e"
|
||||
|
@ -10199,11 +10203,6 @@ electron-to-chromium@^1.3.103:
|
|||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.108.tgz#2e79a6fcaa4b3e7c75abf871505bda8e268c910e"
|
||||
integrity sha512-/QI4hMpAh48a1Sea6PALGv+kuVne9A2EWGd8HrWHMdYhIzGtbhVVHh6heL5fAzGaDnZuPyrlWJRl8WPm4RyiQQ==
|
||||
|
||||
electron-to-chromium@^1.3.113:
|
||||
version "1.3.114"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.114.tgz#1862887589db93f832057c81878c56c404960aa6"
|
||||
integrity sha512-EQEFDVId4dqTrV9wvDmu/Po8Re9nN1sJm9KZECKRf3HC39DUYAEHQ8s7s9HsnhO9iFwl/Gpke9dvm6VwQTss5w==
|
||||
|
||||
electron-to-chromium@^1.3.116:
|
||||
version "1.3.119"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.119.tgz#9a7770da667252aeb81f667853f67c2b26e00197"
|
||||
|
@ -10551,6 +10550,11 @@ es6-promise@^4.0.3, es6-promise@~4.2.4:
|
|||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
|
||||
integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==
|
||||
|
||||
es6-promise@^4.2.5:
|
||||
version "4.2.6"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
|
||||
integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
|
@ -12127,9 +12131,9 @@ fp-ts@^1.0.0:
|
|||
integrity sha512-fWwnAgVlTsV26Ruo9nx+fxNHIm6l1puE1VJ/C0XJ3nRQJJJIgRHYw6sigB3MuNFZL1o4fpGlhwFhcbxHK0RsOA==
|
||||
|
||||
fp-ts@^1.14.2:
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.17.0.tgz#289127353ddbb4622ada1920d4ad6643182c1f1f"
|
||||
integrity sha512-nBq25aCAMbCwVLobUUuM/MZihPKyjn0bCVBf6xMAGriHlf8W8Ze9UhyfLnbmfp0ekFTxMuTfLXrCzpJ34px7PQ==
|
||||
version "1.17.3"
|
||||
resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.17.3.tgz#5064afc4bee8ddcaea567479bfc62d527e015825"
|
||||
integrity sha512-r4gHfAWaRrYPsmdzRl1U9CkpbdOi8fPg5F5KiazAadENz5DKdWEaCDPl2Tf92fvkZGD/ekZ3EHu3gtXIVcsXtA==
|
||||
|
||||
fragment-cache@^0.2.1:
|
||||
version "0.2.1"
|
||||
|
@ -17197,6 +17201,11 @@ lodash.escape@^4.0.1:
|
|||
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
|
||||
integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=
|
||||
|
||||
lodash.fill@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.fill/-/lodash.fill-3.4.0.tgz#a3c74ae640d053adf0dc2079f8720788e8bfef85"
|
||||
integrity sha1-o8dK5kDQU63w3CB5+HIHiOi/74U=
|
||||
|
||||
lodash.filter@^4.4.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace"
|
||||
|
@ -17227,6 +17236,11 @@ lodash.includes@^4.3.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
|
||||
integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
|
||||
|
||||
lodash.intersection@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.intersection/-/lodash.intersection-4.4.0.tgz#0a11ba631d0e95c23c7f2f4cbb9a692ed178e705"
|
||||
integrity sha1-ChG6Yx0OlcI8fy9Mu5ppLtF45wU=
|
||||
|
||||
lodash.isarguments@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
|
||||
|
@ -17306,7 +17320,7 @@ lodash.mean@^4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.mean/-/lodash.mean-4.1.0.tgz#bb985349628c0b9d7fe0f5fcc0011a2ee2c0dd7a"
|
||||
integrity sha1-u5hTSWKMC51/4PX8wAEaLuLA3Xo=
|
||||
|
||||
lodash.merge@^4.4.0:
|
||||
lodash.merge@^4.4.0, lodash.merge@^4.6.1:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
|
||||
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
|
||||
|
@ -17316,6 +17330,11 @@ lodash.mergewith@^4.6.0, lodash.mergewith@^4.6.1:
|
|||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
||||
integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
|
||||
|
||||
lodash.omit@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
|
||||
integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=
|
||||
|
||||
lodash.omitby@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791"
|
||||
|
@ -17346,6 +17365,11 @@ lodash.padstart@^4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b"
|
||||
integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=
|
||||
|
||||
lodash.partialright@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.partialright/-/lodash.partialright-4.2.1.tgz#0130d80e83363264d40074f329b8a3e7a8a1cc4b"
|
||||
integrity sha1-ATDYDoM2MmTUAHTzKbij56ihzEs=
|
||||
|
||||
lodash.pick@^4.2.1, lodash.pick@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||
|
@ -17564,6 +17588,11 @@ long@^2.4.0:
|
|||
resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f"
|
||||
integrity sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=
|
||||
|
||||
long@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
|
||||
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
|
||||
|
||||
longest@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
|
@ -17672,9 +17701,9 @@ lru-queue@0.1:
|
|||
es5-ext "~0.10.2"
|
||||
|
||||
luxon@^1.11.3:
|
||||
version "1.12.1"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.12.1.tgz#924bd61404f70b0cc5168918cb0ac108e52aacc4"
|
||||
integrity sha512-Zv/qJb2X1ESTrlniAViWx2aqGwi2cVpeoZFTbPdPiCu4EsadKsmb/QCH8HQjMUpDZKKJIHKHsJxV5Rwpq47HKQ==
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.13.1.tgz#b7fb7ba1e5c93ebda098af8d579314797e0a0d69"
|
||||
integrity sha512-IQKRIiz9ldUrgcozN13SAeNZVYfD3bEI9X6TcrGu+dkgE4GR/Iik03ozbTM5cTr0lz8ucYPL2jtYT7Va2Flbsg==
|
||||
|
||||
lz-string@^1.4.4:
|
||||
version "1.4.4"
|
||||
|
@ -18825,6 +18854,11 @@ node-forge@0.7.1:
|
|||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300"
|
||||
integrity sha1-naYR6giYL0uUIGs760zJZl8gwwA=
|
||||
|
||||
node-forge@^0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac"
|
||||
integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==
|
||||
|
||||
node-gyp@^3.8.0:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
|
||||
|
@ -18848,6 +18882,27 @@ node-int64@^0.4.0:
|
|||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
|
||||
|
||||
node-jose@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-jose/-/node-jose-1.1.0.tgz#15b0808ed7cf40cc6114c95c1a4d7394051c472a"
|
||||
integrity sha512-Ux5MDElyiAlBQyOdFcwznK2TWMJbG8ZUfIZ28UtBvTB/VUz5HA/1WJV7s+YCah5NilPhkMkNi6xjnFRI+MQAVg==
|
||||
dependencies:
|
||||
base64url "^3.0.0"
|
||||
es6-promise "^4.2.5"
|
||||
lodash.assign "^4.2.0"
|
||||
lodash.clone "^4.5.0"
|
||||
lodash.fill "^3.4.0"
|
||||
lodash.flatten "^4.4.0"
|
||||
lodash.intersection "^4.4.0"
|
||||
lodash.merge "^4.6.1"
|
||||
lodash.omit "^4.5.0"
|
||||
lodash.partialright "^4.2.1"
|
||||
lodash.pick "^4.4.0"
|
||||
lodash.uniq "^4.5.0"
|
||||
long "^4.0.0"
|
||||
node-forge "^0.7.6"
|
||||
uuid "^3.3.2"
|
||||
|
||||
"node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
|
||||
|
@ -18938,13 +18993,6 @@ node-releases@^1.1.3:
|
|||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
node-releases@^1.1.8:
|
||||
version "1.1.10"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.10.tgz#5dbeb6bc7f4e9c85b899e2e7adcc0635c9b2adf7"
|
||||
integrity sha512-KbUPCpfoBvb3oBkej9+nrU0/7xPlVhmhhUJ1PZqwIP5/1dJkRWKWD3OONjo6M2J7tSCBtDCumLwwqeI+DWWaLQ==
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
node-sass@^4.9.4:
|
||||
version "4.9.4"
|
||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.4.tgz#349bd7f1c89422ffe7e1e4b60f2055a69fbc5512"
|
||||
|
@ -21358,21 +21406,7 @@ react-apollo@^2.1.4:
|
|||
lodash "^4.17.10"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-beautiful-dnd@^10.0.1:
|
||||
version "10.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-10.0.4.tgz#56913a77706ad2d1b002041d9cb1ac3849a4ae89"
|
||||
integrity sha512-j2Ra/mW48tXz1Mk6bNBuiENpRBt8wQcPbJgHSswmLDonUE8JPwVikaONoMavdowoMKQJoOJ9IwPTo82d/8aKKg==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs2" "^7.3.0"
|
||||
css-box-model "^1.1.1"
|
||||
memoize-one "^5.0.0"
|
||||
prop-types "^15.6.1"
|
||||
raf-schd "^4.0.0"
|
||||
react-redux "^5.0.7"
|
||||
redux "^4.0.1"
|
||||
tiny-invariant "^1.0.3"
|
||||
|
||||
react-beautiful-dnd@^10.1.0:
|
||||
react-beautiful-dnd@^10.0.1, react-beautiful-dnd@^10.1.0:
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-10.1.1.tgz#d753088d77d7632e77cf8a8935fafcffa38f574b"
|
||||
integrity sha512-TdE06Shfp56wm28EzjgC56EEMgGI5PDHejJ2bxuAZvZr8CVsbksklsJC06Hxf0MSL7FHbflL/RpkJck9isuxHg==
|
||||
|
@ -21732,13 +21766,13 @@ react-markdown@^3.4.1:
|
|||
xtend "^4.0.1"
|
||||
|
||||
react-markdown@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.0.6.tgz#927d44421735cd90b7634bb221e9d7d8656e01e9"
|
||||
integrity sha512-E1d/q+OBk5eumId42oYqVrJRB/+whrZdk+YHqUBCCNeWxqeV+Qzt+yLTsft9+4HRDj89Od7eAbUPQBYq8ZwShQ==
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.0.8.tgz#e3621b5becaac82a651008d7bc8390d3e4e438c0"
|
||||
integrity sha512-Z6oa648rufvzyO0KwYJ/9p9AsdYGIluqK6OlpJ35ouJ8HPF0Ko1WDNdyymjDSHxNrkb7HDyEcIDJCQs8NlET5A==
|
||||
dependencies:
|
||||
html-to-react "^1.3.4"
|
||||
mdast-add-list-metadata "1.0.1"
|
||||
prop-types "^15.6.1"
|
||||
prop-types "^15.7.2"
|
||||
remark-parse "^5.0.0"
|
||||
unified "^6.1.5"
|
||||
unist-util-visit "^1.3.0"
|
||||
|
@ -21966,11 +22000,12 @@ react-sizeme@^2.3.6:
|
|||
lodash "^4.17.4"
|
||||
|
||||
react-spring@^8.0.8:
|
||||
version "8.0.19"
|
||||
resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-8.0.19.tgz#62f4f396b4b73fa402838200a1c80374338cb12e"
|
||||
integrity sha512-DjrwjXqqVEitj6e6GqdW5dUp1BoVyeFQhEcXvPfoQxwyIVSJ9smNt8CNjSvoQqRujVllE7XKaJRWSZO/ewd1/A==
|
||||
version "8.0.20"
|
||||
resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-8.0.20.tgz#e25967f6059364b09cf0339168d73014e87c9d17"
|
||||
integrity sha512-40ZUQ5uI5YHsoQWLPchWNcEUh6zQ6qvcVDeTI2vW10ldoCN3PvDsII9wBH2xEbMl+BQvYmHzGdfLTQxPxJWGnQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-sticky@^6.0.3:
|
||||
version "6.0.3"
|
||||
|
@ -25819,9 +25854,9 @@ ts-invariant@^0.2.1:
|
|||
tslib "^1.9.3"
|
||||
|
||||
ts-invariant@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.3.2.tgz#89a2ffeb70879b777258df1df1c59383c35209b0"
|
||||
integrity sha512-QsY8BCaRnHiB5T6iE4DPlJMAKEG3gzMiUco9FEt1jUXQf0XP6zi0idT0i0rMTu8A326JqNSDsmlkA9dRSh1TRg==
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.3.3.tgz#b5742b1885ecf9e29c31a750307480f045ec0b16"
|
||||
integrity sha512-UReOKsrJFGC9tUblgSRWo+BsVNbEd77Cl6WiV/XpMlkifXwNIJbknViCucHvVZkXSC/mcWeRnIGdY7uprcwvdQ==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
|
@ -28733,10 +28768,10 @@ zen-observable-ts@^0.8.10:
|
|||
dependencies:
|
||||
zen-observable "^0.8.0"
|
||||
|
||||
zen-observable-ts@^0.8.16:
|
||||
version "0.8.16"
|
||||
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.16.tgz#969367299074fe17422fe2f46ee417e9a30cf3fa"
|
||||
integrity sha512-pQl75N7qwgybKVsh6WFO+WwPRijeQ52Gn1vSf4uvPFXald9CbVQXLa5QrOPEJhdZiC+CD4quqOVqSG+Ptz5XLA==
|
||||
zen-observable-ts@^0.8.18:
|
||||
version "0.8.18"
|
||||
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.18.tgz#ade44b1060cc4a800627856ec10b9c67f5f639c8"
|
||||
integrity sha512-q7d05s75Rn1j39U5Oapg3HI2wzriVwERVo4N7uFGpIYuHB9ff02P/E92P9B8T7QVC93jCMHpbXH7X0eVR5LA7A==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
zen-observable "^0.8.0"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue