diff --git a/CHANGELOG b/CHANGELOG index 3ad9b35..44bc54d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +0.2.2 (2017-07-04) +========================= +- Some code cleaning and rewriting +- Fixed displaying 'Database not opened' error message +- Changed icon color to gray when database is not opened or connected +- Added support for UDP port selector for proxy applications + 0.2.1 (2017-06-27) ========================= - get-databasehash request/response is now encrypted diff --git a/README.md b/README.md index d81b36e..82a8363 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Request: { "action": "change-public-keys", "publicKey": "", + "proxyPort": "", "nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q" } ``` diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index 90a770d..ce73871 100644 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -6,12 +6,12 @@ window.browser = (function () { var browserAction = {}; -var BLINK_TIMEOUT_DEFAULT = 7500; -var BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT = -1; -var BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT = 1; +const BLINK_TIMEOUT_DEFAULT = 7500; +const BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT = -1; +const BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT = 1; browserAction.show = function(callback, tab) { - var data = {}; + let data = {}; if (!page.tabs[tab.id] || page.tabs[tab.id].stack.length == 0) { browserAction.showDefault(callback, tab); return; @@ -38,10 +38,10 @@ browserAction.update = function(interval) { return; } - var data = page.tabs[page.currentTabId].stack[page.tabs[page.currentTabId].stack.length - 1]; + let data = page.tabs[page.currentTabId].stack[page.tabs[page.currentTabId].stack.length - 1]; if (typeof data.visibleForMilliSeconds != "undefined") { - if(data.visibleForMilliSeconds <= 0) { + if (data.visibleForMilliSeconds <= 0) { browserAction.stackPop(page.currentTabId); browserAction.show(null, {"id": page.currentTabId}); page.clearCredentials(page.currentTabId); @@ -52,7 +52,7 @@ browserAction.update = function(interval) { if (data.intervalIcon) { data.intervalIcon.counter += 1; - if(data.intervalIcon.counter < data.intervalIcon.max) { + if (data.intervalIcon.counter < data.intervalIcon.max) { return; } @@ -71,12 +71,12 @@ browserAction.update = function(interval) { } browserAction.showDefault = function(callback, tab) { - var stackData = { + let stackData = { level: 1, iconType: "normal", popup: "popup.html" } - keepass.isConfigured(function(response) { + keepass.isConfigured((response) => { if (!response || keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable || page.tabs[tab.id].errorMessage) { stackData.iconType = "cross"; } @@ -87,19 +87,18 @@ browserAction.showDefault = function(callback, tab) { } browserAction.stackUnshift(stackData, tab.id); - browserAction.show(null, tab); }); } browserAction.stackAdd = function(callback, tab, icon, popup, level, push, visibleForMilliSeconds, visibleForPageUpdates, redirectOffset, dontShow) { - var id = tab.id || page.currentTabId; + const id = tab.id || page.currentTabId; if (!level) { level = 1; } - var stackData = { + let stackData = { "level": level, "icon": icon } @@ -142,18 +141,18 @@ browserAction.removeLevelFromStack = function(callback, tab, level, type, dontSh type = "<="; } - var newStack = []; - for (var i = 0; i < page.tabs[tab.id].stack.length; i++) { + let newStack = []; + for (const i of page.tabs[tab.id].stack) { if ( - (type == "<" && page.tabs[tab.id].stack[i].level >= level) || - (type == "<=" && page.tabs[tab.id].stack[i].level > level) || - (type == "=" && page.tabs[tab.id].stack[i].level != level) || - (type == "==" && page.tabs[tab.id].stack[i].level != level) || - (type == "!=" && page.tabs[tab.id].stack[i].level == level) || - (type == ">" && page.tabs[tab.id].stack[i].level <= level) || - (type == ">=" && page.tabs[tab.id].stack[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(page.tabs[tab.id].stack[i]); + newStack.push(i); } } @@ -165,21 +164,18 @@ browserAction.removeLevelFromStack = function(callback, tab, level, type, dontSh } browserAction.stackPop = function(tabId) { - var id = tabId || page.currentTabId; - + const id = tabId || page.currentTabId; page.tabs[id].stack.pop(); }; browserAction.stackPush = function(data, tabId) { - var id = tabId || page.currentTabId; - + const id = tabId || page.currentTabId; browserAction.removeLevelFromStack(null, {"id": id}, data.level, "<=", true); page.tabs[id].stack.push(data); }; browserAction.stackUnshift = function(data, tabId) { - var id = tabId || page.currentTabId; - + const id = tabId || page.currentTabId; browserAction.removeLevelFromStack(null, {"id": id}, data.level, "<=", true); page.tabs[id].stack.unshift(data); }; @@ -194,11 +190,11 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) { page.clearCredentials(tab.id); return; } - var data = page.tabs[tab.id].stack[page.tabs[tab.id].stack.length - 1]; + const data = page.tabs[tab.id].stack[page.tabs[tab.id].stack.length - 1]; if (removeImmediately || !isNaN(data.visibleForPageUpdates)) { - var currentMS = Date.now(); - if( removeImmediately || (data.visibleForPageUpdates <= 0 && data.redirectOffset > 0)) { + const currentMS = Date.now(); + if (removeImmediately || (data.visibleForPageUpdates <= 0 && data.redirectOffset > 0)) { browserAction.stackPop(tab.id); browserAction.show(null, {"id": tab.id}); page.clearCredentials(tab.id); @@ -211,18 +207,18 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) { }; browserAction.setRememberPopup = function(tabId, username, password, url, usernameExists, credentialsList) { - var 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)); - var id = tabId || page.currentTabId; - - var timeoutMinMillis = parseInt(getValueOrDefault(settings, "blinkMinTimeout", BLINK_TIMEOUT_REDIRECT_THRESHOLD_TIME_DEFAULT, 0)) ; if (timeoutMinMillis > 0) { timeoutMinMillis += Date.now(); } - var blinkTimeout = getValueOrDefault(settings, "blinkTimeout", BLINK_TIMEOUT_DEFAULT, 0); - var pageUpdateAllowance = getValueOrDefault(settings, "allowedRedirect", BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT, 0); - var stackData = { + const blinkTimeout = getValueOrDefault(settings, "blinkTimeout", BLINK_TIMEOUT_DEFAULT, 0); + const pageUpdateAllowance = getValueOrDefault(settings, "allowedRedirect", BLINK_TIMEOUT_REDIRECT_COUNT_DEFAULT, 0); + + const stackData = { visibleForMilliSeconds: blinkTimeout, visibleForPageUpdates: pageUpdateAllowance, redirectOffset: timeoutMinMillis, @@ -252,7 +248,7 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna function getValueOrDefault(settings, key, defaultVal, min) { try { - var val = settings[key]; + let val = settings[key]; if (isNaN(val) || val < min) { val = defaultVal; } @@ -265,7 +261,7 @@ browserAction.generateIconName = function(iconType, icon) { return icon; } - var name = "icon_"; + let name = "icon_"; name += (keepass.keePassXCUpdateAvailable()) ? "new_" : ""; name += (!iconType || iconType == "normal") ? "normal" : iconType; name += "_19x19.png"; diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index 91fa8fd..35d8834 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -6,7 +6,6 @@ window.browser = (function () { var event = {}; - event.onMessage = function(request, sender, callback) { if (request.action in event.messageHandlers) { //console.log("onMessage(" + request.action + ") for #" + sender.tab.id); @@ -49,7 +48,7 @@ event.invoke = function(handler, callback, senderTabId, args, secondTime) { // remove information from no longer existing tabs page.removePageInformationFromNotExistingTabs(); - browser.tabs.get(senderTabId, function(tab) { + browser.tabs.get(senderTabId, (tab) => { //browser.tabs.query({"active": true, "windowId": browser.windows.WINDOW_ID_CURRENT}, function(tabs) { //if (tabs.length === 0) // return; // For example: only the background devtools or a popup are opened @@ -119,8 +118,8 @@ event.onSaveSettings = function(callback, tab, settings) { } event.onGetStatus = function(callback, tab) { - keepass.testAssociation(function(response) { - keepass.isConfigured(function(configured) { + keepass.testAssociation((response) => { + keepass.isConfigured((configured) => { var keyId = null; if (configured) { keyId = keepass.keyRing[keepass.databaseHash].id; @@ -145,11 +144,11 @@ event.onGetStatus = function(callback, tab) { event.onReconnect = function(callback, tab) { keepass.connectToNative(); keepass.generateNewKeyPair(); - keepass.changePublicKeys(null, function(pkRes) { - keepass.getDatabaseHash(function(gdRes) { + keepass.changePublicKeys(null, (pkRes) => { + keepass.getDatabaseHash((gdRes) => { if (gdRes) { - keepass.testAssociation(function(response) { - keepass.isConfigured(function(configured) { + keepass.testAssociation((response) => { + keepass.isConfigured((configured) => { var keyId = null; if (configured) { keyId = keepass.keyRing[keepass.databaseHash].id; @@ -179,8 +178,7 @@ event.onPopStack = function(callback, tab) { } event.onGetTabInformation = function(callback, tab) { - var id = tab.id || page.currentTabId; - + const id = tab.id || page.currentTabId; callback(page.tabs[id]); } @@ -193,7 +191,7 @@ event.onGetConnectedDatabase = function(callback, tab) { event.onGetKeePassXCVersions = function(callback, tab) { if (keepass.currentKeePassXC.version == 0) { - keepass.getDatabaseHash(function(response) { + keepass.getDatabaseHash((response) => { callback({"current": keepass.currentKeePassXC.version, "latest": keepass.latestKeePassXC.version}); }, tab); } @@ -210,8 +208,7 @@ event.onUpdateAvailableKeePassXC = function(callback, tab) { } event.onRemoveCredentialsFromTabInformation = function(callback, tab) { - var id = tab.id || page.currentTabId; - + const id = tab.id || page.currentTabId; page.clearCredentials(id); } @@ -220,39 +217,34 @@ event.onSetRememberPopup = function(callback, tab, username, password, url, user } event.onLoginPopup = function(callback, tab, logins) { - var stackData = { + let stackData = { level: 1, iconType: "questionmark", popup: "popup_login.html" } browserAction.stackUnshift(stackData, tab.id); - page.tabs[tab.id].loginList = logins; - browserAction.show(null, tab); } event.onHTTPAuthPopup = function(callback, tab, data) { - var stackData = { + let stackData = { level: 1, iconType: "questionmark", popup: "popup_httpauth.html" } browserAction.stackUnshift(stackData, tab.id); - page.tabs[tab.id].loginList = data; - browserAction.show(null, tab); } event.onMultipleFieldsPopup = function(callback, tab) { - var stackData = { + let stackData = { level: 1, iconType: "normal", popup: "popup_multiple-fields.html" } browserAction.stackUnshift(stackData, tab.id); - browserAction.show(null, tab); } diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index 79dade4..e222519 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -7,8 +7,8 @@ page.initOpenedTabs(); // initial connection with KeePassXC keepass.connectToNative(); keepass.generateNewKeyPair(); -keepass.changePublicKeys(null, function(pkRes) { - keepass.getDatabaseHash(function(gdRes) {}, null); +keepass.changePublicKeys(null, (pkRes) => { + keepass.getDatabaseHash((gdRes) => {}, null); }); window.browser = (function () { @@ -18,13 +18,13 @@ window.browser = (function () { })(); // set initial tab-ID -browser.tabs.query({"active": true, "windowId": browser.windows.WINDOW_ID_CURRENT}, function(tabs) { +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; }); // Milliseconds for intervall (e.g. to update browserAction) -var _interval = 250; +let _interval = 250; /** @@ -32,7 +32,7 @@ var _interval = 250; * functions if tab is created in foreground * @param {object} tab */ -browser.tabs.onCreated.addListener(function(tab) { +browser.tabs.onCreated.addListener((tab) => { if (tab.id > 0) { //console.log("browser.tabs.onCreated(" + tab.id+ ")"); if (tab.selected) { @@ -47,7 +47,7 @@ browser.tabs.onCreated.addListener(function(tab) { * @param {integer} tabId * @param {object} removeInfo */ -browser.tabs.onRemoved.addListener(function(tabId, removeInfo) { +browser.tabs.onRemoved.addListener((tabId, removeInfo) => { delete page.tabs[tabId]; if (page.currentTabId == tabId) { page.currentTabId = -1; @@ -59,12 +59,12 @@ browser.tabs.onRemoved.addListener(function(tabId, removeInfo) { * Invoke functions to retrieve credentials for focused tab * @param {object} activeInfo */ -browser.tabs.onActivated.addListener(function(activeInfo) { +browser.tabs.onActivated.addListener((activeInfo) => { // remove possible credentials from old tab information page.clearCredentials(page.currentTabId, true); browserAction.removeRememberPopup(null, {"id": page.currentTabId}, true); - browser.tabs.get(activeInfo.tabId, function(info) { + browser.tabs.get(activeInfo.tabId, (info) => { //console.log(info.id + ": " + info.url); if (info && info.id) { page.currentTabId = info.id; @@ -81,7 +81,7 @@ browser.tabs.onActivated.addListener(function(activeInfo) { * @param {integer} tabId * @param {object} changeInfo */ -browser.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { +browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.status == "complete") { event.invoke(browserAction.removeRememberPopup, null, tabId, []); } @@ -105,7 +105,7 @@ browser.runtime.onMessage.addListener(event.onMessage); * Add context menu entry for filling in username + password */ browser.contextMenus.create({ - "title": "Fill User + Pass", + "title": "Fill &User + Pass", "contexts": [ "editable" ], "onclick": function(info, tab) { browser.tabs.sendMessage(tab.id, { @@ -118,7 +118,7 @@ browser.contextMenus.create({ * Add context menu entry for filling in only password which matches for given username */ browser.contextMenus.create({ - "title": "Fill Pass Only", + "title": "Fill &Pass Only", "contexts": [ "editable" ], "onclick": function(info, tab) { browser.tabs.sendMessage(tab.id, { @@ -131,7 +131,7 @@ browser.contextMenus.create({ * Add context menu entry for creating icon for generate-password dialog */ browser.contextMenus.create({ - "title": "Show Password Generator Icons", + "title": "Show Password &Generator Icons", "contexts": [ "editable" ], "onclick": function(info, tab) { browser.tabs.sendMessage(tab.id, { @@ -144,7 +144,7 @@ browser.contextMenus.create({ * Add context menu entry for creating icon for generate-password dialog */ browser.contextMenus.create({ - "title": "Save credentials", + "title": "&Save credentials", "contexts": [ "editable" ], "onclick": function(info, tab) { browser.tabs.sendMessage(tab.id, { @@ -156,9 +156,9 @@ browser.contextMenus.create({ /** * Listen for keyboard shortcuts specified by user */ -browser.commands.onCommand.addListener(function(command) { +browser.commands.onCommand.addListener((command) => { if (command === "fill-username-password") { - browser.tabs.query({ active: true, currentWindow: true }, function(tabs) { + browser.tabs.query({ active: true, currentWindow: true }, (tabs) => { if (tabs.length) { browser.tabs.sendMessage(tabs[0].id, { action: "fill_user_pass" }); } @@ -166,7 +166,7 @@ browser.commands.onCommand.addListener(function(command) { } if (command === "fill-password") { - browser.tabs.query({ active: true, currentWindow: true }, function(tabs) { + browser.tabs.query({ active: true, currentWindow: true }, (tabs) => { if (tabs.length) { browser.tabs.sendMessage(tabs[0].id, { action: "fill_pass_only" }); } diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 6f852fe..00a7932 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -13,7 +13,6 @@ keepass.requiredKeePassXC = 220; keepass.nativeHostName = "com.varjolintu.keepassxc_browser"; keepass.nativePort = null; keepass.keySize = 24; -keepass.proxyPort = 19700; 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 @@ -37,7 +36,7 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, // unset error message page.tabs[tab.id].errorMessage = null; - keepass.testAssociation(function(response) { + keepass.testAssociation((response) => { if (!response) { browserAction.showDefault(null, tab); @@ -47,11 +46,11 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, return; } - var dbkeys = keepass.getCryptoKey(); - var id = dbkeys[0]; + const dbkeys = keepass.getCryptoKey(); + const id = dbkeys[0]; // build request - var messageData = { + let messageData = { action: "set-login", id: id, login: username, @@ -60,32 +59,32 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password, submitUrl: url }; - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); + const key = keepass.b64e(keepass.keyPair.publicKey); + const nonce = nacl.randomBytes(keepass.keySize); if (entryId) { messageData.uuid = entryId; } - var request = { + const request = { action: "set-login", message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; console.log(request); - keepass.callbackOnId(keepass.nativePort.onMessage, "set-login", function(response) { + keepass.callbackOnId(keepass.nativePort.onMessage, "set-login", (response) => { if (response.message && response.nonce) { - var res = keepass.decrypt(response.message, response.nonce); + const res = keepass.decrypt(response.message, response.nonce); if (!res) { console.log("Failed to decrypt message"); } else { - var message = nacl.util.encodeUTF8(res); - var parsed = JSON.parse(message); - var code = "error"; + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); + let code = "error"; if (keepass.verifyResponse(parsed, response.nonce)) { code = "success"; @@ -107,7 +106,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); - keepass.testAssociation(function(response) { + keepass.testAssociation((response) => { if (!response) { browserAction.showDefault(null, tab); @@ -124,13 +123,13 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall return; } - var entries = []; - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); - var dbkeys = keepass.getCryptoKey(); - var id = dbkeys[0]; + let entries = []; + const key = keepass.b64e(keepass.keyPair.publicKey); + const nonce = nacl.randomBytes(keepass.keySize); + const dbkeys = keepass.getCryptoKey(); + const id = dbkeys[0]; - var messageData = { + let messageData = { action: "get-logins", id: id, url: url @@ -140,23 +139,23 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall messageData.submitUrl = submiturl; } - var request = { + const request = { action: "get-logins", message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "get-logins", function(response) { + keepass.callbackOnId(keepass.nativePort.onMessage, "get-logins", (response) => { if (response.message && response.nonce) { - var res = keepass.decrypt(response.message, response.nonce); + const res = keepass.decrypt(response.message, response.nonce); if (!res) { console.log("Failed to decrypt message"); } else { - var message = nacl.util.encodeUTF8(res); - var parsed = JSON.parse(message); + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); keepass.setcurrentKeePassXCVersion(parsed.version); @@ -188,8 +187,8 @@ keepass.retrieveCredentials = function (callback, tab, url, submiturl, forceCall // Redirects the callback to a listener (handleReply()) keepass.callbackOnId = function (ev, id, callback) { - var listener = ( function(port, id) { - var handler = function(msg) { + let listener = ( function(port, id) { + let handler = function(msg) { if (msg && msg.action == id) { ev.removeListener(handler); callback(msg); @@ -205,8 +204,8 @@ keepass.generatePassword = function (callback, tab, forceCallback) { return; } - keepass.testAssociation(function(response) { - if (!response) + keepass.testAssociation((taresponse) => { + if (!taresponse) { browserAction.showDefault(null, tab); if (forceCallback) { @@ -220,30 +219,30 @@ keepass.generatePassword = function (callback, tab, forceCallback) { return; } - var passwords = []; - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); + let passwords = []; + const key = keepass.b64e(keepass.keyPair.publicKey); + const nonce = nacl.randomBytes(keepass.keySize); - var request = { + const request = { action: "generate-password", nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "generate-password", function(response) { + keepass.callbackOnId(keepass.nativePort.onMessage, "generate-password", (response) => { if (response.message && response.nonce) { - var res = keepass.decrypt(response.message, response.nonce); + const res = keepass.decrypt(response.message, response.nonce); if (!res) { console.log("Failed to decrypt message"); } else { - var message = nacl.util.encodeUTF8(res); - var parsed = JSON.parse(message); + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); keepass.setcurrentKeePassXCVersion(parsed.version); if (keepass.verifyResponse(parsed, response.nonce)) { - var rIv = response.nonce; + const rIv = response.nonce; if (parsed.entries) { passwords = parsed.entries; keepass.updateLastUsed(keepass.databaseHash); @@ -267,10 +266,10 @@ keepass.generatePassword = function (callback, tab, forceCallback) { } keepass.copyPassword = function(callback, tab, password) { - browser.runtime.getBackgroundPage(function(bg) { - var c2c = bg.document.getElementById("copy2clipboard"); + browser.runtime.getBackgroundPage((bg) => { + let c2c = bg.document.getElementById("copy2clipboard"); if (!c2c) { - var input = document.createElement('input'); + let input = document.createElement('input'); input.type = "text"; input.id = "copy2clipboard"; bg.document.getElementsByTagName('body')[0].appendChild(input); @@ -279,9 +278,14 @@ keepass.copyPassword = function(callback, tab, password) { c2c.value = password; c2c.select(); - document.execCommand("copy"); - c2c.value = ""; - callback(true); + try { + document.execCommand("copy"); + c2c.value = ""; + callback(true); + } + catch (err) { + console.log("Couldn't copy password to clipboard: " + err); + } }); } @@ -290,38 +294,38 @@ keepass.associate = function(callback, tab) { return; } - keepass.getDatabaseHash(function(res) { + keepass.getDatabaseHash((res) => { if (keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable) { return; } page.tabs[tab.id].errorMessage = null; - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); + const key = keepass.b64e(keepass.keyPair.publicKey); + const nonce = nacl.randomBytes(keepass.keySize); - var messageData = { + const messageData = { action: "associate", key: key }; - var request = { + const request = { action: "associate", message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "associate", function(response) { + keepass.callbackOnId(keepass.nativePort.onMessage, "associate", (response) => { if (response.message && response.nonce) { - var res = keepass.decrypt(response.message, response.nonce); + const res = keepass.decrypt(response.message, response.nonce); if (!res) { console.log("Failed to decrypt message"); } else { - var message = nacl.util.encodeUTF8(res); - var parsed = JSON.parse(message); + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); if (parsed.version) { keepass.currentKeePassXC = { @@ -329,7 +333,7 @@ keepass.associate = function(callback, tab) { "versionParsed": parseInt(parsed.version.replace(/\./g,""))}; } - var id = parsed.id; + const id = parsed.id; if (!keepass.verifyResponse(parsed, response.nonce)) { page.tabs[tab.id].errorMessage = "KeePassXC association failed, try again."; } @@ -351,10 +355,10 @@ keepass.associate = function(callback, tab) { } keepass.testAssociation = function (callback, tab, triggerUnlock) { - keepass.getDatabaseHash(function(dbHash) { + keepass.getDatabaseHash((dbHash) => { if (!dbHash) { callback(false); - return; + return false; } if (keepass.isDatabaseClosed || !keepass.isKeePassXCAvailable) { @@ -369,7 +373,7 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { if (!keepass.serverPublicKey) { if (tab && page.tabs[tab.id]) { - var errorMessage = "No KeePassXC public key available."; + const errorMessage = "No KeePassXC public key available."; page.tabs[tab.id].errorMessage = errorMessage; console.log(errorMessage); } @@ -377,12 +381,12 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { return false; } - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); - var dbkeys = keepass.getCryptoKey(); + const key = keepass.b64e(keepass.keyPair.publicKey); + const nonce = nacl.randomBytes(keepass.keySize); + const dbkeys = keepass.getCryptoKey(); if (dbkeys == null) { if (tab && page.tabs[tab.id]) { - var errorMessage = "No saved databases found."; + const errorMessage = "No saved databases found."; page.tabs[tab.id].errorMessage = errorMessage; console.log(errorMessage); } @@ -390,31 +394,31 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { return false; } - var id = dbkeys[0]; - var idkey = dbkeys[1]; + const id = dbkeys[0]; + const idkey = dbkeys[1]; - var messageData = { + const messageData = { action: "test-associate", id: id, key: idkey }; - var request = { + const request = { action: "test-associate", message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - keepass.callbackOnId(keepass.nativePort.onMessage, "test-associate", function(response) { + keepass.callbackOnId(keepass.nativePort.onMessage, "test-associate", (response) => { if (response.message && response.nonce) { - var res = keepass.decrypt(response.message, response.nonce); + const res = keepass.decrypt(response.message, response.nonce); if (!res) { console.log("Failed to decrypt message"); } else { - var message = nacl.util.encodeUTF8(res); - var parsed = JSON.parse(message); + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); if (parsed.version) { keepass.currentKeePassXC = { @@ -422,10 +426,10 @@ keepass.testAssociation = function (callback, tab, triggerUnlock) { "versionParsed": parseInt(parsed.version.replace(/\./g,""))}; } - var id = parsed.id; + const id = parsed.id; keepass.isEncryptionKeyUnrecognized = false; if (!keepass.verifyResponse(parsed, response.nonce)) { - var hash = response.hash || 0; + const hash = response.hash || 0; keepass.deleteKey(hash); keepass.isEncryptionKeyUnrecognized = true; console.log("Encryption key is not recognized!"); @@ -464,36 +468,35 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) { keepass.changePublicKeys(tab, function(res) {}); } - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); + const key = keepass.b64e(keepass.keyPair.publicKey); + const nonce = nacl.randomBytes(keepass.keySize); - var messageData = { + const messageData = { action: "get-databasehash" }; - var request = { + const request = { action: "get-databasehash", message: keepass.encrypt(messageData, nonce), nonce: keepass.b64e(nonce) }; - //var message = { "action": "get-databasehash" }; - keepass.callbackOnId(keepass.nativePort.onMessage, "get-databasehash", function(response) { + keepass.callbackOnId(keepass.nativePort.onMessage, "get-databasehash", (response) => { if (response.message && response.nonce) { - var res = keepass.decrypt(response.message, response.nonce); + const res = keepass.decrypt(response.message, response.nonce); if (!res) { console.log("Failed to decrypt message"); } else { - var message = nacl.util.encodeUTF8(res); - var parsed = JSON.parse(message); + const message = nacl.util.encodeUTF8(res); + const parsed = JSON.parse(message); if (parsed.hash) { console.log("hash reply received: "+ parsed.hash); - var oldDatabaseHash = keepass.databaseHash; + const oldDatabaseHash = keepass.databaseHash; keepass.setcurrentKeePassXCVersion(parsed.version); keepass.databaseHash = parsed.hash || "no-hash"; @@ -517,14 +520,11 @@ keepass.getDatabaseHash = function (callback, tab, triggerUnlock) { } } } - else if (response.error && response.errorCode) { - keepass.handleError(tab.id, response.error, response.errorCode); - } else { keepass.databaseHash = "no-hash"; if (tab && page.tabs[tab.id]) { - page.tabs[tab.id].errorMessage = "Database hash not received."; + page.tabs[tab.id].errorMessage = response.error.length > 0 ? response.error : "Database hash not received."; } callback(keepass.databaseHash); } @@ -537,14 +537,14 @@ keepass.changePublicKeys = function(tab, callback) { return; } - var key = keepass.b64e(keepass.keyPair.publicKey); - var nonce = nacl.randomBytes(keepass.keySize); - nonce = keepass.b64e(nonce); + const key = keepass.b64e(keepass.keyPair.publicKey); + let nonce = nacl.randomBytes(keepass.keySize); + nonce = keepass.b64e(nonce) - var message = { + const message = { "action": "change-public-keys", "publicKey": key, - "proxyPort": keepass.proxyPort, + "proxyPort": (page.settings.port ? page.settings.port : 19700), "nonce": nonce } @@ -579,7 +579,7 @@ keepass.generateNewKeyPair = function() { keepass.isConfigured = function(callback) { if (typeof(keepass.databaseHash) == "undefined") { - keepass.getDatabaseHash(function(dbHash) { + keepass.getDatabaseHash((dbHash) => { callback(keepass.databaseHash in keepass.keyRing); }, null); } @@ -595,7 +595,7 @@ keepass.isAssociated = function() { keepass.convertKeyToKeyRing = function() { if (keepass.keyId in localStorage && keepass.keyBody in localStorage && !("keyRing" in localStorage)) { - keepass.getDatabaseHash(function(hash) { + keepass.getDatabaseHash((hash) => { keepass.saveKey(hash, localStorage[keepass.keyId], localStorage[keepass.keyBody]); if ("keyRing" in localStorage) { @@ -653,8 +653,8 @@ keepass.setcurrentKeePassXCVersion = function(version) { keepass.keePassXCUpdateAvailable = function() { if (page.settings.checkUpdateKeePassXC && page.settings.checkUpdateKeePassXC > 0) { - var lastChecked = (keepass.latestKeePassXC.lastChecked) ? new Date(keepass.latestKeePassXC.lastChecked) : new Date("11/21/1986"); - var daysSinceLastCheck = Math.floor(((new Date()).getTime()-lastChecked.getTime())/86400000); + 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(); } @@ -664,13 +664,13 @@ keepass.keePassXCUpdateAvailable = function() { } keepass.checkForNewKeePassXCVersion = function() { - var xhr = new XMLHttpRequest(); - var version = -1; + let xhr = new XMLHttpRequest(); + let version = -1; xhr.open("GET", keepass.latestVersionUrl, true); xhr.onload = function(e) { if (xhr.readyState == 4) { if (xhr.status == 200) { - var json = JSON.parse(xhr.responseText); + const json = JSON.parse(xhr.responseText); if (json.tag_name) { version = json.tag_name; keepass.latestKeePassXC.version = version; @@ -729,9 +729,7 @@ keepass.verifyKeyResponse = function(response, key, nonce) { return false; } - var reply = false; - - var respnonce = keepass.b64d(response.nonce); + let reply = false; if (keepass.b64d(nonce).length !== nacl.secretbox.nonceLength) return false; @@ -788,8 +786,8 @@ keepass.getCryptoKey = function() { return null; } - var id = keepass.keyRing[keepass.databaseHash].id; - var key = null; + const id = keepass.keyRing[keepass.databaseHash].id; + let key = null; if (id) { key = keepass.keyRing[keepass.databaseHash].key; @@ -803,10 +801,10 @@ keepass.setCryptoKey = function(id, key) { } keepass.encrypt = function(input, nonce) { - var messageData = nacl.util.decodeUTF8(JSON.stringify(input)); + const messageData = nacl.util.decodeUTF8(JSON.stringify(input)); if (keepass.serverPublicKey) { - var message = nacl.box(messageData, nonce, keepass.serverPublicKey, keepass.keyPair.secretKey); + const message = nacl.box(messageData, nonce, keepass.serverPublicKey, keepass.keyPair.secretKey); if (message) { return keepass.b64e(message); } @@ -816,7 +814,7 @@ keepass.encrypt = function(input, nonce) { } keepass.decrypt = function(input, nonce, toStr) { - var m = keepass.b64d(input); - var n = keepass.b64d(nonce); + const m = keepass.b64d(input); + const n = keepass.b64d(nonce); return nacl.box.open(m, n, keepass.serverPublicKey, keepass.keyPair.secretKey); } diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index 0cbe005..60e2710 100644 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -33,26 +33,28 @@ page.initSettings = function() { if (!("autoRetrieveCredentials" in page.settings)) { page.settings.autoRetrieveCredentials = true; } + if (!("port" in page.settings)) { + page.settings.port = "19700"; + } localStorage.settings = JSON.stringify(page.settings); } page.initOpenedTabs = function() { - browser.tabs.query({}, function(tabs) { - for (var i = 0; i < tabs.length; i++) { - page.createTabEntry(tabs[i].id); + browser.tabs.query({}, (tabs) => { + for (const i of tabs) { + page.createTabEntry(i.id); } }); } page.isValidProtocol = function(url) { - var 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")); } page.switchTab = function(callback, tab) { browserAction.showDefault(null, tab); - browser.tabs.sendMessage(tab.id, {action: "activated_tab"}); } @@ -83,19 +85,19 @@ page.createTabEntry = function(tabId) { } page.removePageInformationFromNotExistingTabs = function() { - var rand = Math.floor(Math.random()*1001); + let rand = Math.floor(Math.random()*1001); if (rand == 28) { - browser.tabs.query({}, function(tabs) { - var $tabIds = {}; - var $infoIds = Object.keys(page.tabs); + browser.tabs.query({}, (tabs) => { + let $tabIds = {}; + const $infoIds = Object.keys(page.tabs); - for (var i = 0; i < tabs.length; i++) { - $tabIds[tabs[i].id] = true; + for (const t of tabs) { + $tabIds[t.id] = true; } - for (var i = 0; i < $infoIds.length; i++) { - if (!($infoIds[i] in $tabIds)) { - delete page.tabs[$infoIds[i]]; + for (const i of $infoIds) { + if (!(i in $tabIds)) { + delete page.tabs[i]; } } }); diff --git a/keepassxc-browser/icons/19x19/icon_cross_19x19.png b/keepassxc-browser/icons/19x19/icon_cross_19x19.png index 9c66c87..93caa1c 100644 Binary files a/keepassxc-browser/icons/19x19/icon_cross_19x19.png and b/keepassxc-browser/icons/19x19/icon_cross_19x19.png differ diff --git a/keepassxc-browser/icons/19x19/icon_new_cross_19x19.png b/keepassxc-browser/icons/19x19/icon_new_cross_19x19.png index 526a6b2..9c0642d 100644 Binary files a/keepassxc-browser/icons/19x19/icon_new_cross_19x19.png and b/keepassxc-browser/icons/19x19/icon_new_cross_19x19.png differ diff --git a/keepassxc-browser/icons/19x19/icon_new_questionmark_blue_19x19.png b/keepassxc-browser/icons/19x19/icon_new_questionmark_blue_19x19.png deleted file mode 100644 index 9c9cfcc..0000000 Binary files a/keepassxc-browser/icons/19x19/icon_new_questionmark_blue_19x19.png and /dev/null differ diff --git a/keepassxc-browser/keepassxc-browser.css b/keepassxc-browser/keepassxc-browser.css index c1be006..4a7be25 100644 --- a/keepassxc-browser/keepassxc-browser.css +++ b/keepassxc-browser/keepassxc-browser.css @@ -69,26 +69,50 @@ input.genpw-text { position: absolute; cursor: pointer; } -.cip-genpw-icon.cip-icon-key-small { +.cip-genpw-icon.small { width: 16px; height: 16px; background-image: url(chrome-extension://__MSG_@@extension_id__/icons/key_16x16.png); } -.cip-genpw-icon.cip-icon-key-big { +.cip-genpw-icon.big { width: 24px; height: 24px; background-image: url(chrome-extension://__MSG_@@extension_id__/icons/key_24x24.png); } -.cip-genpw-icon.cip-icon-key-small-moz { +.cip-genpw-icon.small-moz { width: 16px; height: 16px; background-image: url(moz-extension://__MSG_@@extension_id__/icons/key_16x16.png); } -.cip-genpw-icon.cip-icon-key-big-moz { +.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-btn-fillin { margin-right: 5px; diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 97389dd..941492f 100644 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -17,9 +17,9 @@ var _called = {}; browser.runtime.onMessage.addListener(function(req, sender, callback) { if ('action' in req) { - if(req.action == "fill_user_pass_with_specific_login") { - if(cip.credentials[req.id]) { - var combination = null; + 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); @@ -30,8 +30,8 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) { combination = cipFields.getCombination("password", cip.p); } - var list = {}; - if(cip.fillInStringFields(combination.fields, cip.credentials[req.id].stringFields, list)) { + let list = {}; + if (cip.fillInStringFields(combination.fields, cip.credentials[req.id].stringFields, list)) { cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]}); } } @@ -64,7 +64,7 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) { else if (req.action == "redetect_fields") { browser.runtime.sendMessage({ "action": "get_settings", - }, function(response) { + }, (response) => { cip.settings = response.data; cip.initCredentialFields(true); }); @@ -73,12 +73,12 @@ browser.runtime.onMessage.addListener(function(req, sender, callback) { }); function _f(fieldId) { - var 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) { - var 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; } @@ -119,7 +119,7 @@ cipAutocomplete.onOpen = function(event, ui) { } cipAutocomplete.onSource = function (request, callback) { - var matches = jQuery.map( cipAutocomplete.elements, function(tag) { + const matches = jQuery.map(cipAutocomplete.elements, (tag) => { if (tag.label.toUpperCase().indexOf(request.term.toUpperCase()) === 0) { return tag; } @@ -130,8 +130,8 @@ cipAutocomplete.onSource = function (request, callback) { cipAutocomplete.onSelect = function (e, ui) { e.preventDefault(); cip.setValueWithChange(jQuery(this), ui.item.value); - var fieldId = cipFields.prepareId(jQuery(this).attr("data-cip-id")); - var 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); @@ -142,8 +142,8 @@ cipAutocomplete.onBlur = function() { jQuery(this).data("fetched", false); } else { - var fieldId = cipFields.prepareId(jQuery(this).attr("data-cip-id")); - var fields = cipFields.getCombination("username", fieldId); + 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); } @@ -161,7 +161,6 @@ cipAutocomplete.onFocus = function() { var cipPassword = {}; - cipPassword.observedIcons = []; cipPassword.observingLock = false; @@ -190,9 +189,9 @@ cipPassword.initField = function(field, inputs, pos) { cipPassword.createIcon(field); cipPassword.createDialog(); - var $found = false; + let $found = false; if (inputs) { - for (var i = pos + 1; i < inputs.length; i++) { + 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)); @@ -212,13 +211,13 @@ cipPassword.createDialog = function() { _called.passwordCreateDialog = true; - var $dialog = jQuery("
") + const $dialog = jQuery("
") .addClass("dialog-form") .attr("id", "cip-genpw-dialog"); - var $inputDiv = jQuery("
").addClass("form-group"); - var $inputGroup = jQuery("
").addClass("genpw-input-group"); - var $textfieldPassword = jQuery("") + 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") @@ -227,19 +226,19 @@ cipPassword.createDialog = function() { .on('change keypress paste textInput input', function() { jQuery("#cip-genpw-btn-clipboard:first").removeClass("btn-success"); }); - var $quality = jQuery("") + 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); - var $checkGroup = jQuery("
").addClass("genpw-input-group"); - var $checkboxNextField = jQuery("") + const $checkGroup = jQuery("
").addClass("genpw-input-group"); + const $checkboxNextField = jQuery("") .attr("id", "cip-genpw-checkbox-next-field") .attr("type", "checkbox") .addClass("cip-genpw-checkbox"); - var $labelNextField = jQuery("