mirror of
https://github.com/Microsoft/vscode
synced 2024-10-14 15:29:54 +00:00
Git - implement SSH_ASKPASS handler (#159573)
This commit is contained in:
parent
c399c8cce7
commit
a6272c9416
|
@ -16,24 +16,49 @@ function fatal(err: any): void {
|
|||
}
|
||||
|
||||
function main(argv: string[]): void {
|
||||
if (argv.length !== 5) {
|
||||
return fatal('Wrong number of arguments');
|
||||
}
|
||||
|
||||
if (!process.env['VSCODE_GIT_ASKPASS_PIPE']) {
|
||||
return fatal('Missing pipe');
|
||||
}
|
||||
|
||||
if (!process.env['VSCODE_GIT_ASKPASS_TYPE']) {
|
||||
return fatal('Missing type');
|
||||
}
|
||||
|
||||
if (process.env['VSCODE_GIT_ASKPASS_TYPE'] !== 'https' && process.env['VSCODE_GIT_ASKPASS_TYPE'] !== 'ssh') {
|
||||
return fatal(`Invalid type: ${process.env['VSCODE_GIT_ASKPASS_TYPE']}`);
|
||||
}
|
||||
|
||||
if (process.env['VSCODE_GIT_COMMAND'] === 'fetch' && !!process.env['VSCODE_GIT_FETCH_SILENT']) {
|
||||
return fatal('Skip silent fetch commands');
|
||||
}
|
||||
|
||||
const output = process.env['VSCODE_GIT_ASKPASS_PIPE'] as string;
|
||||
const request = argv[2];
|
||||
const host = argv[4].replace(/^["']+|["':]+$/g, '');
|
||||
const ipcClient = new IPCClient('askpass');
|
||||
const askpassType = process.env['VSCODE_GIT_ASKPASS_TYPE'] as 'https' | 'ssh';
|
||||
|
||||
ipcClient.call({ request, host }).then(res => {
|
||||
// HTTPS (username | password), SSH (passphrase | authenticity)
|
||||
const request = askpassType === 'https' ? argv[2] : argv[3];
|
||||
|
||||
let host: string | undefined,
|
||||
file: string | undefined,
|
||||
fingerprint: string | undefined;
|
||||
|
||||
if (askpassType === 'https') {
|
||||
host = argv[4].replace(/^["']+|["':]+$/g, '');
|
||||
}
|
||||
|
||||
if (askpassType === 'ssh') {
|
||||
if (/passphrase/i.test(request)) {
|
||||
// passphrase
|
||||
file = argv[6].replace(/^["']+|["':]+$/g, '');
|
||||
} else {
|
||||
// authenticity
|
||||
host = argv[6].replace(/^["']+|["':]+$/g, '');
|
||||
fingerprint = argv[15];
|
||||
}
|
||||
}
|
||||
|
||||
const ipcClient = new IPCClient('askpass');
|
||||
ipcClient.call({ askpassType, request, host, file, fingerprint }).then(res => {
|
||||
fs.writeFileSync(output, res + '\n');
|
||||
setTimeout(() => process.exit(0), 0);
|
||||
}).catch(err => fatal(err));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh
|
||||
VSCODE_GIT_ASKPASS_PIPE=`mktemp`
|
||||
ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $*
|
||||
ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" VSCODE_GIT_ASKPASS_TYPE="https" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $*
|
||||
cat $VSCODE_GIT_ASKPASS_PIPE
|
||||
rm $VSCODE_GIT_ASKPASS_PIPE
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, InputBoxOptions, Uri, Disposable, workspace } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { window, InputBoxOptions, Uri, Disposable, workspace, QuickPickOptions } from 'vscode';
|
||||
import { IDisposable, EmptyDisposable, toDisposable } from './util';
|
||||
import * as path from 'path';
|
||||
import { IIPCHandler, IIPCServer } from './ipc/ipcServer';
|
||||
import { CredentialsProvider, Credentials } from './api/git';
|
||||
import { ITerminalEnvironmentProvider } from './terminal';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider {
|
||||
|
||||
private env: { [key: string]: string };
|
||||
|
@ -23,14 +26,22 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider {
|
|||
}
|
||||
|
||||
this.env = {
|
||||
// GIT_ASKPASS
|
||||
GIT_ASKPASS: path.join(__dirname, this.ipc ? 'askpass.sh' : 'askpass-empty.sh'),
|
||||
// SSH_ASKPASS
|
||||
SSH_ASKPASS: path.join(__dirname, this.ipc ? 'ssh-askpass.sh' : 'ssh-askpass-empty.sh'),
|
||||
SSH_ASKPASS_REQUIRE: 'force',
|
||||
// VSCODE_GIT_ASKPASS
|
||||
VSCODE_GIT_ASKPASS_NODE: process.execPath,
|
||||
VSCODE_GIT_ASKPASS_EXTRA_ARGS: (process.versions['electron'] && process.versions['microsoft-build']) ? '--ms-enable-electron-run-as-node' : '',
|
||||
VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js'),
|
||||
};
|
||||
}
|
||||
|
||||
async handle({ request, host }: { request: string; host: string }): Promise<string> {
|
||||
async handle(payload:
|
||||
{ askpassType: 'https'; request: string; host: string } |
|
||||
{ askpassType: 'ssh'; request: string; host?: string; file?: string; fingerprint?: string }
|
||||
): Promise<string> {
|
||||
const config = workspace.getConfiguration('git', null);
|
||||
const enabled = config.get<boolean>('enabled');
|
||||
|
||||
|
@ -38,6 +49,16 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider {
|
|||
return '';
|
||||
}
|
||||
|
||||
// https
|
||||
if (payload.askpassType === 'https') {
|
||||
return await this.handleAskpass(payload.request, payload.host);
|
||||
}
|
||||
|
||||
// ssh
|
||||
return await this.handleSSHAskpass(payload.request, payload.host, payload.file, payload.fingerprint);
|
||||
}
|
||||
|
||||
async handleAskpass(request: string, host: string): Promise<string> {
|
||||
const uri = Uri.parse(host);
|
||||
const authority = uri.authority.replace(/^.*@/, '');
|
||||
const password = /password/i.test(request);
|
||||
|
@ -72,6 +93,33 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider {
|
|||
return await window.showInputBox(options) || '';
|
||||
}
|
||||
|
||||
async handleSSHAskpass(request: string, host?: string, file?: string, fingerprint?: string): Promise<string> {
|
||||
// passphrase
|
||||
if (/passphrase/i.test(request)) {
|
||||
const options: InputBoxOptions = {
|
||||
password: true,
|
||||
placeHolder: localize('ssh passphrase', "Passphrase"),
|
||||
prompt: `SSH Key: ${file}`,
|
||||
ignoreFocusOut: true
|
||||
};
|
||||
|
||||
return await window.showInputBox(options) || '';
|
||||
}
|
||||
|
||||
// authenticity
|
||||
const options: QuickPickOptions = {
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true,
|
||||
placeHolder: localize('ssh authenticity prompt', "Are you sure you want to continue connecting?"),
|
||||
title: localize('ssh authenticity title', "\"{0}\" has fingerprint \"{1}\"", host, fingerprint)
|
||||
};
|
||||
const items = [
|
||||
localize('ssh authenticity prompt yes', "yes"),
|
||||
localize('ssh authenticity prompt no', "no")
|
||||
];
|
||||
return await window.showQuickPick(items, options) ?? '';
|
||||
}
|
||||
|
||||
getEnv(): { [key: string]: string } {
|
||||
const config = workspace.getConfiguration('git');
|
||||
return config.get<boolean>('useIntegratedAskPass') ? this.env : {};
|
||||
|
|
2
extensions/git/src/ssh-askpass-empty.sh
Executable file
2
extensions/git/src/ssh-askpass-empty.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
echo ''
|
5
extensions/git/src/ssh-askpass.sh
Executable file
5
extensions/git/src/ssh-askpass.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
VSCODE_GIT_ASKPASS_PIPE=`mktemp`
|
||||
ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" VSCODE_GIT_ASKPASS_TYPE="ssh" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $*
|
||||
cat $VSCODE_GIT_ASKPASS_PIPE
|
||||
rm $VSCODE_GIT_ASKPASS_PIPE
|
Loading…
Reference in a new issue