From ff3484207ed652039dd05607d18a1a79c8beb356 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Fri, 5 Apr 2024 16:58:19 +0200 Subject: [PATCH 1/7] Extract current console transport to a separate function --- .../src/services/logger/loggerService.ts | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/web/packages/teleterm/src/services/logger/loggerService.ts b/web/packages/teleterm/src/services/logger/loggerService.ts index 0b833c67b2ae5..7c12ed798b707 100644 --- a/web/packages/teleterm/src/services/logger/loggerService.ts +++ b/web/packages/teleterm/src/services/logger/loggerService.ts @@ -95,22 +95,7 @@ export function createFileLoggerService( }); if (opts.dev) { - instance.add( - new transports.Console({ - format: format.printf(({ level, message, context }) => { - const loggerName = - opts.loggerNameColor && - `\x1b[${opts.loggerNameColor}m${opts.name.toUpperCase()}\x1b[0m`; - - const text = stringifier(message as unknown as unknown[]); - const logMessage = opts.passThroughMode - ? text - : `[${context}] ${level}: ${text}`; - - return [loggerName, logMessage].filter(Boolean).join(' '); - }), - }) - ); + instance.add(getRegularConsoleTransport(opts)); } return { @@ -217,3 +202,21 @@ type FileLoggerOptions = { * */ omitTimestamp?: boolean; }; + +/** Stringifies log messages and logs with winston's console transport. */ +function getRegularConsoleTransport(opts: FileLoggerOptions) { + return new transports.Console({ + format: format.printf(({ level, message, context }) => { + const loggerName = + opts.loggerNameColor && + `\x1b[${opts.loggerNameColor}m${opts.name.toUpperCase()}\x1b[0m`; + + const text = stringifier(message as unknown as unknown[]); + const logMessage = opts.passThroughMode + ? text + : `[${context}] ${level}: ${text}`; + + return [loggerName, logMessage].filter(Boolean).join(' '); + }), + }); +} From e87f838f57d6232ef129bd69f7ada55110510bf2 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Fri, 5 Apr 2024 16:59:05 +0200 Subject: [PATCH 2/7] Add separate transport for the browser console --- .../src/services/logger/loggerService.ts | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/web/packages/teleterm/src/services/logger/loggerService.ts b/web/packages/teleterm/src/services/logger/loggerService.ts index 7c12ed798b707..8bf61958fc50b 100644 --- a/web/packages/teleterm/src/services/logger/loggerService.ts +++ b/web/packages/teleterm/src/services/logger/loggerService.ts @@ -30,6 +30,8 @@ import split2 from 'split2'; import { Logger, LoggerService, NodeLoggerService } from './types'; import { KeepLastChunks } from './keepLastChunks'; +import type { Logform } from 'winston'; + import type { ChildProcess } from 'node:child_process'; /** @@ -95,7 +97,12 @@ export function createFileLoggerService( }); if (opts.dev) { - instance.add(getRegularConsoleTransport(opts)); + // Browser environment. + if (typeof window !== 'undefined') { + instance.add(getBrowserConsoleTransport(opts)); + } else { + instance.add(getRegularConsoleTransport(opts)); + } } return { @@ -203,6 +210,24 @@ type FileLoggerOptions = { omitTimestamp?: boolean; }; +/** Does not stringify messages and logs directly using `console.x` functions. */ +function getBrowserConsoleTransport(opts: FileLoggerOptions) { + return new transports.Console({ + log({ level, message, context }: Logform.TransformableInfo, next) { + const loggerName = getLoggerName(opts); + + const logMessage = opts.passThroughMode + ? message + : [`[${context}] ${level}:`, ...message]; + + const toLog = [loggerName, logMessage].filter(Boolean).flat(); + // We allow level to be only info, warn and error (createLoggerFromWinston). + console[level](...toLog); + next(); + }, + }); +} + /** Stringifies log messages and logs with winston's console transport. */ function getRegularConsoleTransport(opts: FileLoggerOptions) { return new transports.Console({ @@ -220,3 +245,12 @@ function getRegularConsoleTransport(opts: FileLoggerOptions) { }), }); } + +function getLoggerName( + opts: Pick +) { + return ( + opts.loggerNameColor && + `\x1b[${opts.loggerNameColor}m${opts.name.toUpperCase()}\x1b[0m` + ); +} From 4775ce28037547f38576bf5d022d2b5973a4ed20 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Fri, 5 Apr 2024 17:00:33 +0200 Subject: [PATCH 3/7] Check exact key names when filtering out sensitive properties This will prevent filtering out `pinnedOnly` property. --- web/packages/teleterm/src/services/tshd/interceptors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/packages/teleterm/src/services/tshd/interceptors.ts b/web/packages/teleterm/src/services/tshd/interceptors.ts index 3608039462fb9..59ced6e4906a6 100644 --- a/web/packages/teleterm/src/services/tshd/interceptors.ts +++ b/web/packages/teleterm/src/services/tshd/interceptors.ts @@ -22,7 +22,7 @@ import { isObject } from 'shared/utils/highbar'; import Logger from 'teleterm/logger'; -const SENSITIVE_PROPERTIES = ['passw', 'authClusterId', 'pin']; +const SENSITIVE_PROPERTIES = ['passw', 'password', 'authClusterId', 'pin']; export function loggingInterceptor(logger: Logger): RpcInterceptor { return { @@ -109,7 +109,7 @@ export function filterSensitiveProperties(toFilter: object): object { const transformer = (result: object, value: any, key: any) => { if ( SENSITIVE_PROPERTIES.some( - sensitiveProp => typeof key === 'string' && key.includes(sensitiveProp) + sensitiveProp => typeof key === 'string' && key === sensitiveProp ) ) { result[key] = '~FILTERED~'; From e7943f738a92a1df82b155119a1661a20436727d Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 8 Apr 2024 17:16:08 +0200 Subject: [PATCH 4/7] Remove `passw` --- web/packages/teleterm/src/services/tshd/interceptors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/teleterm/src/services/tshd/interceptors.ts b/web/packages/teleterm/src/services/tshd/interceptors.ts index 59ced6e4906a6..a3375ea1f32a2 100644 --- a/web/packages/teleterm/src/services/tshd/interceptors.ts +++ b/web/packages/teleterm/src/services/tshd/interceptors.ts @@ -22,7 +22,7 @@ import { isObject } from 'shared/utils/highbar'; import Logger from 'teleterm/logger'; -const SENSITIVE_PROPERTIES = ['passw', 'password', 'authClusterId', 'pin']; +const SENSITIVE_PROPERTIES = ['password', 'authClusterId', 'pin']; export function loggingInterceptor(logger: Logger): RpcInterceptor { return { From 081efaf14a94acb91a8c3e4e87e9e5664ad37ff1 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 8 Apr 2024 17:17:11 +0200 Subject: [PATCH 5/7] Use `getLoggerName()` in `getRegularConsoleTransport()` --- web/packages/teleterm/src/services/logger/loggerService.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/packages/teleterm/src/services/logger/loggerService.ts b/web/packages/teleterm/src/services/logger/loggerService.ts index 8bf61958fc50b..183c0d2171303 100644 --- a/web/packages/teleterm/src/services/logger/loggerService.ts +++ b/web/packages/teleterm/src/services/logger/loggerService.ts @@ -232,9 +232,7 @@ function getBrowserConsoleTransport(opts: FileLoggerOptions) { function getRegularConsoleTransport(opts: FileLoggerOptions) { return new transports.Console({ format: format.printf(({ level, message, context }) => { - const loggerName = - opts.loggerNameColor && - `\x1b[${opts.loggerNameColor}m${opts.name.toUpperCase()}\x1b[0m`; + const loggerName = getLoggerName(opts); const text = stringifier(message as unknown as unknown[]); const logMessage = opts.passThroughMode From 0a7a8be20f61abe02fe6d0da8a07ea1630a45105 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 8 Apr 2024 17:40:09 +0200 Subject: [PATCH 6/7] Improve comment --- web/packages/teleterm/src/services/logger/loggerService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/teleterm/src/services/logger/loggerService.ts b/web/packages/teleterm/src/services/logger/loggerService.ts index 183c0d2171303..de88c9b75c38d 100644 --- a/web/packages/teleterm/src/services/logger/loggerService.ts +++ b/web/packages/teleterm/src/services/logger/loggerService.ts @@ -210,7 +210,7 @@ type FileLoggerOptions = { omitTimestamp?: boolean; }; -/** Does not stringify messages and logs directly using `console.x` functions. */ +/** Does not stringify messages and logs directly using `console.*` functions. */ function getBrowserConsoleTransport(opts: FileLoggerOptions) { return new transports.Console({ log({ level, message, context }: Logform.TransformableInfo, next) { From 9f9f7f36ec61bcc089898bc69dcc37a43dfd0548 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 8 Apr 2024 17:47:55 +0200 Subject: [PATCH 7/7] Fix tests --- web/packages/teleterm/src/services/tshd/interceptors.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/packages/teleterm/src/services/tshd/interceptors.test.ts b/web/packages/teleterm/src/services/tshd/interceptors.test.ts index 52d7e0b9adfb8..917906a8184af 100644 --- a/web/packages/teleterm/src/services/tshd/interceptors.test.ts +++ b/web/packages/teleterm/src/services/tshd/interceptors.test.ts @@ -40,7 +40,7 @@ it('do not log sensitive info like password', () => { service: { typeName: 'FooService' } as ServiceInfo, } as MethodInfo, { - passw: {}, + password: {}, userData: { login: 'admin', password: 'admin', @@ -50,7 +50,7 @@ it('do not log sensitive info like password', () => { ); expect(infoLogger).toHaveBeenCalledWith(expect.any(String), { - passw: '~FILTERED~', + password: '~FILTERED~', userData: { login: 'admin', password: '~FILTERED~' }, }); });