From 6e037d5df6a6c55c233f55f9051a3579094331bd Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Fri, 17 Feb 2023 11:14:07 +0100 Subject: [PATCH 1/9] Remove sans serif from config --- .../src/services/config/configService.ts | 6 ----- web/packages/teleterm/src/ui/App.tsx | 3 --- .../src/ui/ThemeProvider/ThemeProvider.tsx | 4 +-- .../teleterm/src/ui/ThemeProvider/theme.ts | 25 +++++++++++++++++-- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 2d97193850c17..7f620030b4998 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -85,9 +85,6 @@ const createAppConfigSchema = (platform: Platform) => { 'keymap.openQuickInput': omitStoredConfigValue( z.string().default(defaultKeymap['open-quick-input']) ), - 'fonts.sansSerifFamily': omitStoredConfigValue( - z.string().default(defaultFonts['sansSerif']) - ), 'fonts.monoFamily': omitStoredConfigValue( z.string().default(defaultFonts['mono']) ), @@ -193,17 +190,14 @@ function getDefaultFonts(platform: Platform) { switch (platform) { case 'win32': return { - sansSerif: "system-ui, 'Segoe WPC', 'Segoe UI', sans-serif", mono: "'Consolas', 'Courier New', monospace", }; case 'linux': return { - sansSerif: "system-ui, 'Ubuntu', 'Droid Sans', sans-serif", mono: "'Droid Sans Mono', 'Courier New', monospace, 'Droid Sans Fallback'", }; case 'darwin': return { - sansSerif: '-apple-system, BlinkMacSystemFont, sans-serif', mono: "Menlo, Monaco, 'Courier New', monospace", }; } diff --git a/web/packages/teleterm/src/ui/App.tsx b/web/packages/teleterm/src/ui/App.tsx index ebd0a2ee1c56c..50c166cfae621 100644 --- a/web/packages/teleterm/src/ui/App.tsx +++ b/web/packages/teleterm/src/ui/App.tsx @@ -39,9 +39,6 @@ export const App: React.FC<{ ctx: AppContext }> = ({ ctx }) => { mono: ctx.mainProcessClient.configService.get( 'fonts.monoFamily' ).value, - sansSerif: ctx.mainProcessClient.configService.get( - 'fonts.sansSerifFamily' - ).value, }} > diff --git a/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx b/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx index 6e037c7cba751..4486acca9435f 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx +++ b/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx @@ -23,14 +23,12 @@ import theme from './theme'; type TeletermThemeProvider = { fonts: { mono: string; - sansSerif: string; }; }; const TeletermThemeProvider: React.FC = props => { if (props?.fonts) { - theme.font = props.fonts.sansSerif; - theme.fonts = props.fonts; + theme.fonts.mono = props.fonts.mono; } return ( diff --git a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts index 2feed3ae1d6a2..631d3d70be125 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts +++ b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts @@ -114,11 +114,32 @@ const borders = [ '32px solid', ]; +function getSansSerif() { + const platform = getPlatform(); + + if (platform.isLinux) { + return "system-ui, 'Ubuntu', 'Droid Sans', sans-serif"; + } + + if (platform.isMac) { + return '-apple-system, BlinkMacSystemFont, sans-serif'; + } + + if (platform.isWin) { + return "system-ui, 'Segoe WPC', 'Segoe UI', sans-serif"; + } +} + +const sansSerif = getSansSerif(); + const theme = { colors, typography, - font: fonts.sansSerif, - fonts: fonts, + font: sansSerif, + fonts: { + sansSerif, + mono: fonts.mono, + }, fontWeights, fontSizes, space, From e9d410cd8bd0b9b94f2956379986b0903a8ba006 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Fri, 17 Feb 2023 11:25:09 +0100 Subject: [PATCH 2/9] Pass 'fonts.monoFamily' as style prop --- .../teleterm/src/services/config/configService.ts | 4 +--- web/packages/teleterm/src/ui/App.tsx | 6 +++--- .../teleterm/src/ui/DocumentGateway/CliCommand.tsx | 4 +++- .../src/ui/DocumentTerminal/Terminal/Terminal.tsx | 5 ++--- .../src/ui/DocumentTerminal/Terminal/ctrl.ts | 3 +-- .../src/ui/Documents/KeyboardShortcutsPanel.tsx | 12 +++++++++--- .../teleterm/src/ui/ThemeProvider/ThemeProvider.tsx | 4 ++-- web/packages/teleterm/src/ui/ThemeProvider/theme.ts | 9 ++++++++- 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 7f620030b4998..58908f79c6cdf 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -85,9 +85,7 @@ const createAppConfigSchema = (platform: Platform) => { 'keymap.openQuickInput': omitStoredConfigValue( z.string().default(defaultKeymap['open-quick-input']) ), - 'fonts.monoFamily': omitStoredConfigValue( - z.string().default(defaultFonts['mono']) - ), + 'fonts.monoFamily': z.string().default(defaultFonts['mono']), }); }; diff --git a/web/packages/teleterm/src/ui/App.tsx b/web/packages/teleterm/src/ui/App.tsx index 50c166cfae621..a30739a126930 100644 --- a/web/packages/teleterm/src/ui/App.tsx +++ b/web/packages/teleterm/src/ui/App.tsx @@ -36,9 +36,9 @@ export const App: React.FC<{ ctx: AppContext }> = ({ ctx }) => { diff --git a/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx b/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx index ae0d2eb87b515..793158fc29f30 100644 --- a/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx +++ b/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx @@ -16,6 +16,7 @@ import React, { useEffect, useState } from 'react'; import { Box, ButtonPrimary, Flex, Indicator } from 'design'; +import { useTheme } from 'styled-components'; interface CliCommandProps { cliCommand: string; @@ -25,6 +26,7 @@ interface CliCommandProps { export function CliCommand({ cliCommand, onRun, isLoading }: CliCommandProps) { const [shouldDisplayIsLoading, setShouldDisplayIsLoading] = useState(false); + const theme = useTheme(); useEffect(() => { let timeout: ReturnType; @@ -52,12 +54,12 @@ export function CliCommand({ cliCommand, onRun, isLoading }: CliCommandProps) { mr="2" color={shouldDisplayIsLoading ? 'text.secondary' : 'text.primary'} width="100%" + style={{ fontFamily: theme.fonts.unsanitizedMono }} css={` overflow: auto; white-space: pre; word-break: break-all; font-size: 12px; - font-family: ${props => props.theme.fonts.mono}; `} > {`$`} diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx index 9969bf7a24c7e..027cbc31a91bf 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx @@ -26,12 +26,11 @@ import XTermCtrl from './ctrl'; export default function Terminal(props: Props) { const refElement = useRef(); const refCtrl = useRef(); - const fontFamily = useTheme().fonts.mono; + const fontFamily = useTheme().fonts.unsanitizedMono; useEffect(() => { const ctrl = new XTermCtrl(props.ptyProcess, { el: refElement.current, - fontFamily, }); ctrl.open(); @@ -70,7 +69,7 @@ export default function Terminal(props: Props) { width="100%" style={{ overflow: 'hidden' }} > - + ); } diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts index a672fb18cdc3c..4fb3853db5b37 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts @@ -27,7 +27,6 @@ const WINDOW_RESIZE_DEBOUNCE_DELAY = 200; type Options = { el: HTMLElement; - fontFamily?: string; }; export default class TtyTerminal { @@ -51,7 +50,7 @@ export default class TtyTerminal { open(): void { this.term = new Terminal({ cursorBlink: false, - fontFamily: this.options.fontFamily, + fontFamily: this.el.style.fontFamily, // grab font family from style to prevent injecting malicious CSS scrollback: 5000, theme: { background: theme.colors.primary.darker, diff --git a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx index c62150a70bbab..e3b6d142ab01b 100644 --- a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx +++ b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { Text } from 'design'; -import styled from 'styled-components'; +import styled, { useTheme } from 'styled-components'; import Document from 'teleterm/ui/Document'; import { useKeyboardShortcutFormatters } from 'teleterm/ui/services/keyboardShortcuts'; @@ -67,12 +67,19 @@ export function KeyboardShortcutsPanel() { } function Entry(props: { title: string; shortcut: string }) { + const theme = useTheme(); return ( <> {props.title} - + {props.shortcut} @@ -80,7 +87,6 @@ function Entry(props: { title: string; shortcut: string }) { } const MonoText = styled(Text)` - font-family: ${props => props.theme.fonts.mono}; width: fit-content; opacity: 0.7; border-radius: 4px; diff --git a/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx b/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx index 4486acca9435f..76631ce6fb399 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx +++ b/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx @@ -22,13 +22,13 @@ import theme from './theme'; type TeletermThemeProvider = { fonts: { - mono: string; + unsanitizedMono: string; }; }; const TeletermThemeProvider: React.FC = props => { if (props?.fonts) { - theme.fonts.mono = props.fonts.mono; + theme.fonts.unsanitizedMono = props.fonts.unsanitizedMono; } return ( diff --git a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts index 631d3d70be125..38e9d9f37abf3 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts +++ b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts @@ -26,6 +26,7 @@ import { yellow, } from 'design/theme/palette'; import typography, { fontSizes, fontWeights } from 'design/theme/typography'; +import { getPlatform } from 'design/theme/utils'; const space = [0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80]; const contrastThreshold = 3; @@ -138,7 +139,13 @@ const theme = { font: sansSerif, fonts: { sansSerif, - mono: fonts.mono, + /** + * This value can be provided by the user and is unsanitized. This means that it cannot be directly interpolated + * in a styled component, as it may inject malicious CSS code. + * Before using it, sanitize it with `CSS.escape` or pass it as a `style` prop. + * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. + */ + unsanitizedMono: fonts.mono, }, fontWeights, fontSizes, From 04b162fd184df7b3874bb24cb08e6b812d148feb Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 20 Feb 2023 17:15:16 +0100 Subject: [PATCH 3/9] Get rid of `getSansSerif` function --- .../teleterm/src/ui/ThemeProvider/theme.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts index 38e9d9f37abf3..3c854cd9d4bee 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts +++ b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts @@ -26,7 +26,6 @@ import { yellow, } from 'design/theme/palette'; import typography, { fontSizes, fontWeights } from 'design/theme/typography'; -import { getPlatform } from 'design/theme/utils'; const space = [0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80]; const contrastThreshold = 3; @@ -115,23 +114,7 @@ const borders = [ '32px solid', ]; -function getSansSerif() { - const platform = getPlatform(); - - if (platform.isLinux) { - return "system-ui, 'Ubuntu', 'Droid Sans', sans-serif"; - } - - if (platform.isMac) { - return '-apple-system, BlinkMacSystemFont, sans-serif'; - } - - if (platform.isWin) { - return "system-ui, 'Segoe WPC', 'Segoe UI', sans-serif"; - } -} - -const sansSerif = getSansSerif(); +const sansSerif = 'system-ui'; const theme = { colors, From b756327a575de508e76ed4d2fd1e39101e261b50 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 20 Feb 2023 17:26:30 +0100 Subject: [PATCH 4/9] Use mono font from theme --- .../src/services/config/configService.ts | 19 --------- web/packages/teleterm/src/ui/App.tsx | 10 +---- .../src/ui/DocumentGateway/CliCommand.tsx | 4 +- .../src/ui/ThemeProvider/ThemeProvider.tsx | 39 +++++++------------ .../teleterm/src/ui/ThemeProvider/index.ts | 3 +- .../teleterm/src/ui/ThemeProvider/theme.ts | 8 +--- 6 files changed, 19 insertions(+), 64 deletions(-) diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 58908f79c6cdf..b01208d36bacc 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -23,7 +23,6 @@ import { createConfigStore } from './configStore'; const createAppConfigSchema = (platform: Platform) => { const defaultKeymap = getDefaultKeymap(platform); - const defaultFonts = getDefaultFonts(platform); // Important: all keys except 'usageReporting.enabled' are currently not // configurable by the user. Before we let the user configure them, @@ -85,7 +84,6 @@ const createAppConfigSchema = (platform: Platform) => { 'keymap.openQuickInput': omitStoredConfigValue( z.string().default(defaultKeymap['open-quick-input']) ), - 'fonts.monoFamily': z.string().default(defaultFonts['mono']), }); }; @@ -184,23 +182,6 @@ const getDefaultKeymap = (platform: Platform) => { } }; -function getDefaultFonts(platform: Platform) { - switch (platform) { - case 'win32': - return { - mono: "'Consolas', 'Courier New', monospace", - }; - case 'linux': - return { - mono: "'Droid Sans Mono', 'Courier New', monospace, 'Droid Sans Fallback'", - }; - case 'darwin': - return { - mono: "Menlo, Monaco, 'Courier New', monospace", - }; - } -} - export function createConfigService( appConfigFileStorage: FileStorage, platform: Platform diff --git a/web/packages/teleterm/src/ui/App.tsx b/web/packages/teleterm/src/ui/App.tsx index a30739a126930..c96f35c28f72c 100644 --- a/web/packages/teleterm/src/ui/App.tsx +++ b/web/packages/teleterm/src/ui/App.tsx @@ -26,7 +26,7 @@ import { AppInitializer } from 'teleterm/ui/AppInitializer'; import CatchError from './components/CatchError'; import AppContextProvider from './appContextProvider'; import AppContext from './appContext'; -import ThemeProvider from './ThemeProvider'; +import { ThemeProvider } from './ThemeProvider'; export const App: React.FC<{ ctx: AppContext }> = ({ ctx }) => { return ( @@ -34,13 +34,7 @@ export const App: React.FC<{ ctx: AppContext }> = ({ ctx }) => { - + diff --git a/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx b/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx index 793158fc29f30..7f67b27b3d7e1 100644 --- a/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx +++ b/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx @@ -16,7 +16,6 @@ import React, { useEffect, useState } from 'react'; import { Box, ButtonPrimary, Flex, Indicator } from 'design'; -import { useTheme } from 'styled-components'; interface CliCommandProps { cliCommand: string; @@ -26,7 +25,6 @@ interface CliCommandProps { export function CliCommand({ cliCommand, onRun, isLoading }: CliCommandProps) { const [shouldDisplayIsLoading, setShouldDisplayIsLoading] = useState(false); - const theme = useTheme(); useEffect(() => { let timeout: ReturnType; @@ -54,8 +52,8 @@ export function CliCommand({ cliCommand, onRun, isLoading }: CliCommandProps) { mr="2" color={shouldDisplayIsLoading ? 'text.secondary' : 'text.primary'} width="100%" - style={{ fontFamily: theme.fonts.unsanitizedMono }} css={` + font-family: ${props => props.theme.fonts.mono}; overflow: auto; white-space: pre; word-break: break-all; diff --git a/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx b/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx index 76631ce6fb399..568f1b2b91cae 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx +++ b/web/packages/teleterm/src/ui/ThemeProvider/ThemeProvider.tsx @@ -15,32 +15,21 @@ limitations under the License. */ import React from 'react'; -import { ThemeProvider, StyleSheetManager } from 'styled-components'; +import { + ThemeProvider as StyledThemeProvider, + StyleSheetManager, +} from 'styled-components'; import { GlobalStyle } from './globals'; import theme from './theme'; -type TeletermThemeProvider = { - fonts: { - unsanitizedMono: string; - }; -}; - -const TeletermThemeProvider: React.FC = props => { - if (props?.fonts) { - theme.fonts.unsanitizedMono = props.fonts.unsanitizedMono; - } - - return ( - - - - - {props.children} - - - - ); -}; - -export default TeletermThemeProvider; +export const ThemeProvider: React.FC = props => ( + + + + + {props.children} + + + +); diff --git a/web/packages/teleterm/src/ui/ThemeProvider/index.ts b/web/packages/teleterm/src/ui/ThemeProvider/index.ts index f98fcd7e014e0..8820126cfdff8 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/index.ts +++ b/web/packages/teleterm/src/ui/ThemeProvider/index.ts @@ -14,5 +14,4 @@ See the License for the specific language governing permissions and limitations under the License. */ -import ThemeProvider from './ThemeProvider'; -export default ThemeProvider; +export { ThemeProvider } from './ThemeProvider'; diff --git a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts index 3c854cd9d4bee..7be2ca80023ec 100644 --- a/web/packages/teleterm/src/ui/ThemeProvider/theme.ts +++ b/web/packages/teleterm/src/ui/ThemeProvider/theme.ts @@ -122,13 +122,7 @@ const theme = { font: sansSerif, fonts: { sansSerif, - /** - * This value can be provided by the user and is unsanitized. This means that it cannot be directly interpolated - * in a styled component, as it may inject malicious CSS code. - * Before using it, sanitize it with `CSS.escape` or pass it as a `style` prop. - * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. - */ - unsanitizedMono: fonts.mono, + mono: fonts.mono, }, fontWeights, fontSizes, From a51ae25828f7d371fb8c1fa5922ad9d5f86de092 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 20 Feb 2023 17:52:43 +0100 Subject: [PATCH 5/9] Add 'terminal.fontFamily' and 'terminal.fontSize' config options --- .../src/services/config/configService.ts | 20 ++++++++++++ .../ui/DocumentTerminal/DocumentTerminal.tsx | 9 +++++- .../ui/DocumentTerminal/Terminal/Terminal.tsx | 31 +++++++++++++------ .../src/ui/DocumentTerminal/Terminal/ctrl.ts | 2 ++ .../src/ui/DocumentTerminal/Terminal/index.ts | 4 +-- 5 files changed, 52 insertions(+), 14 deletions(-) diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index b01208d36bacc..9d865d06f3feb 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -23,6 +23,7 @@ import { createConfigStore } from './configStore'; const createAppConfigSchema = (platform: Platform) => { const defaultKeymap = getDefaultKeymap(platform); + const defaultTerminalFont = getDefaultTerminalFont(platform); // Important: all keys except 'usageReporting.enabled' are currently not // configurable by the user. Before we let the user configure them, @@ -84,6 +85,14 @@ const createAppConfigSchema = (platform: Platform) => { 'keymap.openQuickInput': omitStoredConfigValue( z.string().default(defaultKeymap['open-quick-input']) ), + /** + * This value can be provided by the user and is unsanitized. This means that it cannot be directly interpolated + * in a styled component or used in CSS, as it may inject malicious CSS code. + * Before using it, sanitize it with `CSS.escape` or pass it as a `style` prop. + * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. + */ + 'terminal.fontFamily': z.string().default(defaultTerminalFont), + 'terminal.fontSize': z.number().min(5).max(100).default(15), }); }; @@ -182,6 +191,17 @@ const getDefaultKeymap = (platform: Platform) => { } }; +function getDefaultTerminalFont(platform: Platform) { + switch (platform) { + case 'win32': + return "'Consolas', 'Courier New', monospace"; + case 'linux': + return "'Droid Sans Mono', 'Courier New', monospace, 'Droid Sans Fallback'"; + case 'darwin': + return "Menlo, Monaco, 'Courier New', monospace"; + } +} + export function createConfigService( appConfigFileStorage: FileStorage, platform: Platform diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/DocumentTerminal.tsx b/web/packages/teleterm/src/ui/DocumentTerminal/DocumentTerminal.tsx index 14f860cc22593..a9219bcd80d0c 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/DocumentTerminal.tsx +++ b/web/packages/teleterm/src/ui/DocumentTerminal/DocumentTerminal.tsx @@ -25,7 +25,7 @@ import { import Document from 'teleterm/ui/Document'; import { useAppContext } from 'teleterm/ui/appContextProvider'; -import Terminal from './Terminal'; +import { Terminal } from './Terminal'; import DocumentReconnect from './DocumentReconnect'; import useDocTerminal, { Props } from './useDocumentTerminal'; import { useTshFileTransferHandlers } from './useTshFileTransferHandlers'; @@ -40,10 +40,15 @@ export default function DocumentTerminalContainer({ doc, visible }: Props) { export function DocumentTerminal(props: Props & { visible: boolean }) { const ctx = useAppContext(); + const { configService } = ctx.mainProcessClient; const { visible, doc } = props; const state = useDocTerminal(doc); const ptyProcess = state.data?.ptyProcess; const { upload, download } = useTshFileTransferHandlers(); + const unsanitizedTerminalFontFamily = configService.get( + 'terminal.fontFamily' + ).value; + const terminalFontSize = configService.get('terminal.fontSize').value; return ( diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx index 027cbc31a91bf..f0eb7915bd51c 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx @@ -16,21 +16,35 @@ limitations under the License. import { debounce } from 'lodash'; import React, { useEffect, useRef } from 'react'; -import styled, { useTheme } from 'styled-components'; +import styled from 'styled-components'; import { Box, Flex } from 'design'; import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost'; import XTermCtrl from './ctrl'; -export default function Terminal(props: Props) { +type TerminalProps = { + ptyProcess: IPtyProcess; + visible: boolean; + /** + * This value can be provided by the user and is unsanitized. This means that it cannot be directly interpolated + * in a styled component or used in CSS, as it may inject malicious CSS code. + * Before using it, sanitize it with `CSS.escape` or pass it as a `style` prop. + * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. + */ + unsanitizedFontFamily: string; + fontSize: number; + onEnterKey?(): void; +}; + +export function Terminal(props: TerminalProps) { const refElement = useRef(); const refCtrl = useRef(); - const fontFamily = useTheme().fonts.unsanitizedMono; useEffect(() => { const ctrl = new XTermCtrl(props.ptyProcess, { el: refElement.current, + fontSize: props.fontSize, }); ctrl.open(); @@ -69,17 +83,14 @@ export default function Terminal(props: Props) { width="100%" style={{ overflow: 'hidden' }} > - + ); } -type Props = { - ptyProcess: IPtyProcess; - visible: boolean; - onEnterKey?(): void; -}; - const StyledXterm = styled(Box)` height: 100%; width: 100%; diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts index 4fb3853db5b37..55e1a79db1177 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts @@ -27,6 +27,7 @@ const WINDOW_RESIZE_DEBOUNCE_DELAY = 200; type Options = { el: HTMLElement; + fontSize: number; }; export default class TtyTerminal { @@ -51,6 +52,7 @@ export default class TtyTerminal { this.term = new Terminal({ cursorBlink: false, fontFamily: this.el.style.fontFamily, // grab font family from style to prevent injecting malicious CSS + fontSize: this.options.fontSize, scrollback: 5000, theme: { background: theme.colors.primary.darker, diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/index.ts b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/index.ts index fc620f54061e9..23e3538925c91 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/index.ts +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/index.ts @@ -14,6 +14,4 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Terminal from './Terminal'; - -export default Terminal; +export { Terminal } from './Terminal'; From ee22d1f589fa11c363ef8acdb228ca1f669d95be Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Tue, 21 Feb 2023 08:39:03 +0100 Subject: [PATCH 6/9] Require 'terminal.fontSize' size to be int --- web/packages/teleterm/src/services/config/configService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 9d865d06f3feb..36174753f453b 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -92,7 +92,7 @@ const createAppConfigSchema = (platform: Platform) => { * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. */ 'terminal.fontFamily': z.string().default(defaultTerminalFont), - 'terminal.fontSize': z.number().min(5).max(100).default(15), + 'terminal.fontSize': z.number().int().min(5).max(100).default(15), }); }; From a8a0f74521f9cceeedf90063d1e73cfed32da13e Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Tue, 21 Feb 2023 16:32:46 +0100 Subject: [PATCH 7/9] Revert unneeded changes to mono font usage --- .../teleterm/src/ui/DocumentGateway/CliCommand.tsx | 2 +- .../src/ui/Documents/KeyboardShortcutsPanel.tsx | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx b/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx index 7f67b27b3d7e1..ae0d2eb87b515 100644 --- a/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx +++ b/web/packages/teleterm/src/ui/DocumentGateway/CliCommand.tsx @@ -53,11 +53,11 @@ export function CliCommand({ cliCommand, onRun, isLoading }: CliCommandProps) { color={shouldDisplayIsLoading ? 'text.secondary' : 'text.primary'} width="100%" css={` - font-family: ${props => props.theme.fonts.mono}; overflow: auto; white-space: pre; word-break: break-all; font-size: 12px; + font-family: ${props => props.theme.fonts.mono}; `} > {`$`} diff --git a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx index e3b6d142ab01b..c62150a70bbab 100644 --- a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx +++ b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { Text } from 'design'; -import styled, { useTheme } from 'styled-components'; +import styled from 'styled-components'; import Document from 'teleterm/ui/Document'; import { useKeyboardShortcutFormatters } from 'teleterm/ui/services/keyboardShortcuts'; @@ -67,19 +67,12 @@ export function KeyboardShortcutsPanel() { } function Entry(props: { title: string; shortcut: string }) { - const theme = useTheme(); return ( <> {props.title} - + {props.shortcut} @@ -87,6 +80,7 @@ function Entry(props: { title: string; shortcut: string }) { } const MonoText = styled(Text)` + font-family: ${props => props.theme.fonts.mono}; width: fit-content; opacity: 0.7; border-radius: 4px; From 5d359e0fa540754cae85ba02162f7c4566febcb4 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Tue, 21 Feb 2023 16:39:47 +0100 Subject: [PATCH 8/9] Add comment with a link to `ctrl.ts` --- .../teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts index 55e1a79db1177..c45839de912b1 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts @@ -51,7 +51,13 @@ export default class TtyTerminal { open(): void { this.term = new Terminal({ cursorBlink: false, - fontFamily: this.el.style.fontFamily, // grab font family from style to prevent injecting malicious CSS + /** + * `fontFamily` can be provided by the user and is unsanitized. This means that it cannot be directly used in CSS, + * as it may inject malicious CSS code. + * To sanitize the value, we set it as a style on the HTML element and then read it from it. + * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. + */ + fontFamily: this.el.style.fontFamily, fontSize: this.options.fontSize, scrollback: 5000, theme: { From 326c11ba6513589c3fa648ba7374dea2cf512c8f Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Wed, 22 Feb 2023 09:54:13 +0100 Subject: [PATCH 9/9] Allow 'terminal.fontSize' to be in the range 1-256 --- web/packages/teleterm/src/services/config/configService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 36174753f453b..2e153c59939de 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -92,7 +92,7 @@ const createAppConfigSchema = (platform: Platform) => { * Read more https://frontarm.com/james-k-nelson/how-can-i-use-css-in-js-securely/. */ 'terminal.fontFamily': z.string().default(defaultTerminalFont), - 'terminal.fontSize': z.number().int().min(5).max(100).default(15), + 'terminal.fontSize': z.number().int().min(1).max(256).default(15), }); };