diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 41e71b02b44..9f51da76ac0 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -23,7 +23,7 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IMenuService, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions'; import { createAndFillInContextMenuActions, createAndFillInActionBarActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IRemoteExplorerService, TunnelModel, makeAddress, TunnelType, ITunnelItem, Tunnel, TUNNEL_VIEW_ID, parseAddress, CandidatePort, TunnelPrivacy, TunnelEditId } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { IRemoteExplorerService, TunnelModel, makeAddress, TunnelType, ITunnelItem, Tunnel, TUNNEL_VIEW_ID, parseAddress, CandidatePort, TunnelPrivacy, TunnelEditId, mapHasAddressLocalhostOrAllInterfaces } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -895,6 +895,7 @@ const invalidPortString: string = nls.localize('remote.tunnelsView.portNumberVal const maxPortNumber: number = 65536; const invalidPortNumberString: string = nls.localize('remote.tunnelsView.portNumberToHigh', "Port number must be \u2265 0 and < {0}.", maxPortNumber); const requiresSudoString: string = nls.localize('remote.tunnelView.inlineElevationMessage', "May Require Sudo"); +const alreadyForwarded: string = nls.localize('remote.tunnelView.alreadyForwarded', "Port is already forwarded"); export namespace ForwardPortAction { export const INLINE_ID = 'remote.tunnel.forwardInline'; @@ -903,7 +904,7 @@ export namespace ForwardPortAction { export const TREEITEM_LABEL = nls.localize('remote.tunnel.forwardItem', "Forward Port"); const forwardPrompt = nls.localize('remote.tunnel.forwardPrompt', "Port number or address (eg. 3000 or 10.10.10.10:2000)."); - function validateInput(value: string, canElevate: boolean): { content: string, severity: Severity } | null { + function validateInput(remoteExplorerService: IRemoteExplorerService, value: string, canElevate: boolean): { content: string, severity: Severity } | null { const parsed = parseAddress(value); if (!parsed) { return { content: invalidPortString, severity: Severity.Error }; @@ -911,6 +912,8 @@ export namespace ForwardPortAction { return { content: invalidPortNumberString, severity: Severity.Error }; } else if (canElevate && isPortPrivileged(parsed.port)) { return { content: requiresSudoString, severity: Severity.Info }; + } else if (mapHasAddressLocalhostOrAllInterfaces(remoteExplorerService.tunnelModel.forwarded, parsed.host, parsed.port)) { + return { content: alreadyForwarded, severity: Severity.Error }; } return null; } @@ -934,7 +937,7 @@ export namespace ForwardPortAction { remoteExplorerService.forward({ host: parsed.host, port: parsed.port }, undefined, undefined, undefined, true).then(tunnel => error(notificationService, tunnel, parsed!.host, parsed!.port)); } }, - validationMessage: (value) => validateInput(value, tunnelService.canElevate), + validationMessage: (value) => validateInput(remoteExplorerService, value, tunnelService.canElevate), placeholder: forwardPrompt }); }; @@ -950,7 +953,7 @@ export namespace ForwardPortAction { await viewsService.openView(TunnelPanel.ID, true); const value = await quickInputService.input({ prompt: forwardPrompt, - validateInput: (value) => Promise.resolve(validateInput(value, tunnelService.canElevate)) + validateInput: (value) => Promise.resolve(validateInput(remoteExplorerService, value, tunnelService.canElevate)) }); let parsed: { host: string, port: number } | undefined; if (value && (parsed = parseAddress(value))) {