diff --git a/index.js b/index.js index 42698ce..646afe9 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,8 @@ const objectAssign = require('object-assign'); const nodeUrl = require('url'); const electron = require('electron'); const BrowserWindow = electron.BrowserWindow || electron.remote.BrowserWindow; +const {ipcMain} = require('electron'); +const path = require('path'); var generateRandomString = function (length) { var text = ''; @@ -47,6 +49,61 @@ module.exports = function (config, windowParams) { return new Promise(function (resolve, reject) { const authWindow = new BrowserWindow(windowParams || {'use-content-size': true}); + let receivedCode = false; + let receivedError = false; + + /* DIALOG BOX PART */ + var promptWindow; + var promptOptions; + var promptAnswer; + + // Clearing the dialog + function promptModal(parent, options, callback) { + promptOptions = options; + promptWindow = new BrowserWindow({ + width: 300, height: 150, + parent: parent, + show: true, + modal: true, + alwaysOnTop: true, + title: options.title, + autoHideMenuBar: true, + webPreferences: { + nodeIntegration: true, + sandbox: false + } + }); + + promptWindow.on('closed', () => { + promptWindow = null; + callback(promptAnswer); + }); + + // Load the HTML dialog box + promptWindow.loadURL(nodeUrl.format({ + pathname: path.join(__dirname, 'prompt.html'), + protocol: 'file:', + slashes: true + })); + } + + // Called by the dialog box to get its parameters + ipcMain.on('openDialog', event => { + event.returnValue = JSON.stringify(promptOptions, null, ''); + }); + + // Called by the dialog box when closed + ipcMain.on('closeDialog', (event, data) => { + promptAnswer = data; + }); + + // If the certificate used for TLS in any redirects is not trusted, + // handle it here. Default behavior is hung app with white screen + authWindow.webContents.on('certificate-error', (event, url) => { + authWindow.hide(); + reject(new Error('Certificate presented for ' + url + ' is not trusted')); + }); + authWindow.loadURL(url); authWindow.show(); @@ -54,27 +111,66 @@ module.exports = function (config, windowParams) { reject(new Error('window was closed by user')); }); - function onCallback(url) { + function closeAuthWindow() { + authWindow.removeAllListeners(); + setImmediate(function () { + authWindow.close(); + }); + } + + function onCallback(url, err) { + if (receivedCode || receivedError) { + return; + } + + if (err) { + receivedError = true; + reject(err); + closeAuthWindow(); + return; + } + var url_parts = nodeUrl.parse(url, true); var query = url_parts.query; - var code = query.code; + var code = null; var error = query.error; + // Grant code should be captured only from the redirect uri specified in the config + // This allows for multiple brokers in OIDC chain which may url parameter with name code + if (url.startsWith(config.redirectUri + '?') || + url.startsWith(config.redirectUri + '/?')) { + code = query.code; + } + if (error !== undefined) { + receivedError = true; reject(error); - authWindow.removeAllListeners('closed'); - setImmediate(function () { - authWindow.close(); - }); + closeAuthWindow(); + return; } else if (code) { + receivedCode = true; resolve(code); - authWindow.removeAllListeners('closed'); - setImmediate(function () { - authWindow.close(); - }); + closeAuthWindow(); + return; } } + authWindow.webContents.on('login', (event, request, authInfo, callback) => { + event.preventDefault(); + + promptModal(authWindow, { + label: 'Login to ' + authInfo.host + ' :' + }, + function (data) { + if (data) { + callback(data.username, data.password); + } else { + onCallback(null, new Error('User cancelled authentication')); + } + } + ); + }); + authWindow.webContents.on('will-navigate', (event, url) => { onCallback(url); }); diff --git a/package.json b/package.json index c17458c..c356702 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "url": "marcel.wiehle.me" }, "files": [ - "index.js" + "index.js", + "prompt.html" ], "scripts": { "test": "xo" diff --git a/prompt.html b/prompt.html new file mode 100755 index 0000000..8895bb8 --- /dev/null +++ b/prompt.html @@ -0,0 +1,41 @@ + + +
+ ++ + +
++ + +
+ + + \ No newline at end of file