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

Block requests to ui_metric API if telemetry is disabled #35268

Merged
merged 12 commits into from
Apr 25, 2019
20 changes: 20 additions & 0 deletions src/legacy/core_plugins/ui_metric/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export const API_BASE_PATH = '/api/ui_metric';
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
* under the License.
*/

import { resolve } from 'path';
import { registerUserActionRoute } from './server/routes/api/ui_metric';
import { registerUiMetricUsageCollector } from './server/usage/index';

export default function (kibana) {
return new kibana.Plugin({
id: 'ui_metric',
require: ['kibana', 'elasticsearch'],
publicDir: resolve(__dirname, 'public'),

uiExports: {
mappings: require('./mappings.json'),
hacks: [ 'plugins/ui_metric' ]
},

init: function (server) {
Expand Down
56 changes: 56 additions & 0 deletions src/legacy/core_plugins/ui_metric/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import chrome from 'ui/chrome';
import { uiModules } from 'ui/modules';
import { getCanGatherUiMetrics } from 'ui/ui_metric';
import { API_BASE_PATH } from '../common';

const module = uiModules.get('kibana');

let _http;

module.run($http => {
_http = $http;
});

module.config(($httpProvider) => {
$httpProvider.interceptors.push(($q) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we using an interceptor to accomplish this? Would it be possible to just not make the calls when telemetry is disabled instead of trying to block them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, yes! I implemented the interceptor solution before creating the common track method, so completely overlooked the obvious. I'll update the code to just perform the check there.

return {
request: config => {
const { url } = config;
const isUiMetricRequest = url.indexOf(`${chrome.getBasePath()}${API_BASE_PATH}`) === 0;
const canGatherUiMetrics = getCanGatherUiMetrics();

if (isUiMetricRequest && !canGatherUiMetrics) {
// Block request from going out if the user has disabled telemetry.
return $q.reject('uiMetricsDisallowed');
} else {
return $q.resolve(config);
}
},
};
});
});

export function track(appName: string, actionType: string) {
const uri = chrome.addBasePath(`${API_BASE_PATH}/${appName}/${actionType}`);
// Silently swallow request failures.
_http.post(uri).then(() => {}, () => {});
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@

import Boom from 'boom';
import { Server } from 'hapi';
import { API_BASE_PATH } from '../../../common';

export const registerUserActionRoute = (server: Server) => {
/*
* Increment a count on an object representing a specific interaction with the UI.
*/
server.route({
path: '/api/ui_metric/{appName}/{metricTypes}',
path: `${API_BASE_PATH}/{appName}/{metricTypes}`,
method: 'POST',
handler: async (request: any) => {
const { appName, metricTypes } = request.params;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import chrome from 'ui/chrome';
let _canGatherUiMetrics = false;

export function createUiMetricUri(appName: string, actionType: string): string {
return chrome.addBasePath(`/api/ui_metric/${appName}/${actionType}`);
export function setCanGatherUiMetrics(flag: boolean) {
_canGatherUiMetrics = flag;
}

export function getCanGatherUiMetrics(): boolean {
return _canGatherUiMetrics;
}
7 changes: 0 additions & 7 deletions x-pack/common/ui_metric/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createUiMetricUri } from '../../../../../common/ui_metric';
import { track } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../constants';
import { getHttpClient } from './api';

export function trackUiMetric(actionType) {
const uiMetricUri = createUiMetricUri(UIM_APP_NAME, actionType);
getHttpClient().post(uiMetricUri);
track(UIM_APP_NAME, actionType);
}

/**
Expand Down
10 changes: 5 additions & 5 deletions x-pack/plugins/index_lifecycle_management/public/services/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export async function loadPolicies(withIndices, httpClient = getHttpClient()) {
export async function deletePolicy(policyName, httpClient = getHttpClient()) {
const response = await httpClient.delete(`${apiPrefix}/policies/${encodeURIComponent(policyName)}`);
// Only track successful actions.
trackUiMetric(UIM_POLICY_DELETE, httpClient);
trackUiMetric(UIM_POLICY_DELETE);
return response.data;
}

Expand All @@ -73,27 +73,27 @@ export async function getAffectedIndices(indexTemplateName, policyName, httpClie
export const retryLifecycleForIndex = async (indexNames, httpClient = getHttpClient()) => {
const response = await httpClient.post(`${apiPrefix}/index/retry`, { indexNames });
// Only track successful actions.
trackUiMetric(UIM_INDEX_RETRY_STEP, httpClient);
trackUiMetric(UIM_INDEX_RETRY_STEP);
return response.data;
};

export const removeLifecycleForIndex = async (indexNames, httpClient = getHttpClient()) => {
const response = await httpClient.post(`${apiPrefix}/index/remove`, { indexNames });
// Only track successful actions.
trackUiMetric(UIM_POLICY_DETACH_INDEX, httpClient);
trackUiMetric(UIM_POLICY_DETACH_INDEX);
return response.data;
};

export const addLifecyclePolicyToIndex = async (body, httpClient = getHttpClient()) => {
const response = await httpClient.post(`${apiPrefix}/index/add`, body);
// Only track successful actions.
trackUiMetric(UIM_POLICY_ATTACH_INDEX, httpClient);
trackUiMetric(UIM_POLICY_ATTACH_INDEX);
return response.data;
};

export const addLifecyclePolicyToTemplate = async (body, httpClient = getHttpClient()) => {
const response = await httpClient.post(`${apiPrefix}/template`, body);
// Only track successful actions.
trackUiMetric(UIM_POLICY_ATTACH_INDEX_TEMPLATE, httpClient);
trackUiMetric(UIM_POLICY_ATTACH_INDEX_TEMPLATE);
return response.data;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { get } from 'lodash';

import { createUiMetricUri } from '../../../../common/ui_metric';
import { track } from '../../../../../src/legacy/core_plugins/ui_metric/public';

import {
UIM_APP_NAME,
Expand All @@ -29,11 +29,8 @@ import {
defaultHotPhase,
} from '../store/defaults';

import { getHttpClient } from './api';

export function trackUiMetric(metricType, httpClient = getHttpClient()) {
const uiMetricUri = createUiMetricUri(UIM_APP_NAME, metricType);
httpClient.post(uiMetricUri);
export function trackUiMetric(metricType) {
track(UIM_APP_NAME, metricType);
}

export function getUiMetricsForPhases(phases) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createUiMetricUri } from '../../../../common/ui_metric';
import { track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../../common/constants';
import { getHttpClient } from './api';

export function trackUiMetric(metricType) {
const uiMetricUri = createUiMetricUri(UIM_APP_NAME, metricType);
getHttpClient().post(uiMetricUri);
track(UIM_APP_NAME, metricType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createUiMetricUri } from '../../../../common/ui_metric';
import { track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../constants';
import { getHttpClient } from './api';

export function trackUiMetric(actionType) {
const uiMetricUri = createUiMetricUri(UIM_APP_NAME, actionType);
getHttpClient().post(uiMetricUri);
track(UIM_APP_NAME, actionType);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createUiMetricUri } from '../../../../../common/ui_metric';
import { track } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../../../common';
import { getHttp } from './http_provider';

export function trackUiMetric(actionType) {
const uiMetricUri = createUiMetricUri(UIM_APP_NAME, actionType);
getHttp().post(uiMetricUri);
track(UIM_APP_NAME, actionType);
}

/**
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/security/public/hacks/on_session_timeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ module.config(($httpProvider) => {

function interceptorFactory(responseHandler) {
return function interceptor(response) {
if (!isUnauthenticated && !isSystemApiRequest(response.config) && sessionTimeout !== null) {
// If another interceptor has rejected a request, then config will be undefined.
const isSystemRequest = response.config ? isSystemApiRequest(response.config) : false;

This comment was marked as outdated.

if (!isUnauthenticated && !isSystemRequest && sessionTimeout !== null) {
clearNotifications();
scheduleNotification();
}
Expand Down
25 changes: 14 additions & 11 deletions x-pack/plugins/xpack_main/public/hacks/check_xpack_info_change.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,21 @@ module.factory('checkXPackInfoChange', ($q, Private) => {
return handleResponse(response);
}

const currentSignature = response.headers('kbn-xpack-sig');
const cachedSignature = xpackInfoSignature.get();
// If another interceptor has rejected a request, then headers will be undefined.
if (response.headers) {

This comment was marked as outdated.

const currentSignature = response.headers('kbn-xpack-sig');
const cachedSignature = xpackInfoSignature.get();

if (currentSignature && cachedSignature !== currentSignature) {
// Signature from the server differ from the signature of our
// cached info, so we need to refresh it.
// Intentionally swallowing this error
// because nothing catches it and it's an ugly console error.
xpackInfo.refresh().then(
() => notifyIfLicenseIsExpired(),
() => {}
);
if (currentSignature && cachedSignature !== currentSignature) {
// Signature from the server differ from the signature of our
// cached info, so we need to refresh it.
// Intentionally swallowing this error
// because nothing catches it and it's an ugly console error.
xpackInfo.refresh().then(
() => notifyIfLicenseIsExpired(),
() => {}
);
}
}

return handleResponse(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
*/

import moment from 'moment';
import { setCanGatherUiMetrics } from 'ui/ui_metric';

export function TelemetryOptInProvider($injector, chrome) {

const Notifier = $injector.get('Notifier');
const notify = new Notifier();
let currentOptInStatus = $injector.get('telemetryOptedIn');
setCanGatherUiMetrics(currentOptInStatus);

return {
getOptIn: () => currentOptInStatus,
setOptIn: async (enabled) => {
setCanGatherUiMetrics(enabled);

const $http = $injector.get('$http');

try {
Expand Down