Skip to content

Commit b885e2c

Browse files
authored
Cache and reuse SSH passwords in the current session (#9654)
* Cache and reuse SSH passwords in the current session
1 parent 853a4f3 commit b885e2c

File tree

5 files changed

+45
-20
lines changed

5 files changed

+45
-20
lines changed

Extension/src/Debugger/configurationProvider.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,12 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
332332
logger.getOutputChannelLogger().showErrorMessage(localize("vs.code.1.69+.required", "'deploySteps' require VS Code 1.69+."));
333333
return undefined;
334334
}
335-
const deploySucceeded: boolean = await this.deploySteps(config, token);
335+
336+
const deploySucceeded: boolean = await vscode.window.withProgress({
337+
location: vscode.ProgressLocation.Notification,
338+
title: localize("running.deploy.steps", "Running deploy steps...")
339+
}, async () => this.deploySteps(config, token));
340+
336341
if (!deploySucceeded || token?.isCancellationRequested) {
337342
return undefined;
338343
}

Extension/src/SSH/commandInteractors.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
* ------------------------------------------------------------------------------------------ */
55

66
import * as vscode from 'vscode';
7-
import { stripEscapeSequences, isWindows, escapeStringForRegex } from '../common';
7+
import { stripEscapeSequences, isWindows, escapeStringForRegex, ISshHostInfo, getFullHostAddress, extensionContext } from '../common';
8+
9+
/**
10+
* The users that we autofilled their passwords.
11+
* If a user's password is already used and yet we still get the same prompt, we probably got a wrong password.
12+
* Needs to be reset for each command.
13+
*/
14+
export const autoFilledPasswordForUsers: Set<string> = new Set<string>();
815

916
export type IDifferingHostConfirmationProvider =
1017
(message: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
@@ -208,7 +215,7 @@ function getPasswordPrompt(data: string, details?: IInteractorDataDetails): { us
208215
export class PasswordInteractor implements IInteractor {
209216
static ID = 'password';
210217

211-
constructor(private readonly passwordProvider: IStringProvider) { }
218+
constructor(private readonly host: ISshHostInfo, private readonly passwordProvider: IStringProvider) { }
212219

213220
get id(): string {
214221
return PasswordInteractor.ID;
@@ -219,12 +226,23 @@ export class PasswordInteractor implements IInteractor {
219226
const pwPrompt: { user?: string; message?: string } | undefined = getPasswordPrompt(data, extraDetails);
220227
if (pwPrompt && typeof pwPrompt.user === 'string') {
221228
result.postAction = 'consume';
222-
const password: string | undefined = await this.passwordProvider(pwPrompt.user, pwPrompt.message, cancelToken);
223-
if (typeof password === 'string') {
224-
result.response = password;
229+
const actualUser: string = pwPrompt.user === '' ? getFullHostAddress(this.host) : pwPrompt.user;
230+
const passwordCacheKey: string = `SSH:${actualUser}`;
231+
const cachedPassword: string | undefined = await extensionContext?.secrets?.get(passwordCacheKey);
232+
if (cachedPassword !== undefined && !autoFilledPasswordForUsers.has(actualUser)) {
233+
autoFilledPasswordForUsers.add(actualUser);
234+
result.response = cachedPassword;
225235
result.isPassword = true;
226236
} else {
227-
result.canceled = true;
237+
const password: string | undefined = await this.passwordProvider(pwPrompt.user, pwPrompt.message, cancelToken);
238+
if (typeof password === 'string') {
239+
await extensionContext?.secrets?.store(passwordCacheKey, password);
240+
autoFilledPasswordForUsers.add(actualUser);
241+
result.response = password;
242+
result.isPassword = true;
243+
} else {
244+
result.canceled = true;
245+
}
228246
}
229247
}
230248

Extension/src/SSH/commands.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode';
77
import * as nls from 'vscode-nls';
8-
import { ISshHostInfo, ISshLocalForwardInfo, ProcessReturnType } from '../common';
8+
import { getFullHostAddress, getFullHostAddressNoPort, ISshHostInfo, ISshLocalForwardInfo, ProcessReturnType } from '../common';
99
import { defaultSystemInteractor } from './commandInteractors';
1010
import { runSshTerminalCommandWithLogin } from './sshCommandRunner';
1111

@@ -86,13 +86,3 @@ function localForwardToArgs(localForward: ISshLocalForwardInfo): string[] {
8686

8787
return ['-L', arg];
8888
}
89-
90-
/** user@host */
91-
function getFullHostAddressNoPort(host: ISshHostInfo): string {
92-
return host.user ? `${host.user}@${host.hostName}` : `${host.hostName}`;
93-
}
94-
95-
function getFullHostAddress(host: ISshHostInfo): string {
96-
const fullHostName: string = getFullHostAddressNoPort(host);
97-
return host.port ? `${fullHostName}:${host.port}` : fullHostName;
98-
}

Extension/src/SSH/sshCommandRunner.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import {
1818
TwoFacInteractor,
1919
ContinueOnInteractor,
2020
ISystemInteractor,
21-
IInteraction
21+
IInteraction,
22+
autoFilledPasswordForUsers
2223
} from './commandInteractors';
2324
import { isWindows, ISshHostInfo, splitLines, stripEscapeSequences, ProcessReturnType } from '../common';
2425
import { getOutputChannelLogger } from '../logger';
@@ -194,12 +195,13 @@ export async function runSshTerminalCommandWithLogin(
194195
}
195196

196197
if (!showLoginTerminal) {
198+
autoFilledPasswordForUsers.clear();
197199
interactors.push(
198200
new MitmInteractor(),
199201
new FingerprintInteractor(host.hostName, showHostKeyConfirmation),
200202
new PassphraseInteractor(showPassphraseInputBox),
201203
new DifferingHostKeyInteractor(showDifferingHostConfirmation),
202-
new PasswordInteractor(showPasswordInputBox),
204+
new PasswordInteractor(host, showPasswordInputBox),
203205
new TwoFacInteractor(showVerificationCodeInputBox),
204206
new DuoTwoFacInteractor(showVerificationCodeInputBox)
205207
);

Extension/src/common.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,16 @@ export interface ISshHostInfo {
14891489
port?: number | string;
14901490
}
14911491

1492+
/** user@host */
1493+
export function getFullHostAddressNoPort(host: ISshHostInfo): string {
1494+
return host.user ? `${host.user}@${host.hostName}` : `${host.hostName}`;
1495+
}
1496+
1497+
export function getFullHostAddress(host: ISshHostInfo): string {
1498+
const fullHostName: string = getFullHostAddressNoPort(host);
1499+
return host.port ? `${fullHostName}:${host.port}` : fullHostName;
1500+
}
1501+
14921502
export interface ISshLocalForwardInfo {
14931503
bindAddress?: string;
14941504
port?: number | string;

0 commit comments

Comments
 (0)