Show badge with the number of matching entries (#50)

This commit is contained in:
Maxim Baz
2019-03-30 20:09:05 +01:00
committed by GitHub
parent 0f8b5a31ff
commit 99a58b41ea
3 changed files with 169 additions and 69 deletions

View File

@@ -2,6 +2,7 @@
"use strict";
require("chrome-extension-async");
var TldJS = require("tldjs");
var sha1 = require("sha1");
// native application id
@@ -17,8 +18,12 @@ var defaultSettings = {
var authListeners = {};
chrome.browserAction.setBadgeBackgroundColor({
color: "#666"
});
// watch for tab updates
chrome.tabs.onUpdated.addListener(function(tabId, info) {
chrome.tabs.onUpdated.addListener((tabId, info) => {
// ignore non-complete status
if (info.status !== "complete") {
return;
@@ -29,6 +34,9 @@ chrome.tabs.onUpdated.addListener(function(tabId, info) {
chrome.webRequest.onAuthRequired.removeListener(authListeners[tabId]);
delete authListeners[tabId];
}
// show number of matching passwords in a badge
updateMatchingPasswordsCount(tabId);
});
// handle incoming messages
@@ -43,6 +51,79 @@ chrome.runtime.onInstalled.addListener(onExtensionInstalled);
//----------------------------------- Function definitions ----------------------------------//
/**
* Get the deepest available domain component of a path
*
* @since 3.0.0
*
* @param string path Path to parse
* @return string|null Extracted domain
*/
function pathToDomain(path) {
var parts = path.split(/\//).reverse();
for (var key in parts) {
if (parts[key].indexOf("@") >= 0) {
continue;
}
var t = TldJS.parse(parts[key]);
if (t.isValid && t.domain !== null) {
return t.hostname;
}
}
return null;
}
/**
* Set badge text with the number of matching password entries
*
* @since 3.0.0
*
* @param int tabId Tab id
*/
async function updateMatchingPasswordsCount(tabId) {
try {
const settings = await getFullSettings();
var response = await hostAction(settings, "list");
if (response.status != "ok") {
throw new Error(JSON.stringify(response));
}
// Get tab info
let currentDomain = undefined;
try {
const tab = await chrome.tabs.get(tabId);
currentDomain = new URL(tab.url).hostname;
} catch (e) {
throw new Error(`Unable to determine domain of the tab with id ${tabId}`);
}
let matchedPasswordsCount = 0;
for (var storeId in response.data.files) {
for (var key in response.data.files[storeId]) {
const login = response.data.files[storeId][key].replace(/\.gpg$/i, "");
const domain = pathToDomain(storeId + "/" + login);
const inCurrentDomain =
currentDomain === domain || currentDomain.endsWith("." + domain);
const recent = settings.recent[sha1(currentDomain + sha1(storeId + sha1(login)))];
if (recent || inCurrentDomain) {
matchedPasswordsCount++;
}
}
}
if (matchedPasswordsCount) {
// Set badge for the current tab
chrome.browserAction.setBadgeText({
text: "" + matchedPasswordsCount,
tabId: tabId
});
}
} catch (e) {
console.log(e);
}
}
/**
* Copy text to clipboard
*
@@ -89,6 +170,11 @@ function saveRecent(settings, login, remove = false) {
// save to local storage
localStorage.setItem("recent", JSON.stringify(settings.recent));
// a new entry was added to the popup matching list, need to refresh the count
if (!login.inCurrentDomain && login.recent.count === 1) {
updateMatchingPasswordsCount(settings.tab.id);
}
}
/**
@@ -226,6 +312,83 @@ function getLocalSettings() {
return settings;
}
/**
* Get full settings from the extension and host application
*
* @since 3.0.0
*
* @return object Full settings object
*/
async function getFullSettings() {
var settings = getLocalSettings();
var configureSettings = Object.assign(deepCopy(settings), {
defaultStore: {}
});
var response = await hostAction(configureSettings, "configure");
if (response.status != "ok") {
throw new Error(JSON.stringify(response)); // TODO handle host error
}
settings.version = response.version;
if (Object.keys(settings.stores).length > 0) {
// there are user-configured stores present
for (var storeId in settings.stores) {
if (response.data.storeSettings.hasOwnProperty(storeId)) {
var fileSettings = JSON.parse(response.data.storeSettings[storeId]);
if (typeof settings.stores[storeId].settings !== "object") {
settings.stores[storeId].settings = {};
}
var storeSettings = settings.stores[storeId].settings;
for (var settingKey in fileSettings) {
if (!storeSettings.hasOwnProperty(settingKey)) {
storeSettings[settingKey] = fileSettings[settingKey];
}
}
}
}
} else {
// no user-configured stores, so use the default store
settings.stores.default = {
id: "default",
name: "pass",
path: response.data.defaultStore.path
};
var fileSettings = JSON.parse(response.data.defaultStore.settings);
if (typeof settings.stores.default.settings !== "object") {
settings.stores.default.settings = {};
}
var storeSettings = settings.stores.default.settings;
for (var settingKey in fileSettings) {
if (!storeSettings.hasOwnProperty(settingKey)) {
storeSettings[settingKey] = fileSettings[settingKey];
}
}
}
// Fill recent data
for (var storeId in settings.stores) {
var when = localStorage.getItem("recent:" + storeId);
if (when) {
settings.stores[storeId].when = JSON.parse(when);
} else {
settings.stores[storeId].when = 0;
}
}
settings.recent = localStorage.getItem("recent");
if (settings.recent) {
settings.recent = JSON.parse(settings.recent);
} else {
settings.recent = {};
}
// Fill current tab info
try {
settings.tab = (await chrome.tabs.query({ active: true, currentWindow: true }))[0];
settings.host = new URL(settings.tab.url).hostname;
} catch (e) {}
return settings;
}
/**
* Get most relevant setting value
*
@@ -602,73 +765,8 @@ async function receiveMessage(message, sender, sendResponse) {
return;
}
var settings = getLocalSettings();
try {
var configureSettings = Object.assign(deepCopy(settings), {
defaultStore: {}
});
var response = await hostAction(configureSettings, "configure");
if (response.status != "ok") {
throw new Error(JSON.stringify(response)); // TODO handle host error
}
settings.version = response.version;
if (Object.keys(settings.stores).length > 0) {
// there are user-configured stores present
for (var storeId in settings.stores) {
if (response.data.storeSettings.hasOwnProperty(storeId)) {
var fileSettings = JSON.parse(response.data.storeSettings[storeId]);
if (typeof settings.stores[storeId].settings !== "object") {
settings.stores[storeId].settings = {};
}
var storeSettings = settings.stores[storeId].settings;
for (var settingKey in fileSettings) {
if (!storeSettings.hasOwnProperty(settingKey)) {
storeSettings[settingKey] = fileSettings[settingKey];
}
}
}
}
} else {
// no user-configured stores, so use the default store
settings.stores.default = {
id: "default",
name: "pass",
path: response.data.defaultStore.path
};
var fileSettings = JSON.parse(response.data.defaultStore.settings);
if (typeof settings.stores.default.settings !== "object") {
settings.stores.default.settings = {};
}
var storeSettings = settings.stores.default.settings;
for (var settingKey in fileSettings) {
if (!storeSettings.hasOwnProperty(settingKey)) {
storeSettings[settingKey] = fileSettings[settingKey];
}
}
}
// Fill recent data
for (var storeId in settings.stores) {
var when = localStorage.getItem("recent:" + storeId);
if (when) {
settings.stores[storeId].when = JSON.parse(when);
} else {
settings.stores[storeId].when = 0;
}
}
settings.recent = localStorage.getItem("recent");
if (settings.recent) {
settings.recent = JSON.parse(settings.recent);
} else {
settings.recent = {};
}
// Fill current tab info
try {
settings.tab = (await chrome.tabs.query({ active: true, currentWindow: true }))[0];
settings.host = new URL(settings.tab.url).hostname;
} catch (e) {}
const settings = await getFullSettings();
handleMessage(settings, message, sendResponse);
} catch (e) {
// handle error

View File

@@ -23,8 +23,9 @@
"open_in_tab": false
},
"permissions": [
"clipboardWrite",
"activeTab",
"tabs",
"clipboardWrite",
"nativeMessaging",
"notifications",
"webRequest",

View File

@@ -21,8 +21,9 @@
"open_in_tab": false
},
"permissions": [
"clipboardWrite",
"activeTab",
"tabs",
"clipboardWrite",
"nativeMessaging",
"notifications",
"webRequest",