Skip to content

Commit d7240c3

Browse files
committed
Merge remote-tracking branch 'upstream' into include_modern_net_flag
2 parents eceefa8 + ed84442 commit d7240c3

13 files changed

+528
-23
lines changed

debugger-launchjson.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,18 @@ Example:
338338
```json
339339
"targetArchitecture": "arm64"
340340
```
341+
342+
## Check for DevCert
343+
344+
This option controls if, on launch, the the debugger should check if the computer has a self-signed HTTPS certificate used to develop web projects running on https endpoints. For this it will try to run `dotnet dev-certs https --check --trust`, if no certs are found it will prompt the user to suggest creating one. If approved by the user, the extension will run `dotnet dev-certs https --trust` to create a trusted self-signed certificate.
345+
346+
If unspecified, defaults to true when `serverReadyAction` is set.
347+
This option does nothing on Linux, VS Code remote, and VS Code Web UI scenarios.
348+
349+
You can override this behavior by setting `checkForDevCert` to false in your `launch.json`.
350+
351+
Example:
352+
353+
```json
354+
"checkForDevCert": "false"
355+
```

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,6 +1982,11 @@
19821982
"targetArchitecture": {
19831983
"type": "string",
19841984
"description": "[Only supported in local macOS debugging] The architecture of the debuggee. This will automatically be detected unless this parameter is set. Allowed values are x86_64 or arm64."
1985+
},
1986+
"checkForDevCert": {
1987+
"type": "boolean",
1988+
"description": "When true, the debugger will check if the computer has a self-signed HTTPS certificate used to develop web servers running on https endpoints. If unspecified, defaults to true when `serverReadyAction` is set. This option does nothing on Linux, VS Code remote, and VS Code Web UI scenarios. If the HTTPS certificate is not found or isn't trusted, the user will be prompted to install/trust it.",
1989+
"default": true
19851990
}
19861991
}
19871992
},
@@ -3109,6 +3114,11 @@
31093114
"targetArchitecture": {
31103115
"type": "string",
31113116
"description": "[Only supported in local macOS debugging] The architecture of the debuggee. This will automatically be detected unless this parameter is set. Allowed values are x86_64 or arm64."
3117+
},
3118+
"checkForDevCert": {
3119+
"type": "boolean",
3120+
"description": "When true, the debugger will check if the computer has a self-signed HTTPS certificate used to develop web servers running on https endpoints. If unspecified, defaults to true when `serverReadyAction` is set. This option does nothing on Linux, VS Code remote, and VS Code Web UI scenarios. If the HTTPS certificate is not found or isn't trusted, the user will be prompted to install/trust it.",
3121+
"default": true
31123122
}
31133123
}
31143124
},

src/coreclr-debug/activate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ export async function activate(thisExtension: vscode.Extension<CSharpExtensionEx
3232
}
3333

3434
const factory = new DebugAdapterExecutableFactory(debugUtil, platformInformation, eventStream, thisExtension.packageJSON, thisExtension.extensionPath, options);
35-
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('coreclr', new DotnetDebugConfigurationProvider(platformInformation)));
36-
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('clr', new DotnetDebugConfigurationProvider(platformInformation)));
35+
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('coreclr', new DotnetDebugConfigurationProvider(platformInformation, eventStream, options)));
36+
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('clr', new DotnetDebugConfigurationProvider(platformInformation, eventStream, options)));
3737
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('coreclr', factory));
3838
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('clr', factory));
3939
}

src/coreclr-debug/debugConfigurationProvider.ts

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
import * as vscode from 'vscode';
77

88
import { RemoteAttachPicker, DotNetAttachItemsProviderFactory, AttachPicker, AttachItem } from '../features/processPicker';
9+
import { Options } from '../omnisharp/options';
910
import { PlatformInformation } from '../platform';
10-
11+
import { hasDotnetDevCertsHttps, createSelfSignedCert, CertToolStatusCodes } from '../utils/DotnetDevCertsHttps';
12+
import { EventStream } from '../EventStream';
13+
import { DevCertCreationFailure, ShowChannel } from '../omnisharp/loggingEvents';
14+
1115
export class DotnetDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
12-
constructor(public platformInformation: PlatformInformation) {}
16+
constructor(public platformInformation: PlatformInformation, private readonly eventStream: EventStream, private options: Options) {}
1317

1418
public async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration, token?: vscode.CancellationToken): Promise<vscode.DebugConfiguration | null | undefined>
1519
{
@@ -59,7 +63,66 @@ export class DotnetDebugConfigurationProvider implements vscode.DebugConfigurati
5963
return undefined;
6064
}
6165
}
66+
67+
// We want to ask the user if we should run dotnet dev-certs https --trust, but this doesn't work in a few cases --
68+
// Linux -- not supported by the .NET CLI as there isn't a single root cert store
69+
// VS Code remoting/Web UI -- the trusted cert work would need to happen on the client machine, but we don't have a way to run code there currently
70+
// pipeTransport -- the dev cert on the server will be different from the client
71+
if (!this.platformInformation.isLinux() && !vscode.env.remoteName && vscode.env.uiKind != vscode.UIKind.Web && !debugConfiguration.pipeTransport)
72+
{
73+
if(debugConfiguration.checkForDevCert === undefined && debugConfiguration.serverReadyAction)
74+
{
75+
debugConfiguration.checkForDevCert = true;
76+
}
77+
78+
if (debugConfiguration.checkForDevCert)
79+
{
80+
checkForDevCerts(this.options.dotNetCliPaths, this.eventStream);
81+
}
82+
}
6283

6384
return debugConfiguration;
6485
}
6586
}
87+
88+
function checkForDevCerts(dotNetCliPaths: string[], eventStream: EventStream){
89+
hasDotnetDevCertsHttps(dotNetCliPaths).then(async (returnData) => {
90+
let errorCode = returnData.error?.code;
91+
if(errorCode === CertToolStatusCodes.CertificateNotTrusted || errorCode === CertToolStatusCodes.ErrorNoValidCertificateFound)
92+
{
93+
const labelYes: string = "Yes";
94+
const labelNotNow: string = "Not Now";
95+
const labelMoreInfo: string = "More Information";
96+
97+
const result = await vscode.window.showInformationMessage(
98+
"The selected launch configuration is configured to launch a web browser but no trusted development certificate was found. Create a trusted self-signed certificate?",
99+
{ title:labelYes }, { title:labelNotNow, isCloseAffordance: true }, { title:labelMoreInfo }
100+
);
101+
if (result?.title === labelYes)
102+
{
103+
let returnData = await createSelfSignedCert(dotNetCliPaths);
104+
if (returnData.error === null) //if the prcess returns 0, returnData.error is null, otherwise the return code can be acessed in returnData.error.code
105+
{
106+
let message = errorCode === CertToolStatusCodes.CertificateNotTrusted ? 'trusted' : 'created';
107+
vscode.window.showInformationMessage(`Self-signed certificate sucessfully ${message}.`);
108+
}
109+
else
110+
{
111+
eventStream.post(new DevCertCreationFailure(`${returnData.error.message}\ncode: ${returnData.error.code}\nstdout: ${returnData.stdout}`));
112+
113+
const labelShowOutput: string = "Show Output";
114+
const result = await vscode.window.showWarningMessage("Couldn't create self-signed certificate. See output for more information.", labelShowOutput);
115+
if (result === labelShowOutput){
116+
eventStream.post(new ShowChannel());
117+
}
118+
}
119+
}
120+
if (result?.title === labelMoreInfo)
121+
{
122+
const launchjsonDescriptionURL = 'https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#check-for-devcert';
123+
vscode.env.openExternal(vscode.Uri.parse(launchjsonDescriptionURL));
124+
checkForDevCerts(dotNetCliPaths, eventStream);
125+
}
126+
}
127+
});
128+
}

src/features/documentSymbolProvider.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ export default class OmnisharpDocumentSymbolProvider extends AbstractSupport imp
3131
}
3232
}
3333

34-
function createSymbols(elements: Structure.CodeElement[]): vscode.DocumentSymbol[] {
34+
function createSymbols(elements: Structure.CodeElement[], parentElement?: Structure.CodeElement): vscode.DocumentSymbol[] {
3535
let results: vscode.DocumentSymbol[] = [];
3636

3737
elements.forEach(element => {
38-
let symbol = createSymbolForElement(element);
38+
let symbol = createSymbolForElement(element, parentElement);
3939
if (element.Children) {
40-
symbol.children = createSymbols(element.Children);
40+
symbol.children = createSymbols(element.Children, element);
4141
}
4242

4343
results.push(symbol);
@@ -46,11 +46,43 @@ function createSymbols(elements: Structure.CodeElement[]): vscode.DocumentSymbol
4646
return results;
4747
}
4848

49-
function createSymbolForElement(element: Structure.CodeElement): vscode.DocumentSymbol {
49+
function getNameForElement(element: Structure.CodeElement, parentElement?: Structure.CodeElement): string {
50+
switch (element.Kind) {
51+
case SymbolKinds.Class:
52+
case SymbolKinds.Delegate:
53+
case SymbolKinds.Enum:
54+
case SymbolKinds.Interface:
55+
case SymbolKinds.Struct:
56+
return element.Name;
57+
58+
case SymbolKinds.Namespace:
59+
return typeof parentElement !== 'undefined' && element.DisplayName.startsWith(`${parentElement.DisplayName}.`)
60+
? element.DisplayName.slice(parentElement.DisplayName.length + 1)
61+
: element.DisplayName;
62+
63+
case SymbolKinds.Constant:
64+
case SymbolKinds.Constructor:
65+
case SymbolKinds.Destructor:
66+
case SymbolKinds.EnumMember:
67+
case SymbolKinds.Event:
68+
case SymbolKinds.Field:
69+
case SymbolKinds.Indexer:
70+
case SymbolKinds.Method:
71+
case SymbolKinds.Operator:
72+
case SymbolKinds.Property:
73+
case SymbolKinds.Unknown:
74+
default:
75+
return element.DisplayName;
76+
}
77+
}
78+
79+
function createSymbolForElement(element: Structure.CodeElement, parentElement?: Structure.CodeElement): vscode.DocumentSymbol {
5080
const fullRange = element.Ranges[SymbolRangeNames.Full];
5181
const nameRange = element.Ranges[SymbolRangeNames.Name];
82+
const name = getNameForElement(element, parentElement);
83+
const details = name === element.DisplayName ? '' : element.DisplayName;
5284

53-
return new vscode.DocumentSymbol(element.DisplayName, /*detail*/ "", toSymbolKind(element.Kind), toRange3(fullRange), toRange3(nameRange));
85+
return new vscode.DocumentSymbol(name, details, toSymbolKind(element.Kind), toRange3(fullRange), toRange3(nameRange));
5486
}
5587

5688
const kinds: { [kind: string]: vscode.SymbolKind; } = {};

src/observers/CsharpChannelObserver.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export class CsharpChannelObserver extends BaseChannelObserver {
1818
case EventType.ProjectJsonDeprecatedWarning:
1919
this.showChannel(true);
2020
break;
21+
case EventType.ShowChannel:
22+
this.showChannel(false);
23+
break;
2124
}
2225
}
2326
}

src/observers/CsharpLoggerObserver.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ export class CsharpLoggerObserver extends BaseLoggerObserver {
6868
case EventType.IntegrityCheckSuccess:
6969
this.handleIntegrityCheckSuccess(<Event.IntegrityCheckSuccess>event);
7070
break;
71+
case EventType.DevCertCreationFailure:
72+
this.handleDevCertCreationFailure(<Event.DevCertCreationFailure>event);
73+
break;
7174
}
7275
}
7376

@@ -146,4 +149,8 @@ export class CsharpLoggerObserver extends BaseLoggerObserver {
146149
private handleDocumentSynchronizationFailure(event: Event.DocumentSynchronizationFailure) {
147150
this.logger.appendLine(`Failed to synchronize document '${event.documentPath}': ${event.errorMessage}`);
148151
}
152+
153+
private handleDevCertCreationFailure(event: Event.DevCertCreationFailure) {
154+
this.logger.appendLine(`Couldn't create self-signed certificate. ${event.errorMessage}`);
155+
}
149156
}

src/omnisharp/EventType.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ export enum EventType {
8585
TelemetryErrorEvent = 78,
8686
OmnisharpServerRequestCancelled = 79,
8787
BackgroundDiagnosticStatus = 80,
88+
DevCertCreationFailure = 81,
89+
ShowChannel = 82,
8890
}
8991

9092
//Note that the EventType protocol is shared with Razor.VSCode and the numbers here should not be altered

src/omnisharp/loggingEvents.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,10 @@ export class DotNetTestDebugComplete implements BaseEvent {
350350
export class DownloadValidation implements BaseEvent {
351351
type = EventType.DownloadValidation;
352352
}
353+
export class DevCertCreationFailure implements BaseEvent {
354+
type = EventType.DevCertCreationFailure;
355+
constructor(public errorMessage: string) { }
356+
}
357+
export class ShowChannel implements BaseEvent {
358+
type = EventType.ShowChannel;
359+
}

0 commit comments

Comments
 (0)