Skip to content

Commit

Permalink
Merge pull request microsoft#22369 from joaomoreno/proxy-auth
Browse files Browse the repository at this point in the history
Handle proxy authentication
  • Loading branch information
joaomoreno authored Jul 3, 2017
2 parents b31643d + 073d279 commit a4667bf
Showing 3 changed files with 225 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/vs/code/electron-main/app.ts
Original file line number Diff line number Diff line change
@@ -39,8 +39,9 @@ import { resolveCommonProperties, machineIdStorageKey, machineIdIpcChannel } fro
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
import { ProxyAuthHandler } from './auth';
import { IDisposable, dispose } from "vs/base/common/lifecycle";
import { ConfigurationService } from "vs/platform/configuration/node/configurationService";
import { TPromise } from "vs/base/common/winjs.base";
import { IWindowsMainService } from "vs/platform/windows/electron-main/windows";
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
@@ -267,6 +268,10 @@ export class CodeApplication {
// Services
const appInstantiationService = this.initServices();

// Setup Auth Handler
const authHandler = appInstantiationService.createInstance(ProxyAuthHandler);
this.toDispose.push(authHandler);

// Open Windows
appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor));

125 changes: 125 additions & 0 deletions src/vs/code/electron-main/auth.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8" />
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
}

body {
font-family: "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
font-size: 10pt;
background-color: #F3F3F3;
}

#main {
box-sizing: border-box;
padding: 10px;
}

h1 {
margin: 0;
padding: 10px 0;
font-size: 16px;
background-color: #555;
color: #f0f0f0;
text-align: center;
}

#form {
margin-top: 10px;
}

#username,
#password {
padding: 6px 10px;
font-size: 12px;
box-sizing: border-box;
width: 100%;
}

#buttons {
text-align: center;
}

p {
margin: 6px 0;
}

input {
font-family: "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback" !important;
}
</style>
</head>

<body>
<h1 id="title"></h1>
<section id="main">
<p id="message"></p>
<form id="form">
<p><input type="text" id="username" placeholder="Username" required/></p>
<p><input type="password" id="password" placeholder="Password" required/></p>
<p id="buttons">
<input id="ok" type="submit" value="OK" />
<input id="cancel" type="button" value="Cancel" />
</p>
</form>
</section>
</body>

<script>
const electron = require('electron');
const shell = electron.shell;
const ipc = electron.ipcRenderer;
const remote = electron.remote;
const currentWindow = remote.getCurrentWindow();

function promptForCredentials(data) {
return new Promise((c, e) => {
const $title = document.getElementById('title');
const $username = document.getElementById('username');
const $password = document.getElementById('password');
const $form = document.getElementById('form');
const $cancel = document.getElementById('cancel');
const $message = document.getElementById('message');

function submit() {
c({ username: $username.value, password: $password.value });
return false;
};

function cancel() {
c({ username: '', password: '' });
return false;
};

$form.addEventListener('submit', submit);
$cancel.addEventListener('click', cancel);

document.body.addEventListener('keydown', function (e) {
switch (e.keyCode) {
case 27: e.preventDefault(); e.stopPropagation(); return cancel();
case 13: e.preventDefault(); e.stopPropagation(); return submit();
}
});

$title.textContent = data.title;
$message.textContent = data.message;
$username.focus();
});
}

</script>

</html>
93 changes: 93 additions & 0 deletions src/vs/code/electron-main/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

import { localize } from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { fromEventEmitter } from 'vs/base/node/event';
import { BrowserWindow, app } from 'electron';

type LoginEvent = {
event: Electron.Event;
webContents: Electron.WebContents;
req: Electron.LoginRequest;
authInfo: Electron.LoginAuthInfo;
cb: (username: string, password: string) => void;
};

type Credentials = {
username: string;
password: string;
};

export class ProxyAuthHandler {

_serviceBrand: any;

private retryCount = 0;
private disposables: IDisposable[] = [];

constructor(
@IWindowsMainService private windowsService: IWindowsMainService
) {
const onLogin = fromEventEmitter<LoginEvent>(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb }));
onLogin(this.onLogin, this, this.disposables);
}

private onLogin({ event, authInfo, cb }: LoginEvent): void {
if (!authInfo.isProxy) {
return;
}

if (this.retryCount++ > 1) {
return;
}

event.preventDefault();

const opts: any = {
alwaysOnTop: true,
skipTaskbar: true,
resizable: false,
width: 450,
height: 220,
show: true,
title: 'VS Code'
};

const focusedWindow = this.windowsService.getFocusedWindow();

if (focusedWindow) {
opts.parent = focusedWindow.win;
opts.modal = true;
}

const win = new BrowserWindow(opts);
const config = {};
const baseUrl = require.toUrl('./auth.html');
const url = `${baseUrl}?config=${encodeURIComponent(JSON.stringify(config))}`;
const proxyUrl = `${authInfo.host}:${authInfo.port}`;
const title = localize('authRequire', "Proxy Authentication Required");
const message = localize('proxyauth', "The proxy {0} requires authentication.", proxyUrl);
const data = { title, message };
const javascript = 'promptForCredentials(' + JSON.stringify(data) + ')';

const onWindowClose = () => cb('', '');
win.on('close', onWindowClose);

win.loadURL(url);
win.webContents.executeJavaScript(javascript, true).then(({ username, password }: Credentials) => {
cb(username, password);
win.removeListener('close', onWindowClose);
win.close();
});
}

dispose(): void {
this.disposables = dispose(this.disposables);
}
}

0 comments on commit a4667bf

Please sign in to comment.