Skip to content

Commit

Permalink
Merge pull request #53 from mountainash/51-loginkeychain
Browse files Browse the repository at this point in the history
51 loginkeychain + Safer `openExternal` handling
  • Loading branch information
mountainash authored May 6, 2021
2 parents f16efb2 + 86ee720 commit 6262bc4
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 31 deletions.
32 changes: 19 additions & 13 deletions browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,36 @@ document.addEventListener('readystatechange', async () => {
const loginusername = loginform.querySelector(DomHooks.loginusername);
const loginpassword = loginform.querySelector(DomHooks.loginpassword);

try { // try using saved login
const loginkeys = await keyStore.getKey();

// setTimeout(function() {
loginusername.value = loginkeys.username || 'nothing';
loginpassword.value = loginkeys.password;
// }, 100); // running later as Asana clears the inputs (changed: using `readystatechange` for document listener instead of `DOMContentLoaded`)
} catch (error) {
console.log('no login previously stored');
// try using saved login
const loginkeys = await keyStore.getKey();

// Trigger the attached `change` event to get the values into the Virtual DOM (as Asana runs React/Nuxt.js)
const event = new Event('HTMLEvents');
event.initEvent('change', true, false);

if (loginkeys && loginkeys.username) {
loginusername.value = loginkeys.username;
loginusername.dispatchEvent(event);
}

if (loginkeys && loginkeys.password) {
loginpassword.value = loginkeys.password;
loginpassword.dispatchEvent(event);
}

const loginsubmitted = function() {
const loginsubmitted = async function() {
let username = loginusername.value;
let password = loginpassword.value;

if (username && password) {
keyStore.deleteKeys(); // delete any exiting logins
keyStore.addKey(username, password); // store the users details for auto-login next time
await keyStore.deleteKeys(); // delete any exiting logins
await keyStore.addKey(username, password); // store the users details for auto-login next time
}
};

// add a listener to the form to capture login details and store them
// would be nice to add to just the <FORM> submit event, but React/Nuxt (used by Asana) captures the events lower in the DOM
loginform.addEventListener('submit', loginsubmitted);
// loginform.addEventListener('submit', loginsubmitted);
loginform.querySelector(DomHooks.loginbutton).addEventListener('click', loginsubmitted);
loginusername.addEventListener('keyup', (e) => {
if (e.code == 'Enter')
Expand Down
79 changes: 64 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { app, BrowserWindow, Menu, ipcMain, shell } = require('electron');
const { app, BrowserWindow, Menu, shell, ipcMain } = require('electron');
const { autoUpdater } = require('electron-updater');
const __DEV__ = require('electron-is-dev');
const path = require('path');
Expand All @@ -8,6 +8,7 @@ const fs = require('fs');
const Config = require('electron-config')
const config = new Config();

const BASE_URL = 'https://app.asana.com/';
const notificationIndicator = '●';

require('electron-debug')();
Expand All @@ -23,18 +24,22 @@ let isQuitting = false;
let mainWindow;
let page;

const isRunning = app.requestSingleInstanceLock();
function basicURL(url) {
if (typeof url !== 'string') return false;

if (!isRunning) {
app.quit();
const parsed = new URL(url);
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
return false;

return true;
}

app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.show();
}
});
function isURLAllowed(url) {
return [
/^https:\/\/accounts\.google\.com\/.*/i,
/^https:\/\/app\.asana\.com\/.*/i
].some((re) => url.match(re));
}

function updateBadgeInfo(title) {
if (process.platform !== 'darwin' && process.platform !== 'linux') return;
Expand Down Expand Up @@ -67,7 +72,7 @@ function createMainWindow() {

const win = new BrowserWindow(opts);

win.loadURL('https://app.asana.com/');
win.loadURL(BASE_URL);

win.on('close', (e) => {
if (!isQuitting) {
Expand All @@ -92,6 +97,17 @@ function createMainWindow() {
return win;
}

if ( !app.requestSingleInstanceLock() ) {
app.quit();
}

app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.show();
}
});

ipcMain.on('update-menu', () => {
Menu.setApplicationMenu(menu.slice(1));
})
Expand All @@ -103,16 +119,49 @@ app.on('ready', () => {
page = mainWindow.webContents;

// Open new browser window on external open
page.on('new-window', (event, url) => {
event.preventDefault();
shell.openExternal(url);
page.setWindowOpenHandler(({ url }) => {
if ( basicURL(url) )
shell.openExternal(url);

return { action: 'deny' }; // prevent a new Electron window
});

page.on('will-navigate', (e, url) => {
if (basicURL(url) && !isURLAllowed(url)) {
e.preventDefault();
shell.openExternal(url);
}
});

page.on('will-redirect', (e, url) => {
// `will-navigate` doesn't catch redirects
if (basicURL(url) && !isURLAllowed(url)) {
e.preventDefault();
mainWindow.loadURL(BASE_URL);
shell.openExternal(url);
}
});

// Set the menu application menu
Menu.setApplicationMenu(menu);

page.on('dom-ready', function() {
// Insert CSS
page.on('dom-ready', () => {
page.insertCSS(fs.readFileSync(path.join(__dirname, 'browser.css'), 'utf8'));
mainWindow.show();
});
});

// Quit when all windows are closed, except on macOS. There, it's common for applications and their menu bar to stay active until the user quits explicitly with Cmd + Q
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});

// On OS X it's common to re-create a window in the app when the dock icon is clicked and there are no other windows open
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createMainWindow();
}
});
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "taskana",
"productName": "Taskana",
"version": "1.13.0",
"version": "1.13.2",
"description": "Application wrapper for Asana web application",
"keywords": [
"macOS",
Expand Down

0 comments on commit 6262bc4

Please sign in to comment.