Barebones implementation of 'list' action (#2)
This commit is contained in:
@@ -17,7 +17,12 @@ var defaultSettings = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// handle incoming messages
|
// handle incoming messages
|
||||||
browser.runtime.onMessage.addListener(receiveMessage);
|
browser.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||||
|
receiveMessage(message, sender, sendResponse);
|
||||||
|
|
||||||
|
// allow async responses after this function returns
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
//----------------------------------- Function definitions ----------------------------------//
|
//----------------------------------- Function definitions ----------------------------------//
|
||||||
/**
|
/**
|
||||||
@@ -49,7 +54,7 @@ function getLocalSettings() {
|
|||||||
* @param function(mixed) sendResponse Callback to send response
|
* @param function(mixed) sendResponse Callback to send response
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handleMessage(settings, message, sendResponse) {
|
async function handleMessage(settings, message, sendResponse) {
|
||||||
// check that action is present
|
// check that action is present
|
||||||
if (typeof message !== "object" || !message.hasOwnProperty("action")) {
|
if (typeof message !== "object" || !message.hasOwnProperty("action")) {
|
||||||
sendResponse({ status: "error", message: "Action is missing" });
|
sendResponse({ status: "error", message: "Action is missing" });
|
||||||
@@ -66,6 +71,14 @@ function handleMessage(settings, message, sendResponse) {
|
|||||||
saveSettings(message.settings);
|
saveSettings(message.settings);
|
||||||
sendResponse({ status: "ok" });
|
sendResponse({ status: "ok" });
|
||||||
break;
|
break;
|
||||||
|
case "listFiles":
|
||||||
|
try {
|
||||||
|
var response = await hostAction(settings, "list");
|
||||||
|
sendResponse(response.data.files);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sendResponse({
|
sendResponse({
|
||||||
status: "error",
|
status: "error",
|
||||||
@@ -75,6 +88,28 @@ function handleMessage(settings, message, sendResponse) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a request to the host app
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @param object settings Live settings object
|
||||||
|
* @param string action Action to run
|
||||||
|
* @param params object Additional params to pass to the host app
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
function hostAction(settings, action, params = {}) {
|
||||||
|
var request = {
|
||||||
|
settings: settings,
|
||||||
|
action: action
|
||||||
|
};
|
||||||
|
for (var key in params) {
|
||||||
|
request[key] = params[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return browser.runtime.sendNativeMessage(appID, request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap inbound messages to fetch native configuration
|
* Wrap inbound messages to fetch native configuration
|
||||||
*
|
*
|
||||||
@@ -105,7 +140,7 @@ async function receiveMessage(message, sender, sendResponse) {
|
|||||||
for (var key in settings.stores) {
|
for (var key in settings.stores) {
|
||||||
if (response.data.storeSettings.hasOwnProperty(key)) {
|
if (response.data.storeSettings.hasOwnProperty(key)) {
|
||||||
var fileSettings = JSON.parse(response.data.storeSettings[key]);
|
var fileSettings = JSON.parse(response.data.storeSettings[key]);
|
||||||
if (typeof(settings.stores[key].settings) !== "object") {
|
if (typeof settings.stores[key].settings !== "object") {
|
||||||
settings.stores[key].settings = {};
|
settings.stores[key].settings = {};
|
||||||
}
|
}
|
||||||
var storeSettings = settings.stores[key].settings;
|
var storeSettings = settings.stores[key].settings;
|
||||||
@@ -130,9 +165,6 @@ async function receiveMessage(message, sender, sendResponse) {
|
|||||||
console.log(e);
|
console.log(e);
|
||||||
sendResponse({ status: "error", message: e.toString() });
|
sendResponse({ status: "error", message: e.toString() });
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow async responses after this function returns
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
6
src/global.css
Normal file
6
src/global.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
html, body {
|
||||||
|
font-family: sans;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
@@ -20,14 +20,7 @@
|
|||||||
"default_popup": "popup.html"
|
"default_popup": "popup.html"
|
||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"tabs",
|
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"nativeMessaging",
|
"nativeMessaging"
|
||||||
"notifications",
|
|
||||||
"storage",
|
|
||||||
"webRequest",
|
|
||||||
"webRequestBlocking",
|
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chrome-extension-async": "^3.0.0"
|
"chrome-extension-async": "^3.0.0",
|
||||||
|
"fuzzysort": "^1.1.0",
|
||||||
|
"mithril": "^1.1.0",
|
||||||
|
"tldjs": "^2.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "^16.2.0",
|
"browserify": "^16.2.0",
|
||||||
|
28
src/popup.css
Normal file
28
src/popup.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 4px 4px 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part:last-child {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part.error {
|
||||||
|
color: #F00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part.notice {
|
||||||
|
color: #090;
|
||||||
|
}
|
||||||
|
|
@@ -1,9 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="global.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="popup.css" />
|
||||||
<script src="popup.js"></script>
|
<script src="popup.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>TODO</p>
|
<div class="part notice">Loading available logins...</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
201
src/popup.src.js
201
src/popup.src.js
@@ -2,23 +2,208 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
require("chrome-extension-async");
|
require("chrome-extension-async");
|
||||||
|
var Mithril = require("mithril");
|
||||||
|
var TldJS = require("tldjs");
|
||||||
|
var FuzzySort = require("fuzzysort");
|
||||||
|
|
||||||
|
var startTime = Date.now();
|
||||||
var settings = null;
|
var settings = null;
|
||||||
|
var error = null;
|
||||||
|
var notice = null;
|
||||||
|
var logins = [];
|
||||||
|
var domainLogins = [];
|
||||||
|
|
||||||
if (typeof browser === "undefined") {
|
if (typeof browser === "undefined") {
|
||||||
var browser = chrome;
|
var browser = chrome;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.runtime.sendMessage({ action: "getSettings" }).then(
|
// performance debugging function - TODO remove once extension is ready for release
|
||||||
function(response) {
|
function checkpoint(activity) {
|
||||||
|
console.log("Elapsed: " + (Date.now() - startTime) + "ms (" + activity + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap with current tab & settings
|
||||||
|
checkpoint("start");
|
||||||
|
browser.tabs.query({ active: true, currentWindow: true }, async function(tabs) {
|
||||||
|
checkpoint("after tab");
|
||||||
|
try {
|
||||||
|
var response = browser.runtime.sendMessage({ action: "getSettings" });
|
||||||
|
checkpoint("after getSettings");
|
||||||
settings = response;
|
settings = response;
|
||||||
|
settings.tab = tabs[0];
|
||||||
|
settings.host = new URL(settings.tab.url).hostname;
|
||||||
run();
|
run();
|
||||||
},
|
} catch (e) {
|
||||||
function(response) {
|
console.log(e.toString()); // TODO
|
||||||
console.log(response); // TODO
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
//----------------------------------- Function definitions ----------------------------------//
|
//----------------------------------- Function definitions ----------------------------------//
|
||||||
function run() {
|
|
||||||
console.log(settings); // TODO
|
/**
|
||||||
|
* Get the logins which match the provided domain
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @param string domain Domain to filter against
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getDomainLogins(domain) {
|
||||||
|
var domainLogins = [];
|
||||||
|
var t = TldJS.parse(domain);
|
||||||
|
|
||||||
|
// ignore invalid domains
|
||||||
|
if (!t.isValid || t.domain === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter against the domain
|
||||||
|
for (var key in logins) {
|
||||||
|
if (logins[key].domain === t.hostname) {
|
||||||
|
domainLogins.push(logins[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse and add matching domains to the list
|
||||||
|
domainLogins = domainLogins.concat(getDomainLogins(t.hostname.replace(/^.+?\./, "")));
|
||||||
|
|
||||||
|
return domainLogins;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the popup contents
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function render() {
|
||||||
|
var body = document.getElementsByTagName("body")[0];
|
||||||
|
Mithril.mount(body, {
|
||||||
|
view: function() {
|
||||||
|
return [renderError(), renderNotice(), renderList()];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
checkpoint("after render");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render any error messages
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @return Vnode
|
||||||
|
*/
|
||||||
|
function renderError() {
|
||||||
|
return error === null ? null : Mithril("div.part.error", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render any notices
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @return Vnode
|
||||||
|
*/
|
||||||
|
function renderNotice() {
|
||||||
|
return notice === null ? null : Mithril("div.part.notice", notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the list of available logins
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @return []Vnode
|
||||||
|
*/
|
||||||
|
function renderList() {
|
||||||
|
if (!logins.length) {
|
||||||
|
showError("There are no matching logins available");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = [];
|
||||||
|
domainLogins.forEach(function(login) {
|
||||||
|
list.push(
|
||||||
|
Mithril("div.part.login", { title: login.domain }, login.store + ":" + login.login)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (!list.length) {
|
||||||
|
showNotice("There are no logins matching " + settings.host + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkpoint("after renderList");
|
||||||
|
return Mithril("div.logins", list);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
try {
|
||||||
|
// get list of logins
|
||||||
|
var response = await browser.runtime.sendMessage({ action: "listFiles" });
|
||||||
|
checkpoint("after listFiles");
|
||||||
|
for (var store in response) {
|
||||||
|
for (var key in response[store]) {
|
||||||
|
var login = {
|
||||||
|
store: store,
|
||||||
|
login: response[store][key].replace(/\.gpg$/i, "")
|
||||||
|
};
|
||||||
|
login.domain = pathToDomain(login.store + "/" + login.login);
|
||||||
|
logins.push(login);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkpoint("after listFiles post-processing");
|
||||||
|
|
||||||
|
domainLogins = getDomainLogins(settings.host);
|
||||||
|
|
||||||
|
render();
|
||||||
|
} catch (e) {
|
||||||
|
showError(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an error message
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @param string message Message text
|
||||||
|
*/
|
||||||
|
function showError(message) {
|
||||||
|
error = message;
|
||||||
|
Mithril.redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an informational message
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*
|
||||||
|
* @param string message Message text
|
||||||
|
*/
|
||||||
|
function showNotice(message) {
|
||||||
|
notice = message;
|
||||||
|
Mithril.redraw();
|
||||||
}
|
}
|
||||||
|
@@ -400,6 +400,10 @@ function-bind@^1.0.2:
|
|||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||||
|
|
||||||
|
fuzzysort@^1.1.0:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-1.1.1.tgz#bf128f1a4cc6e6b7188665ac5676de46a3d81768"
|
||||||
|
|
||||||
glob@^7.1.0:
|
glob@^7.1.0:
|
||||||
version "7.1.2"
|
version "7.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||||
@@ -572,6 +576,10 @@ minimist@^1.1.0, minimist@^1.1.1:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||||
|
|
||||||
|
mithril@^1.1.0:
|
||||||
|
version "1.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/mithril/-/mithril-1.1.6.tgz#bd2cc0de3d3c86076a6a7a30367a601a1bd108f3"
|
||||||
|
|
||||||
mkdirp@^0.5.0:
|
mkdirp@^0.5.0:
|
||||||
version "0.5.1"
|
version "0.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||||
@@ -680,7 +688,7 @@ punycode@1.3.2:
|
|||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||||
|
|
||||||
punycode@^1.3.2:
|
punycode@^1.3.2, punycode@^1.4.1:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||||
|
|
||||||
@@ -837,6 +845,12 @@ timers-browserify@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
process "~0.11.0"
|
process "~0.11.0"
|
||||||
|
|
||||||
|
tldjs@^2.3.0:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tldjs/-/tldjs-2.3.1.tgz#cf09c3eb5d7403a9e214b7d65f3cf9651c0ab039"
|
||||||
|
dependencies:
|
||||||
|
punycode "^1.4.1"
|
||||||
|
|
||||||
to-arraybuffer@^1.0.0:
|
to-arraybuffer@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||||
|
Reference in New Issue
Block a user