55
66import { Emitter , Event } from 'vs/base/common/event' ;
77import { IDisposable } from 'vs/base/common/lifecycle' ;
8+ import { isWindows } from 'vs/base/common/platform' ;
89import { URI } from 'vs/base/common/uri' ;
910import { createDecorator } from 'vs/platform/instantiation/common/instantiation' ;
1011import { ILogService } from 'vs/platform/log/common/log' ;
@@ -30,6 +31,10 @@ export interface TunnelCreationOptions {
3031 elevationRequired ?: boolean ;
3132}
3233
34+ export interface TunnelProviderFeatures {
35+ elevation : boolean ;
36+ }
37+
3338export interface ITunnelProvider {
3439 forwardPort ( tunnelOptions : TunnelOptions , tunnelCreationOptions : TunnelCreationOptions ) : Promise < RemoteTunnel | undefined > | undefined ;
3540}
@@ -40,10 +45,11 @@ export interface ITunnelService {
4045 readonly tunnels : Promise < readonly RemoteTunnel [ ] > ;
4146 readonly onTunnelOpened : Event < RemoteTunnel > ;
4247 readonly onTunnelClosed : Event < { host : string , port : number } > ;
48+ readonly canElevate : boolean ;
4349
44- openTunnel ( addressProvider : IAddressProvider | undefined , remoteHost : string | undefined , remotePort : number , localPort ?: number ) : Promise < RemoteTunnel | undefined > | undefined ;
50+ openTunnel ( addressProvider : IAddressProvider | undefined , remoteHost : string | undefined , remotePort : number , localPort ?: number , elevateIfNeeded ?: boolean ) : Promise < RemoteTunnel | undefined > | undefined ;
4551 closeTunnel ( remoteHost : string , remotePort : number ) : Promise < void > ;
46- setTunnelProvider ( provider : ITunnelProvider | undefined ) : IDisposable ;
52+ setTunnelProvider ( provider : ITunnelProvider | undefined , features : TunnelProviderFeatures ) : IDisposable ;
4753}
4854
4955export function extractLocalHostUriMetaDataForPortMapping ( uri : URI ) : { address : string , port : number } | undefined {
@@ -74,6 +80,10 @@ function getOtherLocalhost(host: string): string | undefined {
7480 return ( host === 'localhost' ) ? '127.0.0.1' : ( ( host === '127.0.0.1' ) ? 'localhost' : undefined ) ;
7581}
7682
83+ export function isPortPrivileged ( port : number ) : boolean {
84+ return ! isWindows && ( port < 1024 ) ;
85+ }
86+
7787export abstract class AbstractTunnelService implements ITunnelService {
7888 declare readonly _serviceBrand : undefined ;
7989
@@ -83,25 +93,33 @@ export abstract class AbstractTunnelService implements ITunnelService {
8393 public onTunnelClosed : Event < { host : string , port : number } > = this . _onTunnelClosed . event ;
8494 protected readonly _tunnels = new Map < /*host*/ string , Map < /* port */ number , { refcount : number , readonly value : Promise < RemoteTunnel | undefined > } > > ( ) ;
8595 protected _tunnelProvider : ITunnelProvider | undefined ;
96+ protected _canElevate : boolean = false ;
8697
8798 public constructor (
8899 @ILogService protected readonly logService : ILogService
89100 ) { }
90101
91- setTunnelProvider ( provider : ITunnelProvider | undefined ) : IDisposable {
102+ setTunnelProvider ( provider : ITunnelProvider | undefined , features : TunnelProviderFeatures ) : IDisposable {
103+ this . _tunnelProvider = provider ;
92104 if ( ! provider ) {
105+ // clear features
106+ this . _canElevate = false ;
93107 return {
94108 dispose : ( ) => { }
95109 } ;
96110 }
97- this . _tunnelProvider = provider ;
111+ this . _canElevate = features . elevation ;
98112 return {
99113 dispose : ( ) => {
100114 this . _tunnelProvider = undefined ;
101115 }
102116 } ;
103117 }
104118
119+ public get canElevate ( ) : boolean {
120+ return this . _canElevate ;
121+ }
122+
105123 public get tunnels ( ) : Promise < readonly RemoteTunnel [ ] > {
106124 return new Promise ( async ( resolve ) => {
107125 const tunnels : RemoteTunnel [ ] = [ ] ;
@@ -129,7 +147,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
129147 this . _tunnels . clear ( ) ;
130148 }
131149
132- openTunnel ( addressProvider : IAddressProvider | undefined , remoteHost : string | undefined , remotePort : number , localPort : number ) : Promise < RemoteTunnel | undefined > | undefined {
150+ openTunnel ( addressProvider : IAddressProvider | undefined , remoteHost : string | undefined , remotePort : number , localPort ? : number , elevateIfNeeded : boolean = false ) : Promise < RemoteTunnel | undefined > | undefined {
133151 if ( ! addressProvider ) {
134152 return undefined ;
135153 }
@@ -138,7 +156,7 @@ export abstract class AbstractTunnelService implements ITunnelService {
138156 remoteHost = 'localhost' ;
139157 }
140158
141- const resolvedTunnel = this . retainOrCreateTunnel ( addressProvider , remoteHost , remotePort , localPort ) ;
159+ const resolvedTunnel = this . retainOrCreateTunnel ( addressProvider , remoteHost , remotePort , localPort , elevateIfNeeded ) ;
142160 if ( ! resolvedTunnel ) {
143161 return resolvedTunnel ;
144162 }
@@ -238,15 +256,11 @@ export abstract class AbstractTunnelService implements ITunnelService {
238256 return portMap ? portMap . get ( remotePort ) : undefined ;
239257 }
240258
241- protected abstract retainOrCreateTunnel ( addressProvider : IAddressProvider , remoteHost : string , remotePort : number , localPort ?: number ) : Promise < RemoteTunnel | undefined > | undefined ;
242-
243- protected isPortPrivileged ( port : number ) : boolean {
244- return port < 1024 ;
245- }
259+ protected abstract retainOrCreateTunnel ( addressProvider : IAddressProvider , remoteHost : string , remotePort : number , localPort : number | undefined , elevateIfNeeded : boolean ) : Promise < RemoteTunnel | undefined > | undefined ;
246260}
247261
248262export class TunnelService extends AbstractTunnelService {
249- protected retainOrCreateTunnel ( _addressProvider : IAddressProvider , remoteHost : string , remotePort : number , localPort ? : number | undefined ) : Promise < RemoteTunnel | undefined > | undefined {
263+ protected retainOrCreateTunnel ( _addressProvider : IAddressProvider , remoteHost : string , remotePort : number , localPort : number | undefined , elevateIfNeeded : boolean ) : Promise < RemoteTunnel | undefined > | undefined {
250264 const existing = this . getTunnelFromMap ( remoteHost , remotePort ) ;
251265 if ( existing ) {
252266 ++ existing . refcount ;
@@ -256,7 +270,7 @@ export class TunnelService extends AbstractTunnelService {
256270 if ( this . _tunnelProvider ) {
257271 const preferredLocalPort = localPort === undefined ? remotePort : localPort ;
258272 const tunnelOptions = { remoteAddress : { host : remoteHost , port : remotePort } , localAddressPort : localPort } ;
259- const creationInfo = { elevationRequired : this . isPortPrivileged ( preferredLocalPort ) } ;
273+ const creationInfo = { elevationRequired : elevateIfNeeded ? isPortPrivileged ( preferredLocalPort ) : false } ;
260274 const tunnel = this . _tunnelProvider . forwardPort ( tunnelOptions , creationInfo ) ;
261275 if ( tunnel ) {
262276 this . addTunnelToMap ( remoteHost , remotePort , tunnel ) ;
0 commit comments