diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-07-26 13:09:07 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-07-26 13:09:07 +0200 |
| commit | af847806058c21cdb72d6fea6fda91230e2e34c1 (patch) | |
| tree | 973f33dd20049a072d0ba3cdc8436d2785a0b945 /gui/src | |
| parent | c8bd194d7d9ecad52902fd48f0c7dc507d0c3b01 (diff) | |
| parent | e6725d8e5c60c2218c3856143a748a438e4b6756 (diff) | |
| download | mullvadvpn-af847806058c21cdb72d6fea6fda91230e2e34c1.tar.xz mullvadvpn-af847806058c21cdb72d6fea6fda91230e2e34c1.zip | |
Merge branch 'obfuscation-gui'
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/main/daemon-rpc.ts | 64 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 10 | ||||
| -rw-r--r-- | gui/src/renderer/app.tsx | 6 | ||||
| -rw-r--r-- | gui/src/renderer/components/ConnectionPanel.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/components/Filter.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/components/SelectLanguage.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardSettings.tsx | 124 | ||||
| -rw-r--r-- | gui/src/renderer/components/cell/Section.tsx | 15 | ||||
| -rw-r--r-- | gui/src/renderer/components/cell/Selector.tsx | 90 | ||||
| -rw-r--r-- | gui/src/renderer/redux/settings/actions.ts | 20 | ||||
| -rw-r--r-- | gui/src/renderer/redux/settings/reducers.ts | 15 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 20 | ||||
| -rw-r--r-- | gui/src/shared/ipc-schema.ts | 2 |
13 files changed, 333 insertions, 45 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index 310a9a5c83..646a09a9c7 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -17,6 +17,7 @@ import { DaemonEvent, DeviceEvent, DeviceState, + EndpointObfuscationType, ErrorStateCause, FirewallPolicyError, IAccountData, @@ -40,6 +41,7 @@ import { IWireguardConstraints, LoggedInDeviceState, LoggedOutDeviceState, + ObfuscationSettings, ObfuscationType, Ownership, ProxySettings, @@ -378,6 +380,42 @@ export class DaemonRpc { ); } + public async setObfuscationSettings(obfuscationSettings: ObfuscationSettings): Promise<void> { + const grpcObfuscationSettings = new grpcTypes.ObfuscationSettings(); + switch (obfuscationSettings.selectedObfuscation) { + case ObfuscationType.auto: + grpcObfuscationSettings.setSelectedObfuscation( + grpcTypes.ObfuscationSettings.SelectedObfuscation.AUTO, + ); + break; + case ObfuscationType.off: + grpcObfuscationSettings.setSelectedObfuscation( + grpcTypes.ObfuscationSettings.SelectedObfuscation.OFF, + ); + break; + case ObfuscationType.udp2tcp: + grpcObfuscationSettings.setSelectedObfuscation( + grpcTypes.ObfuscationSettings.SelectedObfuscation.UDP2TCP, + ); + break; + } + + if (obfuscationSettings.udp2tcpSettings) { + const grpcUdp2tcpSettings = new grpcTypes.Udp2TcpObfuscationSettings(); + grpcUdp2tcpSettings.setPort( + obfuscationSettings.udp2tcpSettings.port === 'any' + ? 0 + : obfuscationSettings.udp2tcpSettings.port.only, + ); + grpcObfuscationSettings.setUdp2tcp(grpcUdp2tcpSettings); + } + + await this.call<grpcTypes.ObfuscationSettings, Empty>( + this.client.setObfuscationSettings, + grpcObfuscationSettings, + ); + } + public async setOpenVpnMssfix(mssfix?: number): Promise<void> { await this.callNumber(this.client.setOpenvpnMssfix, mssfix); } @@ -922,7 +960,7 @@ function convertFromProxyEndpoint(proxyEndpoint: grpcTypes.ProxyEndpoint.AsObjec function convertFromObfuscationEndpoint( obfuscationEndpoint: grpcTypes.ObfuscationEndpoint.AsObject, ): IObfuscationEndpoint { - const obfuscationTypes: Record<grpcTypes.ObfuscationType, ObfuscationType> = { + const obfuscationTypes: Record<grpcTypes.ObfuscationType, EndpointObfuscationType> = { [grpcTypes.ObfuscationType.UDP2TCP]: 'udp2tcp', }; @@ -947,6 +985,7 @@ function convertFromSettings(settings: grpcTypes.Settings): ISettings | undefine const bridgeSettings = convertFromBridgeSettings(settingsObject.bridgeSettings!); const tunnelOptions = convertFromTunnelOptions(settingsObject.tunnelOptions!); const splitTunnel = settingsObject.splitTunnel ?? { enableExclusions: false, appsList: [] }; + const obfuscationSettings = convertFromObfuscationSettings(settingsObject.obfuscationSettings); return { ...settings.toObject(), bridgeState, @@ -954,6 +993,7 @@ function convertFromSettings(settings: grpcTypes.Settings): ISettings | undefine bridgeSettings, tunnelOptions, splitTunnel, + obfuscationSettings, }; } @@ -1150,6 +1190,28 @@ function convertFromTunnelOptions(tunnelOptions: grpcTypes.TunnelOptions.AsObjec }; } +function convertFromObfuscationSettings( + obfuscationSettings?: grpcTypes.ObfuscationSettings.AsObject, +): ObfuscationSettings { + let selectedObfuscationType = ObfuscationType.auto; + switch (obfuscationSettings?.selectedObfuscation) { + case grpcTypes.ObfuscationSettings.SelectedObfuscation.OFF: + selectedObfuscationType = ObfuscationType.off; + break; + case grpcTypes.ObfuscationSettings.SelectedObfuscation.UDP2TCP: + selectedObfuscationType = ObfuscationType.udp2tcp; + break; + } + + return { + selectedObfuscation: selectedObfuscationType, + udp2tcpSettings: + obfuscationSettings?.udp2tcp && obfuscationSettings.udp2tcp.port !== 0 + ? { port: { only: obfuscationSettings.udp2tcp.port } } + : { port: 'any' }, + }; +} + function convertFromDaemonEvent(data: grpcTypes.DaemonEvent): DaemonEvent { const tunnelState = data.getTunnelState(); if (tunnelState !== undefined) { diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index 461cac3214..669f406c19 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -36,6 +36,7 @@ import { IRelayList, ISettings, liftConstraint, + ObfuscationType, Ownership, RelaySettings, RelaySettingsUpdate, @@ -212,6 +213,12 @@ class ApplicationMain { }, }, }, + obfuscationSettings: { + selectedObfuscation: ObfuscationType.auto, + udp2tcpSettings: { + port: 'any', + }, + }, }; private deviceState?: DeviceState; private guiSettings = new GuiSettings(); @@ -1340,6 +1347,9 @@ class ApplicationMain { IpcMainEventChannel.autoStart.handleSet((autoStart: boolean) => { return this.setAutoStart(autoStart); }); + IpcMainEventChannel.settings.handleSetObfuscationSettings((obfuscationSettings) => { + return this.daemonRpc.setObfuscationSettings(obfuscationSettings); + }); IpcMainEventChannel.location.handleGet(() => this.daemonRpc.getLocation()); diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index ec69b5d8a7..f8d1796fc1 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -17,6 +17,7 @@ import { ILocation, ISettings, liftConstraint, + ObfuscationSettings, RelaySettings, RelaySettingsUpdate, TunnelState, @@ -518,6 +519,10 @@ export default class AppRenderer { ); } + public setObfuscationSettings(obfuscationSettings: ObfuscationSettings) { + return IpcRendererEventChannel.settings.setObfuscationSettings(obfuscationSettings); + } + public collectProblemReport(toRedact?: string): Promise<string> { return IpcRendererEventChannel.problemReport.collectLogs(toRedact); } @@ -812,6 +817,7 @@ export default class AppRenderer { reduxSettings.updateBridgeState(newSettings.bridgeState); reduxSettings.updateDnsOptions(newSettings.tunnelOptions.dns); reduxSettings.updateSplitTunnelingState(newSettings.splitTunnel.enableExclusions); + reduxSettings.updateObfuscationSettings(newSettings.obfuscationSettings); this.setRelaySettings(newSettings.relaySettings); this.setBridgeSettings(newSettings.bridgeSettings); diff --git a/gui/src/renderer/components/ConnectionPanel.tsx b/gui/src/renderer/components/ConnectionPanel.tsx index 7f4c28286b..552a9e3187 100644 --- a/gui/src/renderer/components/ConnectionPanel.tsx +++ b/gui/src/renderer/components/ConnectionPanel.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { colors } from '../../config.json'; import { - ObfuscationType, + EndpointObfuscationType, ProxyType, proxyTypeToString, RelayProtocol, @@ -31,7 +31,7 @@ export interface IBridgeData extends IEndpoint { } export interface IObfuscationData extends IEndpoint { - obfuscationType: ObfuscationType; + obfuscationType: EndpointObfuscationType; } export interface IOutAddress { diff --git a/gui/src/renderer/components/Filter.tsx b/gui/src/renderer/components/Filter.tsx index 86e0d2dbb3..79253ed7b0 100644 --- a/gui/src/renderer/components/Filter.tsx +++ b/gui/src/renderer/components/Filter.tsx @@ -174,9 +174,9 @@ function providersSelector(state: IReduxState): Record<string, boolean> { ); } -const StyledSelector = (styled(Selector)({ +const StyledSelector = styled(Selector)({ marginBottom: 0, -}) as unknown) as new <T>() => Selector<T>; +}) as typeof Selector; interface IFilterByOwnershipProps { ownership: Ownership; diff --git a/gui/src/renderer/components/SelectLanguage.tsx b/gui/src/renderer/components/SelectLanguage.tsx index 86d0c8166f..419557f700 100644 --- a/gui/src/renderer/components/SelectLanguage.tsx +++ b/gui/src/renderer/components/SelectLanguage.tsx @@ -31,9 +31,9 @@ const StyledNavigationScrollbars = styled(NavigationScrollbars)({ flex: 1, }); -const StyledSelector = (styled(Selector)({ +const StyledSelector = styled(Selector)({ marginBottom: 0, -}) as unknown) as new <T>() => Selector<T>; +}) as typeof Selector; export default class SelectLanguage extends React.Component<IProps, IState> { private scrollView = React.createRef<CustomScrollbarsRef>(); diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx index a4c7a11e08..222e845001 100644 --- a/gui/src/renderer/components/WireguardSettings.tsx +++ b/gui/src/renderer/components/WireguardSettings.tsx @@ -3,7 +3,12 @@ import { sprintf } from 'sprintf-js'; import styled from 'styled-components'; import { strings } from '../../config.json'; -import { IpVersion } from '../../shared/daemon-rpc-types'; +import { + IpVersion, + liftConstraint, + LiftedConstraint, + ObfuscationType, +} from '../../shared/daemon-rpc-types'; import { messages } from '../../shared/gettext'; import log from '../../shared/logging'; import { useAppContext } from '../context'; @@ -18,7 +23,7 @@ import Selector, { ISelectorItem } from './cell/Selector'; import { InfoIcon } from './InfoButton'; import { BackAction } from './KeyboardNavigation'; import { Layout, SettingsContainer } from './Layout'; -import { ModalAlert, ModalAlertType } from './Modal'; +import { ModalAlert, ModalAlertType, ModalMessage } from './Modal'; import { NavigationBar, NavigationContainer, @@ -31,6 +36,7 @@ import SettingsHeader, { HeaderTitle } from './SettingsHeader'; const MIN_WIREGUARD_MTU_VALUE = 1280; const MAX_WIREGUARD_MTU_VALUE = 1420; const WIREUGARD_UDP_PORTS = [51820, 53]; +const UDP2TCP_PORTS = [80, 443, 5001]; type OptionalPort = number | undefined; type OptionalIpVersion = IpVersion | undefined; @@ -98,6 +104,11 @@ export default function WireguardSettings() { </Cell.Group> <Cell.Group> + <ObfuscationSettings /> + <Udp2tcpPortSetting /> + </Cell.Group> + + <Cell.Group> <MultihopSetting /> </Cell.Group> @@ -184,6 +195,115 @@ function PortSelector() { ); } +function ObfuscationSettings() { + const { setObfuscationSettings } = useAppContext(); + const obfuscationSettings = useSelector((state) => state.settings.obfuscationSettings); + + const obfuscationType = obfuscationSettings.selectedObfuscation; + const obfuscationTypeItems: ISelectorItem<ObfuscationType>[] = useMemo( + () => [ + { + label: messages.gettext('Automatic'), + value: ObfuscationType.auto, + }, + { + label: messages.pgettext('wireguard-settings-view', 'On (UDP-over-TCP)'), + value: ObfuscationType.udp2tcp, + }, + { + label: messages.gettext('Off'), + value: ObfuscationType.off, + }, + ], + [], + ); + + const selectObfuscationType = useCallback( + async (value: ObfuscationType) => { + await setObfuscationSettings({ + ...obfuscationSettings, + selectedObfuscation: value, + }); + }, + [setObfuscationSettings, obfuscationSettings], + ); + + return ( + <AriaInputGroup> + <StyledSelectorContainer> + <Selector + // TRANSLATORS: The title for the WireGuard obfuscation selector. + title={messages.pgettext('wireguard-settings-view', 'Obfuscation')} + details={ + <ModalMessage> + {messages.pgettext( + 'wireguard-settings-view', + 'Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connect would be blocked.', + )} + </ModalMessage> + } + values={obfuscationTypeItems} + value={obfuscationType} + onSelect={selectObfuscationType} + /> + </StyledSelectorContainer> + </AriaInputGroup> + ); +} + +function Udp2tcpPortSetting() { + const { setObfuscationSettings } = useAppContext(); + const obfuscationSettings = useSelector((state) => state.settings.obfuscationSettings); + + const port = liftConstraint(obfuscationSettings.udp2tcpSettings.port); + const portItems: ISelectorItem<LiftedConstraint<number>>[] = useMemo(() => { + const automaticItem: ISelectorItem<LiftedConstraint<number>> = { + label: messages.gettext('Automatic'), + value: 'any', + }; + + return [automaticItem].concat(UDP2TCP_PORTS.map(mapPortToSelectorItem)); + }, []); + + const selectPort = useCallback( + async (port: LiftedConstraint<number>) => { + await setObfuscationSettings({ + ...obfuscationSettings, + udp2tcpSettings: { + ...obfuscationSettings.udp2tcpSettings, + port: port === 'any' ? 'any' : { only: port }, + }, + }); + }, + [setObfuscationSettings, obfuscationSettings], + ); + + return ( + <AriaInputGroup> + <StyledSelectorContainer> + <Selector + // TRANSLATORS: The title for the UDP-over-TCP port selector. + title={messages.pgettext('wireguard-settings-view', 'UDP-over-TCP port')} + details={ + <ModalMessage> + {messages.pgettext( + 'wireguard-settings-view', + 'Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.', + )} + </ModalMessage> + } + values={portItems} + value={port} + onSelect={selectPort} + disabled={obfuscationSettings.selectedObfuscation === ObfuscationType.off} + expandable + thinTitle + /> + </StyledSelectorContainer> + </AriaInputGroup> + ); +} + function MultihopSetting() { const relaySettings = useSelector((state) => state.settings.relaySettings); const { updateRelaySettings } = useAppContext(); diff --git a/gui/src/renderer/components/cell/Section.tsx b/gui/src/renderer/components/cell/Section.tsx index 1c1779248f..83c179d3cc 100644 --- a/gui/src/renderer/components/cell/Section.tsx +++ b/gui/src/renderer/components/cell/Section.tsx @@ -2,20 +2,29 @@ import React from 'react'; import styled from 'styled-components'; import { colors } from '../../../config.json'; -import { buttonText } from '../common-styles'; +import { buttonText, openSans, sourceSansPro } from '../common-styles'; const StyledSection = styled.div({ display: 'flex', flexDirection: 'column', }); -export const SectionTitle = styled.span(buttonText, { +interface SectionTitleProps { + disabled?: boolean; + thin?: boolean; +} + +export const SectionTitle = styled.span(buttonText, (props: SectionTitleProps) => ({ display: 'flex', minHeight: '44px', alignItems: 'center', backgroundColor: colors.blue, padding: '0 16px 0 22px', -}); + color: props.disabled ? colors.white20 : colors.white, + fontWeight: props.thin ? 400 : 600, + fontSize: props.thin ? '15px' : '18px', + ...(props.thin ? openSans : sourceSansPro), +})); export const CellSectionContext = React.createContext<boolean>(false); diff --git a/gui/src/renderer/components/cell/Selector.tsx b/gui/src/renderer/components/cell/Selector.tsx index ea2abb90ef..e815519552 100644 --- a/gui/src/renderer/components/cell/Selector.tsx +++ b/gui/src/renderer/components/cell/Selector.tsx @@ -2,10 +2,28 @@ import * as React from 'react'; import styled from 'styled-components'; import { colors } from '../../../config.json'; -import { AriaInput, AriaLabel } from '../AriaGroup'; +import { useBoolean } from '../../lib/utilityHooks'; +import Accordion from '../Accordion'; +import { AriaDetails, AriaInput, AriaLabel } from '../AriaGroup'; +import ChevronButton from '../ChevronButton'; import { normalText } from '../common-styles'; +import InfoButton from '../InfoButton'; import * as Cell from '.'; +const StyledTitle = styled(Cell.Container)({ + display: 'flex', + padding: 0, +}); + +const StyledTitleLabel = styled(Cell.SectionTitle)({ + flex: 1, +}); + +const StyledChevronButton = styled(ChevronButton)({ + padding: 0, + marginRight: '16px', +}); + export interface ISelectorItem<T> { label: string; value: T; @@ -19,41 +37,55 @@ interface ISelectorProps<T> { onSelect: (value: T) => void; selectedCellRef?: React.Ref<HTMLButtonElement>; className?: string; + details?: React.ReactElement; + expandable?: boolean; + disabled?: boolean; + thinTitle?: boolean; } -export default class Selector<T> extends React.Component<ISelectorProps<T>> { - public render() { - const items = this.props.values.map((item, i) => { - const selected = item.value === this.props.value; +export default function Selector<T>(props: ISelectorProps<T>) { + const [expanded, , , toggleExpanded] = useBoolean(!props.expandable); - return ( - <SelectorCell - key={i} - value={item.value} - selected={selected} - disabled={item.disabled} - forwardedRef={selected ? this.props.selectedCellRef : undefined} - onSelect={this.props.onSelect}> - {item.label} - </SelectorCell> - ); - }); + const items = props.values.map((item, i) => { + const selected = item.value === props.value; - const title = this.props.title && ( + return ( + <SelectorCell + key={i} + value={item.value} + selected={selected} + disabled={props.disabled || item.disabled} + forwardedRef={selected ? props.selectedCellRef : undefined} + onSelect={props.onSelect}> + {item.label} + </SelectorCell> + ); + }); + + const title = props.title && ( + <StyledTitle> <AriaLabel> - <Cell.SectionTitle as="label">{this.props.title}</Cell.SectionTitle> + <StyledTitleLabel as="label" disabled={props.disabled} thin={props.thinTitle}> + {props.title} + </StyledTitleLabel> </AriaLabel> - ); + {props.details && ( + <AriaDetails> + <InfoButton>{props.details}</InfoButton> + </AriaDetails> + )} + {props.expandable && <StyledChevronButton up={expanded} onClick={toggleExpanded} />} + </StyledTitle> + ); - return ( - <AriaInput> - <Cell.Section role="listbox" className={this.props.className}> - {title} - {items} - </Cell.Section> - </AriaInput> - ); - } + return ( + <AriaInput> + <Cell.Section role="listbox" className={props.className}> + {title} + {props.expandable ? <Accordion expanded={expanded}>{items}</Accordion> : items} + </Cell.Section> + </AriaInput> + ); } const StyledCellIcon = styled(Cell.Icon)((props: { visible: boolean }) => ({ diff --git a/gui/src/renderer/redux/settings/actions.ts b/gui/src/renderer/redux/settings/actions.ts index 9e12df542d..8126f30205 100644 --- a/gui/src/renderer/redux/settings/actions.ts +++ b/gui/src/renderer/redux/settings/actions.ts @@ -1,5 +1,5 @@ import { IWindowsApplication } from '../../../shared/application-types'; -import { BridgeState, IDnsOptions } from '../../../shared/daemon-rpc-types'; +import { BridgeState, IDnsOptions, ObfuscationSettings } from '../../../shared/daemon-rpc-types'; import { IGuiSettingsState } from '../../../shared/gui-settings-state'; import { BridgeSettingsRedux, IRelayLocationRedux, RelaySettingsRedux } from './reducers'; @@ -83,6 +83,11 @@ export interface ISetSplitTunnelingApplicationsAction { applications: IWindowsApplication[]; } +export interface ISetObfuscationSettings { + type: 'SET_OBFUSCATION_SETTINGS'; + obfuscationSettings: ObfuscationSettings; +} + export type SettingsAction = | IUpdateGuiSettingsAction | IUpdateRelayAction @@ -99,7 +104,8 @@ export type SettingsAction = | IUpdateAutoStartAction | IUpdateDnsOptionsAction | IUpdateSplitTunnelingStateAction - | ISetSplitTunnelingApplicationsAction; + | ISetSplitTunnelingApplicationsAction + | ISetObfuscationSettings; function updateGuiSettings(guiSettings: IGuiSettingsState): IUpdateGuiSettingsAction { return { @@ -219,6 +225,15 @@ function setSplitTunnelingApplications( }; } +function updateObfuscationSettings( + obfuscationSettings: ObfuscationSettings, +): ISetObfuscationSettings { + return { + type: 'SET_OBFUSCATION_SETTINGS', + obfuscationSettings, + }; +} + export default { updateGuiSettings, updateRelay, @@ -236,4 +251,5 @@ export default { updateDnsOptions, updateSplitTunnelingState, setSplitTunnelingApplications, + updateObfuscationSettings, }; diff --git a/gui/src/renderer/redux/settings/reducers.ts b/gui/src/renderer/redux/settings/reducers.ts index 8e4c922192..ee9d81e37f 100644 --- a/gui/src/renderer/redux/settings/reducers.ts +++ b/gui/src/renderer/redux/settings/reducers.ts @@ -4,6 +4,8 @@ import { IDnsOptions, IpVersion, LiftedConstraint, + ObfuscationSettings, + ObfuscationType, Ownership, ProxySettings, RelayLocation, @@ -95,6 +97,7 @@ export interface ISettingsReduxState { dns: IDnsOptions; splitTunneling: boolean; splitTunnelingApplications: IWindowsApplication[]; + obfuscationSettings: ObfuscationSettings; } const initialState: ISettingsReduxState = { @@ -151,6 +154,12 @@ const initialState: ISettingsReduxState = { }, splitTunneling: false, splitTunnelingApplications: [], + obfuscationSettings: { + selectedObfuscation: ObfuscationType.auto, + udp2tcpSettings: { + port: 'any', + }, + }, }; export default function ( @@ -260,6 +269,12 @@ export default function ( splitTunnelingApplications: action.applications, }; + case 'SET_OBFUSCATION_SETTINGS': + return { + ...state, + obfuscationSettings: action.obfuscationSettings, + }; + default: return state; } diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index d0507cab98..5893e4def6 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -61,7 +61,7 @@ export function tunnelTypeToString(tunnel: TunnelType): string { } export type RelayProtocol = 'tcp' | 'udp'; -export type ObfuscationType = 'udp2tcp'; +export type EndpointObfuscationType = 'udp2tcp'; export type Constraint<T> = 'any' | { only: T }; export type LiftedConstraint<T> = 'any' | T; @@ -107,7 +107,7 @@ export interface IObfuscationEndpoint { address: string; port: number; protocol: RelayProtocol; - obfuscationType: ObfuscationType; + obfuscationType: EndpointObfuscationType; } export interface IProxyEndpoint { @@ -347,6 +347,7 @@ export interface ISettings { bridgeSettings: BridgeSettings; bridgeState: BridgeState; splitTunnel: SplitTunnelSettings; + obfuscationSettings: ObfuscationSettings; } export type BridgeState = 'auto' | 'on' | 'off'; @@ -356,6 +357,21 @@ export type SplitTunnelSettings = { appsList: string[]; }; +export type Udp2TcpObfuscationSettings = { + port: Constraint<number>; +}; + +export enum ObfuscationType { + auto, + off, + udp2tcp, +} + +export type ObfuscationSettings = { + selectedObfuscation: ObfuscationType; + udp2tcpSettings: Udp2TcpObfuscationSettings; +}; + export interface IBridgeConstraints { location: Constraint<RelayLocation>; providers: string[]; diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts index 8dece5168d..33ac82180e 100644 --- a/gui/src/shared/ipc-schema.ts +++ b/gui/src/shared/ipc-schema.ts @@ -15,6 +15,7 @@ import { ILocation, IRelayList, ISettings, + ObfuscationSettings, RelaySettingsUpdate, TunnelState, VoucherResponse, @@ -170,6 +171,7 @@ export const ipcSchema = { updateRelaySettings: invoke<RelaySettingsUpdate, void>(), updateBridgeSettings: invoke<BridgeSettings, void>(), setDnsOptions: invoke<IDnsOptions, void>(), + setObfuscationSettings: invoke<ObfuscationSettings, void>(), }, guiSettings: { '': notifyRenderer<IGuiSettingsState>(), |
