From af4ea0a31708c6d92469fd94be2c5d0b96ca263f Mon Sep 17 00:00:00 2001 From: Vitalii Parfonov Date: Fri, 14 Feb 2020 15:05:10 +0200 Subject: [PATCH] Implemented a possibility of obtaining client IP address for telemetry plugin (#624) * Implement a possibility of obtaining client IP address for telemetry plugin Signed-off-by: Vitalii Parfonov --- .../src/browser/che-telemetry-main.ts | 29 ++++++++++++++++--- .../src/common/che-protocol.ts | 1 + .../src/node/che-backend-module.ts | 3 ++ .../src/node/che-client-ip-service.ts | 27 +++++++++++++++++ .../src/plugin/che-api.ts | 3 ++ .../src/plugin/che-telemetry.ts | 6 +++- .../src/che-proposed.d.ts | 6 ++++ 7 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 extensions/eclipse-che-theia-plugin-ext/src/node/che-client-ip-service.ts diff --git a/extensions/eclipse-che-theia-plugin-ext/src/browser/che-telemetry-main.ts b/extensions/eclipse-che-theia-plugin-ext/src/browser/che-telemetry-main.ts index b2801e6bb..b5d8d1066 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/browser/che-telemetry-main.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/browser/che-telemetry-main.ts @@ -13,10 +13,13 @@ import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol'; import { CheTelemetryMain, PLUGIN_RPC_CONTEXT, CheTelemetry } from '../common/che-protocol'; import { CheApiService } from '../common/che-protocol'; import { CommandRegistry } from '@theia/core'; +import * as axios from 'axios'; +import { ClientAddressInfo } from '@eclipse-che/plugin'; export class CheTelemetryMainImpl implements CheTelemetryMain { private readonly cheApiService: CheApiService; + private ip: string; constructor(container: interfaces.Container, rpc: RPCProtocol) { const proxy: CheTelemetry = rpc.getProxy(PLUGIN_RPC_CONTEXT.CHE_TELEMETRY); @@ -28,9 +31,10 @@ export class CheTelemetryMainImpl implements CheTelemetryMain { } async $event(id: string, ownerId: string, properties: [string, string][]): Promise { - // TODO : get the infos from the browser - const ip = ''; - + if (!this.ip) { + const client = await this.getClientAddressInfo(); + this.ip = client.ip !== undefined ? client.ip : ''; + } let agent = ''; let resolution = ''; const navigator = window.navigator; @@ -46,6 +50,23 @@ export class CheTelemetryMainImpl implements CheTelemetryMain { } } - return this.cheApiService.submitTelemetryEvent(id, ownerId, ip, agent, resolution, properties); + return this.cheApiService.submitTelemetryEvent(id, ownerId, this.ip, agent, resolution, properties); + } + + async $getClientAddressInfo(): Promise { + return this.getClientAddressInfo(); + } + + async getClientAddressInfo(): Promise { + const response = await axios.default.get('/che/client-ip'); + if (response.status === 200) { + return response.data; + } + console.log('Can`t obtain client adress information. Status: ' + response.status + 'Error message: ' + response.data); + return { + ip: undefined, + ipFamily: undefined, + port: undefined + }; } } diff --git a/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts b/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts index 47c2497b1..57ad60aea 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts @@ -80,6 +80,7 @@ export interface CheTelemetry { export interface CheTelemetryMain { $event(id: string, ownerId: string, properties: [string, string][]): Promise; + $getClientAddressInfo(): Promise; } /** diff --git a/extensions/eclipse-che-theia-plugin-ext/src/node/che-backend-module.ts b/extensions/eclipse-che-theia-plugin-ext/src/node/che-backend-module.ts index 1cd423500..3dce20b32 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/node/che-backend-module.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/node/che-backend-module.ts @@ -34,13 +34,16 @@ import { ChePluginServiceImpl } from './che-plugin-service'; import { CheProductServiceImpl } from './che-product-service'; import { PluginApiContributionIntercepted } from './plugin-service'; import { PluginApiContribution } from '@theia/plugin-ext/lib/main/node/plugin-service'; +import { CheClientIpServiceContribution } from './che-client-ip-service'; export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(ChePluginApiProvider).toSelf().inSingletonScope(); bind(Symbol.for(ExtPluginApiProvider)).toService(ChePluginApiProvider); bind(ChePluginApiContribution).toSelf().inSingletonScope(); + bind(CheClientIpServiceContribution).toSelf().inSingletonScope(); bind(BackendApplicationContribution).toService(ChePluginApiContribution); + bind(BackendApplicationContribution).toService(CheClientIpServiceContribution); rebind(PluginApiContribution).to(PluginApiContributionIntercepted).inSingletonScope(); diff --git a/extensions/eclipse-che-theia-plugin-ext/src/node/che-client-ip-service.ts b/extensions/eclipse-che-theia-plugin-ext/src/node/che-client-ip-service.ts new file mode 100644 index 000000000..9cbaf95ac --- /dev/null +++ b/extensions/eclipse-che-theia-plugin-ext/src/node/che-client-ip-service.ts @@ -0,0 +1,27 @@ +/********************************************************************* + * Copyright (c) 2020 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import * as express from 'express'; +import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application'; +import { injectable } from 'inversify'; + +@injectable() +export class CheClientIpServiceContribution implements BackendApplicationContribution { + + configure(app: express.Application): void { + app.get('/che/client-ip', (req, res) => { + res.json({ + ip: req.connection.remoteAddress, + ipFamily: req.connection.remoteFamily, + port: req.connection.remotePort + }); + }); + } +} diff --git a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts index 104ddce98..dee40b3ec 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts @@ -105,6 +105,9 @@ export function createAPIFactory(rpc: RPCProtocol): CheApiFactory { }, addCommandListener(commandId: string, listener: che.TelemetryListener): Promise { return cheTelemetryImpl.addCommandListener(commandId, listener); + }, + getClienAddressInfo(): Promise { + return cheTelemetryImpl.getClientAddressInfo(); } }; diff --git a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-telemetry.ts b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-telemetry.ts index ecdda3ac6..288d98ab0 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-telemetry.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-telemetry.ts @@ -9,7 +9,7 @@ **********************************************************************/ import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol'; import { PLUGIN_RPC_CONTEXT, CheTelemetry, CheTelemetryMain } from '../common/che-protocol'; -import { TelemetryListener, TelemetryListenerParam } from '@eclipse-che/plugin'; +import { TelemetryListener, TelemetryListenerParam, ClientAddressInfo } from '@eclipse-che/plugin'; export class CheTelemetryImpl implements CheTelemetry { private readonly telemetryMain: CheTelemetryMain; private listeners: Map = new Map(); @@ -35,4 +35,8 @@ export class CheTelemetryImpl implements CheTelemetry { listener(commandId); } } + + async getClientAddressInfo(): Promise { + return this.telemetryMain.$getClientAddressInfo(); + } } diff --git a/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts b/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts index 678fff3f5..d76969bee 100644 --- a/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts +++ b/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts @@ -70,10 +70,16 @@ declare module '@eclipse-che/plugin' { * Listener for global command invocation */ export type TelemetryListener = (commandId: string, param?: TelemetryListenerParam) => void; + export interface ClientAddressInfo { + ip?: string, + port?: string + ipFamily?: number + } export namespace telemetry { export function event(id: string, ownerId: string, properties: [string, string][]): Promise; /** Fires when a command will starts. */ export function addCommandListener(commandId: string, listener: TelemetryListener): Promise; + export function getClienAddressInfo(): Promise; } /**