Skip to content

Commit

Permalink
Issue #24 - Track modifications if sync is set up
Browse files Browse the repository at this point in the history
  • Loading branch information
palant committed Feb 19, 2018
1 parent 00092f2 commit 7e61dfd
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 18 deletions.
12 changes: 5 additions & 7 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@ panelPort.on("connect", () =>

Promise.all([
getCurrentHost(),
masterPassword.state
]).then(([currentHost, masterPasswordState]) =>
masterPassword.state,
sync.provider
]).then(([currentHost, masterPasswordState, syncProvider]) =>
{
if (masterPasswordState != "known")
return panelPort.emit("init", {masterPasswordState, origSite: currentHost});
return panelPort.emit("init", {masterPasswordState, origSite: currentHost, syncProvider});

return Promise.all([
passwords.getPasswords(currentHost),
sync.provider
]).then(([[origSite, site, pwdList], syncProvider]) =>
return passwords.getPasswords(currentHost).then(([origSite, site, pwdList]) =>
{
panelPort.emit("init", {
masterPasswordState, origSite, site, pwdList, syncProvider
Expand Down
44 changes: 39 additions & 5 deletions lib/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
let browser = require("./browserAPI");
let {generateSalt, deriveKey} = require("./crypto");

const prefsPrefix = "pref:";

function has(name)
{
return browser.storage.local.get(name).then(items =>
Expand Down Expand Up @@ -45,7 +47,7 @@ function getAllByPrefix(prefix, key)
{
let {decrypt} = require("./masterPassword");
let result = {};
let names = Object.keys(items).filter(name => name.startsWith(prefix));
let names = Object.keys(items).filter(name => name.startsWith(prefix) && !name.startsWith(prefsPrefix));
let decryptNextName = () =>
{
if (!names.length)
Expand All @@ -68,33 +70,65 @@ function set(name, value, key)
return require("./masterPassword").encrypt(value, key).then(ciphertext =>
{
return browser.storage.local.set({[name]: ciphertext});
}).then(() =>
{
triggerModificationListeners(name);
});
}
exports.set = set;

function delete_(name)
{
return browser.storage.local.remove(name);
return browser.storage.local.remove(name).then(() =>
{
if (Array.isArray(name))
{
for (let n of name)
triggerModificationListeners(n);
}
else
triggerModificationListeners(name);
});
}
exports.delete = delete_;

function deleteByPrefix(prefix)
{
return browser.storage.local.get(null).then(items =>
{
let keys = Object.keys(items).filter(name => name.substr(0, prefix.length) == prefix);
let keys = Object.keys(items).filter(name => name.startsWith(prefix));
return delete_(keys);
});
}
exports.deleteByPrefix = deleteByPrefix;

function clear()
{
const prefsPrefix = "pref:";
return browser.storage.local.get(null).then(items =>
{
let keys = Object.keys(items).filter(name => name.substr(0, prefsPrefix.length) != prefsPrefix);
let keys = Object.keys(items).filter(name => !name.startsWith(prefsPrefix));
return delete_(keys);
});
}
exports.clear = clear;

let modificationListeners = [];
function triggerModificationListeners(key)
{
for (let listener of modificationListeners)
listener(key);
}

function addModificationListener(listener)
{
modificationListeners.push(listener);
}
exports.addModificationListener = addModificationListener;

function removeModificationListener(listener)
{
let index = modificationListeners.indexOf(listener);
if (index >= 0)
modificationListeners.splice(index, 1);
}
exports.removeModificationListener = removeModificationListener;
91 changes: 85 additions & 6 deletions lib/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,104 @@
"use strict";

let storage = require("./storage");
let {lock, STORAGE_PREFIX: passwordsPrefix} = require("./passwords");

Object.defineProperty(exports, "provider", {
enumerable: true,
get: () =>
const dataKey = "syncData";

function isKeyIncluded(key)
{
return key.startsWith(passwordsPrefix);
}

let tracker = {
enabled: false,
prefix: "sync:",

onModified(key)
{
return storage.get("syncData").then(value => value ? value.provider : null);
if (!isKeyIncluded(key))
return;

lock.acquire().then(() =>
{
return storage.set(this.prefix + key, true, null);
}).finally(() => lock.release());
},

enable(startUp)
{
if (this.enabled)
return Promise.resolve();

this.enabled = true;
let waitFor;
if (startUp)
{
storage.addModificationListener(this.onModified);
return Promise.resolve();
}
else
{
return storage.getAllByPrefix(passwordsPrefix, null).then(items =>
{
storage.addModificationListener(this.onModified);
let actions = [];
for (let key in items)
actions.push(storage.set(this.prefix + key, true, null));
return Promise.all(actions);
});
}
},

disable()
{
if (!this.enabled)
return Promise.resolve();

storage.removeModificationListener(this.onModified);
this.enabled = false;
return storage.deleteByPrefix(this.prefix);
}
};
tracker.onModified = tracker.onModified.bind(tracker);

let syncData = null;
storage.get(dataKey, null).then(value =>
{
syncData = value;
if (syncData)
tracker.enable(true);
});

Object.defineProperty(exports, "provider", {
enumerable: true,
get: () => syncData ? syncData.provider : null
});

exports.authorize = function()
{
let provider = require("./sync-providers/dropbox");
return provider.authorize().then(token =>
{
storage.set("syncData", {provider: "dropbox", token});
return lock.acquire().then(() =>
{
syncData = {provider: "dropbox", token};
return Promise.all([
storage.set(dataKey, syncData, null),
tracker.enable()
]);
}).finally(() => lock.release());
});
};

exports.disable = function()
{
return storage.delete("syncData");
return lock.acquire().then(() =>
{
syncData = null;
return Promise.all([
storage.delete(dataKey),
tracker.disable()
]);
}).finally(() => lock.release());
};

0 comments on commit 7e61dfd

Please sign in to comment.