From ff6ced1ff9e3235f66ba797d543194c835ad8e9b Mon Sep 17 00:00:00 2001 From: Charlie Cruzan Date: Mon, 6 Jan 2025 12:58:38 -1000 Subject: [PATCH] add security prompt --- src/extension.ts | 21 ++++++++++++++------ src/securityPrompt.ts | 40 ++++++++++++++++++++++++++++++++++++++ src/stripeDebugProvider.ts | 8 +++++++- 3 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 src/securityPrompt.ts diff --git a/src/extension.ts b/src/extension.ts index f7c8f777..2bf2fd52 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -19,6 +19,7 @@ import { } from './stripeWorkspaceState'; import {Commands} from './commands'; import {Git} from './git'; +import {SecurityPrompt} from './securityPrompt'; import {StripeClient} from './stripeClient'; import {StripeDaemon} from './daemon/stripeDaemon'; import {StripeDebugProvider} from './stripeDebugProvider'; @@ -42,6 +43,7 @@ export function activate(this: any, context: ExtensionContext) { initializeStripeWorkspaceState(context); new TelemetryPrompt(context).activate(); + new SecurityPrompt(context).activate(); const surveyPrompt: SurveyPrompt = new SurveyPrompt(context); surveyPrompt.activate(); @@ -93,7 +95,7 @@ export function activate(this: any, context: ExtensionContext) { }); stripeHelpView.message = 'This extension runs with your Stripe account in test mode.'; - debug.registerDebugConfigurationProvider('stripe', new StripeDebugProvider(telemetry)); + debug.registerDebugConfigurationProvider('stripe', new StripeDebugProvider(telemetry, context)); workspace.registerTextDocumentContentProvider( 'stripeEvent', @@ -137,8 +139,10 @@ export function activate(this: any, context: ExtensionContext) { const stripeCommands = new Commands(telemetry, stripeTerminal, context); const commandCallbackPairs: [string, (...args: any[]) => any][] = [ - ['stripe.createStripeSample', - (sampleName?: string, integration?: string) => stripeCommands.createStripeSample(stripeSamples, sampleName ?? '', integration ?? ''), + [ + 'stripe.createStripeSample', + (sampleName?: string, integration?: string) => + stripeCommands.createStripeSample(stripeSamples, sampleName ?? '', integration ?? ''), ], ['stripe.login', () => stripeCommands.startLogin(stripeDaemon)], ['stripe.openCLI', stripeCommands.openCLI], @@ -171,7 +175,12 @@ export function activate(this: any, context: ExtensionContext) { ['stripe.openWebhooksListen', stripeCommands.openWebhooksListen], [ 'stripe.createWebhookEndpoint', - () => stripeCommands.createWebhookEndpoint(stripeDaemon, stripeOutputChannel, stripeWebhooksViewProvider), + () => + stripeCommands.createWebhookEndpoint( + stripeDaemon, + stripeOutputChannel, + stripeWebhooksViewProvider, + ), ], [ 'stripe.resendEvent', @@ -209,8 +218,8 @@ export function activate(this: any, context: ExtensionContext) { console.log('Integration from URI:', integration); vscode.commands.executeCommand('stripe.createStripeSample', sampleName, integration); } - } - }) + }, + }), ); } diff --git a/src/securityPrompt.ts b/src/securityPrompt.ts new file mode 100644 index 00000000..77b33f50 --- /dev/null +++ b/src/securityPrompt.ts @@ -0,0 +1,40 @@ +import * as vscode from 'vscode'; + +enum StorageKeys { + doNotShowSecurityPromptAgain = 'stripeDoNotShowSecurityPromptAgain', +} + +export class SecurityPrompt { + storage: vscode.Memento; + + constructor(context: vscode.ExtensionContext) { + this.storage = context.globalState; + } + + public activate(): void { + if (this.shouldShowBannerOnStartup()) { + this.show(); + } + } + + public shouldShowBannerOnStartup(): boolean { + if (vscode.workspace.getConfiguration('stripe').has('projectName')) { + return true; + } + return false; + } + + public async show() { + if (this.storage.get(StorageKeys.doNotShowSecurityPromptAgain)) { + return; + } + const selection = await vscode.window.showInformationMessage( + "Warning: Debugging from `launch.json` files you didn't create or using code from unofficial sources can expose your system to security risks. Please ensure you understand the implications of the code you are executing.", + 'Do not show again', + ); + if (!selection) { + return; + } + this.storage.update(StorageKeys.doNotShowSecurityPromptAgain, true); + } +} diff --git a/src/stripeDebugProvider.ts b/src/stripeDebugProvider.ts index 1fd15d3b..7d9cbdad 100644 --- a/src/stripeDebugProvider.ts +++ b/src/stripeDebugProvider.ts @@ -1,12 +1,15 @@ /* eslint-disable no-warning-comments */ import * as vscode from 'vscode'; +import {SecurityPrompt} from './securityPrompt'; import {Telemetry} from './telemetry'; export class StripeDebugProvider implements vscode.DebugConfigurationProvider { telemetry: Telemetry; + context: vscode.ExtensionContext; - constructor(telemetry: Telemetry) { + constructor(telemetry: Telemetry, context: vscode.ExtensionContext) { this.telemetry = telemetry; + this.context = context; vscode.debug.onDidTerminateDebugSession((e: vscode.DebugSession) => { if (e.name === 'Stripe: Webhooks listen') { // TODO: Find a way to stop the CLI from the given debug session. @@ -28,6 +31,9 @@ export class StripeDebugProvider implements vscode.DebugConfigurationProvider { ) { this.telemetry.sendEvent('debug.launch'); + if (config.forwardTo || config.forwardConnectTo || config.events || config.skipVerify) { + new SecurityPrompt(this.context).show(); + } vscode.commands.executeCommand('stripe.openWebhooksListen', { forwardTo: config.forwardTo, forwardConnectTo: config.forwardConnectTo,