diff options
| author | Oskar <oskar@mullvad.net> | 2024-08-29 21:57:17 +0200 |
|---|---|---|
| committer | Oskar <oskar@mullvad.net> | 2024-08-30 20:04:00 +0200 |
| commit | 6fd7f455fa2a393f4fa50e54b83c02d5a8743498 (patch) | |
| tree | f7da2ef09547e3d77d18f3f0b3e5c34a6ef25be3 /gui/src | |
| parent | bda71f3d5860ebff96364ca4d8b6d81f3834ff23 (diff) | |
| download | mullvadvpn-6fd7f455fa2a393f4fa50e54b83c02d5a8743498.tar.xz mullvadvpn-6fd7f455fa2a393f4fa50e54b83c02d5a8743498.zip | |
Add Shadowsocks settings
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/components/Shadowsocks.tsx | 137 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardSettings.tsx | 11 |
2 files changed, 148 insertions, 0 deletions
diff --git a/gui/src/renderer/components/Shadowsocks.tsx b/gui/src/renderer/components/Shadowsocks.tsx new file mode 100644 index 0000000000..0614bc44cf --- /dev/null +++ b/gui/src/renderer/components/Shadowsocks.tsx @@ -0,0 +1,137 @@ +import { useCallback } from 'react'; +import { sprintf } from 'sprintf-js'; +import styled from 'styled-components'; + +import { wrapConstraint } from '../../shared/daemon-rpc-types'; +import { messages } from '../../shared/gettext'; +import { removeNonNumericCharacters } from '../../shared/string-helpers'; +import { useAppContext } from '../context'; +import { useHistory } from '../lib/history'; +import { useSelector } from '../redux/store'; +import { AriaDescription, AriaInputGroup } from './AriaGroup'; +import * as Cell from './cell'; +import { SelectorItem, SelectorWithCustomItem } from './cell/Selector'; +import { BackAction } from './KeyboardNavigation'; +import { Layout, SettingsContainer } from './Layout'; +import { + NavigationBar, + NavigationContainer, + NavigationItems, + NavigationScrollbars, + TitleBarItem, +} from './NavigationBar'; +import SettingsHeader, { HeaderTitle } from './SettingsHeader'; + +const PORTS: Array<SelectorItem<number>> = []; +const ALLOWED_RANGE = [1, 65000]; + +const StyledContent = styled.div({ + display: 'flex', + flexDirection: 'column', + flex: 1, + marginBottom: '2px', +}); + +const StyledSelectorContainer = styled.div({ + flex: 0, +}); + +export default function Shadowsocks() { + const { pop } = useHistory(); + + return ( + <BackAction action={pop}> + <Layout> + <SettingsContainer> + <NavigationContainer> + <NavigationBar> + <NavigationItems> + <TitleBarItem> + { + // TRANSLATORS: Title label in navigation bar + messages.pgettext('wireguard-settings-nav', 'Shadowsocks') + } + </TitleBarItem> + </NavigationItems> + </NavigationBar> + + <NavigationScrollbars> + <SettingsHeader> + <HeaderTitle> + {messages.pgettext('wireguard-settings-view', 'Shadowsocks')} + </HeaderTitle> + </SettingsHeader> + + <StyledContent> + <Cell.Group> + <ShadowsocksPortSelector /> + </Cell.Group> + </StyledContent> + </NavigationScrollbars> + </NavigationContainer> + </SettingsContainer> + </Layout> + </BackAction> + ); +} + +function ShadowsocksPortSelector() { + const { setObfuscationSettings } = useAppContext(); + const obfuscationSettings = useSelector((state) => state.settings.obfuscationSettings); + + const port = + obfuscationSettings.shadowsocksSettings.port === 'any' + ? null + : obfuscationSettings.shadowsocksSettings.port.only; + + const setShadowsocksPort = useCallback( + async (port: number | null) => { + await setObfuscationSettings({ + ...obfuscationSettings, + shadowsocksSettings: { + ...obfuscationSettings.shadowsocksSettings, + port: wrapConstraint(port), + }, + }); + }, + [setObfuscationSettings, obfuscationSettings], + ); + + const parseValue = useCallback((port: string) => parseInt(port), []); + + const validateValue = useCallback( + (value: number) => value >= ALLOWED_RANGE[0] && value <= ALLOWED_RANGE[1], + [], + ); + + return ( + <AriaInputGroup> + <StyledSelectorContainer> + <SelectorWithCustomItem + // TRANSLATORS: The title for the WireGuard port selector. + title={messages.pgettext('wireguard-settings-view', 'Port')} + items={PORTS} + value={port} + onSelect={setShadowsocksPort} + inputPlaceholder={messages.pgettext('wireguard-settings-view', 'Port')} + automaticValue={null} + parseValue={parseValue} + modifyValue={removeNonNumericCharacters} + validateValue={validateValue} + maxLength={`${ALLOWED_RANGE[1]}`.length} + /> + </StyledSelectorContainer> + <Cell.CellFooter> + <AriaDescription> + <Cell.CellFooterText> + {sprintf( + // TRANSLATORS: Text describing the valid port range for a port selector. + messages.pgettext('wireguard-settings-view', 'Valid range: %(min)s - %(max)s'), + { min: ALLOWED_RANGE[0], max: ALLOWED_RANGE[1] }, + )} + </Cell.CellFooterText> + </AriaDescription> + </Cell.CellFooter> + </AriaInputGroup> + ); +} diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx index f0aa06fb0f..035ecc6af1 100644 --- a/gui/src/renderer/components/WireguardSettings.tsx +++ b/gui/src/renderer/components/WireguardSettings.tsx @@ -219,6 +219,17 @@ function ObfuscationSettings() { const obfuscationTypeItems: SelectorItem<ObfuscationType>[] = useMemo( () => [ { + label: messages.pgettext('wireguard-settings-view', 'Shadowsocks'), + subLabel: sprintf(subLabelTemplate, { + port: formatPortForSubLabel(obfuscationSettings.shadowsocksSettings.port), + }), + value: ObfuscationType.shadowsocks, + details: { + path: RoutePath.shadowsocks, + ariaLabel: messages.pgettext('accessibility', 'Shadowsocks settings'), + }, + }, + { label: messages.pgettext('wireguard-settings-view', 'UDP-over-TCP'), subLabel: sprintf(subLabelTemplate, { port: formatPortForSubLabel(obfuscationSettings.udp2tcpSettings.port), |
