mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Update error dialog to include instructions text for SSL cert validation failure (#21036)
This commit is contained in:
@@ -5244,6 +5244,17 @@ Error: {1}</source>
|
||||
<trans-unit id="kerberosKinit">
|
||||
<source xml:lang="en">If you have previously connected you may need to re-run kinit.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="runKinit">
|
||||
<source xml:lang="en">Run Kinit</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="enableTrustServerCertificate">
|
||||
<source xml:lang="en">Enable Trust server certificate</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="trustServerCertInstructionText">
|
||||
<source xml:lang="en">Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or enable 'Trust server certificate' in the connection dialog.
|
||||
|
||||
Note: A self-signed certificate offers only limited protection and is not a recommended practice for production environments. Do you want to enable 'Trust server certificate' on this connection and retry? </source>
|
||||
</trans-unit>
|
||||
</body></file>
|
||||
<file original="src/sql/workbench/services/connection/browser/connectionDialogWidget" source-language="en" datatype="plaintext"><body>
|
||||
<trans-unit id="connectType">
|
||||
|
||||
@@ -24,6 +24,9 @@ export const passwordChars = '***************';
|
||||
/* default authentication type setting name*/
|
||||
export const defaultAuthenticationType = 'defaultAuthenticationType';
|
||||
|
||||
/* Connection Properties */
|
||||
export const trustServerCertificate = 'trustServerCertificate';
|
||||
|
||||
/**
|
||||
* Well-known Authentication types commonly supported by connection providers.
|
||||
*/
|
||||
|
||||
@@ -10,5 +10,15 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
export const IErrorMessageService = createDecorator<IErrorMessageService>('errorMessageService');
|
||||
export interface IErrorMessageService {
|
||||
_serviceBrand: undefined;
|
||||
showDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[]): void;
|
||||
/**
|
||||
* Shows error dialog with given parameters
|
||||
* @param severity Severity of the error
|
||||
* @param headerTitle Title to show on Error modal dialog
|
||||
* @param message Message containng error message
|
||||
* @param messageDetails Message details containing stacktrace along with error message
|
||||
* @param actions Custom actions to display on the error message dialog
|
||||
* @param instructionText Spcial instructions to display to user when displaying error message
|
||||
* @param readMoreLink External link to read more about the instructions.
|
||||
*/
|
||||
showDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[], instructionText?: string, readMoreLink?: string): void;
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
this._logService.debug(`ConnectionDialogService: Error handled and connection reset - Error: ${connectionResult.errorMessage}`);
|
||||
} else {
|
||||
this._connectionDialog.resetConnection();
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack);
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack, connectionResult.errorCode);
|
||||
this._logService.debug(`ConnectionDialogService: Connection error: ${connectionResult.errorMessage}`);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -456,7 +456,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
await this.showDialogWithModel();
|
||||
|
||||
if (connectionResult && connectionResult.errorMessage) {
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack);
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack, connectionResult.errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +488,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
recentConnections.forEach(conn => conn.dispose());
|
||||
}
|
||||
|
||||
private showErrorDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string): void {
|
||||
private showErrorDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, errorCode?: number): void {
|
||||
// Kerberos errors are currently very hard to understand, so adding handling of these to solve the common scenario
|
||||
// note that ideally we would have an extensible service to handle errors by error code and provider, but for now
|
||||
// this solves the most common "hard error" that we've noticed
|
||||
@@ -502,7 +502,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
localize('kerberosHelpLink', "Help configuring Kerberos is available at {0}", helpLink),
|
||||
localize('kerberosKinit', "If you have previously connected you may need to re-run kinit.")
|
||||
].join('\r\n');
|
||||
actions.push(new Action('Kinit', 'Run kinit', null, true, async () => {
|
||||
actions.push(new Action('Kinit', localize('runKinit', "Run Kinit"), undefined, true, async () => {
|
||||
this._connectionDialog.close();
|
||||
await this._clipboardService.writeText('kinit\r');
|
||||
await this._commandService.executeCommand('workbench.action.terminal.focus');
|
||||
@@ -512,9 +512,25 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
}, 10);
|
||||
return;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
this._logService.error(message);
|
||||
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, actions);
|
||||
|
||||
// Set instructionText for MSSQL Provider Encryption error code -2146893019 thrown by SqlClient when certificate validation fails.
|
||||
if (errorCode === -2146893019) {
|
||||
let enableTrustServerCert = localize('enableTrustServerCertificate', "Enable Trust server certificate");
|
||||
let instructionText = localize('trustServerCertInstructionText', `Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or enable 'Trust server certificate' in the connection dialog.
|
||||
|
||||
Note: A self-signed certificate offers only limited protection and is not a recommended practice for production environments. Do you want to enable 'Trust server certificate' on this connection and retry? `);
|
||||
let readMoreLink = "https://learn.microsoft.com/sql/database-engine/configure-windows/enable-encrypted-connections-to-the-database-engine"
|
||||
actions.push(new Action('trustServerCert', enableTrustServerCert, undefined, true, async () => {
|
||||
this._model.options[Constants.trustServerCertificate] = true;
|
||||
await this.handleOnConnect(this._connectionDialog.newConnectionParams, this._model as IConnectionProfile);
|
||||
return;
|
||||
}));
|
||||
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, actions, instructionText, readMoreLink);
|
||||
} else {
|
||||
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import { attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
import { Link } from 'vs/platform/opener/browser/link';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
const maxActions = 1;
|
||||
|
||||
@@ -36,9 +38,12 @@ export class ErrorMessageDialog extends Modal {
|
||||
private _actions: IAction[] = [];
|
||||
private _severity?: Severity;
|
||||
private _message?: string;
|
||||
private _instructionText?: string;
|
||||
private _readMoreLink?: string;
|
||||
private _messageDetails?: string;
|
||||
private _okLabel: string;
|
||||
private _closeLabel: string;
|
||||
private _readMoreLabel: string;
|
||||
|
||||
private _onOk = new Emitter<void>();
|
||||
public onOk: Event<void> = this._onOk.event;
|
||||
@@ -50,11 +55,13 @@ export class ErrorMessageDialog extends Modal {
|
||||
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ILogService logService: ILogService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService
|
||||
) {
|
||||
super('', TelemetryKeys.ModalDialogName.ErrorMessage, telemetryService, layoutService, clipboardService, themeService, logService, textResourcePropertiesService, contextKeyService, { dialogStyle: 'normal', hasTitleIcon: true });
|
||||
this._okLabel = localize('errorMessageDialog.ok', "OK");
|
||||
this._closeLabel = localize('errorMessageDialog.close', "Close");
|
||||
this._readMoreLabel = localize('errorMessageDialog.readMore', "Read More");
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
@@ -88,7 +95,7 @@ export class ErrorMessageDialog extends Modal {
|
||||
}
|
||||
|
||||
private createStandardButton(label: string, onSelect: () => void): Button {
|
||||
let button = this.addFooterButton(label, onSelect, 'right', true);
|
||||
let button = this.addFooterButton(label, onSelect, 'right', false);
|
||||
this._register(attachButtonStyler(button, this._themeService));
|
||||
return button;
|
||||
}
|
||||
@@ -109,6 +116,17 @@ export class ErrorMessageDialog extends Modal {
|
||||
protected updateDialogBody(): void {
|
||||
DOM.clearNode(this._body!);
|
||||
DOM.append(this._body!, DOM.$('div.error-message')).innerText = this._message!;
|
||||
if (this._instructionText) {
|
||||
let childElement = DOM.$('div.error-instruction-text');
|
||||
childElement.innerText = this._instructionText!;
|
||||
if (this._readMoreLink) {
|
||||
new Link(childElement, {
|
||||
label: this._readMoreLabel,
|
||||
href: this._readMoreLink
|
||||
}, undefined, this._openerService);
|
||||
}
|
||||
DOM.append(this._body!, childElement);
|
||||
}
|
||||
}
|
||||
|
||||
protected getBody(): HTMLElement {
|
||||
@@ -148,9 +166,11 @@ export class ErrorMessageDialog extends Modal {
|
||||
this.hide(hideReason);
|
||||
}
|
||||
|
||||
public open(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[]) {
|
||||
public open(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[], instructionText?: string, readMoreLink?: string): void {
|
||||
this._severity = severity;
|
||||
this._message = message;
|
||||
this._instructionText = instructionText;
|
||||
this._readMoreLink = readMoreLink;
|
||||
this.title = headerTitle;
|
||||
this._messageDetails = messageDetails;
|
||||
if (this._messageDetails) {
|
||||
@@ -162,21 +182,31 @@ export class ErrorMessageDialog extends Modal {
|
||||
this._bodyContainer.setAttribute('aria-description', this._message);
|
||||
}
|
||||
this.resetActions();
|
||||
if (actions && actions.length > 0) {
|
||||
if (actions?.length > 0) {
|
||||
for (let i = 0; i < maxActions && i < actions.length; i++) {
|
||||
this._actions.push(actions[i]);
|
||||
let button = this._actionButtons[i];
|
||||
button.label = actions[i].label;
|
||||
button.element.style.visibility = 'visible';
|
||||
}
|
||||
this._okButton!.label = this._closeLabel;
|
||||
//Remove and add button again to update style.
|
||||
this.removeFooterButton(this._okLabel);
|
||||
this.removeFooterButton(this._closeLabel);
|
||||
this._okButton = this.addFooterButton(this._closeLabel, () => this.ok(), undefined, true);
|
||||
} else {
|
||||
this._okButton!.label = this._okLabel;
|
||||
//Remove and add button again to update style
|
||||
this.removeFooterButton(this._okLabel);
|
||||
this.removeFooterButton(this._closeLabel);
|
||||
this._okButton = this.addFooterButton(this._okLabel, () => this.ok());
|
||||
}
|
||||
this.updateIconTitle();
|
||||
this.updateDialogBody();
|
||||
this.show();
|
||||
this._okButton!.focus();
|
||||
if (actions?.length > 0) {
|
||||
this._actionButtons[0].focus();
|
||||
} else {
|
||||
this._okButton!.focus();
|
||||
}
|
||||
}
|
||||
|
||||
private resetActions(): void {
|
||||
|
||||
@@ -24,11 +24,11 @@ export class ErrorMessageService implements IErrorMessageService {
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) { }
|
||||
|
||||
public showDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[]): void {
|
||||
this.doShowDialog(severity, headerTitle, message, messageDetails, actions);
|
||||
public showDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[], instructionText?: string, readMoreLink?: string): void {
|
||||
this.doShowDialog(severity, headerTitle, message, messageDetails, actions, instructionText, readMoreLink);
|
||||
}
|
||||
|
||||
private doShowDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[]): void {
|
||||
private doShowDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[], instructionText?: string, readMoreLink?: string): void {
|
||||
if (!this._errorDialog) {
|
||||
this._errorDialog = this._instantiationService.createInstance(ErrorMessageDialog);
|
||||
this._errorDialog.onOk(() => this.handleOnOk());
|
||||
@@ -36,7 +36,7 @@ export class ErrorMessageService implements IErrorMessageService {
|
||||
}
|
||||
|
||||
let title = headerTitle ? headerTitle : this.getDefaultTitle(severity);
|
||||
return this._errorDialog.open(severity, title, message, messageDetails, actions);
|
||||
return this._errorDialog.open(severity, title, message, messageDetails, actions, instructionText, readMoreLink);
|
||||
}
|
||||
|
||||
private getDefaultTitle(severity: Severity) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.error-dialog {
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
height: 200px;
|
||||
height: 210px;
|
||||
}
|
||||
|
||||
.error-dialog .codicon.error, .error-dialog .codicon.warning , .error-dialog .codicon.info {
|
||||
@@ -22,6 +22,11 @@
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.error-dialog .error-instruction-text{
|
||||
margin-top: 40px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.modal .footer-button a.monaco-button.monaco-text-button.codicon.scriptToClipboard {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user