diff --git a/extensions/git/src/askpass-main.ts b/extensions/git/src/askpass-main.ts index 3759c11dd0a..db1bdeac366 100644 --- a/extensions/git/src/askpass-main.ts +++ b/extensions/git/src/askpass-main.ts @@ -22,8 +22,8 @@ function main(argv: string[]): void { return fatal('Wrong number of arguments'); } - if (!process.env['VSCODE_GIT_ASKPASS_PORT']) { - return fatal('Missing port'); + if (!process.env['VSCODE_GIT_ASKPASS_HANDLE']) { + return fatal('Missing handle'); } if (!process.env['VSCODE_GIT_ASKPASS_PIPE']) { @@ -35,13 +35,11 @@ function main(argv: string[]): void { } const output = process.env['VSCODE_GIT_ASKPASS_PIPE']; - const port = Number.parseInt(process.env['VSCODE_GIT_ASKPASS_PORT']); + const socketPath = process.env['VSCODE_GIT_ASKPASS_HANDLE']; const request = argv[2]; const host = argv[4].substring(1, argv[4].length - 2); - const opts: http.RequestOptions = { - hostname: 'localhost', - port, + socketPath, path: '/', method: 'POST' }; diff --git a/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts index bbd2ca576e7..300e666834c 100644 --- a/extensions/git/src/askpass.ts +++ b/extensions/git/src/askpass.ts @@ -6,25 +6,59 @@ 'use strict'; import { Disposable, window, InputBoxOptions } from 'vscode'; +import { denodeify } from './util'; import * as path from 'path'; import * as http from 'http'; +import * as os from 'os'; +import * as crypto from 'crypto'; + +const randomBytes = denodeify(crypto.randomBytes); + +export interface AskpassEnvironment { + GIT_ASKPASS: string; + ELECTRON_RUN_AS_NODE?: string; + VSCODE_GIT_ASKPASS_NODE?: string; + VSCODE_GIT_ASKPASS_MAIN?: string; + VSCODE_GIT_ASKPASS_HANDLE?: string; +} + +function getIPCHandlePath(nonce: string): string { + if (process.platform === 'win32') { + return `\\\\.\\pipe\\vscode-git-askpass-${nonce}-sock`; + } + + if (process.env['XDG_RUNTIME_DIR']) { + return path.join(process.env['XDG_RUNTIME_DIR'], `vscode-git-askpass-${nonce}.sock`); + } + + return path.join(os.tmpdir(), `vscode-git-askpass-${nonce}.sock`); +} export class Askpass implements Disposable { private server: http.Server; - private portPromise: Promise; + private ipcHandlePathPromise: Promise; private enabled = true; constructor() { this.server = http.createServer((req, res) => this.onRequest(req, res)); + this.ipcHandlePathPromise = this.setup().catch(err => console.error(err)); + } + + private async setup(): Promise { + const buffer = await randomBytes(20); + const nonce = buffer.toString('hex'); + const ipcHandlePath = getIPCHandlePath(nonce); try { - this.server.listen(0); - this.portPromise = new Promise(c => this.server.on('listening', () => c(this.server.address().port))); + this.server.listen(ipcHandlePath); this.server.on('error', err => console.error(err)); } catch (err) { + console.error('Could not launch git askpass helper.'); this.enabled = false; } + + return ipcHandlePath; } private onRequest(req: http.ServerRequest, res: http.ServerResponse): void { @@ -55,7 +89,7 @@ export class Askpass implements Disposable { return await window.showInputBox(options) || ''; } - async getEnv(): Promise { + async getEnv(): Promise { if (!this.enabled) { return { GIT_ASKPASS: path.join(__dirname, 'askpass-empty.sh') @@ -67,7 +101,7 @@ export class Askpass implements Disposable { GIT_ASKPASS: path.join(__dirname, 'askpass.sh'), VSCODE_GIT_ASKPASS_NODE: process.execPath, VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js'), - VSCODE_GIT_ASKPASS_PORT: String(await this.portPromise) + VSCODE_GIT_ASKPASS_HANDLE: await this.ipcHandlePathPromise }; }