From 7139fa0077971adf6a6eb42097e46dd532693025 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Mon, 30 Oct 2017 11:19:26 +0200 Subject: [PATCH 1/5] Switched localStorage to browser.local.storage --- keepassxc-browser/background/browserAction.js | 2 +- keepassxc-browser/background/event.js | 53 ++++++----- keepassxc-browser/background/init.js | 18 ++-- keepassxc-browser/background/keepass.js | 88 +++++++++++-------- keepassxc-browser/background/page.js | 78 ++++++++-------- keepassxc-browser/keepassxc-browser.js | 12 +-- keepassxc-browser/options/options.js | 32 +++---- 7 files changed, 158 insertions(+), 125 deletions(-) diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index 3a67a12..34547a5 100644 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -70,7 +70,7 @@ browserAction.showDefault = function(callback, tab) { iconType: 'normal', popup: 'popup.html' }; - keepass.isConfigured((response) => { + keepass.isConfigured().then((response) => { if (!response || keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable || page.tabs[tab.id].errorMessage) { stackData.iconType = 'cross'; } diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index 2b0a440..d4af4e4 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -100,32 +100,37 @@ kpxcEvent.showStatus = function(configured, tab, callback) { }; kpxcEvent.onLoadSettings = function(callback, tab) { - page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.parse(localStorage.settings); + browser.storage.local.get({'settings': {}}).then((item) => { + callback(item.settings); + }, (err) => { + console.log('error loading settings: ' + err); + }); }; kpxcEvent.onLoadKeyRing = function(callback, tab) { - keepass.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing); - if (keepass.isAssociated() && !keepass.keyRing[keepass.associated.hash]) { - keepass.associated = { - value: false, - hash: null - }; - } -}; - -kpxcEvent.onGetSettings = function(callback, tab) { - kpxcEvent.onLoadSettings(); - callback({ data: page.settings }); + browser.storage.local.get({'keyRing': {}}).then(function(item) { + keepass.keyRing = item.keyRing; + if (keepass.isAssociated() && !keepass.keyRing[keepass.associated.hash]) { + keepass.associated = { + "value": false, + "hash": null + }; + } + callback(item.keyRing); + }, (err) => { + console.log('error loading keyRing: ' + err); + }); }; kpxcEvent.onSaveSettings = function(callback, tab, settings) { - localStorage.settings = JSON.stringify(settings); - kpxcEvent.onLoadSettings(); + browser.storage.local.set({'settings': settings}).then(function() { + kpxcEvent.onLoadSettings(); + }); }; kpxcEvent.onGetStatus = function(callback, tab) { keepass.testAssociation((response) => { - keepass.isConfigured((configured) => { + keepass.isConfigured().then((configured) => { kpxcEvent.showStatus(configured, tab, callback); }); }, tab, true); @@ -141,7 +146,7 @@ kpxcEvent.onReconnect = function(callback, tab) { keepass.getDatabaseHash((gdRes) => { if (gdRes) { keepass.testAssociation((response) => { - keepass.isConfigured((configured) => { + keepass.isConfigured().then((configured) => { kpxcEvent.showStatus(configured, tab, callback); }); }, tab); @@ -175,12 +180,13 @@ kpxcEvent.onGetConnectedDatabase = function(callback, tab) { }; kpxcEvent.onGetKeePassXCVersions = function(callback, tab) { - if (keepass.currentKeePassXC.version === 0) { - keepass.getDatabaseHash((response) => { - callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); - }, tab); - } - callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); + if(keepass.currentKeePassXC.version == 0) { + keepass.getDatabaseHash(tab).then(() => { + callback({"current": keepass.currentKeePassXC.version, "latest": keepass.currentKeePassXC.version}); + }); + } else { + callback({"current": keepass.currentKeePassXC.version, "latest": keepass.currentKeePassXC.version}); +} }; kpxcEvent.onCheckUpdateKeePassXC = function(callback, tab) { @@ -254,7 +260,6 @@ kpxcEvent.messageHandlers = { 'check_update_keepassxc': kpxcEvent.onCheckUpdateKeePassXC, 'get_connected_database': kpxcEvent.onGetConnectedDatabase, 'get_keepassxc_versions': kpxcEvent.onGetKeePassXCVersions, - 'get_settings': kpxcEvent.onGetSettings, 'get_status': kpxcEvent.onGetStatus, 'get_tab_information': kpxcEvent.onGetTabInformation, 'load_keyring': kpxcEvent.onLoadKeyRing, diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index 6bc33c1..fa369a9 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -1,13 +1,15 @@ -keepass.convertKeyToKeyRing(); -page.initSettings(); -page.initOpenedTabs(); -keepass.connectToNative(); -keepass.generateNewKeyPair(); -keepass.changePublicKeys(null, (pkRes) => { - keepass.getDatabaseHash((gdRes) => {}, null); +keepass.migrateKeyRing().then(() => { + page.initSettings().then(() => { + page.initOpenedTabs().then(() => { + keepass.connectToNative(); + keepass.generateNewKeyPair(); + keepass.changePublicKeys(null, (pkRes) => { + keepass.getDatabaseHash((gdRes) => {}, null); + }); + }); + }); }); - // Milliseconds for intervall (e.g. to update browserAction) let _interval = 250; diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 39be7cb..5b80f13 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -11,7 +11,6 @@ keepass.isDatabaseClosed = false; keepass.isKeePassXCAvailable = false; keepass.isEncryptionKeyUnrecognized = false; keepass.currentKeePassXC = {'version': 0, 'versionParsed': 0}; -keepass.latestKeePassXC = (typeof(localStorage.latestKeePassXC) === 'undefined') ? {'version': 0, 'versionParsed': 0, 'lastChecked': null} : JSON.parse(localStorage.latestKeePassXC); keepass.requiredKeePassXC = 220; keepass.nativeHostName = 'com.varjolintu.keepassxc_browser'; keepass.nativePort = null; @@ -77,6 +76,13 @@ const kpErrors = { } }; +browser.storage.local.get({ + 'latestKeePassXC': {'version': 0, 'versionParsed': 0, 'lastChecked': null}, + 'keyRing': {}}).then((item) => { + keepass.latestKeePassXC = item.latestKeePassXC; + keepass.keyRing = item.keyRing; +}); + keepass.addCredentials = function(callback, tab, username, password, url) { keepass.updateCredentials(callback, tab, null, username, password, url); }; @@ -621,15 +627,16 @@ keepass.generateNewKeyPair = function() { //console.log(keepass.b64e(keepass.keyPair.publicKey) + ' ' + keepass.b64e(keepass.keyPair.secretKey)); }; -keepass.isConfigured = function(callback) { - if (typeof(keepass.databaseHash) === 'undefined') { - keepass.getDatabaseHash((dbHash) => { - callback(keepass.databaseHash in keepass.keyRing); - }, null); - } - else { - callback(keepass.databaseHash in keepass.keyRing); - } +keepass.isConfigured = function() { + return new Promise((resolve, reject) => { + if (typeof(keepass.databaseHash) === 'undefined') { + keepass.getDatabaseHash().then((hash) => { + resolve(hash in keepass.keyRing); + }); + } else { + resolve(keepass.databaseHash in keepass.keyRing); + } + }); }; keepass.checkDatabaseHash = function(callback, tab) { @@ -640,22 +647,33 @@ keepass.isAssociated = function() { return (keepass.associated.value && keepass.associated.hash && keepass.associated.hash === keepass.databaseHash); }; -keepass.convertKeyToKeyRing = function() { - if (keepass.keyId in localStorage && keepass.keyBody in localStorage && !('keyRing' in localStorage)) { - keepass.getDatabaseHash((hash) => { - keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]); - - if ('keyRing' in localStorage) { - delete localStorage[keepass.keyId]; - delete localStorage[keepass.keyBody]; +keepass.migrateKeyRing = function() { + return new Promise((resolve, reject) => { + browser.storage.local.get('keyRing').then((item) => { + const keyring = item.keyRing; + // change dates to numbers, for compatibilty with chrome + if (keyring) { + let num = 0; + for (let keyHash in keyring) { + let key = keyring[keyHash]; + ['created', 'lastUsed'].forEach((fld) => { + let v = key[fld]; + if (v instanceof Date && v.valueOf() >= 0) { + key[fld] = v.valueOf(); + num++; + } else if (typeof v !== 'number') { + key[fld] = Date.now().valueOf(); + num++; + } + }); + } + if (num > 0) { + browser.storage.local.set({ keyRing: keyring }); + } } - }, null); - } - - if ('keyRing' in localStorage) { - delete localStorage[keepass.keyId]; - delete localStorage[keepass.keyBody]; - } + resolve(); + }); + }); }; keepass.saveKey = function(hash, id, key) { @@ -664,8 +682,8 @@ keepass.saveKey = function(hash, id, key) { id: id, key: key, hash: hash, - created: new Date(), - lastUsed: new Date() + created: new Date().valueOf(), + lastUsed: new Date().valueOf() }; } else { @@ -673,19 +691,19 @@ keepass.saveKey = function(hash, id, key) { keepass.keyRing[hash].key = key; keepass.keyRing[hash].hash = hash; } - localStorage.keyRing = JSON.stringify(keepass.keyRing); + browser.storage.local.set({'keyRing': keepass.keyRing}); }; keepass.updateLastUsed = function(hash) { if ((hash in keepass.keyRing)) { - keepass.keyRing[hash].lastUsed = new Date(); - localStorage.keyRing = JSON.stringify(keepass.keyRing); + keepass.keyRing[hash].lastUsed = new Date().valueOf(); + browser.storage.local.set({'keyRing': keepass.keyRing}); } }; keepass.deleteKey = function(hash) { delete keepass.keyRing[hash]; - localStorage.keyRing = JSON.stringify(keepass.keyRing); + browser.storage.local.set({'keyRing': keepass.keyRing}); }; keepass.setcurrentKeePassXCVersion = function(version) { @@ -699,7 +717,7 @@ keepass.setcurrentKeePassXCVersion = function(version) { keepass.keePassXCUpdateAvailable = function() { if (page.settings.checkUpdateKeePassXC && page.settings.checkUpdateKeePassXC > 0) { - const lastChecked = (keepass.latestKeePassXC.lastChecked) ? new Date(keepass.latestKeePassXC.lastChecked) : new Date('11/21/1986'); + const lastChecked = (keepass.latestKeePassXC.lastChecked) ? new Date(keepass.latestKeePassXC.lastChecked) : new Date(1986, 11, 21); const daysSinceLastCheck = Math.floor(((new Date()).getTime()-lastChecked.getTime())/86400000); if (daysSinceLastCheck >= page.settings.checkUpdateKeePassXC) { keepass.checkForNewKeePassXCVersion(); @@ -724,7 +742,7 @@ keepass.checkForNewKeePassXCVersion = function() { } if (version !== -1) { - localStorage.latestKeePassXC = JSON.stringify(keepass.latestKeePassXC); + browser.storage.local.set({'latestKeePassXC': keepass.latestKeePassXC}); } }; @@ -739,7 +757,7 @@ keepass.checkForNewKeePassXCVersion = function() { catch (ex) { console.log(ex); } - keepass.latestKeePassXC.lastChecked = new Date(); + keepass.latestKeePassXC.lastChecked = new Date().valueOf(); }; keepass.connectToNative = function() { @@ -749,7 +767,7 @@ keepass.connectToNative = function() { }; keepass.onNativeMessage = function(response) { - //console.log('Received message: ' + JSON.stringify(response)); + console.log('Received message: ' + JSON.stringify(response)); // Handle database lock/unlock status if (response.action === kpActions.DATABASE_LOCKED || response.action === kpActions.DATABASE_UNLOCKED) { diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index d6ee9fc..8e868d3 100644 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -10,50 +10,56 @@ const defaultSettings = { var page = {}; page.tabs = {}; - page.currentTabId = -1; -page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.parse(localStorage.settings); page.blockedTabs = {}; page.initSettings = function() { - kpxcEvent.onLoadSettings(); - if (!('checkUpdateKeePassXC' in page.settings)) { - page.settings.checkUpdateKeePassXC = defaultSettings.checkUpdateKeePassXC; - } - if (!('autoCompleteUsernames' in page.settings)) { - page.settings.autoCompleteUsernames = defaultSettings.autoCompleteUsernames; - } - if (!('autoFillAndSend' in page.settings)) { - page.settings.autoFillAndSend = defaultSettings.autoFillAndSend; - } - if (!('usePasswordGenerator' in page.settings)) { - page.settings.usePasswordGenerator = defaultSettings.usePasswordGenerator; - } - if (!('autoFillSingleEntry' in page.settings)) { - page.settings.autoFillSingleEntry = defaultSettings.autoFillSingleEntry; - } - if (!('autoRetrieveCredentials' in page.settings)) { - page.settings.autoRetrieveCredentials = defaultSettings.autoRetrieveCredentials; - } - if (!('port' in page.settings)) { - page.settings.port = defaultSettings.proxyPort; - } - localStorage.settings = JSON.stringify(page.settings); + return new Promise((resolve, reject) => { + kpxcEvent.onLoadSettings((settings) => { + page.settings = settings; + if (!('checkUpdateKeePassXC' in page.settings)) { + page.settings.checkUpdateKeePassXC = defaultSettings.checkUpdateKeePassXC; + } + if (!('autoCompleteUsernames' in page.settings)) { + page.settings.autoCompleteUsernames = defaultSettings.autoCompleteUsernames; + } + if (!('autoFillAndSend' in page.settings)) { + page.settings.autoFillAndSend = defaultSettings.autoFillAndSend; + } + if (!('usePasswordGenerator' in page.settings)) { + page.settings.usePasswordGenerator = defaultSettings.usePasswordGenerator; + } + if (!('autoFillSingleEntry' in page.settings)) { + page.settings.autoFillSingleEntry = defaultSettings.autoFillSingleEntry; + } + if (!('autoRetrieveCredentials' in page.settings)) { + page.settings.autoRetrieveCredentials = defaultSettings.autoRetrieveCredentials; + } + if (!('port' in page.settings)) { + page.settings.port = defaultSettings.proxyPort; + } + browser.storage.local.set({'settings': page.settings}); + resolve(); + }); + }); }; page.initOpenedTabs = function() { - browser.tabs.query({}).then((tabs) => { - for (const i of tabs) { - page.createTabEntry(i.id); - } - - // set initial tab-ID - browser.tabs.query({ "active": true, "currentWindow": true }).then((tabs) => { - if (tabs.length === 0) { - return; // For example: only the background devtools or a popup are opened + return new Promise((resolve, reject) => { + browser.tabs.query({}).then((tabs) => { + for (const i of tabs) { + page.createTabEntry(i.id); } - page.currentTabId = tabs[0].id; - browserAction.show(null, tabs[0]); + + // set initial tab-ID + browser.tabs.query({ "active": true, "currentWindow": true }).then((tabs) => { + if (tabs.length === 0) { + return; // For example: only the background devtools or a popup are opened + } + page.currentTabId = tabs[0].id; + browserAction.show(null, tabs[0]); + resolve(); + }); }); }); }; diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index af6ecbc..41962ac 100644 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -54,7 +54,7 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) { } else if (req.action === 'redetect_fields') { browser.runtime.sendMessage({ - action: 'get_settings', + action: 'load_settings', }).then((response) => { cip.settings = response.data; cip.initCredentialFields(true); @@ -1109,9 +1109,9 @@ jQuery(function() { cip.init = function() { browser.runtime.sendMessage({ - action: 'get_settings', + action: 'load_settings', }).then((response) => { - cip.settings = response.data; + cip.settings = response; cip.initCredentialFields(); }); }; @@ -1134,7 +1134,7 @@ cip.detectNewActiveFields = function() { // Try to do this in a way that database value if checked without polling the KeePassXC.. too many messages jumping around // Switch credentials if database is changed or closed cip.detectDatabaseChange = function() { - const dbDetectInterval = setInterval(function() { + let dbDetectInterval = setInterval(function() { if (document.visibilityState !== 'hidden') { browser.runtime.sendMessage({ action: 'check_databasehash' @@ -1153,9 +1153,9 @@ cip.detectDatabaseChange = function() { } else { if (response.new !== 'no-hash' && response.new !== response.old) { browser.runtime.sendMessage({ - action: 'get_settings', + action: 'load_settings', }).then((response) => { - cip.settings = response.data; + cip.settings = response; cip.initCredentialFields(true); }); } diff --git a/keepassxc-browser/options/options.js b/keepassxc-browser/options/options.js index 446ccb2..6328a29 100644 --- a/keepassxc-browser/options/options.js +++ b/keepassxc-browser/options/options.js @@ -3,18 +3,21 @@ if (jQuery) { } $(function() { - options.initMenu(); - options.initGeneralSettings(); - options.initConnectedDatabases(); - options.initSpecifiedCredentialFields(); - options.initAbout(); + browser.runtime.sendMessage({ action: 'load_settings' }).then((settings) => { + options.settings = settings; + browser.runtime.sendMessage({ action: 'load_keyring' }).then((keyRing) => { + options.keyRing = keyRing; + options.initMenu(); + options.initGeneralSettings(); + options.initConnectedDatabases(); + options.initSpecifiedCredentialFields(); + options.initAbout(); + }); + }); }); var options = options || {}; -options.settings = typeof(localStorage.settings) === 'undefined' ? {} : JSON.parse(localStorage.settings); -options.keyRing = typeof(localStorage.keyRing) === 'undefined' ? {} : JSON.parse(localStorage.keyRing); - options.initMenu = function() { $('.navbar:first ul.nav:first li a').click(function(e) { e.preventDefault(); @@ -32,22 +35,21 @@ options.saveSetting = function(name) { $($id).closest('.control-group').removeClass('error').addClass('success'); setTimeout(() => { $($id).closest('.control-group').removeClass('success'); }, 2500); - localStorage.settings = JSON.stringify(options.settings); - + browser.storage.local.set({'settings': options.settings}); browser.runtime.sendMessage({ action: 'load_settings' }); }; options.saveSettings = function() { - localStorage.settings = JSON.stringify(options.settings); + browser.storage.local.set({'settings': options.settings}); browser.runtime.sendMessage({ action: 'load_settings' }); }; options.saveKeyRing = function() { - localStorage.keyRing = JSON.stringify(options.keyRing); + browser.storage.local.set({'keyRing': options.keyRing}); browser.runtime.sendMessage({ action: 'load_keyring' }); @@ -107,7 +109,7 @@ options.initGeneralSettings = function() { $('#blinkTimeoutButton').click(function(){ const blinkTimeout = $.trim($('#blinkTimeout').val()); const blinkTimeoutval = Number(blinkTimeout); - + options.settings['blinkTimeout'] = String(blinkTimeoutval); options.saveSetting('blinkTimeout'); }); @@ -115,7 +117,7 @@ options.initGeneralSettings = function() { $('#blinkMinTimeoutButton').click(function(){ const blinkMinTimeout = $.trim($('#blinkMinTimeout').val()); const blinkMinTimeoutval = Number(blinkMinTimeout); - + options.settings['blinkMinTimeout'] = String(blinkMinTimeoutval); options.saveSetting('blinkMinTimeout'); }); @@ -123,7 +125,7 @@ options.initGeneralSettings = function() { $('#allowedRedirectButton').click(function(){ const allowedRedirect = $.trim($('#allowedRedirect').val()); const allowedRedirectval = Number(allowedRedirect); - + options.settings['allowedRedirect'] = String(allowedRedirectval); options.saveSetting('allowedRedirect'); }); From b1ea0b180b9e97173a5bff3c0b368b996297ea6c Mon Sep 17 00:00:00 2001 From: varjolintu Date: Mon, 30 Oct 2017 12:29:38 +0200 Subject: [PATCH 2/5] New sendNativeMessage implementation --- keepassxc-browser/background/event.js | 2 +- keepassxc-browser/background/keepass.js | 107 ++++++++++++------------ 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index d4af4e4..caf36e3 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -148,7 +148,7 @@ kpxcEvent.onReconnect = function(callback, tab) { keepass.testAssociation((response) => { keepass.isConfigured().then((configured) => { kpxcEvent.showStatus(configured, tab, callback); - }); + }).catch((e) => {console.log(e);}); }, tab); } }, null); diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 5b80f13..78cfe98 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -122,9 +122,8 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, nonce: keepass.b64e(nonce), clientID: keepass.clientID }; - console.log(request); - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); if (res) { @@ -140,7 +139,6 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, browserAction.showDefault(null, tab); } }); - keepass.nativePort.postMessage(request); }); }; @@ -186,7 +184,7 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); if (res) { @@ -216,40 +214,47 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb browserAction.showDefault(null, tab); } }); - keepass.nativePort.postMessage(request); }, tab); }; -// Redirects the callback to a listener (handleReply()) -keepass.callbackOnId = function(ev, action, tab, callback, enableTimeout = false) { - let timeout; - let listener = ((port, action) => { - let handler = (msg) => { - if (msg && msg.action === action) { - ev.removeListener(handler); - if (enableTimeout) { - clearTimeout(timeout); - } - callback(msg); - } - }; - return handler; - })(ev, action, tab, callback); - ev.addListener(listener); +keepass.sendNativeMessage = function(request, enableTimeout = false) { + return new Promise((resolve, reject) => { + let timeout; + let action = request.action; + let ev = keepass.nativePort.onMessage; - // Handle timeouts - if (enableTimeout) { - timeout = setTimeout(() => { - const errorMessage = { - action: action, - error: kpErrors.getError(5), - errorCode: 5 + let listener = ((port, action) => { + let handler = (msg) => { + if (msg && msg.action === action) { + port.removeListener(handler); + if (enableTimeout) { + clearTimeout(timeout); + } + resolve(msg); + } }; - keepass.isKeePassXCAvailable = false; - callback(errorMessage); - ev.removeListener(listener.handler); - }, keepass.messageTimeout); - } + return handler; + })(ev, action); + ev.addListener(listener); + + + // Handle timeouts + if (enableTimeout) { + timeout = setTimeout(() => { + const errorMessage = { + action: action, + error: kpErrors.getError(kpErrors.TIMEOUT_OR_NOT_CONNECTED), + errorCode: kpErrors.TIMEOUT_OR_NOT_CONNECTED + }; + keepass.isKeePassXCAvailable = false; + ev.removeListener(listener.handler); + resolve(errorMessage); + }, keepass.messageTimeout); + } + + // Send the request + keepass.nativePort.postMessage(request); + }); }; keepass.generatePassword = function(callback, tab, forceCallback) { @@ -283,10 +288,10 @@ keepass.generatePassword = function(callback, tab, forceCallback) { clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (res) { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); keepass.setcurrentKeePassXCVersion(parsed.version); @@ -310,7 +315,6 @@ keepass.generatePassword = function(callback, tab, forceCallback) { keepass.handleError(tab, response.errorCode, response.error); } }); - keepass.nativePort.postMessage(request); }, tab); }; @@ -344,7 +348,7 @@ keepass.associate = function(callback, tab) { clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); if (res) { @@ -369,7 +373,6 @@ keepass.associate = function(callback, tab) { keepass.handleError(tab, response.errorCode, response.error); } }); - keepass.nativePort.postMessage(request); }, tab); }; @@ -427,7 +430,7 @@ keepass.testAssociation = function(callback, tab, enableTimeout = false) { clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request, enableTimeout).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); if (res) { @@ -459,7 +462,6 @@ keepass.testAssociation = function(callback, tab, enableTimeout = false) { } callback(keepass.isAssociated()); }); - keepass.nativePort.postMessage(request); }, tab, enableTimeout); }; @@ -495,7 +497,7 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) { clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request, enableTimeout).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); if (res) { @@ -536,8 +538,7 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) { } callback(keepass.databaseHash); } - }, enableTimeout); - keepass.nativePort.postMessage(request); + }); }; keepass.changePublicKeys = function(tab, callback) { @@ -552,7 +553,7 @@ keepass.changePublicKeys = function(tab, callback) { nonce = keepass.b64e(nonce); keepass.clientID = keepass.b64e(nacl.randomBytes(keepass.keySize)); - const message = { + const request = { action: kpAction, publicKey: key, proxyPort: (page.settings.port ? page.settings.port : 19700), @@ -560,7 +561,7 @@ keepass.changePublicKeys = function(tab, callback) { clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request).then((response) => { keepass.setcurrentKeePassXCVersion(response.version); if (!keepass.verifyKeyResponse(response, key, nonce)) { @@ -575,7 +576,6 @@ keepass.changePublicKeys = function(tab, callback) { } callback(true); }); - keepass.nativePort.postMessage(message); }; keepass.lockDatabase = function(callback, tab, forceCallback) { @@ -599,7 +599,7 @@ keepass.lockDatabase = function(callback, tab, forceCallback) { clientID: keepass.clientID }; - keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, tab, (response) => { + keepass.sendNativeMessage(request).then((response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); if (res) { @@ -619,7 +619,6 @@ keepass.lockDatabase = function(callback, tab, forceCallback) { } callback(false); }); - keepass.nativePort.postMessage(request); }; keepass.generateNewKeyPair = function() { @@ -651,7 +650,7 @@ keepass.migrateKeyRing = function() { return new Promise((resolve, reject) => { browser.storage.local.get('keyRing').then((item) => { const keyring = item.keyRing; - // change dates to numbers, for compatibilty with chrome + // Change dates to numbers, for compatibilty with Chromium based browsers if (keyring) { let num = 0; for (let keyHash in keyring) { @@ -761,18 +760,22 @@ keepass.checkForNewKeePassXCVersion = function() { }; keepass.connectToNative = function() { - if (!keepass.isConnected) { + /*if (!keepass.isConnected) { keepass.nativeConnect(); + }*/ + if (keepass.nativePort) { + keepass.nativePort.disconnect(); } + keepass.nativeConnect(); }; keepass.onNativeMessage = function(response) { - console.log('Received message: ' + JSON.stringify(response)); + //console.log('Received message: ' + JSON.stringify(response)); // Handle database lock/unlock status if (response.action === kpActions.DATABASE_LOCKED || response.action === kpActions.DATABASE_UNLOCKED) { keepass.testAssociation((response) => { - keepass.isConfigured((configured) => { + keepass.isConfigured().then((configured) => { let data = page.tabs[page.currentTabId].stack[page.tabs[page.currentTabId].stack.length - 1]; data.iconType = configured ? 'normal' : 'cross'; browserAction.show(null, {'id': page.currentTabId}); From b94e0f33e79f7b0505547f7381ad15de7be2b2f3 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Mon, 30 Oct 2017 13:48:45 +0200 Subject: [PATCH 3/5] Database locking fixes --- keepassxc-browser/background/event.js | 6 +- keepassxc-browser/background/init.js | 2 +- keepassxc-browser/background/keepass.js | 133 ++++++++++++------------ 3 files changed, 72 insertions(+), 69 deletions(-) diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index caf36e3..666ad07 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -142,7 +142,7 @@ kpxcEvent.onReconnect = function(callback, tab) { // Add a small timeout after reconnecting. Just to make sure. It's not pretty, I know :( setTimeout(() => { keepass.generateNewKeyPair(); - keepass.changePublicKeys(tab, (pkRes) => { + keepass.changePublicKeys(tab).then((pkRes) => { keepass.getDatabaseHash((gdRes) => { if (gdRes) { keepass.testAssociation((response) => { @@ -157,9 +157,9 @@ kpxcEvent.onReconnect = function(callback, tab) { }; kpxcEvent.lockDatabase = function(callback, tab) { - keepass.lockDatabase((response) => { + keepass.lockDatabase(tab).then((response => { kpxcEvent.showStatus(true, tab, callback); - }, tab); + })); }; kpxcEvent.onPopStack = function(callback, tab) { diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index fa369a9..127f4d6 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -3,7 +3,7 @@ keepass.migrateKeyRing().then(() => { page.initOpenedTabs().then(() => { keepass.connectToNative(); keepass.generateNewKeyPair(); - keepass.changePublicKeys(null, (pkRes) => { + keepass.changePublicKeys(null, keepass.messageTimeout).then((pkRes) => { keepass.getDatabaseHash((gdRes) => {}, null); }); }); diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 78cfe98..568245f 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -473,7 +473,7 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) { } if (!keepass.serverPublicKey) { - keepass.changePublicKeys(tab, null); + keepass.changePublicKeys(tab); } const kpAction = kpActions.GET_DATABASE_HASH; @@ -529,8 +529,8 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) { else { keepass.databaseHash = 'no-hash'; keepass.isDatabaseClosed = true; - keepass.isKeePassXCAvailable = false; - if (response.message === "") { + if (response.message === '') { + keepass.isKeePassXCAvailable = false; keepass.handleError(tab, kpErrors.TIMEOUT_OR_NOT_CONNECTED); } else { @@ -541,83 +541,86 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) { }); }; -keepass.changePublicKeys = function(tab, callback) { - if (!keepass.isConnected) { - callback([]); - return; - } +keepass.changePublicKeys = function(tab, enableTimeout = false) { + return new Promise((resolve, reject) => { + if (!keepass.isConnected) { + reject(false); + } - const kpAction = kpActions.CHANGE_PUBLIC_KEYS; - const key = keepass.b64e(keepass.keyPair.publicKey); - let nonce = nacl.randomBytes(keepass.keySize); - nonce = keepass.b64e(nonce); - keepass.clientID = keepass.b64e(nacl.randomBytes(keepass.keySize)); + const kpAction = kpActions.CHANGE_PUBLIC_KEYS; + const key = keepass.b64e(keepass.keyPair.publicKey); + let nonce = nacl.randomBytes(keepass.keySize); + nonce = keepass.b64e(nonce); + keepass.clientID = keepass.b64e(nacl.randomBytes(keepass.keySize)); - const request = { - action: kpAction, - publicKey: key, - proxyPort: (page.settings.port ? page.settings.port : 19700), - nonce: nonce, - clientID: keepass.clientID - }; + const request = { + action: kpAction, + publicKey: key, + proxyPort: (page.settings.port ? page.settings.port : 19700), + nonce: nonce, + clientID: keepass.clientID + }; - keepass.sendNativeMessage(request).then((response) => { - keepass.setcurrentKeePassXCVersion(response.version); + keepass.sendNativeMessage(request, enableTimeout).then((response) => { + keepass.setcurrentKeePassXCVersion(response.version); - if (!keepass.verifyKeyResponse(response, key, nonce)) { - if (tab && page.tabs[tab.id]) { - keepass.handleError(tab, kpErrors.KEY_CHANGE_FAILED); - callback(false); + if (!keepass.verifyKeyResponse(response, key, nonce)) { + if (tab && page.tabs[tab.id]) { + keepass.handleError(tab, kpErrors.KEY_CHANGE_FAILED); + reject(false); + } } - } - else { - keepass.isKeePassXCAvailable = true; - console.log('Server public key: ' + keepass.b64e(keepass.serverPublicKey)); - } - callback(true); + else { + keepass.isKeePassXCAvailable = true; + console.log('Server public key: ' + keepass.b64e(keepass.serverPublicKey)); + } + resolve(true); + }); }); }; -keepass.lockDatabase = function(callback, tab, forceCallback) { - if (!keepass.isConnected) { - keepass.handleError(tab, kpErrors.TIMEOUT_OR_NOT_CONNECTED); - callback([]); - return; - } +keepass.lockDatabase = function(tab) { + return new Promise((resolve, reject) => { + if (!keepass.isConnected) { + keepass.handleError(tab, kpErrors.TIMEOUT_OR_NOT_CONNECTED); + reject(false); + } - const kpAction = kpActions.LOCK_DATABASE; - const nonce = nacl.randomBytes(keepass.keySize); + const kpAction = kpActions.LOCK_DATABASE; + const nonce = nacl.randomBytes(keepass.keySize); - const messageData = { - action: kpAction - }; + const messageData = { + action: kpAction + }; - const request = { - action: kpAction, - message: keepass.encrypt(messageData, nonce), - nonce: keepass.b64e(nonce), - clientID: keepass.clientID - }; + const request = { + action: kpAction, + message: keepass.encrypt(messageData, nonce), + nonce: keepass.b64e(nonce), + clientID: keepass.clientID + }; - keepass.sendNativeMessage(request).then((response) => { - if (response.message && response.nonce) { - const res = keepass.decrypt(response.message, response.nonce); - if (res) { - const message = nacl.util.encodeUTF8(res); - const parsed = JSON.parse(message); - keepass.setcurrentKeePassXCVersion(parsed.version); + keepass.sendNativeMessage(request).then((response) => { + if (response.message && response.nonce) { + const res = keepass.decrypt(response.message, response.nonce); + if (res) { + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); + keepass.setcurrentKeePassXCVersion(parsed.version); - if (keepass.verifyResponse(parsed, response.nonce)) { - keepass.isDatabaseClosed = true; - keepass.handleError(tab, kpErrors.DATABASE_NOT_OPENED); - callback(false); + if (keepass.verifyResponse(parsed, response.nonce)) { + keepass.isDatabaseClosed = true; + keepass.handleError(tab, kpErrors.DATABASE_NOT_OPENED); + resolve(false); + } } } - } - else if (response.error && response.errorCode) { - keepass.handleError(tab, response.errorCode, response.error); - } - callback(false); + else if (response.error && response.errorCode) { + keepass.isDatabaseClosed = true; + keepass.handleError(tab, response.errorCode, response.error); + } + resolve(false); + }); }); }; From 192e64746520e694e81ed3754fe5cfce1feea195 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Mon, 30 Oct 2017 14:43:24 +0200 Subject: [PATCH 4/5] Small fixes --- keepassxc-browser/background/keepass.js | 85 ++++++++++++------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 568245f..d5294bf 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -83,6 +83,48 @@ browser.storage.local.get({ keepass.keyRing = item.keyRing; }); +keepass.sendNativeMessage = function(request, enableTimeout = false) { + return new Promise((resolve, reject) => { + let timeout; + let action = request.action; + let ev = keepass.nativePort.onMessage; + + let listener = ((port, action) => { + let handler = (msg) => { + if (msg && msg.action === action) { + port.removeListener(handler); + if (enableTimeout) { + clearTimeout(timeout); + } + resolve(msg); + } + }; + return handler; + })(ev, action); + ev.addListener(listener); + + + // Handle timeouts + if (enableTimeout) { + timeout = setTimeout(() => { + const errorMessage = { + action: action, + error: kpErrors.getError(kpErrors.TIMEOUT_OR_NOT_CONNECTED), + errorCode: kpErrors.TIMEOUT_OR_NOT_CONNECTED + }; + keepass.isKeePassXCAvailable = false; + ev.removeListener(listener.handler); + resolve(errorMessage); + }, keepass.messageTimeout); + } + + // Send the request + if (keepass.nativePort) { + keepass.nativePort.postMessage(request); + } + }); +}; + keepass.addCredentials = function(callback, tab, username, password, url) { keepass.updateCredentials(callback, tab, null, username, password, url); }; @@ -217,46 +259,6 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb }, tab); }; -keepass.sendNativeMessage = function(request, enableTimeout = false) { - return new Promise((resolve, reject) => { - let timeout; - let action = request.action; - let ev = keepass.nativePort.onMessage; - - let listener = ((port, action) => { - let handler = (msg) => { - if (msg && msg.action === action) { - port.removeListener(handler); - if (enableTimeout) { - clearTimeout(timeout); - } - resolve(msg); - } - }; - return handler; - })(ev, action); - ev.addListener(listener); - - - // Handle timeouts - if (enableTimeout) { - timeout = setTimeout(() => { - const errorMessage = { - action: action, - error: kpErrors.getError(kpErrors.TIMEOUT_OR_NOT_CONNECTED), - errorCode: kpErrors.TIMEOUT_OR_NOT_CONNECTED - }; - keepass.isKeePassXCAvailable = false; - ev.removeListener(listener.handler); - resolve(errorMessage); - }, keepass.messageTimeout); - } - - // Send the request - keepass.nativePort.postMessage(request); - }); -}; - keepass.generatePassword = function(callback, tab, forceCallback) { if (!keepass.isConnected) { callback([]); @@ -763,9 +765,6 @@ keepass.checkForNewKeePassXCVersion = function() { }; keepass.connectToNative = function() { - /*if (!keepass.isConnected) { - keepass.nativeConnect(); - }*/ if (keepass.nativePort) { keepass.nativePort.disconnect(); } From 08b8b0e252ab063c621a6d11048d3673c49af2b1 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Tue, 31 Oct 2017 19:05:36 +0200 Subject: [PATCH 5/5] More minor fixes --- CHANGELOG | 5 +++++ keepassxc-browser/background/event.js | 4 ++-- keepassxc-browser/background/keepass.js | 5 ++--- keepassxc-browser/manifest.json | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fa98f6f..c5d27b6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +0.3.8 (??-??-2017) +========================= +- Use browser.local.storage instead of localStorage +- Switched some functions to promise + 0.3.7 (22-10-2017) ========================= - Improved credentials check (does not use protocol requests for polling) diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index 666ad07..bf9b5d2 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -181,9 +181,9 @@ kpxcEvent.onGetConnectedDatabase = function(callback, tab) { kpxcEvent.onGetKeePassXCVersions = function(callback, tab) { if(keepass.currentKeePassXC.version == 0) { - keepass.getDatabaseHash(tab).then(() => { + keepass.getDatabaseHash((res) => { callback({"current": keepass.currentKeePassXC.version, "latest": keepass.currentKeePassXC.version}); - }); + }, tab); } else { callback({"current": keepass.currentKeePassXC.version, "latest": keepass.currentKeePassXC.version}); } diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index d5294bf..0134883 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -18,7 +18,6 @@ keepass.keySize = 24; keepass.latestVersionUrl = 'https://api.github.com/repos/keepassxreboot/keepassxc/releases/latest'; keepass.cacheTimeout = 30 * 1000; // milliseconds keepass.databaseHash = 'no-hash'; //no-hash = KeePassXC is too old and does not return a hash value -keepass.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing); keepass.keyId = 'keepassxc-browser-cryptokey-name'; keepass.keyBody = 'keepassxc-browser-key'; keepass.messageTimeout = 500; // milliseconds @@ -633,8 +632,8 @@ keepass.generateNewKeyPair = function() { keepass.isConfigured = function() { return new Promise((resolve, reject) => { - if (typeof(keepass.databaseHash) === 'undefined') { - keepass.getDatabaseHash().then((hash) => { + if (typeof(keepass.databaseHash) === 'undefined' || keepass.databaseHash === 'no-hash') { + keepass.getDatabaseHash((hash) => { resolve(hash in keepass.keyRing); }); } else { diff --git a/keepassxc-browser/manifest.json b/keepassxc-browser/manifest.json index 9d8273b..0ae891e 100644 --- a/keepassxc-browser/manifest.json +++ b/keepassxc-browser/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "keepassxc-browser", - "version": "0.3.7", + "version": "0.3.8", "description": "KeePassXC integration for modern web browsers", "author": "Sami Vänttinen", "icons": {