From cd4bd7e64b472ed4eeb7a01bf3227fa0329ae769 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 8 Sep 2023 10:19:50 -0700 Subject: [PATCH] forwarding: add a warning for public ports (#192599) * forwarding: add a warning for public ports A number of users have raised some security concerns about port forwarding. Forwarded ports are private (requiring auth with the same GH account that did the forwarding) by default. When making a port public, show the following dialog: ![](https://memes.peet.io/img/23-09-3f3351c7-cdcd-46e5-9d0f-123e4dda6b3c.png) * Update extensions/tunnel-forwarding/src/extension.ts Co-authored-by: Joyce Er --------- Co-authored-by: Joyce Er --- extensions/tunnel-forwarding/src/extension.ts | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/extensions/tunnel-forwarding/src/extension.ts b/extensions/tunnel-forwarding/src/extension.ts index f6ef85e71b1..951fc6f5b8d 100644 --- a/extensions/tunnel-forwarding/src/extension.ts +++ b/extensions/tunnel-forwarding/src/extension.ts @@ -67,7 +67,7 @@ export async function activate(context: vscode.ExtensionContext) { } const logger = new Logger(vscode.l10n.t('Port Forwarding')); - const provider = new TunnelProvider(logger); + const provider = new TunnelProvider(logger, context); context.subscriptions.push( vscode.commands.registerCommand('tunnel-forwarding.showLog', () => logger.show()), @@ -120,6 +120,8 @@ class Logger { } } +const didWarnPublicKey = 'didWarnPublic'; + class TunnelProvider implements vscode.TunnelProvider { private readonly tunnels = new Set(); private readonly stateChange = new vscode.EventEmitter(); @@ -136,10 +138,16 @@ class TunnelProvider implements vscode.TunnelProvider { public readonly onDidStateChange = this.stateChange.event; - constructor(private readonly logger: Logger) { } + constructor(private readonly logger: Logger, private readonly context: vscode.ExtensionContext) { } /** @inheritdoc */ - public async provideTunnel(tunnelOptions: vscode.TunnelOptions): Promise { + public async provideTunnel(tunnelOptions: vscode.TunnelOptions): Promise { + if (tunnelOptions.privacy === TunnelPrivacyId.Public) { + if (!(await this.consentPublicPort(tunnelOptions.remoteAddress.port))) { + return; + } + } + const tunnel = new Tunnel( tunnelOptions.remoteAddress, (tunnelOptions.privacy as TunnelPrivacyId) || TunnelPrivacyId.Private, @@ -184,6 +192,31 @@ class TunnelProvider implements vscode.TunnelProvider { this.updateActivePortsIfRunning(); } + private async consentPublicPort(portNumber: number) { + const didWarn = this.context.globalState.get(didWarnPublicKey, false); + if (didWarn) { + return true; + } + + const continueOpt = vscode.l10n.t('Continue'); + const dontShowAgain = vscode.l10n.t("Don't show again"); + const r = await vscode.window.showWarningMessage( + vscode.l10n.t("You're about to create a publicly forwarded port. Anyone on the internet will be able to connect to the service listening on port {0}. You should only proceed if this service is secure and non-sensitive.", portNumber), + { modal: true }, + continueOpt, + dontShowAgain, + ); + if (r === continueOpt) { + // continue + } else if (r === dontShowAgain) { + await this.context.globalState.update(didWarnPublicKey, true); + } else { + return false; + } + + return true; + } + private isInStateWithProcess(process: ChildProcessWithoutNullStreams) { return ( (this.state.state === State.Starting || this.state.state === State.Active) &&