Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions web/packages/teleterm/src/services/tshd/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
} from 'teleterm/helpers';

import { createFileTransferStream } from './createFileTransferStream';
import middleware, { withLogging } from './middleware';
import { loggingInterceptor } from './interceptors';
import * as types from './types';
import {
ReportUsageEventRequest,
Expand All @@ -56,9 +56,9 @@ export function createTshdClient(
credentials: grpc.ChannelCredentials
): types.TshdClient {
const logger = new Logger('tshd');
const tshd = middleware(new TerminalServiceClient(addr, credentials), [
withLogging(logger),
]);
const tshd = new TerminalServiceClient(addr, credentials, {
interceptors: [loggingInterceptor(logger)],
});

// Create a client instance that could be shared with the renderer (UI) via Electron contextBridge
const client = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { InterceptingCall, InterceptorOptions } from '@grpc/grpc-js';

import Logger from 'teleterm/logger';

import { withLogging } from './middleware';
import { loggingInterceptor } from './interceptors';

it('do not log sensitive info like password', () => {
const infoLogger = jest.fn();
Expand All @@ -31,22 +31,20 @@ it('do not log sensitive info like password', () => {
warn: () => {},
}),
});
const loggingMiddleware = withLogging(new Logger())(
const interceptor = loggingInterceptor(new Logger())(
{ method_definition: { path: 'LogIn' } } as InterceptorOptions,
() =>
({
sendMessageWithContext: () => {},
} as unknown as InterceptingCall)
);

loggingMiddleware.sendMessage({
toObject: () => ({
passw: {},
userData: {
login: 'admin',
password: 'admin',
},
}),
interceptor.sendMessage({
passw: {},
userData: {
login: 'admin',
password: 'admin',
},
});

expect(infoLogger).toHaveBeenCalledWith(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,65 +28,7 @@ export type UnaryInterceptor = (
nextCall: (options: grpc.InterceptorOptions) => grpc.InterceptingCall
) => grpc.InterceptingCall;

// This is custom grpc middleware implementation that uses JS Proxy to intercept method calls
// Curtesy of https://github.com/echo-health/node-grpc-interceptors/blob/master/client-proxy.js
export default function middleware<T extends Record<string, any>>(
client: T,
interceptors: UnaryInterceptor[]
) {
return new Proxy(client, {
get(target, propKey: any) {
// store the original func being called
const origFunc = target[propKey];

// IMPORTANT - we only want to intercept gRPC request functions!
// Validate this is a gRPC request func by checking the object for
// a requestSerialize() function
let grpcMethod = false;
for (const k in origFunc) {
if (k === 'requestSerialize' && typeof origFunc[k] === 'function') {
grpcMethod = true;
break;
}
}

// if this doesn't look like a gRPC request func, return the original func
if (!grpcMethod) {
return function (...args) {
return origFunc.call(target, ...args);
};
}

// setup the original method with provided interceptors
return function (...args) {
let message, options, callback;

if (args.length >= 3) {
message = args[0];
options = args[1];
callback = args[2];
} else {
message = args[0] || undefined;
callback = args[1] || undefined;
}

if (!options) {
options = {};
}

if (!(options.interceptors && Array.isArray(options.interceptors))) {
options.interceptors = [];
}

options.interceptors = options.interceptors.concat(interceptors);

return origFunc.call(target, message, options, callback);
};
},
});
}

export const withLogging = (logger: Logger): UnaryInterceptor => {
export const loggingInterceptor = (logger: Logger): UnaryInterceptor => {
return (options, nextCall) => {
const method = options.method_definition.path;
const params: grpc.Requester = {
Expand All @@ -97,9 +39,7 @@ export const withLogging = (logger: Logger): UnaryInterceptor => {
},

onReceiveMessage(message, next) {
const json = message
? filterSensitiveProperties(message.toObject())
: null;
const json = message ? filterSensitiveProperties(message) : null;
logger.info(`receive: ${method} -> (${JSON.stringify(json)})`);
next(message);
},
Expand All @@ -117,7 +57,7 @@ export const withLogging = (logger: Logger): UnaryInterceptor => {
sendMessage(message, next) {
logger.info(
`send: ${method}(${JSON.stringify(
filterSensitiveProperties(message.toObject())
filterSensitiveProperties(message)
)})`
);
next(message);
Expand Down
2 changes: 1 addition & 1 deletion web/packages/teleterm/src/services/tshdEvents/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
ExtractResponseType,
TshdEventContextBridgeService,
} from 'teleterm/types';
import { filterSensitiveProperties } from 'teleterm/services/tshd/middleware';
import { filterSensitiveProperties } from 'teleterm/services/tshd/interceptors';

export interface ReloginRequest extends api.ReloginRequest {
rootClusterUri: uri.RootClusterUri;
Expand Down