diff --git a/CHANGELOG b/CHANGELOG index 4613414..3e638bd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +0.2.4 (2017-07-11) +========================= +- Changed comparison operators to strict ones (and some code cleaning) +- Copy and Fill & copy buttons are now hidden when Password Generator has an error +- Fix to a bug when reconnecting to KeePassXC (sometimes public keys are changed too quickly) +- Fix for password generator (error is now shown immediately instead of a blank dialog) +- Use a single password generator icon + 0.2.3 (2017-07-05) ========================= - Fixed a few variables diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index ce73871..75bef16 100644 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -22,28 +22,28 @@ browserAction.show = function(callback, tab) { browser.browserAction.setIcon({ tabId: tab.id, - path: "/icons/19x19/" + browserAction.generateIconName(data.iconType, data.icon) + path: '/icons/19x19/' + browserAction.generateIconName(data.iconType, data.icon) }); if (data.popup) { browser.browserAction.setPopup({ tabId: tab.id, - popup: "popups/" + data.popup + popup: 'popups/' + data.popup }); } } browserAction.update = function(interval) { - if (!page.tabs[page.currentTabId] || page.tabs[page.currentTabId].stack.length == 0) { + if (!page.tabs[page.currentTabId] || page.tabs[page.currentTabId].stack.length === 0) { return; } let data = page.tabs[page.currentTabId].stack[page.tabs[page.currentTabId].stack.length - 1]; - if (typeof data.visibleForMilliSeconds != "undefined") { + if (typeof data.visibleForMilliSeconds !== 'undefined') { if (data.visibleForMilliSeconds <= 0) { browserAction.stackPop(page.currentTabId); - browserAction.show(null, {"id": page.currentTabId}); + browserAction.show(null, {'id': page.currentTabId}); page.clearCredentials(page.currentTabId); return; } @@ -65,7 +65,7 @@ browserAction.update = function(interval) { browser.browserAction.setIcon({ tabId: page.currentTabId, - path: "/icons/19x19/" + browserAction.generateIconName(null, data.intervalIcon.icons[data.intervalIcon.index]) + path: '/icons/19x19/' + browserAction.generateIconName(null, data.intervalIcon.icons[data.intervalIcon.index]) }); } } @@ -73,17 +73,17 @@ browserAction.update = function(interval) { browserAction.showDefault = function(callback, tab) { let stackData = { level: 1, - iconType: "normal", - popup: "popup.html" + iconType: 'normal', + popup: 'popup.html' } keepass.isConfigured((response) => { if (!response || keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable || page.tabs[tab.id].errorMessage) { - stackData.iconType = "cross"; + stackData.iconType = 'cross'; } if (page.tabs[tab.id].loginList.length > 0) { - stackData.iconType = "questionmark"; - stackData.popup = "popup_login.html"; + stackData.iconType = 'questionmark'; + stackData.popup = 'popup_login.html'; } browserAction.stackUnshift(stackData, tab.id); @@ -99,8 +99,8 @@ browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visib } let stackData = { - "level": level, - "icon": icon + level: level, + icon: icon } if (popup) { @@ -127,7 +127,7 @@ browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visib } if (!dontShow) { - browserAction.show(null, {"id": id}); + browserAction.show(null, {'id': id}); } } @@ -138,19 +138,19 @@ browserAction.removeLevelFromStack = function(callback, tab, level, type, dontSh } if (!type) { - type = "<="; + type = '<='; } let newStack = []; for (const i of page.tabs[tab.id].stack) { if ( - (type == "<" && i.level >= level) || - (type == "<=" && i.level > level) || - (type == "=" && i.level != level) || - (type == "==" && i.level != level) || - (type == "!=" && i.level == level) || - (type == ">" && i.level <= level) || - (type == ">=" && i.level < level) + (type == '<' && i.level >= level) || + (type == '<=' && i.level > level) || + (type == '=' && i.level != level) || + (type == '==' && i.level != level) || + (type == '!=' && i.level == level) || + (type == '>' && i.level <= level) || + (type == '>=' && i.level < level) ) { newStack.push(i); } @@ -170,13 +170,13 @@ browserAction.stackPop = function(tabId) { browserAction.stackPush = function(data, tabId) { const id = tabId || page.currentTabId; - browserAction.removeLevelFromStack(null, {"id": id}, data.level, "<=", true); + browserAction.removeLevelFromStack(null, {'id': id}, data.level, '<=', true); page.tabs[id].stack.push(data); }; browserAction.stackUnshift = function(data, tabId) { const id = tabId || page.currentTabId; - browserAction.removeLevelFromStack(null, {"id": id}, data.level, "<=", true); + browserAction.removeLevelFromStack(null, {'id': id}, data.level, '<=', true); page.tabs[id].stack.unshift(data); }; @@ -207,16 +207,16 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) { }; browserAction.setRememberPopup = function(tabId, username, password, url, usernameExists, credentialsList) { - const settings = typeof(localStorage.settings)=='undefined' ? {} : JSON.parse(localStorage.settings); + const settings = typeof(localStorage.settings) === 'undefined' ? {} : JSON.parse(localStorage.settings); const id = tabId || page.currentTabId; - var timeoutMinMillis = parseInt(getValueOrDefault(settings, "blinkMinTimeout", BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT, 0)); + let timeoutMinMillis = Number(getValueOrDefault(settings, 'blinkMinTimeout', BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT, 0)); if (timeoutMinMillis > 0) { timeoutMinMillis += Date.now(); } - const blinkTimeout = getValueOrDefault(settings, "blinkTimeout", BLINK_TIMEOUT_DEFAULT, 0); - const pageUpdateAllowance = getValueOrDefault(settings, "allowedRedirect", BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT, 0); + const blinkTimeout = getValueOrDefault(settings, 'blinkTimeout', BLINK_TIMEOUT_DEFAULT, 0); + const pageUpdateAllowance = getValueOrDefault(settings, 'allowedRedirect', BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT, 0); const stackData = { visibleForMilliSeconds: blinkTimeout, @@ -227,23 +227,23 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna index: 0, counter: 0, max: 2, - icons: ["icon_remember_red_background_19x19.png", "icon_remember_red_lock_19x19.png"] + icons: ['icon_remember_red_background_19x19.png', 'icon_remember_red_lock_19x19.png'] }, - icon: "icon_remember_red_background_19x19.png", - popup: "popup_remember.html" + icon: 'icon_remember_red_background_19x19.png', + popup: 'popup_remember.html' } browserAction.stackPush(stackData, id); page.tabs[id].credentials = { - "username": username, - "password": password, - "url": url, - "usernameExists": usernameExists, - "list": credentialsList + username: username, + password: password, + url: url, + usernameExists: usernameExists, + list: credentialsList }; - browserAction.show(null, {"id": id}); + browserAction.show(null, {'id': id}); } function getValueOrDefault(settings, key, defaultVal, min) { @@ -261,10 +261,10 @@ browserAction.generateIconName = function(iconType, icon) { return icon; } - let name = "icon_"; - name += (keepass.keePassXCUpdateAvailable()) ? "new_" : ""; - name += (!iconType || iconType == "normal") ? "normal" : iconType; - name += "_19x19.png"; + let name = 'icon_'; + name += (keepass.keePassXCUpdateAvailable()) ? 'new_' : ''; + name += (!iconType || iconType === 'normal') ? 'normal' : iconType; + name += '_19x19.png'; return name; } \ No newline at end of file diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index 35d8834..df48312 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -9,7 +9,6 @@ var event = {}; event.onMessage = function(request, sender, callback) { if (request.action in event.messageHandlers) { //console.log("onMessage(" + request.action + ") for #" + sender.tab.id); - if (!sender.hasOwnProperty('tab') || sender.tab.id < 1) { sender.tab = {}; sender.tab.id = page.currentTabId; @@ -82,7 +81,7 @@ event.invoke = function(handler, callback, senderTabId, args, secondTime) { handler.apply(this, args); } else { - console.log("undefined handler for tab " + tab.id); + console.log('undefined handler for tab ' + tab.id); } }); } @@ -94,15 +93,15 @@ event.onShowAlert = function(callback, tab, message) { } event.onLoadSettings = function(callback, tab) { - page.settings = (typeof(localStorage.settings) == 'undefined') ? {} : JSON.parse(localStorage.settings); + page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.parse(localStorage.settings); } event.onLoadKeyRing = function(callback, tab) { - keepass.keyRing = (typeof(localStorage.keyRing) == 'undefined') ? {} : JSON.parse(localStorage.keyRing); + keepass.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing); if (keepass.isAssociated() && !keepass.keyRing[keepass.associated.hash]) { keepass.associated = { - "value": false, - "hash": null + value: false, + hash: null }; } } @@ -120,14 +119,13 @@ event.onSaveSettings = function(callback, tab, settings) { event.onGetStatus = function(callback, tab) { keepass.testAssociation((response) => { keepass.isConfigured((configured) => { - var keyId = null; + let keyId = null; if (configured) { keyId = keepass.keyRing[keepass.databaseHash].id; } browserAction.showDefault(null, tab); console.log(page.tabs[tab.id].errorMessage); - console.log("Configured: " + configured + " Key id: " + keyId + " closed: " + keepass.isDatabaseClosed + " avail: " + keepass.isKeePassXCAvailable + " unreg: " + keepass.isEncryptionKeyUnrecognized + " isass: " + keepass.isAssociated()); callback({ identifier: keyId, configured: configured, @@ -143,33 +141,37 @@ event.onGetStatus = function(callback, tab) { event.onReconnect = function(callback, tab) { keepass.connectToNative(); - keepass.generateNewKeyPair(); - keepass.changePublicKeys(null, (pkRes) => { - keepass.getDatabaseHash((gdRes) => { - if (gdRes) { - keepass.testAssociation((response) => { - keepass.isConfigured((configured) => { - var keyId = null; - if (configured) { - keyId = keepass.keyRing[keepass.databaseHash].id; - } - browserAction.showDefault(null, tab); - console.log(page.tabs[tab.id].errorMessage); - callback({ - identifier: keyId, - configured: configured, - databaseClosed: keepass.isDatabaseClosed, - keePassXCAvailable: keepass.isKeePassXCAvailable, - encryptionKeyUnrecognized: keepass.isEncryptionKeyUnrecognized, - associated: keepass.isAssociated(), - error: page.tabs[tab.id].errorMessage - }); - }); - }, tab); - } - }, null); - }); + // Add a small timeout after reconnecting. Just to make sure. It's not pretty, I know :( + setTimeout(() => { + keepass.generateNewKeyPair(); + keepass.changePublicKeys(tab, (pkRes) => { + keepass.getDatabaseHash((gdRes) => { + if (gdRes) { + keepass.testAssociation((response) => { + keepass.isConfigured((configured) => { + let keyId = null; + if (configured) { + keyId = keepass.keyRing[keepass.databaseHash].id; + } + + browserAction.showDefault(null, tab); + console.log(page.tabs[tab.id].errorMessage); + callback({ + identifier: keyId, + configured: configured, + databaseClosed: keepass.isDatabaseClosed, + keePassXCAvailable: keepass.isKeePassXCAvailable, + encryptionKeyUnrecognized: keepass.isEncryptionKeyUnrecognized, + associated: keepass.isAssociated(), + error: page.tabs[tab.id].errorMessage + }); + }); + }, tab); + } + }, null); + }); + }, 2000); } event.onPopStack = function(callback, tab) { @@ -184,23 +186,23 @@ event.onGetTabInformation = function(callback, tab) { event.onGetConnectedDatabase = function(callback, tab) { callback({ - "count": Object.keys(keepass.keyRing).length, - "identifier": (keepass.keyRing[keepass.associated.hash]) ? keepass.keyRing[keepass.associated.hash].id : null + count: Object.keys(keepass.keyRing).length, + identifier: (keepass.keyRing[keepass.associated.hash]) ? keepass.keyRing[keepass.associated.hash].id : null }); } event.onGetKeePassXCVersions = function(callback, tab) { - if (keepass.currentKeePassXC.version == 0) { + if (keepass.currentKeePassXC.version === 0) { keepass.getDatabaseHash((response) => { - callback({"current": keepass.currentKeePassXC.version, "latest": keepass.latestKeePassXC.version}); + callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); }, tab); } - callback({"current": keepass.currentKeePassXC.version, "latest": keepass.latestKeePassXC.version}); + callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); } event.onCheckUpdateKeePassXC = function(callback, tab) { keepass.checkForNewKeePassXCVersion(); - callback({"current": keepass.currentKeePassXC.version, "latest": keepass.latestKeePassXC.version}); + callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); } event.onUpdateAvailableKeePassXC = function(callback, tab) { @@ -219,8 +221,8 @@ event.onSetRememberPopup = function(callback, tab, username, password, url, user event.onLoginPopup = function(callback, tab, logins) { let stackData = { level: 1, - iconType: "questionmark", - popup: "popup_login.html" + iconType: 'questionmark', + popup: 'popup_login.html' } browserAction.stackUnshift(stackData, tab.id); page.tabs[tab.id].loginList = logins; @@ -230,8 +232,8 @@ event.onLoginPopup = function(callback, tab, logins) { event.onHTTPAuthPopup = function(callback, tab, data) { let stackData = { level: 1, - iconType: "questionmark", - popup: "popup_httpauth.html" + iconType: 'questionmark', + popup: 'popup_httpauth.html' } browserAction.stackUnshift(stackData, tab.id); page.tabs[tab.id].loginList = data; @@ -241,8 +243,8 @@ event.onHTTPAuthPopup = function(callback, tab, data) { event.onMultipleFieldsPopup = function(callback, tab) { let stackData = { level: 1, - iconType: "normal", - popup: "popup_multiple-fields.html" + iconType: 'normal', + popup: 'popup_multiple-fields.html' } browserAction.stackUnshift(stackData, tab.id); browserAction.show(null, tab); diff --git a/keepassxc-browser/background/httpauth.js b/keepassxc-browser/background/httpauth.js index bd7223d..065f362 100644 --- a/keepassxc-browser/background/httpauth.js +++ b/keepassxc-browser/background/httpauth.js @@ -1,7 +1,7 @@ var httpAuth = httpAuth || {}; httpAuth.pendingCallbacks = []; -httpAuth.requestId = ""; +httpAuth.requestId = ''; httpAuth.callback = null; httpAuth.tabId = 0; httpAuth.url = null; @@ -34,16 +34,16 @@ httpAuth.processPendingCallbacks = function(details) { // but in background.js only tab.id is used. To get tabs we could use // chrome.tabs.get(tabId, callback) <-- but what should callback be? - var url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url; + const url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url; - keepass.retrieveCredentials(httpAuth.loginOrShowCredentials, { "id" : details.tabId }, url, url, true); + keepass.retrieveCredentials(httpAuth.loginOrShowCredentials, { 'id' : details.tabId }, url, url, true); } httpAuth.loginOrShowCredentials = function(logins) { // at least one login found --> use first to login if (logins.length > 0) { - var url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url; - event.onHTTPAuthPopup(null, {"id": httpAuth.tabId}, {"logins": logins, "url": url}); + const url = (httpAuth.isProxy && httpAuth.proxyUrl) ? httpAuth.proxyUrl : httpAuth.url; + event.onHTTPAuthPopup(null, {'id': httpAuth.tabId}, {'logins': logins, 'url': url}); //generate popup-list for HTTP Auth usernames + descriptions if (page.settings.autoFillAndSend) { diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index e222519..c2f1150 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -1,10 +1,6 @@ -// since version 2.0 the extension is using a keyRing instead of a single key-name-pair keepass.convertKeyToKeyRing(); -// load settings page.initSettings(); -// create tab information structure for every opened tab page.initOpenedTabs(); -// initial connection with KeePassXC keepass.connectToNative(); keepass.generateNewKeyPair(); keepass.changePublicKeys(null, (pkRes) => { @@ -17,8 +13,8 @@ window.browser = (function () { window.chrome; })(); -// set initial tab-ID -browser.tabs.query({"active": true, "windowId": browser.windows.WINDOW_ID_CURRENT}, (tabs) => { +// Set initial tab-ID +browser.tabs.query({'active': true, 'windowId': browser.windows.WINDOW_ID_CURRENT}, (tabs) => { if (tabs.length === 0) return; // For example: only the background devtools or a popup are opened page.currentTabId = tabs[0].id; @@ -49,7 +45,7 @@ browser.tabs.onCreated.addListener((tab) => { */ browser.tabs.onRemoved.addListener((tabId, removeInfo) => { delete page.tabs[tabId]; - if (page.currentTabId == tabId) { + if (page.currentTabId === tabId) { page.currentTabId = -1; } }); @@ -62,13 +58,13 @@ browser.tabs.onRemoved.addListener((tabId, removeInfo) => { browser.tabs.onActivated.addListener((activeInfo) => { // remove possible credentials from old tab information page.clearCredentials(page.currentTabId, true); - browserAction.removeRememberPopup(null, {"id": page.currentTabId}, true); + browserAction.removeRememberPopup(null, {'id': page.currentTabId}, true); browser.tabs.get(activeInfo.tabId, (info) => { //console.log(info.id + ": " + info.url); if (info && info.id) { page.currentTabId = info.id; - if (info.status == "complete") { + if (info.status === 'complete') { //console.log("event.invoke(page.switchTab, null, "+info.id + ", []);"); event.invoke(page.switchTab, null, info.id, []); } @@ -82,101 +78,58 @@ browser.tabs.onActivated.addListener((activeInfo) => { * @param {object} changeInfo */ browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - if (changeInfo.status == "complete") { + if (changeInfo.status === 'complete') { event.invoke(browserAction.removeRememberPopup, null, tabId, []); } }); - -/** - * Retrieve Credentials and try auto-login for HTTPAuth requests - */ +// Retrieve Credentials and try auto-login for HTTPAuth requests browser.webRequest.onAuthRequired.addListener(httpAuth.handleRequest, - { urls: [""] }, ["asyncBlocking"] + { urls: [''] }, ['asyncBlocking'] ); -/** - * Interaction between background-script and front-script - */ browser.runtime.onMessage.addListener(event.onMessage); +const contextMenuItems = [ + {title: 'Fill &User + Pass', action: 'fill_user_pass'}, + {title: 'Fill &Pass Only', action: 'fill_pass_only'}, + {title: 'Show Password &Generator Icons', action: 'activate_password_generator'}, + {title: '&Save credentials', action: 'remember_credentials'} +] -/** - * Add context menu entry for filling in username + password - */ -browser.contextMenus.create({ - "title": "Fill &User + Pass", - "contexts": [ "editable" ], - "onclick": function(info, tab) { - browser.tabs.sendMessage(tab.id, { - action: "fill_user_pass" - }); - } -}); +// Create context menu items +for (const item of contextMenuItems) { + browser.contextMenus.create({ + title: item.title, + contexts: [ 'editable' ], + onclick: (info, tab) => { + browser.tabs.sendMessage(tab.id, { + action: item.action + }); + } + }); +} -/** - * Add context menu entry for filling in only password which matches for given username - */ -browser.contextMenus.create({ - "title": "Fill &Pass Only", - "contexts": [ "editable" ], - "onclick": function(info, tab) { - browser.tabs.sendMessage(tab.id, { - action: "fill_pass_only" - }); - } -}); - -/** - * Add context menu entry for creating icon for generate-password dialog - */ -browser.contextMenus.create({ - "title": "Show Password &Generator Icons", - "contexts": [ "editable" ], - "onclick": function(info, tab) { - browser.tabs.sendMessage(tab.id, { - action: "activate_password_generator" - }); - } -}); - -/** - * Add context menu entry for creating icon for generate-password dialog - */ -browser.contextMenus.create({ - "title": "&Save credentials", - "contexts": [ "editable" ], - "onclick": function(info, tab) { - browser.tabs.sendMessage(tab.id, { - action: "remember_credentials" - }); - } -}); - -/** - * Listen for keyboard shortcuts specified by user - */ +// Listen for keyboard shortcuts specified by user browser.commands.onCommand.addListener((command) => { - if (command === "fill-username-password") { + if (command === 'fill-username-password') { browser.tabs.query({ active: true, currentWindow: true }, (tabs) => { if (tabs.length) { - browser.tabs.sendMessage(tabs[0].id, { action: "fill_user_pass" }); + browser.tabs.sendMessage(tabs[0].id, { action: 'fill_user_pass' }); } }); } - if (command === "fill-password") { + if (command === 'fill-password') { browser.tabs.query({ active: true, currentWindow: true }, (tabs) => { if (tabs.length) { - browser.tabs.sendMessage(tabs[0].id, { action: "fill_pass_only" }); + browser.tabs.sendMessage(tabs[0].id, { action: 'fill_pass_only' }); } }); } }); -/** - * Interval which updates the browserAction (e.g. blinking icon) - */ +// Interval which updates the browserAction (e.g. blinking icon) window.setInterval(function() { browserAction.update(_interval); }, _interval); \ No newline at end of file diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 696609e..4ce6be0 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -1,24 +1,24 @@ var keepass = {}; -keepass.associated = {"value": false, "hash": null}; +keepass.associated = {'value': false, 'hash': null}; keepass.keyPair = {publicKey: null, secretKey: null}; -keepass.serverPublicKey = ""; +keepass.serverPublicKey = ''; keepass.isConnected = false; 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.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.nativeHostName = 'com.varjolintu.keepassxc_browser'; keepass.nativePort = null; keepass.keySize = 24; -keepass.latestVersionUrl = "https://api.github.com/repos/keepassxreboot/keepassxc/releases/latest"; +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.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing); +keepass.keyId = 'keepassxc-browser-cryptokey-name'; +keepass.keyBody = 'keepassxc-browser-key'; window.browser = (function () { return window.msBrowser || @@ -26,14 +26,22 @@ window.browser = (function () { window.chrome; })(); +const kpActions = { + SET_LOGIN: 'set-login', + GET_LOGINS: 'get-logins', + GENERATE_PASSWORD: 'generate-password', + ASSOCIATE: 'associate', + TEST_ASSOCIATE: 'test-associate', + GET_DATABASE_HASH: 'get-databasehash', + CHANGE_PUBLIC_KEYS: 'change-public-keys' +} + keepass.addCredentials = function(callback, tab, username, password, url) { keepass.updateCredentials(callback, tab, null, username, password, url); } keepass.updateCredentials = function(callback, tab, entryId, username, password, url) { - page.debug("keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})", tab.id, entryId, username, url); - - // unset error message + page.debug('keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})', tab.id, entryId, username, url); page.tabs[tab.id].errorMessage = null; keepass.testAssociation((response) => { @@ -46,49 +54,37 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, return; } - const dbkeys = keepass.getCryptoKey(); - const id = dbkeys[0]; + const kpAction = kpActions.SET_LOGIN; + const {dbid} = keepass.getCryptoKey(); + const nonce = nacl.randomBytes(keepass.keySize); - // build request let messageData = { - action: "set-login", - id: id, + action: kpAction, + id: dbid, login: username, password: password, url: url, submitUrl: url }; - const nonce = nacl.randomBytes(keepass.keySize); - if (entryId) { messageData.uuid = entryId; } const request = { - action: "set-login", + action: kpAction, message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; console.log(request); - keepass.callbackOnId(keepass.nativePort.onMessage, "set-login", (response) => { + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (!res) - { - console.log("Failed to decrypt message"); - } - else - { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); - let code = "error"; - - if (keepass.verifyResponse(parsed, response.nonce)) { - code = "success"; - } - callback(code); + callback(keepass.verifyResponse(parsed, response.nonce) ? 'success' : 'error'); } } else if (response.error && response.errorCode) { @@ -103,7 +99,7 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, } keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCallback, triggerUnlock) { - page.debug("keepass.retrieveCredentials(callback, {1}, {2}, {3}, {4})", tab.id, url, submiturl, forceCallback); + page.debug('keepass.retrieveCredentials(callback, {1}, {2}, {3}, {4})', tab.id, url, submiturl, forceCallback); keepass.testAssociation((response) => { if (!response) @@ -115,7 +111,6 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall return; } - // unset error message page.tabs[tab.id].errorMessage = null; if (!keepass.isConnected) { @@ -123,13 +118,13 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall } let entries = []; + const kpAction = kpActions.GET_LOGINS; const nonce = nacl.randomBytes(keepass.keySize); - const dbkeys = keepass.getCryptoKey(); - const id = dbkeys[0]; + const {dbid} = keepass.getCryptoKey(); let messageData = { - action: "get-logins", - id: id, + action: kpAction, + id: dbid, url: url }; @@ -138,38 +133,32 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall } const request = { - action: "get-logins", + action: kpAction, message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "get-logins", (response) => { + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (!res) - { - console.log("Failed to decrypt message"); - } - else - { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); - keepass.setcurrentKeePassXCVersion(parsed.version); if (keepass.verifyResponse(parsed, response.nonce)) { entries = parsed.entries; keepass.updateLastUsed(keepass.databaseHash); - if (entries.length == 0) { + if (entries.length === 0) { //questionmark-icon is not triggered, so we have to trigger for the normal symbol browserAction.showDefault(null, tab); } callback(entries); } else { - console.log("RetrieveCredentials for " + url + " rejected"); + console.log('RetrieveCredentials for ' + url + ' rejected'); } - page.debug("keepass.retrieveCredentials() => entries.length = {1}", entries.length); + page.debug('keepass.retrieveCredentials() => entries.length = {1}', entries.length); } } else if (response.error && response.errorCode) { @@ -187,7 +176,7 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall keepass.callbackOnId = function (ev, id, callback) { let listener = ( (port, id) => { let handler = (msg) => { - if (msg && msg.action == id) { + if (msg && msg.action === id) { ev.removeListener(handler); callback(msg); } @@ -199,6 +188,7 @@ keepass.callbackOnId = function (ev, id, callback) { keepass.generatePassword = function (callback, tab, forceCallback) { if (!keepass.isConnected) { + callback([]); return; } @@ -218,26 +208,22 @@ keepass.generatePassword = function (callback, tab, forceCallback) { } let passwords = []; + const kpAction = kpActions.GENERATE_PASSWORD; const nonce = nacl.randomBytes(keepass.keySize); const request = { - action: "generate-password", + action: kpAction, nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "generate-password", (response) => { + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (!res) - { - console.log("Failed to decrypt message"); - } - else - { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); - keepass.setcurrentKeePassXCVersion(parsed.version); + if (keepass.verifyResponse(parsed, response.nonce)) { const rIv = response.nonce; if (parsed.entries) { @@ -245,11 +231,11 @@ keepass.generatePassword = function (callback, tab, forceCallback) { keepass.updateLastUsed(keepass.databaseHash); } else { - console.log("No entries returned. Is KeePassXC up-to-date?"); + console.log('No entries returned. Is KeePassXC up-to-date?'); } } else { - console.log("GeneratePassword rejected"); + console.log('GeneratePassword rejected'); } callback(passwords); } @@ -264,24 +250,24 @@ keepass.generatePassword = function (callback, tab, forceCallback) { keepass.copyPassword = function(callback, tab, password) { browser.runtime.getBackgroundPage((bg) => { - let c2c = bg.document.getElementById("copy2clipboard"); + let c2c = bg.document.getElementById('copy2clipboard'); if (!c2c) { let input = document.createElement('input'); - input.type = "text"; - input.id = "copy2clipboard"; + input.type = 'text'; + input.id = 'copy2clipboard'; bg.document.getElementsByTagName('body')[0].appendChild(input); - c2c = bg.document.getElementById("copy2clipboard"); + c2c = bg.document.getElementById('copy2clipboard'); } c2c.value = password; c2c.select(); try { - document.execCommand("copy"); - c2c.value = ""; + document.execCommand('copy'); + c2c.value = ''; callback(true); } catch (err) { - console.log("Couldn't copy password to clipboard: " + err); + console.log('Could not copy password to clipboard: ' + err); } }); } @@ -298,41 +284,32 @@ keepass.associate = function(callback, tab) { page.tabs[tab.id].errorMessage = null; + const kpAction = kpActions.ASSOCIATE; const key = keepass.b64e(keepass.keyPair.publicKey); const nonce = nacl.randomBytes(keepass.keySize); const messageData = { - action: "associate", + action: kpAction, key: key }; const request = { - action: "associate", + action: kpAction, message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "associate", (response) => { + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (!res) - { - console.log("Failed to decrypt message"); - } - else - { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); - - if (parsed.version) { - keepass.currentKeePassXC = { - "version": parsed.version, - "versionParsed": parseInt(parsed.version.replace(/\./g,""))}; - } - + keepass.setcurrentKeePassXCVersion(parsed.version); const id = parsed.id; + if (!keepass.verifyResponse(parsed, response.nonce)) { - page.tabs[tab.id].errorMessage = "KeePassXC association failed, try again."; + page.tabs[tab.id].errorMessage = 'KeePassXC association failed, try again.'; } else { keepass.setCryptoKey(id, key); // Save the current public key as id key for the database @@ -370,7 +347,7 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { if (!keepass.serverPublicKey) { if (tab && page.tabs[tab.id]) { - const errorMessage = "No KeePassXC public key available."; + const errorMessage = 'No KeePassXC public key available.'; page.tabs[tab.id].errorMessage = errorMessage; console.log(errorMessage); } @@ -378,11 +355,13 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { return false; } + const kpAction = kpActions.TEST_ASSOCIATE; const nonce = nacl.randomBytes(keepass.keySize); - const dbkeys = keepass.getCryptoKey(); - if (dbkeys == null) { + const {dbid, dbkey} = keepass.getCryptoKey(); + + if (dbkey === null) { if (tab && page.tabs[tab.id]) { - const errorMessage = "No saved databases found."; + const errorMessage = 'No saved databases found.'; page.tabs[tab.id].errorMessage = errorMessage; console.log(errorMessage); } @@ -390,52 +369,42 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { return false; } - const id = dbkeys[0]; - const idkey = dbkeys[1]; - const messageData = { - action: "test-associate", - id: id, - key: idkey + action: kpAction, + id: dbid, + key: dbkey }; const request = { - action: "test-associate", + action: kpAction, message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "test-associate", (response) => { + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (!res) { - console.log("Failed to decrypt message"); - } - else - { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); - - if (parsed.version) { - keepass.currentKeePassXC = { - "version": parsed.version, - "versionParsed": parseInt(parsed.version.replace(/\./g,""))}; - } - + keepass.setcurrentKeePassXCVersion(parsed.version); const id = parsed.id; keepass.isEncryptionKeyUnrecognized = false; + if (!keepass.verifyResponse(parsed, response.nonce)) { const hash = response.hash || 0; keepass.deleteKey(hash); keepass.isEncryptionKeyUnrecognized = true; - console.log("Encryption key is not recognized!"); - page.tabs[tab.id].errorMessage = "Encryption key is not recognized."; + const errMsg = 'Encryption key is not recognized!'; + console.log(errMsg); + page.tabs[tab.id].errorMessage = errMsg; keepass.associated.value = false; keepass.associated.hash = null; } else if (!keepass.isAssociated()) { - console.log("Association was not successful"); - page.tabs[tab.id].errorMessage = "Association was not successful."; + const errMsg = 'Association was not successful!'; + console.log(errMsg); + page.tabs[tab.id].errorMessage = errMsg; } else { if (tab && page.tabs[tab.id]) { @@ -455,61 +424,58 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { keepass.getDatabaseHash = function (callback, tab, triggerUnlock) { if (!keepass.isConnected) { - page.tabs[tab.id].errorMessage = "Not connected with KeePassXC."; + page.tabs[tab.id].errorMessage = 'Not connected with KeePassXC.'; callback([]); return; } if (!keepass.serverPublicKey) { - keepass.changePublicKeys(tab, function(res) {}); + keepass.changePublicKeys(tab, null); } + const kpAction = kpActions.GET_DATABASE_HASH; const nonce = nacl.randomBytes(keepass.keySize); const messageData = { - action: "get-databasehash" + action: kpAction }; const request = { - action: "get-databasehash", + action: kpAction, message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "get-databasehash", (response) => { + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, (response) => { if (response.message && response.nonce) { const res = keepass.decrypt(response.message, response.nonce); - if (!res) - { - console.log("Failed to decrypt message"); - } - else - { + if (res) { const message = nacl.util.encodeUTF8(res); const parsed = JSON.parse(message); if (parsed.hash) { - console.log("hash reply received: "+ parsed.hash); + console.log('hash reply received: ' + parsed.hash); const oldDatabaseHash = keepass.databaseHash; keepass.setcurrentKeePassXCVersion(parsed.version); - keepass.databaseHash = parsed.hash || "no-hash"; + keepass.databaseHash = parsed.hash || 'no-hash'; if (oldDatabaseHash && oldDatabaseHash != keepass.databaseHash) { keepass.associated.value = false; keepass.associated.hash = null; } - statusOK(); + keepass.isDatabaseClosed = false; + keepass.isKeePassXCAvailable = true; callback(parsed.hash); } else if (parsed.errorCode) { - keepass.databaseHash = "no-hash"; + keepass.databaseHash = 'no-hash'; keepass.isDatabaseClosed = true; - console.log("Error: KeePass database is not opened."); + console.log('Error: KeePass database is not opened.'); if (tab && page.tabs[tab.id]) { - page.tabs[tab.id].errorMessage = "KeePass database is not opened."; + page.tabs[tab.id].errorMessage = 'KeePass database is not opened.'; } callback(keepass.databaseHash); } @@ -517,9 +483,9 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) { } else { - keepass.databaseHash = "no-hash"; + keepass.databaseHash = 'no-hash'; if (tab && page.tabs[tab.id]) { - page.tabs[tab.id].errorMessage = response.error.length > 0 ? response.error : "Database hash not received."; + page.tabs[tab.id].errorMessage = response.error.length > 0 ? response.error : 'Database hash not received.'; } callback(keepass.databaseHash); } @@ -532,34 +498,31 @@ keepass.changePublicKeys = function(tab, callback) { return; } + const kpAction = kpActions.CHANGE_PUBLIC_KEYS; const key = keepass.b64e(keepass.keyPair.publicKey); let nonce = nacl.randomBytes(keepass.keySize); nonce = keepass.b64e(nonce) const message = { - "action": "change-public-keys", - "publicKey": key, - "proxyPort": (page.settings.port ? page.settings.port : 19700), - "nonce": nonce + action: kpAction, + publicKey: key, + proxyPort: (page.settings.port ? page.settings.port : 19700), + nonce: nonce } - keepass.callbackOnId(keepass.nativePort.onMessage, "change-public-keys", function(response) { - if (response.version) { - keepass.currentKeePassXC = { - "version": response.version, - "versionParsed": parseInt(response.version.replace(/\./g,"")) - }; - } + keepass.callbackOnId(keepass.nativePort.onMessage, kpAction, function(response) { + keepass.setcurrentKeePassXCVersion(response.version); if (!keepass.verifyKeyResponse(response, key, nonce)) { if (tab && page.tabs[tab.id]) { - page.tabs[tab.id].errorMessage = "Key change was not successful."; - console.log("Key change was not successful."); + const errMsg = 'Key change was not successful.'; + page.tabs[tab.id].errorMessage = errMsg; + console.log(errMsg); callback(false); } } else { - console.log("Server public key: " + keepass.b64e(keepass.serverPublicKey)); + console.log('Server public key: ' + keepass.b64e(keepass.serverPublicKey)); } callback(true); @@ -569,11 +532,11 @@ keepass.changePublicKeys = function(tab, callback) { keepass.generateNewKeyPair = function() { keepass.keyPair = nacl.box.keyPair(); - //console.log(keepass.b64e(keepass.keyPair.publicKey) + " " + keepass.b64e(keepass.keyPair.secretKey)); + //console.log(keepass.b64e(keepass.keyPair.publicKey) + ' ' + keepass.b64e(keepass.keyPair.secretKey)); } keepass.isConfigured = function(callback) { - if (typeof(keepass.databaseHash) == "undefined") { + if (typeof(keepass.databaseHash) === 'undefined') { keepass.getDatabaseHash((dbHash) => { callback(keepass.databaseHash in keepass.keyRing); }, null); @@ -585,22 +548,22 @@ keepass.isConfigured = function(callback) { } keepass.isAssociated = function() { - return (keepass.associated.value && keepass.associated.hash && keepass.associated.hash == keepass.databaseHash); + 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)) { + 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) { + if ('keyRing' in localStorage) { delete localStorage[keepass.keyId]; delete localStorage[keepass.keyBody]; } }, null); } - if ("keyRing" in localStorage) { + if ('keyRing' in localStorage) { delete localStorage[keepass.keyId]; delete localStorage[keepass.keyBody]; } @@ -609,12 +572,11 @@ keepass.convertKeyToKeyRing = function() { keepass.saveKey = function(hash, id, key) { if (!(hash in keepass.keyRing)) { keepass.keyRing[hash] = { - "id": id, - "key": key, - "hash": hash, - "icon": "blue", - "created": new Date(), - "last-used": new Date() + id: id, + key: key, + hash: hash, + created: new Date(), + lastUsed: new Date() } } else { @@ -640,15 +602,15 @@ keepass.deleteKey = function(hash) { keepass.setcurrentKeePassXCVersion = function(version) { if (version) { keepass.currentKeePassXC = { - "version": version, - "versionParsed": parseInt(version.replace(/\./g,"")) + version: version, + versionParsed: Number(version.replace(/\./g, '')) }; } } 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('11/21/1986'); const daysSinceLastCheck = Math.floor(((new Date()).getTime()-lastChecked.getTime())/86400000); if (daysSinceLastCheck >= page.settings.checkUpdateKeePassXC) { keepass.checkForNewKeePassXCVersion(); @@ -661,26 +623,26 @@ keepass.keePassXCUpdateAvailable = function() { keepass.checkForNewKeePassXCVersion = function() { let xhr = new XMLHttpRequest(); let version = -1; - xhr.open("GET", keepass.latestVersionUrl, true); + xhr.open('GET', keepass.latestVersionUrl, true); xhr.onload = function(e) { - if (xhr.readyState == 4) { - if (xhr.status == 200) { + if (xhr.readyState === 4) { + if (xhr.status === 200) { const json = JSON.parse(xhr.responseText); if (json.tag_name) { version = json.tag_name; keepass.latestKeePassXC.version = version; - keepass.latestKeePassXC.versionParsed = parseInt(version.replace(/\./g,"")); + keepass.latestKeePassXC.versionParsed = Number(version.replace(/\./g, '')); } } } - if (version != -1) { + if (version !== -1) { localStorage.latestKeePassXC = JSON.stringify(keepass.latestKeePassXC); } }; xhr.onerror = function(e) { - console.log("checkForNewKeePassXCVersion error: " + e); + console.log('checkForNewKeePassXCVersion error: ${e}'); } xhr.send(); @@ -693,17 +655,12 @@ keepass.connectToNative = function() { } } -function statusOK() { - keepass.isDatabaseClosed = false; - keepass.isKeePassXCAvailable = true; -} - keepass.onNativeMessage = function (response) { //console.log("Received message: " + JSON.stringify(response)); } function onDisconnected() { - console.log("Failed to connect: " + browser.runtime.lastError.message); + console.log('Failed to connect: ' + browser.runtime.lastError.message); keepass.nativePort = null; keepass.isConnected = false; keepass.isDatabaseClosed = true; @@ -711,7 +668,7 @@ function onDisconnected() { } keepass.nativeConnect = function() { - console.log("Connecting to native messaging host " + keepass.nativeHostName) + console.log('Connecting to native messaging host ' + keepass.nativeHostName) keepass.nativePort = browser.runtime.connectNative(keepass.nativeHostName); keepass.nativePort.onMessage.addListener(keepass.onNativeMessage); keepass.nativePort.onDisconnect.addListener(onDisconnected); @@ -728,7 +685,7 @@ keepass.verifyKeyResponse = function(response, key, nonce) { if (keepass.b64d(nonce).length !== nacl.secretbox.nonceLength) return false; - reply = (response.nonce == nonce); + reply = (response.nonce === nonce); if (response.publicKey) { keepass.serverPublicKey = keepass.b64d(response.publicKey); @@ -741,7 +698,7 @@ keepass.verifyKeyResponse = function(response, key, nonce) { keepass.verifyResponse = function(response, nonce, id) { keepass.associated.value = response.success; - if (response.success != "true") { + if (response.success !== 'true') { keepass.associated.hash = null; return false; } @@ -751,10 +708,10 @@ keepass.verifyResponse = function(response, nonce, id) { if (keepass.b64d(response.nonce).length !== nacl.secretbox.nonceLength) return false; - keepass.associated.value = (response.nonce == nonce); + keepass.associated.value = (response.nonce === nonce); if (id) { - keepass.associated.value = (keepass.associated.value && id == response.id); + keepass.associated.value = (keepass.associated.value && id === response.id); } keepass.associated.hash = (keepass.associated.value) ? keepass.databaseHash : null; @@ -764,7 +721,7 @@ keepass.verifyResponse = function(response, nonce, id) { } keepass.handleError = function(tabId, errorMessage, errorCode) { - console.log("Received error " + errorCode + ": " + errorMessage); + console.log('Received error ${errorCode}: ${errorMessage}'); page.tabs[tabId].errorMessage = errorMessage; } @@ -781,14 +738,14 @@ keepass.getCryptoKey = function() { return null; } - const id = keepass.keyRing[keepass.databaseHash].id; - let key = null; + const dbid = keepass.keyRing[keepass.databaseHash].id; + let dbkey = null; - if (id) { - key = keepass.keyRing[keepass.databaseHash].key; + if (dbid) { + dbkey = keepass.keyRing[keepass.databaseHash].key; } - return key ? [id, key] : null; + return {dbid, dbkey}; } keepass.setCryptoKey = function(id, key) { @@ -804,12 +761,17 @@ keepass.encrypt = function(input, nonce) { return keepass.b64e(message); } } - console.log("Cannot encrypt message! Server public key needed."); - return ""; + console.log('Cannot encrypt message! Server public key needed.'); + return ''; } keepass.decrypt = function(input, nonce, toStr) { const m = keepass.b64d(input); const n = keepass.b64d(nonce); - return nacl.box.open(m, n, keepass.serverPublicKey, keepass.keyPair.secretKey); + const res = nacl.box.open(m, n, keepass.serverPublicKey, keepass.keyPair.secretKey); + + if (!res) { + console.log('Failed to decrypt message'); + } + return res; } diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index 60e2710..f8421c3 100644 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -5,36 +5,34 @@ window.browser = (function () { })(); var page = {}; - -// special information for every tab page.tabs = {}; page.currentTabId = -1; -page.settings = (typeof(localStorage.settings) == 'undefined') ? {} : JSON.parse(localStorage.settings); +page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.parse(localStorage.settings); page.blockedTabs = {}; page.initSettings = function() { event.onLoadSettings(); - if (!("checkUpdateKeePassXC" in page.settings)) { + if (!('checkUpdateKeePassXC' in page.settings)) { page.settings.checkUpdateKeePassXC = 3; } - if (!("autoCompleteUsernames" in page.settings)) { + if (!('autoCompleteUsernames' in page.settings)) { page.settings.autoCompleteUsernames = true; } - if (!("autoFillAndSend" in page.settings)) { + if (!('autoFillAndSend' in page.settings)) { page.settings.autoFillAndSend = true; } - if (!("usePasswordGenerator" in page.settings)) { + if (!('usePasswordGenerator' in page.settings)) { page.settings.usePasswordGenerator = true; } - if (!("autoFillSingleEntry" in page.settings)) { + if (!('autoFillSingleEntry' in page.settings)) { page.settings.autoFillSingleEntry = false; } - if (!("autoRetrieveCredentials" in page.settings)) { + if (!('autoRetrieveCredentials' in page.settings)) { page.settings.autoRetrieveCredentials = true; } - if (!("port" in page.settings)) { - page.settings.port = "19700"; + if (!('port' in page.settings)) { + page.settings.port = '19700'; } localStorage.settings = JSON.stringify(page.settings); } @@ -48,14 +46,14 @@ page.initOpenedTabs = function() { } page.isValidProtocol = function(url) { - let protocol = url.substring(0, url.indexOf(":")); + let protocol = url.substring(0, url.indexOf(':')); protocol = protocol.toLowerCase(); - return !(url.indexOf(".") == -1 || (protocol != "http" && protocol != "https" && protocol != "ftp" && protocol != "sftp")); + return !(url.indexOf('.') === -1 || (protocol !== 'http' && protocol !== 'https' && protocol !== 'ftp' && protocol !== 'sftp')); } page.switchTab = function(callback, tab) { browserAction.showDefault(null, tab); - browser.tabs.sendMessage(tab.id, {action: "activated_tab"}); + browser.tabs.sendMessage(tab.id, {action: 'activated_tab'}); } page.clearCredentials = function(tabId, complete) { @@ -70,7 +68,7 @@ page.clearCredentials = function(tabId, complete) { page.tabs[tabId].loginList = []; browser.tabs.sendMessage(tabId, { - action: "clear_credentials" + action: 'clear_credentials' }); } } @@ -78,15 +76,15 @@ page.clearCredentials = function(tabId, complete) { page.createTabEntry = function(tabId) { //console.log("page.createTabEntry("+tabId+")"); page.tabs[tabId] = { - "stack": [], - "errorMessage": null, - "loginList": {} + 'stack': [], + 'errorMessage': null, + 'loginList': {} }; } page.removePageInformationFromNotExistingTabs = function() { let rand = Math.floor(Math.random()*1001); - if (rand == 28) { + if (rand === 28) { browser.tabs.query({}, (tabs) => { let $tabIds = {}; const $infoIds = Object.keys(page.tabs); @@ -114,9 +112,9 @@ page.debugConsole = function() { }; page.sprintf = function(input, args) { - return input.replace(/{(\d+)}/g, function(match, number) { - return typeof args[number] != 'undefined' - ? (typeof args[number] == 'object' ? JSON.stringify(args[number]) : args[number]) + return input.replace(/{(\d+)}/g, (match, number) => { + return typeof args[number] !== 'undefined' + ? (typeof args[number] === 'object' ? JSON.stringify(args[number]) : args[number]) : match ; }); @@ -129,10 +127,10 @@ page.debug = page.debugDummy; page.setDebug = function(bool) { if (bool) { page.debug = page.debugConsole; - return "Debug mode enabled"; + return 'Debug mode enabled'; } else { page.debug = page.debugDummy; - return "Debug mode disabled"; + return 'Debug mode disabled'; } }; diff --git a/keepassxc-browser/icons/key_24x24.png b/keepassxc-browser/icons/key.png similarity index 100% rename from keepassxc-browser/icons/key_24x24.png rename to keepassxc-browser/icons/key.png diff --git a/keepassxc-browser/icons/key_16x16.png b/keepassxc-browser/icons/key_16x16.png deleted file mode 100644 index 1dafc30..0000000 Binary files a/keepassxc-browser/icons/key_16x16.png and /dev/null differ diff --git a/keepassxc-browser/keepassxc-browser.css b/keepassxc-browser/keepassxc-browser.css index 4a7be25..d640627 100644 --- a/keepassxc-browser/keepassxc-browser.css +++ b/keepassxc-browser/keepassxc-browser.css @@ -69,49 +69,13 @@ input.genpw-text { position: absolute; cursor: pointer; } -.cip-genpw-icon.small { - width: 16px; - height: 16px; - background-image: url(chrome-extension://__MSG_@@extension_id__/icons/key_16x16.png); +.cip-genpw-icon.key { + background: url('chrome-extension://__MSG_@@extension_id__/icons/key.png') right no-repeat; + background-size: contain; } -.cip-genpw-icon.big { - width: 24px; - height: 24px; - background-image: url(chrome-extension://__MSG_@@extension_id__/icons/key_24x24.png); -} -.cip-genpw-icon.small-moz { - width: 16px; - height: 16px; - background-image: url(moz-extension://__MSG_@@extension_id__/icons/key_16x16.png); -} -.cip-genpw-icon.big-moz { - width: 24px; - height: 24px; - background-image: url(moz-extension://__MSG_@@extension_id__/icons/key_24x24.png); -} -.cip-warning-icon { - position: absolute; - cursor: pointer; -} -.cip-warning-icon.small { - width: 16px; - height: 16px; - background-image: url(chrome-extension://__MSG_@@extension_id__/icons/warning_16x16.png); -} -.cip-warning-icon.big { - width: 24px; - height: 24px; - background-image: url(chrome-extension://__MSG_@@extension_id__/icons/warning_24x24.png); -} -.cip-warning-icon.small-moz { - width: 16px; - height: 16px; - background-image: url(moz-extension://__MSG_@@extension_id__/icons/warning_16x16.png); -} -.cip-warning-icon.big-moz { - width: 24px; - height: 24px; - background-image: url(moz-extension://__MSG_@@extension_id__/icons/warning_24x24.png); +.cip-genpw-icon.key-moz { + background: url('moz-extension://__MSG_@@extension_id__/icons/key.png') right no-repeat; + background-size: contain; } #cip-genpw-btn-fillin { diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index e56ad55..2449087 100644 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -17,53 +17,53 @@ var _called = {}; browser.runtime.onMessage.addListener(function(req, sender, callback) { if ('action' in req) { - if (req.action == "fill_user_pass_with_specific_login") { + if (req.action === 'fill_user_pass_with_specific_login') { if (cip.credentials[req.id]) { let combination = null; if (cip.u) { cip.setValueWithChange(cip.u, cip.credentials[req.id].login); - combination = cipFields.getCombination("username", cip.u); + combination = cipFields.getCombination('username', cip.u); cip.u.focus(); } if (cip.p) { cip.setValueWithChange(cip.p, cip.credentials[req.id].password); - combination = cipFields.getCombination("password", cip.p); + combination = cipFields.getCombination('password', cip.p); } let list = {}; if (cip.fillInStringFields(combination.fields, cip.credentials[req.id].stringFields, list)) { - cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]}); + cipForm.destroy(false, {'password': list.list[0], 'username': list.list[1]}); } } // wish I could clear out _logins and _u, but a subsequent // selection may be requested. } - else if (req.action == "fill_user_pass") { + else if (req.action === 'fill_user_pass') { cip.receiveCredentialsIfNecessary(); cip.fillInFromActiveElement(false); } - else if (req.action == "fill_pass_only") { + else if (req.action === 'fill_pass_only') { cip.receiveCredentialsIfNecessary(); cip.fillInFromActiveElementPassOnly(false); } - else if (req.action == "activate_password_generator") { + else if (req.action === 'activate_password_generator') { cip.initPasswordGenerator(cipFields.getAllFields()); } - else if (req.action == "remember_credentials") { + else if (req.action === 'remember_credentials') { cip.contextMenuRememberCredentials(); } - else if (req.action == "choose_credential_fields") { + else if (req.action === 'choose_credential_fields') { cipDefine.init(); } - else if (req.action == "clear_credentials") { + else if (req.action === 'clear_credentials') { cipEvents.clearCredentials(); } - else if (req.action == "activated_tab") { + else if (req.action === 'activated_tab') { cipEvents.triggerActivatedTab(); } - else if (req.action == "redetect_fields") { + else if (req.action === 'redetect_fields') { browser.runtime.sendMessage({ - "action": "get_settings", + action: 'get_settings', }, (response) => { cip.settings = response.data; cip.initCredentialFields(true); @@ -73,12 +73,12 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) { }); function _f(fieldId) { - const field = (fieldId) ? jQuery("input[data-cip-id='"+fieldId+"']:first") : []; + const field = (fieldId) ? jQuery('input[data-cip-id=\''+fieldId+'\']:first') : []; return (field.length > 0) ? field : null; } function _fs(fieldId) { - const field = (fieldId) ? jQuery("input[data-cip-id='"+fieldId+"']:first,select[data-cip-id='"+fieldId+"']:first").first() : []; + const field = (fieldId) ? jQuery('input[data-cip-id=\''+fieldId+'\']:first,select[data-cip-id=\''+fieldId+'\']:first').first() : []; return (field.length > 0) ? field : null; } @@ -90,9 +90,9 @@ var cipAutocomplete = {}; cipAutocomplete.elements = []; cipAutocomplete.init = function(field) { - if (field.hasClass("ui-autocomplete-input")) { + if (field.hasClass('ui-autocomplete-input')) { //_f(credentialInputs[i].username).autocomplete("source", autocompleteSource); - field.autocomplete("destroy"); + field.autocomplete('destroy'); } field @@ -109,13 +109,13 @@ cipAutocomplete.init = function(field) { } cipAutocomplete.onClick = function() { - jQuery(this).autocomplete("search", jQuery(this).val()); + jQuery(this).autocomplete('search', jQuery(this).val()); } cipAutocomplete.onOpen = function(event, ui) { // NOT BEAUTIFUL! // modifies ALL ui-autocomplete menus of class .cip-ui-menu - jQuery("ul.ui-autocomplete.ui-menu").css("z-index", 2147483636); + jQuery('ul.ui-autocomplete.ui-menu').css('z-index', 2147483636); } cipAutocomplete.onSource = function (request, callback) { @@ -130,21 +130,21 @@ cipAutocomplete.onSource = function (request, callback) { cipAutocomplete.onSelect = function (e, ui) { e.preventDefault(); cip.setValueWithChange(jQuery(this), ui.item.value); - const fieldId = cipFields.prepareId(jQuery(this).attr("data-cip-id")); - const combination = cipFields.getCombination("username", fieldId); + const fieldId = cipFields.prepareId(jQuery(this).attr('data-cip-id')); + const combination = cipFields.getCombination('username', fieldId); combination.loginId = ui.item.loginId; cip.fillInCredentials(combination, true, false); - jQuery(this).data("fetched", true); + jQuery(this).data('fetched', true); } cipAutocomplete.onBlur = function() { - if (jQuery(this).data("fetched") == true) { - jQuery(this).data("fetched", false); + if (jQuery(this).data('fetched') === true) { + jQuery(this).data('fetched', false); } else { - const fieldId = cipFields.prepareId(jQuery(this).attr("data-cip-id")); - const fields = cipFields.getCombination("username", fieldId); - if (_f(fields.password) && _f(fields.password).data("unchanged") != true && jQuery(this).val() != "") { + const fieldId = cipFields.prepareId(jQuery(this).attr('data-cip-id')); + const fields = cipFields.getCombination('username', fieldId); + if (_f(fields.password) && _f(fields.password).data('unchanged') !== true && jQuery(this).val() !== "") { cip.fillInCredentials(fields, true, true); } } @@ -153,8 +153,8 @@ cipAutocomplete.onBlur = function() { cipAutocomplete.onFocus = function() { cip.u = jQuery(this); - if (jQuery(this).val() == "") { - jQuery(this).autocomplete("search", ""); + if (jQuery(this).val() === '') { + jQuery(this).autocomplete('search', ''); } } @@ -165,7 +165,7 @@ cipPassword.observedIcons = []; cipPassword.observingLock = false; cipPassword.init = function() { - if ("initPasswordGenerator" in _called) { + if ('initPasswordGenerator' in _called) { return; } @@ -177,14 +177,14 @@ cipPassword.init = function() { } cipPassword.initField = function(field, inputs, pos) { - if (!field || field.length != 1) { + if (!field || field.length !== 1) { return; } - if (field.data("cip-password-generator")) { + if (field.data('cip-password-generator')) { return; } - field.data("cip-password-generator", true); + field.data('cip-password-generator', true); cipPassword.createIcon(field); cipPassword.createDialog(); @@ -192,242 +192,232 @@ cipPassword.initField = function(field, inputs, pos) { let $found = false; if (inputs) { for (let i = pos + 1; i < inputs.length; i++) { - if (inputs[i] && inputs[i].attr("type") && inputs[i].attr("type").toLowerCase() == "password") { - field.data("cip-genpw-next-field-id", inputs[i].data("cip-id")); - field.data("cip-genpw-next-is-password-field", (i == 0)); + if (inputs[i] && inputs[i].attr('type') && inputs[i].attr('type').toLowerCase() === 'password') { + field.data('cip-genpw-next-field-id', inputs[i].data('cip-id')); + field.data('cip-genpw-next-is-password-field', (i === 0)); $found = true; break; } } } - field.data("cip-genpw-next-field-exists", $found); + field.data('cip-genpw-next-field-exists', $found); } cipPassword.createDialog = function() { - if ("passwordCreateDialog" in _called) { + if ('passwordCreateDialog' in _called) { return; } _called.passwordCreateDialog = true; - const $dialog = jQuery("
") - .addClass("dialog-form") - .attr("id", "cip-genpw-dialog"); + const $dialog = jQuery('
') + .addClass('dialog-form') + .attr('id', 'cip-genpw-dialog'); - const $inputDiv = jQuery("
").addClass("form-group"); - const $inputGroup = jQuery("
").addClass("genpw-input-group"); - const $textfieldPassword = jQuery("") - .attr("id", "cip-genpw-textfield-password") - .attr("type", "text") - .attr("aria-describedby", "cip-genpw-quality") - .attr("placeholder", "Generated password") - .addClass("genpw-text ui-widget-content ui-corner-all") + const $inputDiv = jQuery('
').addClass('form-group'); + const $inputGroup = jQuery('
').addClass('genpw-input-group'); + const $textfieldPassword = jQuery('') + .attr('id', 'cip-genpw-textfield-password') + .attr('type', 'text') + .attr('aria-describedby', 'cip-genpw-quality') + .attr('placeholder', 'Generated password') + .addClass('genpw-text ui-widget-content ui-corner-all') .on('change keypress paste textInput input', function() { - jQuery("#cip-genpw-btn-clipboard:first").removeClass("btn-success"); + jQuery('#cip-genpw-btn-clipboard:first').removeClass('btn-success'); }); - const $quality = jQuery("") - .addClass("genpw-input-group-addon") - .addClass("b2c-add-on") - .attr("id", "cip-genpw-quality") - .text("123 Bits"); + const $quality = jQuery('') + .addClass('genpw-input-group-addon') + .addClass('b2c-add-on') + .attr('id', 'cip-genpw-quality') + .text('123 Bits'); $inputGroup.append($textfieldPassword).append($quality); - const $checkGroup = jQuery("
").addClass("genpw-input-group"); - const $checkboxNextField = jQuery("") - .attr("id", "cip-genpw-checkbox-next-field") - .attr("type", "checkbox") - .addClass("cip-genpw-checkbox"); - const $labelNextField = jQuery("