2016-09-28 04:44:42 +02:00
|
|
|
var isBackground = true;
|
2016-09-21 07:17:46 +02:00
|
|
|
var utilsService = new UtilsService();
|
2016-09-16 05:24:45 +02:00
|
|
|
var cryptoService = new CryptoService();
|
2016-09-03 06:03:13 +02:00
|
|
|
var tokenService = new TokenService();
|
2016-09-03 06:38:27 +02:00
|
|
|
var apiService = new ApiService(tokenService);
|
2016-09-21 05:30:16 +02:00
|
|
|
var userService = new UserService(tokenService, apiService, cryptoService);
|
2016-09-04 03:45:45 +02:00
|
|
|
var siteService = new SiteService(cryptoService, userService, apiService);
|
2016-09-04 06:34:24 +02:00
|
|
|
var folderService = new FolderService(cryptoService, userService, apiService);
|
2016-09-07 05:30:49 +02:00
|
|
|
var syncService = new SyncService(siteService, folderService, userService, apiService);
|
2016-09-17 06:00:17 +02:00
|
|
|
var autofillService = new AutofillService();
|
2016-09-18 04:57:51 +02:00
|
|
|
var passwordGenerationService = new PasswordGenerationService();
|
2016-09-23 05:00:22 +02:00
|
|
|
var appIdService = new AppIdService();
|
2016-09-16 05:24:45 +02:00
|
|
|
|
2016-10-08 22:37:50 +02:00
|
|
|
chrome.commands.onCommand.addListener(function (command) {
|
|
|
|
if (command === 'generate_password') {
|
2016-10-09 00:09:38 +02:00
|
|
|
ga('send', {
|
|
|
|
hitType: 'event',
|
|
|
|
eventAction: 'Generated Password From Command'
|
|
|
|
});
|
2016-10-08 22:37:50 +02:00
|
|
|
passwordGenerationService.getOptions().then(function (options) {
|
|
|
|
var password = passwordGenerationService.generatePassword(options);
|
|
|
|
copyToClipboard(password);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-09-29 01:12:14 +02:00
|
|
|
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
|
|
|
|
if (msg.command === 'loggedOut') {
|
|
|
|
setIcon(true);
|
|
|
|
refreshBadgeAndMenu();
|
|
|
|
}
|
|
|
|
else if (msg.command === 'loggedIn') {
|
|
|
|
setIcon(false);
|
|
|
|
}
|
|
|
|
else if (msg.command === 'syncCompleted' && msg.successfully) {
|
|
|
|
setTimeout(refreshBadgeAndMenu, 2000);
|
|
|
|
}
|
2016-09-29 06:14:15 +02:00
|
|
|
else if (msg.command === 'bgOpenOverlayPopup') {
|
|
|
|
messageCurrentTab('openOverlayPopup', msg.data);
|
|
|
|
}
|
|
|
|
else if (msg.command === 'bgCloseOverlayPopup') {
|
|
|
|
messageCurrentTab('closeOverlayPopup');
|
|
|
|
}
|
2016-09-28 05:36:55 +02:00
|
|
|
});
|
|
|
|
|
2016-09-29 01:12:14 +02:00
|
|
|
userService.isAuthenticated(function (isAuthenticated) {
|
|
|
|
setIcon(!isAuthenticated);
|
|
|
|
});
|
|
|
|
|
|
|
|
function setIcon(grayedOut) {
|
|
|
|
var suffix = '';
|
|
|
|
if (grayedOut) {
|
|
|
|
suffix = '_gray';
|
|
|
|
}
|
|
|
|
|
|
|
|
chrome.browserAction.setIcon({
|
|
|
|
path: {
|
|
|
|
'19': 'images/icon19' + suffix + '.png',
|
|
|
|
'38': 'images/icon38' + suffix + '.png',
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chrome.runtime.onInstalled) {
|
|
|
|
chrome.runtime.onInstalled.addListener(function (details) {
|
|
|
|
ga('send', {
|
|
|
|
hitType: 'event',
|
|
|
|
eventAction: 'onInstalled ' + details.reason
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-17 02:20:02 +02:00
|
|
|
function buildContextMenu() {
|
|
|
|
chrome.contextMenus.removeAll();
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
|
|
|
id: 'autofill',
|
2016-09-17 04:48:41 +02:00
|
|
|
contexts: ['all'],
|
2016-09-17 02:20:02 +02:00
|
|
|
title: 'Auto-fill'
|
|
|
|
});
|
|
|
|
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
|
|
|
id: 'copy-username',
|
2016-09-17 04:48:41 +02:00
|
|
|
contexts: ['all'],
|
2016-09-17 02:20:02 +02:00
|
|
|
title: 'Copy Username'
|
|
|
|
});
|
|
|
|
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
|
|
|
id: 'copy-password',
|
2016-09-17 04:48:41 +02:00
|
|
|
contexts: ['all'],
|
2016-09-17 02:20:02 +02:00
|
|
|
title: 'Copy Password'
|
|
|
|
});
|
2016-10-09 00:09:38 +02:00
|
|
|
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'separator'
|
|
|
|
});
|
|
|
|
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
|
|
|
id: 'generate-password',
|
|
|
|
contexts: ['all'],
|
|
|
|
title: 'Generate Password (copied)'
|
|
|
|
});
|
2016-09-17 02:20:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
chrome.tabs.onActivated.addListener(function (activeInfo) {
|
|
|
|
buildContextMenu();
|
2016-09-29 01:12:14 +02:00
|
|
|
refreshBadgeAndMenu();
|
2016-09-17 02:20:02 +02:00
|
|
|
});
|
|
|
|
|
2016-09-23 04:04:50 +02:00
|
|
|
var loadedMenu = false;
|
|
|
|
chrome.tabs.onReplaced.addListener(function (addedTabId, removedTabId) {
|
2016-09-29 01:12:14 +02:00
|
|
|
refreshBadgeAndMenu();
|
|
|
|
});
|
|
|
|
|
|
|
|
function refreshBadgeAndMenu() {
|
|
|
|
chrome.tabs.query({ active: true }, function (tabs) {
|
2016-09-23 04:04:50 +02:00
|
|
|
var tab = null;
|
|
|
|
if (tabs.length > 0) {
|
|
|
|
tab = tabs[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tab) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-29 01:12:14 +02:00
|
|
|
buildContextMenu();
|
|
|
|
loadMenuAndUpdateBadge(tab.url, tab.id, true);
|
2016-09-23 04:04:50 +02:00
|
|
|
});
|
2016-09-29 01:12:14 +02:00
|
|
|
}
|
2016-09-23 04:04:50 +02:00
|
|
|
|
2016-09-16 05:24:45 +02:00
|
|
|
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
|
2016-09-17 02:20:02 +02:00
|
|
|
buildContextMenu();
|
2016-09-23 04:04:50 +02:00
|
|
|
loadMenuAndUpdateBadge(tab.url, tabId, true);
|
|
|
|
});
|
|
|
|
|
|
|
|
function loadMenuAndUpdateBadge(url, tabId, loadContextMenuOptions) {
|
|
|
|
loadedMenu = false;
|
|
|
|
if (!url) {
|
2016-09-16 05:24:45 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-23 04:04:50 +02:00
|
|
|
var tabDomain = tldjs.getDomain(url);
|
2016-09-16 05:24:45 +02:00
|
|
|
if (!tabDomain) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var count = 0;
|
|
|
|
chrome.browserAction.setBadgeBackgroundColor({ color: '#294e5f' });
|
|
|
|
|
|
|
|
siteService.getAllDecrypted().then(function (sites) {
|
2016-09-23 04:04:50 +02:00
|
|
|
if (loadedMenu) {
|
2016-09-17 02:20:02 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-09-23 04:04:50 +02:00
|
|
|
loadedMenu = true;
|
2016-09-17 02:20:02 +02:00
|
|
|
|
|
|
|
sortSites(sites);
|
2016-09-16 05:24:45 +02:00
|
|
|
for (var i = 0; i < sites.length; i++) {
|
2016-09-21 06:26:23 +02:00
|
|
|
if (sites[i].domain && tabDomain === sites[i].domain) {
|
2016-09-16 05:24:45 +02:00
|
|
|
count++;
|
2016-09-23 04:04:50 +02:00
|
|
|
|
|
|
|
if (loadContextMenuOptions) {
|
|
|
|
loadSiteContextMenuOptions(sites[i]);
|
|
|
|
}
|
2016-09-16 05:24:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 0 && count < 9) {
|
|
|
|
chrome.browserAction.setBadgeText({
|
|
|
|
text: count.toString(),
|
|
|
|
tabId: tabId
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if (count > 0) {
|
|
|
|
chrome.browserAction.setBadgeText({
|
|
|
|
text: '9+',
|
|
|
|
tabId: tabId
|
|
|
|
});
|
|
|
|
}
|
2016-09-21 06:04:59 +02:00
|
|
|
else {
|
2016-09-22 05:59:53 +02:00
|
|
|
loadNoSitesContextMenuOptions();
|
2016-09-21 06:04:59 +02:00
|
|
|
chrome.browserAction.setBadgeText({
|
2016-09-29 01:12:14 +02:00
|
|
|
text: '',
|
2016-09-21 06:04:59 +02:00
|
|
|
tabId: tabId
|
|
|
|
});
|
|
|
|
}
|
2016-09-16 05:24:45 +02:00
|
|
|
});
|
2016-09-23 04:04:50 +02:00
|
|
|
}
|
2016-09-17 02:20:02 +02:00
|
|
|
|
|
|
|
chrome.contextMenus.onClicked.addListener(function (info, tab) {
|
2016-10-09 00:09:38 +02:00
|
|
|
if (info.menuItemId === 'generate-password') {
|
|
|
|
ga('send', {
|
|
|
|
hitType: 'event',
|
|
|
|
eventAction: 'Generated Password From Context Menu'
|
|
|
|
});
|
|
|
|
passwordGenerationService.getOptions().then(function (options) {
|
|
|
|
var password = passwordGenerationService.generatePassword(options);
|
|
|
|
copyToClipboard(password);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if (info.parentMenuItemId === 'autofill' || info.parentMenuItemId === 'copy-username' ||
|
2016-09-17 06:13:12 +02:00
|
|
|
info.parentMenuItemId === 'copy-password') {
|
2016-09-17 02:20:02 +02:00
|
|
|
var id = info.menuItemId.split('_')[1];
|
2016-09-22 05:59:53 +02:00
|
|
|
if (id === 'noop') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-17 02:20:02 +02:00
|
|
|
siteService.getAllDecrypted().then(function (sites) {
|
|
|
|
for (var i = 0; i < sites.length; i++) {
|
2016-09-21 06:26:23 +02:00
|
|
|
if (sites[i].id === id) {
|
2016-09-17 06:13:12 +02:00
|
|
|
if (info.parentMenuItemId === 'autofill') {
|
2016-09-28 05:19:33 +02:00
|
|
|
ga('send', {
|
|
|
|
hitType: 'event',
|
|
|
|
eventAction: 'Autofilled From Context Menu'
|
|
|
|
});
|
2016-09-17 06:13:12 +02:00
|
|
|
autofillPage(sites[i]);
|
|
|
|
}
|
|
|
|
else if (info.parentMenuItemId === 'copy-username') {
|
2016-09-28 05:19:33 +02:00
|
|
|
ga('send', {
|
|
|
|
hitType: 'event',
|
|
|
|
eventAction: 'Copied Username From Context Menu'
|
|
|
|
});
|
2016-09-17 02:20:02 +02:00
|
|
|
copyToClipboard(sites[i].username);
|
|
|
|
}
|
|
|
|
else if (info.parentMenuItemId === 'copy-password') {
|
2016-09-28 05:19:33 +02:00
|
|
|
ga('send', {
|
|
|
|
hitType: 'event',
|
|
|
|
eventAction: 'Copied Password From Context Menu'
|
|
|
|
});
|
2016-09-17 02:20:02 +02:00
|
|
|
copyToClipboard(sites[i].password);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-09-22 05:41:53 +02:00
|
|
|
function messageCurrentTab(command, data) {
|
|
|
|
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
|
|
|
|
var tabId = null;
|
|
|
|
if (tabs.length > 0) {
|
|
|
|
tabId = tabs[0].id;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tabId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var obj = {
|
|
|
|
command: command
|
|
|
|
};
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
obj['data'] = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
chrome.tabs.sendMessage(tabId, obj);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-17 06:13:12 +02:00
|
|
|
function autofillPage(site) {
|
|
|
|
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
|
|
|
|
var tabId = null;
|
|
|
|
if (tabs.length > 0) {
|
|
|
|
tabId = tabs[0].id;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tabId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
chrome.tabs.sendMessage(tabId, { command: 'collectPageDetails' }, function (pageDetails) {
|
|
|
|
var fillScript = null;
|
|
|
|
if (site && pageDetails) {
|
|
|
|
fillScript = autofillService.generateFillScript(pageDetails, site.username, site.password);
|
|
|
|
}
|
|
|
|
|
2016-09-22 05:59:53 +02:00
|
|
|
if (tabId && fillScript && fillScript.script) {
|
2016-09-17 06:13:12 +02:00
|
|
|
chrome.tabs.sendMessage(tabId, {
|
|
|
|
command: 'fillForm',
|
|
|
|
fillScript: fillScript
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-09-17 02:20:02 +02:00
|
|
|
function sortSites(sites) {
|
|
|
|
sites.sort(function (a, b) {
|
|
|
|
var nameA = (a.name + '_' + a.username).toUpperCase();
|
|
|
|
var nameB = (b.name + '_' + b.username).toUpperCase();
|
|
|
|
|
|
|
|
if (nameA < nameB) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (nameA > nameB) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function buildContextMenuOptions(url) {
|
|
|
|
var tabDomain = tldjs.getDomain(url);
|
|
|
|
if (!tabDomain) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
siteService.getAllDecrypted().then(function (sites) {
|
2016-09-22 05:59:53 +02:00
|
|
|
var count = 0;
|
|
|
|
if (sites && sites.length) {
|
|
|
|
sortSites(sites);
|
|
|
|
for (var i = 0; i < sites.length; i++) {
|
|
|
|
if (sites[i].domain && tabDomain === sites[i].domain) {
|
|
|
|
count++;
|
|
|
|
loadSiteContextMenuOptions(sites[i]);
|
|
|
|
}
|
2016-09-17 02:20:02 +02:00
|
|
|
}
|
|
|
|
}
|
2016-09-22 05:59:53 +02:00
|
|
|
|
|
|
|
if (!count) {
|
|
|
|
loadNoSitesContextMenuOptions();
|
|
|
|
}
|
2016-09-17 02:20:02 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-22 05:59:53 +02:00
|
|
|
function loadSiteContextMenuOptions(site) {
|
2016-09-17 02:20:02 +02:00
|
|
|
var title = site.name + ' (' + site.username + ')';
|
2016-09-22 05:59:53 +02:00
|
|
|
loadContextMenuOptions(title, site.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadNoSitesContextMenuOptions() {
|
|
|
|
var title = 'No matching sites.';
|
|
|
|
loadContextMenuOptions(title, 'noop');
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadContextMenuOptions(title, idSuffix) {
|
2016-09-17 02:20:02 +02:00
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
2016-09-22 05:59:53 +02:00
|
|
|
id: 'autofill_' + idSuffix,
|
2016-09-17 02:20:02 +02:00
|
|
|
parentId: 'autofill',
|
2016-09-17 04:48:41 +02:00
|
|
|
contexts: ['all'],
|
2016-09-17 02:20:02 +02:00
|
|
|
title: title
|
|
|
|
});
|
|
|
|
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
2016-09-22 05:59:53 +02:00
|
|
|
id: 'copy-username_' + idSuffix,
|
2016-09-17 02:20:02 +02:00
|
|
|
parentId: 'copy-username',
|
2016-09-17 04:48:41 +02:00
|
|
|
contexts: ['all'],
|
2016-09-17 02:20:02 +02:00
|
|
|
title: title
|
|
|
|
});
|
|
|
|
|
|
|
|
chrome.contextMenus.create({
|
|
|
|
type: 'normal',
|
2016-09-22 05:59:53 +02:00
|
|
|
id: 'copy-password_' + idSuffix,
|
2016-09-17 02:20:02 +02:00
|
|
|
parentId: 'copy-password',
|
2016-09-17 04:48:41 +02:00
|
|
|
contexts: ['all'],
|
2016-09-17 02:20:02 +02:00
|
|
|
title: title
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function copyToClipboard(text) {
|
|
|
|
if (window.clipboardData && window.clipboardData.setData) {
|
|
|
|
// IE specific code path to prevent textarea being shown while dialog is visible.
|
|
|
|
return clipboardData.setData('Text', text);
|
|
|
|
}
|
|
|
|
else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
|
|
|
|
var textarea = document.createElement('textarea');
|
|
|
|
textarea.textContent = text;
|
|
|
|
// Prevent scrolling to bottom of page in MS Edge.
|
|
|
|
textarea.style.position = 'fixed';
|
|
|
|
document.body.appendChild(textarea);
|
|
|
|
textarea.select();
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Security exception may be thrown by some browsers.
|
|
|
|
return document.execCommand('copy');
|
|
|
|
}
|
|
|
|
catch (ex) {
|
|
|
|
console.warn('Copy to clipboard failed.', ex);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
document.body.removeChild(textarea);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-21 06:26:23 +02:00
|
|
|
|
2016-09-22 02:13:52 +02:00
|
|
|
// Sync polling
|
2016-09-21 06:26:23 +02:00
|
|
|
|
2016-09-22 02:13:52 +02:00
|
|
|
fullSync(true);
|
|
|
|
setInterval(fullSync, 5 * 60 * 1000); // check every 5 minutes
|
|
|
|
var syncInternal = 6 * 60 * 60 * 1000; // 6 hours
|
|
|
|
|
|
|
|
function fullSync(override) {
|
|
|
|
syncService.getLastSync(function (lastSync) {
|
|
|
|
var now = new Date();
|
|
|
|
if (override || !lastSync || (now - lastSync) >= syncInternal) {
|
|
|
|
syncService.fullSync(function () { });
|
|
|
|
}
|
|
|
|
});
|
2016-09-21 06:26:23 +02:00
|
|
|
}
|