@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- Add **Allow insecure contents** option to render images with `http://`.
|
- Add **Allow insecure contents** option to render images with `http://`.
|
||||||
|
- Add the login dialog for http authentication.
|
||||||
|
|
||||||
#### OS X
|
#### OS X
|
||||||
- Add the option to show the icon on menu bar
|
- Add the option to show the icon on menu bar
|
||||||
|
@@ -57,8 +57,6 @@ Or you can set proxy by following command line options.
|
|||||||
* `--proxy-server=<SERVER>:<PORT>`
|
* `--proxy-server=<SERVER>:<PORT>`
|
||||||
* `--proxy-pac-url=<URL>`
|
* `--proxy-pac-url=<URL>`
|
||||||
|
|
||||||
*Note: Authorization is not supported yet.*
|
|
||||||
|
|
||||||
|
|
||||||
## Testing and Development
|
## Testing and Development
|
||||||
Node.js is required to test this app.
|
Node.js is required to test this app.
|
||||||
|
@@ -85,7 +85,7 @@ gulp.task('build', ['sync-meta', 'webpack', 'copy'], function() {
|
|||||||
gulp.task('webpack', ['webpack:main', 'webpack:browser', 'webpack:webview']);
|
gulp.task('webpack', ['webpack:main', 'webpack:browser', 'webpack:webview']);
|
||||||
|
|
||||||
gulp.task('webpack:browser', function() {
|
gulp.task('webpack:browser', function() {
|
||||||
return gulp.src('src/browser/**/*.jsx')
|
return gulp.src('src/browser/*.jsx')
|
||||||
.pipe(named())
|
.pipe(named())
|
||||||
.pipe(webpack({
|
.pipe(webpack({
|
||||||
module: {
|
module: {
|
||||||
|
70
src/browser/components/loginModal.jsx
Normal file
70
src/browser/components/loginModal.jsx
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
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({
|
||||||
|
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() {
|
||||||
|
var theServer = '';
|
||||||
|
if (!this.props.show) {
|
||||||
|
theServer = '';
|
||||||
|
} else if (this.props.authInfo.isProxy) {
|
||||||
|
theServer = `The proxy ${authInfo.host}:${authInfo.port}`;
|
||||||
|
} else {
|
||||||
|
theServer = `The server ${this.props.authServerURL}`;
|
||||||
|
}
|
||||||
|
const message = `${theServer} requires a username and password.`;
|
||||||
|
return (
|
||||||
|
<Modal show={ this.props.show }>
|
||||||
|
<Modal.Header>
|
||||||
|
<Modal.Title>Authentication Required</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
<p>
|
||||||
|
{ message }
|
||||||
|
</p>
|
||||||
|
<Form horizontal onSubmit={ this.handleSubmit }>
|
||||||
|
<FormGroup>
|
||||||
|
<Col componentClass={ ControlLabel } sm={ 2 }>User Name</Col>
|
||||||
|
<Col sm={ 10 }>
|
||||||
|
<FormControl type="text" placeholder="User Name" ref="username" />
|
||||||
|
</Col>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<Col componentClass={ ControlLabel } sm={ 2 }>Password</Col>
|
||||||
|
<Col sm={ 10 }>
|
||||||
|
<FormControl type="password" placeholder="Password" ref="password" />
|
||||||
|
</Col>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<Col sm={ 12 }>
|
||||||
|
<div className="pull-right">
|
||||||
|
<Button type="submit" bsStyle="primary">Login</Button>
|
||||||
|
{ ' ' }
|
||||||
|
<Button onClick={ this.props.onCancel }>Cancel</Button>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = LoginModal;
|
@@ -13,8 +13,11 @@ const Badge = ReactBootstrap.Badge;
|
|||||||
const ListGroup = ReactBootstrap.ListGroup;
|
const ListGroup = ReactBootstrap.ListGroup;
|
||||||
const ListGroupItem = ReactBootstrap.ListGroupItem;
|
const ListGroupItem = ReactBootstrap.ListGroupItem;
|
||||||
|
|
||||||
|
const LoginModal = require('./components/loginModal.jsx');
|
||||||
|
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const remote = electron.remote;
|
const remote = electron.remote;
|
||||||
|
const ipcRenderer = electron.ipcRenderer;
|
||||||
|
|
||||||
const osLocale = require('os-locale');
|
const osLocale = require('os-locale');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -32,11 +35,26 @@ var MainPage = React.createClass({
|
|||||||
unreadCounts: new Array(this.props.teams.length),
|
unreadCounts: new Array(this.props.teams.length),
|
||||||
mentionCounts: new Array(this.props.teams.length),
|
mentionCounts: new Array(this.props.teams.length),
|
||||||
unreadAtActive: 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() {
|
componentDidMount: function() {
|
||||||
var thisObj = this;
|
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 focusListener = function() {
|
||||||
var webview = document.getElementById('mattermostView' + thisObj.state.key);
|
var webview = document.getElementById('mattermostView' + thisObj.state.key);
|
||||||
webview.focus();
|
webview.focus();
|
||||||
@@ -124,6 +142,18 @@ var MainPage = React.createClass({
|
|||||||
visibility: visibility
|
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() {
|
render: function() {
|
||||||
var thisObj = this;
|
var thisObj = this;
|
||||||
|
|
||||||
@@ -151,11 +181,25 @@ var MainPage = React.createClass({
|
|||||||
var views_row = (<Row>
|
var views_row = (<Row>
|
||||||
{ views }
|
{ views }
|
||||||
</Row>);
|
</Row>);
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
<Grid fluid>
|
<div>
|
||||||
{ tabs_row }
|
<LoginModal show={ this.state.loginQueue.length !== 0 } request={ request } authInfo={ authInfo } authServerURL={ authServerURL } onLogin={ this.handleLogin }
|
||||||
{ views_row }
|
onCancel={ this.handleLoginCancel }></LoginModal>
|
||||||
</Grid>
|
<Grid fluid>
|
||||||
|
{ tabs_row }
|
||||||
|
{ views_row }
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
27
src/main.js
27
src/main.js
@@ -79,18 +79,6 @@ function shouldShowTrayIcon() {
|
|||||||
return false;
|
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.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', function() {
|
app.on('window-all-closed', function() {
|
||||||
// On OS X it is common for applications and their menu bar
|
// On OS X it is common for applications and their menu bar
|
||||||
@@ -151,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
|
// This method will be called when Electron has finished
|
||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
app.on('ready', function() {
|
app.on('ready', function() {
|
||||||
|
@@ -13,9 +13,8 @@
|
|||||||
"bootstrap": "^3.3.6",
|
"bootstrap": "^3.3.6",
|
||||||
"os-locale": "^1.4.0",
|
"os-locale": "^1.4.0",
|
||||||
"react": "^15.0.1",
|
"react": "^15.0.1",
|
||||||
"react-bootstrap": "^0.28.5",
|
"react-bootstrap": "~0.29.0",
|
||||||
"react-dom": "^15.0.1",
|
"react-dom": "^15.0.1",
|
||||||
"readline-sync": "^1.4.1",
|
|
||||||
"yargs": "^3.31.0"
|
"yargs": "^3.31.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user