From f8678fbec38049d96fa281a45aed7b2b36962f41 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Tue, 19 Apr 2016 20:44:07 +0900 Subject: [PATCH 1/9] Revert existing auth event --- src/main.js | 12 ------------ src/package.json | 1 - 2 files changed, 13 deletions(-) diff --git a/src/main.js b/src/main.js index caf132ab..a82f89fe 100644 --- a/src/main.js +++ b/src/main.js @@ -79,18 +79,6 @@ function shouldShowTrayIcon() { return false; } -app.on('login', function(event, webContents, request, authInfo, callback) { - event.preventDefault(); - var readlineSync = require('readline-sync'); - console.log("HTTP basic auth requiring login, please provide login data."); - var username = readlineSync.question('Username: '); - var password = readlineSync.question('Password: ', { - hideEchoBack: true - }); - console.log("Replacing default auth behaviour."); - callback(username, password); -}); - // Quit when all windows are closed. app.on('window-all-closed', function() { // On OS X it is common for applications and their menu bar diff --git a/src/package.json b/src/package.json index 59f3bf1e..25bd6641 100644 --- a/src/package.json +++ b/src/package.json @@ -15,7 +15,6 @@ "react": "^15.0.1", "react-bootstrap": "^0.28.5", "react-dom": "^15.0.1", - "readline-sync": "^1.4.1", "yargs": "^3.31.0" } } From 58f1ec5f9a0b733afad7ff153b370e454327a283 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Thu, 21 Apr 2016 22:43:18 +0900 Subject: [PATCH 2/9] Prototype http authentication --- src/browser/index.jsx | 7 +++++++ src/main.js | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 9aac70d6..cd3661e4 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -15,6 +15,7 @@ const ListGroupItem = ReactBootstrap.ListGroupItem; const electron = require('electron'); const remote = electron.remote; +const ipcRenderer = electron.ipcRenderer; const osLocale = require('os-locale'); const fs = require('fs'); @@ -25,6 +26,12 @@ const settings = require('../common/settings'); remote.getCurrentWindow().removeAllListeners('focus'); +ipcRenderer.on('login-request', function(event, request, authInfo) { + setTimeout(() => { + ipcRenderer.send('login-credentials', request, 'user', 'password'); + }, 10000); +}); + // New window should disable nodeIntergration. const originalWindowOpen = window.open; window.open = function(url, name, features) { diff --git a/src/main.js b/src/main.js index a82f89fe..77beb9cd 100644 --- a/src/main.js +++ b/src/main.js @@ -139,6 +139,21 @@ app.on('certificate-error', function(event, webContents, url, error, certificate } }); +const loginCallbackMap = new Map(); + +ipc.on('login-credentials', function(event, request, user, password) { + const callback = loginCallbackMap.get(JSON.stringify(request)); + if (callback != null) { + callback(user, password); + } +}) + +app.on('login', function(event, webContents, request, authInfo, callback) { + event.preventDefault(); + loginCallbackMap.set(JSON.stringify(request), callback); + mainWindow.webContents.send('login-request', request, authInfo); +}); + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { From f39c1543198ea99666731ba0948921d9462efa5a Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Fri, 22 Apr 2016 00:34:37 +0900 Subject: [PATCH 3/9] Update React-Bootstrap to 0.29.0 --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 25bd6641..8527edc0 100644 --- a/src/package.json +++ b/src/package.json @@ -13,7 +13,7 @@ "bootstrap": "^3.3.6", "os-locale": "^1.4.0", "react": "^15.0.1", - "react-bootstrap": "^0.28.5", + "react-bootstrap": "^0.29.0", "react-dom": "^15.0.1", "yargs": "^3.31.0" } From b0a40c66fbefef7b5c54bc30eb546daca081bce5 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 23 Apr 2016 00:50:57 +0900 Subject: [PATCH 4/9] Add the dialog to login --- gulpfile.js | 2 +- src/browser/components/loginModal.jsx | 59 +++++++++++++++++++++++++++ src/browser/index.jsx | 56 ++++++++++++++++++++----- 3 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 src/browser/components/loginModal.jsx diff --git a/gulpfile.js b/gulpfile.js index 61ed0d27..0d5d496c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -85,7 +85,7 @@ gulp.task('build', ['sync-meta', 'webpack', 'copy'], function() { gulp.task('webpack', ['webpack:main', 'webpack:browser', 'webpack:webview']); gulp.task('webpack:browser', function() { - return gulp.src('src/browser/**/*.jsx') + return gulp.src('src/browser/*.jsx') .pipe(named()) .pipe(webpack({ module: { diff --git a/src/browser/components/loginModal.jsx b/src/browser/components/loginModal.jsx new file mode 100644 index 00000000..14a3176e --- /dev/null +++ b/src/browser/components/loginModal.jsx @@ -0,0 +1,59 @@ +const React = require('react'); +const ReactDOM = require('react-dom'); +const ReactBootstrap = require('react-bootstrap'); +const Modal = ReactBootstrap.Modal; +const Form = ReactBootstrap.Form; +const FormGroup = ReactBootstrap.FormGroup; +const FormControl = ReactBootstrap.FormControl; +const ControlLabel = ReactBootstrap.ControlLabel; +const Col = ReactBootstrap.Col; + +const Button = ReactBootstrap.Button; + +const LoginModal = React.createClass({ + handleLogin: function() { + if (this.props.onLogin) { + const username = ReactDOM.findDOMNode(this.refs.username).value; + const password = ReactDOM.findDOMNode(this.refs.password).value; + this.props.onLogin(this.props.request, username, password); + } + }, + render: function() { + return ( + + + Authentication Required + + +

The server + { ' ' + this.props.authServerURL } requires a username and password.

+
+ + User Name + + + + + + Password + + + + + + +
+ + { ' ' } + +
+ +
+
+
+
+ ); + } +}); + +module.exports = LoginModal; diff --git a/src/browser/index.jsx b/src/browser/index.jsx index cd3661e4..17ea3072 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -13,6 +13,8 @@ const Badge = ReactBootstrap.Badge; const ListGroup = ReactBootstrap.ListGroup; const ListGroupItem = ReactBootstrap.ListGroupItem; +const LoginModal = require('./components/loginModal.jsx'); + const electron = require('electron'); const remote = electron.remote; const ipcRenderer = electron.ipcRenderer; @@ -26,12 +28,6 @@ const settings = require('../common/settings'); remote.getCurrentWindow().removeAllListeners('focus'); -ipcRenderer.on('login-request', function(event, request, authInfo) { - setTimeout(() => { - ipcRenderer.send('login-credentials', request, 'user', 'password'); - }, 10000); -}); - // New window should disable nodeIntergration. const originalWindowOpen = window.open; window.open = function(url, name, features) { @@ -49,11 +45,26 @@ var MainPage = React.createClass({ unreadCounts: new Array(this.props.teams.length), mentionCounts: new Array(this.props.teams.length), unreadAtActive: new Array(this.props.teams.length), - mentionAtActiveCounts: new Array(this.props.teams.length) + mentionAtActiveCounts: new Array(this.props.teams.length), + loginQueue: [] }; }, componentDidMount: function() { var thisObj = this; + ipcRenderer.on('login-request', function(event, request, authInfo) { + thisObj.setState({ + loginRequired: true + }); + const loginQueue = thisObj.state.loginQueue; + loginQueue.push({ + request: request, + authInfo: authInfo + }); + thisObj.setState({ + loginQueue: loginQueue + }); + }); + var focusListener = function() { var webview = document.getElementById('mattermostView' + thisObj.state.key); webview.focus(); @@ -141,6 +152,18 @@ var MainPage = React.createClass({ visibility: visibility }; }, + + handleLogin: function(request, username, password) { + ipcRenderer.send('login-credentials', request, username, password); + const loginQueue = this.state.loginQueue; + loginQueue.shift(); + this.setState(loginQueue); + }, + handleLoginCancel: function() { + const loginQueue = this.state.loginQueue; + loginQueue.shift(); + this.setState(loginQueue); + }, render: function() { var thisObj = this; @@ -168,11 +191,22 @@ var MainPage = React.createClass({ var views_row = ( { views } ); + + var request = null; + var authServerURL = null; + if (this.state.loginQueue.length !== 0) { + request = this.state.loginQueue[0].request; + const tmp_url = url.parse(this.state.loginQueue[0].request.url); + authServerURL = `${tmp_url.protocol}//${tmp_url.host}`; + } return ( - - { tabs_row } - { views_row } - +
+ + + { tabs_row } + { views_row } + +
); } }); From d81856629b09fd98bb31d18f0bac0c106e2e1f49 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 23 Apr 2016 19:15:25 +0900 Subject: [PATCH 5/9] Send login credentials on Enter key --- src/browser/components/loginModal.jsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/browser/components/loginModal.jsx b/src/browser/components/loginModal.jsx index 14a3176e..d8dee56a 100644 --- a/src/browser/components/loginModal.jsx +++ b/src/browser/components/loginModal.jsx @@ -11,12 +11,13 @@ const Col = ReactBootstrap.Col; const Button = ReactBootstrap.Button; const LoginModal = React.createClass({ - handleLogin: function() { - if (this.props.onLogin) { - const username = ReactDOM.findDOMNode(this.refs.username).value; - const password = ReactDOM.findDOMNode(this.refs.password).value; - this.props.onLogin(this.props.request, username, password); - } + handleSubmit: function(event) { + event.preventDefault(); + const usernameNode = ReactDOM.findDOMNode(this.refs.username); + const passwordNode = ReactDOM.findDOMNode(this.refs.password); + this.props.onLogin(this.props.request, usernameNode.value, passwordNode.value); + usernameNode.value = ''; + passwordNode.value = ''; }, render: function() { return ( @@ -43,7 +44,7 @@ const LoginModal = React.createClass({
- + { ' ' }
From a55eb6fa0facd833095eb99e4ff4d65c510dc02f Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 23 Apr 2016 19:31:44 +0900 Subject: [PATCH 6/9] Change compatibility for react-bootstrap --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 8527edc0..2c2cc220 100644 --- a/src/package.json +++ b/src/package.json @@ -13,7 +13,7 @@ "bootstrap": "^3.3.6", "os-locale": "^1.4.0", "react": "^15.0.1", - "react-bootstrap": "^0.29.0", + "react-bootstrap": "~0.29.0", "react-dom": "^15.0.1", "yargs": "^3.31.0" } From 507889066a0848f2364dfe4d11dbb22ae092f2e3 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Mon, 25 Apr 2016 20:41:02 +0900 Subject: [PATCH 7/9] Tell whether the server is a proxy --- src/browser/components/loginModal.jsx | 14 ++++++++++++-- src/browser/index.jsx | 5 ++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/browser/components/loginModal.jsx b/src/browser/components/loginModal.jsx index d8dee56a..e61fba1d 100644 --- a/src/browser/components/loginModal.jsx +++ b/src/browser/components/loginModal.jsx @@ -20,14 +20,24 @@ const LoginModal = React.createClass({ passwordNode.value = ''; }, render: function() { + var serverType = ''; + if (!this.props.show) { + serverType = ''; + } else if (this.props.authInfo.isProxy) { + serverType = 'proxy'; + } else { + serverType = 'server'; + } + const message = `The ${serverType} ${this.props.authServerURL} requires a username and password.`; return ( Authentication Required -

The server - { ' ' + this.props.authServerURL } requires a username and password.

+

+ { message } +

User Name diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 17ea3072..e85ad2d7 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -194,14 +194,17 @@ var MainPage = React.createClass({ var request = null; var authServerURL = null; + var authInfo = null; if (this.state.loginQueue.length !== 0) { request = this.state.loginQueue[0].request; const tmp_url = url.parse(this.state.loginQueue[0].request.url); authServerURL = `${tmp_url.protocol}//${tmp_url.host}`; + authInfo = this.state.loginQueue[0].authInfo; } return (
- + { tabs_row } { views_row } From 5fce592b01f4f45f4bda1138468977639943a6b1 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 27 Apr 2016 20:47:52 +0900 Subject: [PATCH 8/9] Show proxy URL on login dialog --- src/browser/components/loginModal.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/browser/components/loginModal.jsx b/src/browser/components/loginModal.jsx index e61fba1d..45f32fd2 100644 --- a/src/browser/components/loginModal.jsx +++ b/src/browser/components/loginModal.jsx @@ -20,15 +20,15 @@ const LoginModal = React.createClass({ passwordNode.value = ''; }, render: function() { - var serverType = ''; + var theServer = ''; if (!this.props.show) { - serverType = ''; + theServer = ''; } else if (this.props.authInfo.isProxy) { - serverType = 'proxy'; + theServer = `The proxy ${authInfo.host}:${authInfo.port}`; } else { - serverType = 'server'; + theServer = `The server ${this.props.authServerURL}`; } - const message = `The ${serverType} ${this.props.authServerURL} requires a username and password.`; + const message = `${theServer} requires a username and password.`; return ( From e99e6c0a0510eb55bdd6c729c58ac2afb710f067 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 27 Apr 2016 20:51:57 +0900 Subject: [PATCH 9/9] Update docs for login dialog --- CHANGELOG.md | 1 + README.md | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f067bd0d..7683b406 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Improvements - Add **Allow insecure contents** option to render images with `http://`. +- Add the login dialog for http authentication. #### OS X - Add the option to show the icon on menu bar diff --git a/README.md b/README.md index ca0dae7d..baee5ff9 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,6 @@ Or you can set proxy by following command line options. * `--proxy-server=:` * `--proxy-pac-url=` -*Note: Authorization is not supported yet.* - ## Testing and Development Node.js is required to test this app.