diff --git a/html/browser_action/views/settings.html b/html/browser_action/views/settings.html
index 51cee82..35b09a9 100644
--- a/html/browser_action/views/settings.html
+++ b/html/browser_action/views/settings.html
@@ -52,6 +52,9 @@
diff --git a/js/background/inject/inject.js b/js/background/inject/inject.js
index 3e6b98e..638fd43 100644
--- a/js/background/inject/inject.js
+++ b/js/background/inject/inject.js
@@ -24,6 +24,7 @@ $j(document).ready(function () {
}
function enterLoginDetails(login) {
+ console.log('called', login)
var username = (login.username.trim() !== '' ) ? login.username : login.email;
fillPassword(username, login.password);
@@ -32,6 +33,7 @@ $j(document).ready(function () {
}
}
+ _this.enterLoginDetails = enterLoginDetails;
function setupAddCredentialFields() {
var labelfield = $j('#savepw-label');
labelfield.val(document.title);
@@ -269,10 +271,10 @@ $j(document).ready(function () {
pickerButton.css('box-sizing', 'content-box');
pickerButton.css('position', 'absolute');
/*
- pickerButton.css('background-color', 'rgb(234, 234, 234)');
- pickerButton.css('border-top-right-radius', el.css('border-top-right-radius'));
- pickerButton.css('border-bottom-right-radius', el.css('border-bottom-right-radius'));
- pickerButton.css('border-color', borderColor);*/
+ pickerButton.css('background-color', 'rgb(234, 234, 234)');
+ pickerButton.css('border-top-right-radius', el.css('border-top-right-radius'));
+ pickerButton.css('border-bottom-right-radius', el.css('border-bottom-right-radius'));
+ pickerButton.css('border-color', borderColor);*/
pickerButton.css('z-index', '999');
pickerButton.css('width', iconWidth);
@@ -283,8 +285,8 @@ $j(document).ready(function () {
pickerButton.css('height', height);
pickerButton.css('margin', margin);
pickerButton.css('font-weight', el.css('font-weight'));
- pickerButton.css('top', Math.round((offset.top + (height / 4) - margin/2 - padding/2 ) - (borderHeight / 2))+ 'px');
- pickerButton.css('left', Math.round((offset.left + width*0.9) + paddingRight - padding + borderWidth ) + 'px');
+ pickerButton.css('top', Math.round((offset.top + (height / 4) - margin / 2 - padding / 2 ) - (borderHeight / 2)) + 'px');
+ pickerButton.css('left', Math.round((offset.left + width * 0.9) + paddingRight - padding + borderWidth) + 'px');
var onClick = function () {
@@ -342,7 +344,7 @@ $j(document).ready(function () {
password: pass
};
//Disable password mining
- $j(fields[1]).attr('type', 'hidden');
+ //$j(fields[1]).attr('type', 'hidden');
API.runtime.sendMessage(API.runtime.id, {method: "minedForm", args: params});
}
@@ -444,37 +446,44 @@ $j(document).ready(function () {
insertFontCSS();
$j(document).unbind('click', togglePasswordPicker);
checkForMined();
- var loginFields = getLoginFields();
- if (loginFields.length > 0) {
- //@TODO prevent chrome from captuting pw's: http://stackoverflow.com/questions/27280461/prevent-chrome-from-prompting-to-save-password-from-input-box
- for (var i = 0; i < loginFields.length; i++) {
- var form = getFormFromElement(loginFields[i][0]);
- createPasswordPicker(loginFields[i], form);
+ API.runtime.sendMessage(API.runtime.id, {method: 'getRuntimeSettings'}).then(function (result) {
+ var disablePasswordPicker = result.disablePasswordPicker;
- //Password miner
- $j(form).submit((function (loginFields) {
- return function () {
- formSubmitted(loginFields);
+ var loginFields = getLoginFields();
+ if (loginFields.length > 0) {
+ //@TODO prevent chrome from captuting pw's: http://stackoverflow.com/questions/27280461/prevent-chrome-from-prompting-to-save-password-from-input-box
+ for (var i = 0; i < loginFields.length; i++) {
+ if(!disablePasswordPicker) {
+ var form = getFormFromElement(loginFields[i][0]);
+ createPasswordPicker(loginFields[i], form);
}
- })(loginFields[i]));
- }
-
- var url = window.location.href; //@TODO use a extension function
- API.runtime.sendMessage(API.runtime.id, {
- method: "getCredentialsByUrl",
- args: [url]
- }).then(function (logins) {
- //console.log('Found ' + logins.length + ' logins for this site');
- if (logins.length === 1) {
- API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
- if(isEnabled){
- enterLoginDetails(logins[0]);
+ //Password miner
+ $j(form).submit((function (loginFields) {
+ return function () {
+ formSubmitted(loginFields);
}
- });
+ })(loginFields[i]));
}
- });
- }
+ var url = window.location.href; //@TODO use a extension function
+ API.runtime.sendMessage(API.runtime.id, {
+ method: "getCredentialsByUrl",
+ args: [url]
+ }).then(function (logins) {
+ //console.log('Found ' + logins.length + ' logins for this site');
+ if (logins.length === 1) {
+ API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
+ if (isEnabled) {
+ enterLoginDetails(logins[0]);
+ }
+ });
+ }
+
+ });
+ }
+
+ });
+
$j(document).click(togglePasswordPicker);
$j(window).on('resize', function () {
if (getLoginFields().length > 0) {
diff --git a/js/background/service/background.js b/js/background/service/background.js
index 08fef6e..a5decd7 100644
--- a/js/background/service/background.js
+++ b/js/background/service/background.js
@@ -335,9 +335,12 @@
return;
}
var tabUrl = tab.url;
- var credentialAmount = getCredentialsByUrl(tabUrl).length;
-
- API.browserAction.setBadgeText({
+ var logins = getCredentialsByUrl(tabUrl);
+ if(tab.active) {
+ window.contextMenu.setContextItems(logins);
+ }
+ var credentialAmount = logins.length;
+ API.browserAction.setBadgeText({
text: credentialAmount.toString(),
tabId: tab.id
});
@@ -392,6 +395,16 @@
}
});
+ API.tabs.onActivated.addListener(function () {
+ API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
+ if(master_password){
+ createIconForTab(tabs[0])
+ } else {
+ displayLogoutIcons();
+ }
+ });
+ });
+
displayLogoutIcons();
storage.get('master_password').then(function (password) {
diff --git a/js/background/service/contextMenu.js b/js/background/service/contextMenu.js
new file mode 100644
index 0000000..3f9a113
--- /dev/null
+++ b/js/background/service/contextMenu.js
@@ -0,0 +1,130 @@
+/* global API */
+
+/**
+ * Nextcloud - passman
+ *
+ * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
+ * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+window.contextMenu = (function () {
+ 'use strict';
+ function initMenus() {
+ API.contextMenus.create({
+ id: 'autoFill:',
+ title: 'Auto fill',
+ contexts: ['all']
+ });
+
+ API.contextMenus.create({
+ id: 'copy:User',
+ title: 'Copy username',
+ contexts: ['all']
+ });
+
+ API.contextMenus.create({
+ id: 'copy:Pass',
+ title: 'Copy password',
+ contexts: ['all']
+ });
+
+
+ API.contextMenus.create({
+ id: 'copy:Url',
+ title: 'Copy URL',
+ contexts: ['all']
+ });
+ /* API.contextMenus.create({
+ id: 'copy:OTP',
+ title: 'Copy OTP',
+ contexts: ['all']
+ });*/
+ }
+
+ function createMenuItem(parentId, id, label, clickcb) {
+ API.contextMenus.create({
+ id: id,
+ title: label,
+ contexts: ["all"],
+ parentId: parentId,
+ onclick: clickcb
+ });
+ }
+
+ function itemClickCallback(menu_action, login) {
+ var action = menu_action.menu.split(':', 1)[0];
+
+ if (action === 'copy') {
+ copyTextToClipboard(login[menu_action.field]);
+ return;
+ }
+
+ if (action === 'autoFill') {
+ API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
+ API.tabs.sendMessage(tabs[0].id, {method: "enterLoginDetails", args: login}).then(function (response) {
+ });
+ });
+ }
+ }
+
+ function copyTextToClipboard(text) {
+ var copyFrom = document.createElement("textarea");
+ copyFrom.textContent = text;
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(copyFrom);
+ copyFrom.select();
+ document.execCommand('copy');
+ body.removeChild(copyFrom);
+ }
+ API.contextMenus.removeAll();
+ initMenus();
+
+ return {
+ setContextItems: function (logins) {
+
+ var fields = [
+ {menu: 'autoFill:', field: 'autoFill'},
+ {field: 'username', menu: 'copy:User'},
+ {field: 'password', menu: 'copy:Pass'},
+ {field: 'url', menu: 'copy:Url'},
+ // {field: 'totp', menu: 'copy:OTP'}
+ ];
+ API.contextMenus.removeAll();
+ initMenus();
+
+ for (var i = 0; i < logins.length; i++) {
+ var login = logins[i];
+ login.autoFill = true;
+ for (var f = 0; f < fields.length; f++) {
+ var field = fields[f];
+ if (field['field'] === 'totp' && login.otp) {
+ login.totp = login.otp.secret;
+ }
+ if (login[field['field']]) {
+ createMenuItem(field['menu'], field['menu'] + ':' + login.guid, login.label, (function (field, login) {
+ return function () {
+ itemClickCallback(field, login);
+ };
+ })(field, login));
+ }
+ }
+ }
+ }
+ }
+
+}());
\ No newline at end of file
diff --git a/js/lib/API/contextmenus.js b/js/lib/API/contextmenus.js
new file mode 100644
index 0000000..1b808a1
--- /dev/null
+++ b/js/lib/API/contextmenus.js
@@ -0,0 +1,22 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+/* global API */
+
+API.contextMenus = {
+
+ create: API.api.contextMenus.create,
+ update: API.api.contextMenus.update,
+ remove: API.api.contextMenus.remove,
+ removeAll: API.api.contextMenus.removeAll,
+
+
+ /**
+ * Event handlers from now on
+ */
+ onClicked: API.api.contextMenus.onClicked
+};
\ No newline at end of file
diff --git a/js/ui/popup/controllers/settings.js b/js/ui/popup/controllers/settings.js
index 80751e9..3e6e52c 100644
--- a/js/ui/popup/controllers/settings.js
+++ b/js/ui/popup/controllers/settings.js
@@ -88,11 +88,7 @@
save_btn.show();
$scope.vaults = vaults;
$scope.$apply();
- setTimeout(function () {
- if($scope.settings.default_vault){
- jQuery('#defaultVault').find('[value="'+ $scope.settings.default_vault +'"]').attr('selected', 'selected');
- }
- });
+
});
};
@@ -112,14 +108,13 @@
$scope.saveSettings = function () {
$scope.errors = [];
var settings = angular.copy($scope.settings);
- var v = getVaultByGuid(settings.default_vault);
try{
- PAPI.decryptString(v.challenge_password, settings.vault_password);
+ PAPI.decryptString(settings.default_vault.challenge_password, settings.vault_password);
} catch (e){
$scope.errors.push('Invalid vault key!');
return;
}
- settings.default_vault = v;
+
$scope.saving = true;
API.runtime.sendMessage(API.runtime.id, {method: "saveSettings", args: settings}).then(function () {
setTimeout(function () {
diff --git a/js/ui/popup/controllers/setup.js b/js/ui/popup/controllers/setup.js
index 2ed4a94..c8b97c1 100644
--- a/js/ui/popup/controllers/setup.js
+++ b/js/ui/popup/controllers/setup.js
@@ -48,7 +48,8 @@
refreshTime: 60,
default_vault: {},
master_password: '',
- disableAutoFill: false
+ disableAutoFill: false,
+ disablePasswordPicker: false
};
$scope.vaults = [];
diff --git a/manifest.json b/manifest.json
index f4e3dd2..43755dc 100644
--- a/manifest.json
+++ b/manifest.json
@@ -28,7 +28,9 @@
"/js/lib/API/cookies.js",
"/js/lib/API/browser_action.js",
"/js/lib/API/tabs.js",
+ "/js/lib/API/contextmenus.js",
"/js/lib/api.js",
+ "/js/background/service/contextMenu.js",
"/js/background/service/background.js"
]
},
@@ -42,6 +44,7 @@
"notifications",
"tabs",
"storage",
+ "contextMenus",
"cookies"
],
"content_scripts": [
|