Implement context menu. Fixes #8
This commit is contained in:
Родитель
bba01d2c42
Коммит
8c82ac773d
|
@ -52,6 +52,9 @@
|
|||
<tr>
|
||||
<td colspan=2><input type="checkbox" id="disableAutoFill" ng-model="settings.disableAutoFill"><small>Disable auto fill of forms</small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2><input type="checkbox" id="disablePasswordPicker" ng-model="settings.disablePasswordPicker"><small>Disable password picker</small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2 align="center">
|
||||
<button class="btn btn-success" ng-click="saveSettings()" ng-disabled="saving"><i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i> Save</button>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}());
|
|
@ -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
|
||||
};
|
|
@ -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 () {
|
||||
|
|
|
@ -48,7 +48,8 @@
|
|||
refreshTime: 60,
|
||||
default_vault: {},
|
||||
master_password: '',
|
||||
disableAutoFill: false
|
||||
disableAutoFill: false,
|
||||
disablePasswordPicker: false
|
||||
};
|
||||
$scope.vaults = [];
|
||||
|
||||
|
|
|
@ -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": [
|
||||
|
|
Загрузка…
Ссылка в новой задаче