mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Select group when adding new credentials
This commit is contained in:
parent
c3a36027b5
commit
34362ff08e
12 changed files with 623 additions and 146 deletions
|
|
@ -307,6 +307,26 @@
|
|||
"message": "Please choose the credentials you want to update.",
|
||||
"description": "A popup message shown choosing what credentials user wants to update."
|
||||
},
|
||||
"popupRememberChooseGroup": {
|
||||
"message": "Please choose the group you want to add the new credentials.",
|
||||
"description": "A popup message shown choosing what group user wants to use for new credentials."
|
||||
},
|
||||
"popupRememberErrorDefaultGroupNotFound": {
|
||||
"message": "Error: Specified default group not found. Creating all necessary groups.",
|
||||
"description": "Error message shown when default group set cannot be found."
|
||||
},
|
||||
"popupRememberErrorCreatingNewGroup": {
|
||||
"message": "New group(s) cannot be created.",
|
||||
"description": "Error message shown when new groups cannot be created."
|
||||
},
|
||||
"popupRememberErrorPasswordNotChanged": {
|
||||
"message": "Error: Credentials not updated. The password has not been changed.",
|
||||
"description": "Error message shown when credential password is not changed."
|
||||
},
|
||||
"popupRememberErrorCannotSaveCredentials": {
|
||||
"message": "Error: Credentials cannot be saved or updated.",
|
||||
"description": "Error message shown when credentials cannot be saved or updated."
|
||||
},
|
||||
"popupLoginText": {
|
||||
"message": "Select the login information you would like to get entered into the page.",
|
||||
"description": "A popup message shown when one or multiple credentials are present."
|
||||
|
|
@ -447,6 +467,22 @@
|
|||
"message": "Maximum (Number of) Redirects:",
|
||||
"description": "RMaximum (Number of) Redirects options text."
|
||||
},
|
||||
"optionsLabelDefaultGroup": {
|
||||
"message": "Default group for saving new passwords:",
|
||||
"description": "Default group options text."
|
||||
},
|
||||
"optionsDefaultGroupHelpText": {
|
||||
"message": "Separate the group with slashes, for example: Group/ChildGroup.",
|
||||
"description": "Default group help text."
|
||||
},
|
||||
"optionsLabelDefaultGroupCheckboxText": {
|
||||
"message": "Always ask where to save new credentials",
|
||||
"description": "Default group checkbox help text."
|
||||
},
|
||||
"optionsLabelDefaultGroupCheckboxHelpText": {
|
||||
"message": "When enabled, the popup shows a group listing.",
|
||||
"description": "Default checkbox explanation help text."
|
||||
},
|
||||
"optionsCheckboxUsePasswordGenerator": {
|
||||
"message": "Activate password generator.",
|
||||
"description": "Activate password generator checkbox text."
|
||||
|
|
|
|||
|
|
@ -167,13 +167,13 @@ browserAction.stackPop = function(tabId) {
|
|||
|
||||
browserAction.stackPush = function(data, tabId) {
|
||||
const id = tabId || page.currentTabId;
|
||||
browserAction.removeLevelFromStack(null, {'id': id}, data.level, '<=', true);
|
||||
browserAction.removeLevelFromStack(null, { 'id': id }, data.level, '<=', true);
|
||||
page.tabs[id].stack.push(data);
|
||||
};
|
||||
|
||||
browserAction.stackUnshift = function(data, tabId) {
|
||||
const id = tabId || page.currentTabId;
|
||||
browserAction.removeLevelFromStack(null, {'id': id}, data.level, '<=', true);
|
||||
browserAction.removeLevelFromStack(null, { 'id': id }, data.level, '<=', true);
|
||||
page.tabs[id].stack.unshift(data);
|
||||
};
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) {
|
|||
const currentMS = Date.now();
|
||||
if (removeImmediately || (data.visibleForPageUpdates <= 0 && data.redirectOffset > 0)) {
|
||||
browserAction.stackPop(tab.id);
|
||||
browserAction.show(null, {"id": tab.id});
|
||||
browserAction.show(null, { 'id': tab.id });
|
||||
page.clearCredentials(tab.id);
|
||||
} else if (!isNaN(data.visibleForPageUpdates) && data.redirectOffset > 0 && currentMS >= data.redirectOffset) {
|
||||
data.visibleForPageUpdates -= 1;
|
||||
|
|
@ -202,7 +202,7 @@ browserAction.removeRememberPopup = function(callback, tab, removeImmediately) {
|
|||
};
|
||||
|
||||
browserAction.setRememberPopup = function(tabId, username, password, url, usernameExists, credentialsList) {
|
||||
browser.storage.local.get({'settings': {}}).then(function(item) {
|
||||
browser.storage.local.get({ 'settings': {} }).then(function(item) {
|
||||
const settings = item.settings;
|
||||
|
||||
// Don't show anything if the site is in the ignore
|
||||
|
|
@ -233,7 +233,7 @@ browserAction.setRememberPopup = function(tabId, username, password, url, userna
|
|||
index: 0,
|
||||
counter: 0,
|
||||
max: 2,
|
||||
icons: ['icon_remember_red_background_19x19.png', 'icon_remember_red_lock_19x19.png']
|
||||
icons: [ 'icon_remember_red_background_19x19.png', 'icon_remember_red_lock_19x19.png' ]
|
||||
},
|
||||
icon: 'icon_remember_red_background_19x19.png',
|
||||
popup: 'popup_remember.html'
|
||||
|
|
|
|||
|
|
@ -284,8 +284,10 @@ kpxcEvent.messageHandlers = {
|
|||
'add_credentials': keepass.addCredentials,
|
||||
'associate': keepass.associate,
|
||||
'check_update_keepassxc': kpxcEvent.onCheckUpdateKeePassXC,
|
||||
'create_new_group': keepass.createNewGroup,
|
||||
'generate_password': keepass.generatePassword,
|
||||
'get_connected_database': kpxcEvent.onGetConnectedDatabase,
|
||||
'get_database_groups': keepass.getDatabaseGroups,
|
||||
'get_keepassxc_versions': kpxcEvent.onGetKeePassXCVersions,
|
||||
'get_status': kpxcEvent.onGetStatus,
|
||||
'get_tab_information': kpxcEvent.onGetTabInformation,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ const kpActions = {
|
|||
CHANGE_PUBLIC_KEYS: 'change-public-keys',
|
||||
LOCK_DATABASE: 'lock-database',
|
||||
DATABASE_LOCKED: 'database-locked',
|
||||
DATABASE_UNLOCKED: 'database-unlocked'
|
||||
DATABASE_UNLOCKED: 'database-unlocked',
|
||||
GET_DATABASE_GROUPS: 'get-database-groups',
|
||||
CREATE_NEW_GROUP: 'create-new-group'
|
||||
};
|
||||
|
||||
const kpErrors = {
|
||||
|
|
@ -127,11 +129,11 @@ keepass.sendNativeMessage = function(request, enableTimeout = false) {
|
|||
});
|
||||
};
|
||||
|
||||
keepass.addCredentials = function(callback, tab, username, password, url) {
|
||||
keepass.updateCredentials(callback, tab, null, username, password, url);
|
||||
keepass.addCredentials = function(callback, tab, username, password, url, group, groupUuid) {
|
||||
keepass.updateCredentials(callback, tab, null, username, password, url, group, groupUuid);
|
||||
};
|
||||
|
||||
keepass.updateCredentials = function(callback, tab, entryId, username, password, url) {
|
||||
keepass.updateCredentials = function(callback, tab, entryId, username, password, url, group, groupUuid) {
|
||||
page.debug('keepass.updateCredentials(callback, {1}, {2}, {3}, [password], {4})', tab.id, entryId, username, url);
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
|
|
@ -162,6 +164,11 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
|
|||
messageData.uuid = entryId;
|
||||
}
|
||||
|
||||
if (group && groupUuid) {
|
||||
messageData.group = group;
|
||||
messageData.groupUuid = groupUuid;
|
||||
}
|
||||
|
||||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
|
|
@ -678,6 +685,135 @@ keepass.lockDatabase = function(tab) {
|
|||
});
|
||||
};
|
||||
|
||||
keepass.getDatabaseGroups = function(callback, tab) {
|
||||
keepass.testAssociation((taResponse) => {
|
||||
if (!taResponse) {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
}
|
||||
|
||||
if (!keepass.isConnected) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
let groups = [];
|
||||
const kpAction = kpActions.GET_DATABASE_GROUPS;
|
||||
const nonce = keepass.getNonce();
|
||||
const incrementedNonce = keepass.incrementedNonce(nonce);
|
||||
|
||||
const messageData = {
|
||||
action: kpAction
|
||||
};
|
||||
|
||||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
nonce: nonce,
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.sendNativeMessage(request).then((response) => {
|
||||
if (response.message && response.nonce) {
|
||||
const res = keepass.decrypt(response.message, response.nonce);
|
||||
if (!res) {
|
||||
keepass.handleError(tab, kpErrors.CANNOT_DECRYPT_MESSAGE);
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const message = nacl.util.encodeUTF8(res);
|
||||
const parsed = JSON.parse(message);
|
||||
|
||||
if (keepass.verifyResponse(parsed, incrementedNonce)) {
|
||||
groups = parsed.groups;
|
||||
groups.defaultGroup = page.settings.defaultGroup;
|
||||
groups.defaultGroupAlwaysAsk = page.settings.defaultGroupAlwaysAsk;
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
callback(groups);
|
||||
} else {
|
||||
console.log('getDatabaseGroups rejected');
|
||||
callback([]);
|
||||
}
|
||||
} else if (response.error && response.errorCode) {
|
||||
keepass.handleError(tab, response.errorCode, response.error);
|
||||
callback([]);
|
||||
} else {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback([]);
|
||||
}
|
||||
});
|
||||
}, tab, false);
|
||||
};
|
||||
|
||||
keepass.createNewGroup = function(callback, tab, groupName) {
|
||||
keepass.testAssociation((taResponse) => {
|
||||
if (!taResponse) {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab && page.tabs[tab.id]) {
|
||||
page.tabs[tab.id].errorMessage = null;
|
||||
}
|
||||
|
||||
if (!keepass.isConnected) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const kpAction = kpActions.CREATE_NEW_GROUP;
|
||||
const nonce = keepass.getNonce();
|
||||
const incrementedNonce = keepass.incrementedNonce(nonce);
|
||||
|
||||
const messageData = {
|
||||
action: kpAction,
|
||||
groupName: groupName
|
||||
};
|
||||
|
||||
const request = {
|
||||
action: kpAction,
|
||||
message: keepass.encrypt(messageData, nonce),
|
||||
nonce: nonce,
|
||||
clientID: keepass.clientID
|
||||
};
|
||||
|
||||
keepass.sendNativeMessage(request).then((response) => {
|
||||
if (response.message && response.nonce) {
|
||||
const res = keepass.decrypt(response.message, response.nonce);
|
||||
if (!res) {
|
||||
keepass.handleError(tab, kpErrors.CANNOT_DECRYPT_MESSAGE);
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const message = nacl.util.encodeUTF8(res);
|
||||
const parsed = JSON.parse(message);
|
||||
|
||||
if (keepass.verifyResponse(parsed, incrementedNonce)) {
|
||||
keepass.updateLastUsed(keepass.databaseHash);
|
||||
callback(parsed);
|
||||
} else {
|
||||
console.log('getDatabaseGroups rejected');
|
||||
callback([]);
|
||||
}
|
||||
} else if (response.error && response.errorCode) {
|
||||
keepass.handleError(tab, response.errorCode, response.error);
|
||||
callback([]);
|
||||
} else {
|
||||
browserAction.showDefault(null, tab);
|
||||
callback([]);
|
||||
}
|
||||
});
|
||||
}, tab, false);
|
||||
};
|
||||
|
||||
keepass.generateNewKeyPair = function() {
|
||||
keepass.keyPair = nacl.box.keyPair();
|
||||
//console.log(nacl.util.encodeBase64(keepass.keyPair.publicKey) + ' ' + nacl.util.encodeBase64(keepass.keyPair.secretKey));
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ const defaultSettings = {
|
|||
autoRetrieveCredentials: true,
|
||||
showNotifications: true,
|
||||
showLoginNotifications: true,
|
||||
saveDomainOnly: true
|
||||
saveDomainOnly: true,
|
||||
defaultGroup: '',
|
||||
defaultGroupAlwaysAsk: false
|
||||
};
|
||||
|
||||
var page = {};
|
||||
|
|
@ -49,7 +51,13 @@ page.initSettings = function() {
|
|||
if (!('saveDomainOnly' in page.settings)) {
|
||||
page.settings.saveDomainOnly = defaultSettings.saveDomainOnly;
|
||||
}
|
||||
browser.storage.local.set({'settings': page.settings});
|
||||
if (!('defaultGroup' in page.settings)) {
|
||||
page.settings.defaultGroup = defaultSettings.defaultGroup;
|
||||
}
|
||||
if (!('defaultGroupAlwaysAsk' in page.settings)) {
|
||||
page.settings.defaultGroupAlwaysAsk = defaultSettings.defaultGroupAlwaysAsk;
|
||||
}
|
||||
browser.storage.local.set({ 'settings': page.settings });
|
||||
resolve(page.settings);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ h2+hr {
|
|||
width: 75%;
|
||||
}
|
||||
|
||||
#defaultGroup {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
tr.clone {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,30 @@
|
|||
</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<div class="form-group">
|
||||
<label for="defaultGroup" data-i18n="optionsLabelDefaultGroup"></label>
|
||||
<div class="control-group">
|
||||
<div class="input-append">
|
||||
<input type="text" id="defaultGroup" placeholder="KeePassXC-Browser Passwords">
|
||||
<button class="btn btn-sm btn-primary" id="defaultGroupButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> <span data-i18n="optionsButtonSave"/></button>
|
||||
<button class="btn btn-sm btn-danger" id="defaultGroupButtonReset"><span class="glyphicon glyphicon-remove-sign"></span> <span data-i18n="optionsButtonReset"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help-block">
|
||||
<span data-i18n="optionsDefaultGroupHelpText"></span>
|
||||
<br />
|
||||
<span data-i18n="optionsDefault"></span> KeePassXC-Browser Passwords
|
||||
</span>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="defaultGroupAlwaysAsk" value="true" /><span data-i18n="optionsLabelDefaultGroupCheckboxText"></span>
|
||||
</label>
|
||||
<span class="help-block" data-i18n="optionsLabelDefaultGroupCheckboxHelpText"></span>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<div class="checkbox">
|
||||
<label class="checkbox">
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ options.saveSettingsPromise = function() {
|
|||
options.saveSetting = function(name) {
|
||||
const id = '#' + name;
|
||||
$(id).closest('.control-group').removeClass('error').addClass('success');
|
||||
setTimeout(() => { $(id).closest('.control-group').removeClass('success'); }, 2500);
|
||||
setTimeout(() => {
|
||||
$(id).closest('.control-group').removeClass('success');
|
||||
}, 2500);
|
||||
|
||||
browser.storage.local.set({ 'settings': options.settings });
|
||||
browser.runtime.sendMessage({
|
||||
|
|
@ -79,6 +81,11 @@ options.saveKeyRing = function() {
|
|||
options.initGeneralSettings = function() {
|
||||
$('#tab-general-settings input[type=checkbox]').each(function() {
|
||||
$(this).attr('checked', options.settings[$(this).attr('name')]);
|
||||
if ($(this).attr('name') === 'defaultGroupAlwaysAsk' && $(this).attr('checked')) {
|
||||
$('#defaultGroup').prop('disabled', true);
|
||||
$('#defaultGroupButton').prop('disabled', true);
|
||||
$('#defaultGroupButtonReset').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
$('#tab-general-settings input[type=checkbox]').change(function() {
|
||||
|
|
@ -87,10 +94,22 @@ options.initGeneralSettings = function() {
|
|||
options.saveSettingsPromise().then((x) => {
|
||||
if (name === 'autoFillAndSend') {
|
||||
browser.runtime.sendMessage({ action: 'init_http_auth' });
|
||||
} else if (name === 'defaultGroupAlwaysAsk') {
|
||||
if ($(this).is(':checked')) {
|
||||
$('#defaultGroup').prop('disabled', true);
|
||||
$('#defaultGroupButton').prop('disabled', true);
|
||||
$('#defaultGroupButtonReset').prop('disabled', true);
|
||||
} else {
|
||||
$('#defaultGroup').prop('disabled', false);
|
||||
$('#defaultGroupButton').prop('disabled', false);
|
||||
$('#defaultGroupButtonReset').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#tab-general-settings input#defaultGroup').val(options.settings['defaultGroup']);
|
||||
|
||||
$('#tab-general-settings input[type=radio]').each(function() {
|
||||
if ($(this).val() === options.settings[$(this).attr('name')]) {
|
||||
$(this).attr('checked', options.settings[$(this).attr('name')]);
|
||||
|
|
@ -155,6 +174,20 @@ options.initGeneralSettings = function() {
|
|||
options.settings['allowedRedirect'] = allowedRedirectval;
|
||||
options.saveSetting('allowedRedirect');
|
||||
});
|
||||
|
||||
$('#defaultGroupButton').click(function() {
|
||||
const value = $('#defaultGroup').val();
|
||||
if (value.length > 0) {
|
||||
options.settings['defaultGroup'] = value;
|
||||
options.saveSettings();
|
||||
}
|
||||
});
|
||||
|
||||
$('#defaultGroupButtonReset').click(function() {
|
||||
$('#defaultGroup').val('');
|
||||
options.settings['defaultGroup'] = '';
|
||||
options.saveSettings();
|
||||
});
|
||||
};
|
||||
|
||||
options.showKeePassXCVersions = function(response) {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ body {
|
|||
font-size: 80%;
|
||||
color: #787878;
|
||||
}
|
||||
#list {
|
||||
padding-left: 0px;
|
||||
}
|
||||
#child {
|
||||
border-top: 0px;
|
||||
}
|
||||
#update-available {
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
|
|
@ -64,9 +70,24 @@ body {
|
|||
}
|
||||
#login-filter {
|
||||
outline:none;
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
margin-bottom: 5px;
|
||||
padding: 2px 10px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.credentials .groups {
|
||||
display: none;
|
||||
border-top: 1px solid #333;
|
||||
}
|
||||
.connected-database {
|
||||
display: none;
|
||||
font-size: 85%;
|
||||
color: #787878;
|
||||
}
|
||||
.credentials .username-new {
|
||||
display: none;
|
||||
}
|
||||
.credentials .username-exists {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,15 +10,6 @@
|
|||
<script type="text/javascript" src="../options/bootstrap.min.js" /></script>
|
||||
<script type="text/javascript" src="popup_functions.js"></script>
|
||||
<script type="text/javascript" src="popup_remember.js"></script>
|
||||
<style type="text/css">
|
||||
.credentials {display: none; border-top: 1px solid #333;}
|
||||
.connected-database {display: none; font-size: 85%; color: #787878;}
|
||||
.credentials .username-new {display: none;}
|
||||
.credentials .username-exists {display: none;}
|
||||
.small { font-weight: bold; }
|
||||
.small .normal { font-weight: normal; }
|
||||
.info { font-weight: normal; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="buttons">
|
||||
|
|
@ -41,11 +32,16 @@
|
|||
<p data-i18n="popupRememberSaving" i18n-placeholder="<span></span><em></em>"></p>
|
||||
</div>
|
||||
|
||||
<div class="credentials">
|
||||
<div class="credentials" style="display: none;">
|
||||
<p class="username-new"><span data-i18n="popupRememberNewUsername" i18n-placeholder="<strong></strong>"></span></p>
|
||||
<p class="username-exists"><span data-i18n="popupRememberUsernameExists" i18n-placeholder="<strong></strong>"></span></p>
|
||||
<p data-i18n="popupRememberChooseCredentials"></p>
|
||||
<ul id="list"></ul>
|
||||
<ul id="list" class="list-group"></ul>
|
||||
</div>
|
||||
|
||||
<div class="groups" style="display: none;">
|
||||
<p data-i18n="popupRememberChooseGroup"></p>
|
||||
<ul id="list" class="list-group"></ul>
|
||||
</div>
|
||||
<script type="text/javascript" src="../translate.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const DEFAULT_BROWSER_GROUP = 'KeePassXC-Browser Passwords';
|
||||
|
||||
var _tab;
|
||||
|
||||
function _initialize(tab) {
|
||||
|
|
@ -27,14 +29,108 @@ function _initialize(tab) {
|
|||
$('.information-username:first').text(_tab.credentials.username);
|
||||
|
||||
$('#btn-new').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('.credentials').hide();
|
||||
$('ul#list').empty();
|
||||
|
||||
// Get group listing from KeePassXC
|
||||
browser.runtime.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [_tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
}).then(_verifyResult);
|
||||
action: 'get_database_groups'
|
||||
}).then((result) => {
|
||||
// Only the Root group and no KeePassXC-Browser passwords -> save to default
|
||||
// Or when default group is not set and defaultGroupAskAlways is disabled -> save to default
|
||||
if ((result.groups === undefined || (result.groups.length > 0 && result.groups[0].children.length === 0)) ||
|
||||
(!result.defaultGroupAlwaysAsk && (result.defaultGroup === '' || result.defaultGroup === DEFAULT_BROWSER_GROUP))) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [ _tab.credentials.username, _tab.credentials.password, _tab.credentials.url ]
|
||||
}).then(_verifyResult);
|
||||
return;
|
||||
} else if (!result.defaultGroupAlwaysAsk && (result.defaultGroup !== '' || result.defaultGroup !== DEFAULT_BROWSER_GROUP)) {
|
||||
// Another group name has been specified
|
||||
const [ gname, guuid ] = getDefaultGroup(result.groups[0].children, result.defaultGroup);
|
||||
if (gname === '' && guuid === '') {
|
||||
showNotification(tr('popupRememberErrorDefaultGroupNotFound'));
|
||||
|
||||
// Create a new group
|
||||
browser.runtime.sendMessage({
|
||||
action: 'create_new_group',
|
||||
args: [ result.defaultGroup ]
|
||||
}).then((newGroup) => {
|
||||
if (newGroup.name && newGroup.uuid) {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [ _tab.credentials.username, _tab.credentials.password, _tab.credentials.url, newGroup.name, newGroup.uuid ]
|
||||
}).then(_verifyResult);
|
||||
} else {
|
||||
showNotification(tr('popupRememberErrorCreatingNewGroup'));
|
||||
}
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [ _tab.credentials.username, _tab.credentials.password, _tab.credentials.url, gname, guuid ]
|
||||
}).then(_verifyResult);
|
||||
return;
|
||||
}
|
||||
|
||||
const addChildren = function(group, parentElement, depth) {
|
||||
++depth;
|
||||
const padding = depth * 20;
|
||||
|
||||
for (const child of group.children) {
|
||||
const a = createLink(child.name, child.uuid, child.children.length > 0);
|
||||
a.attr('id', 'child');
|
||||
a.css('cssText', 'padding-left: ' + String(padding) + 'px !important;');
|
||||
|
||||
if (parentElement.attr('id') === 'root') {
|
||||
a.attr('id', 'root-child');
|
||||
}
|
||||
|
||||
$('ul#list').append(a);
|
||||
addChildren(child, a, depth);
|
||||
}
|
||||
};
|
||||
|
||||
const createLink = function(group, groupUuid, hasChildren) {
|
||||
const a = $('<a>')
|
||||
.attr('href', '#')
|
||||
.attr('class', 'list-group-item')
|
||||
.text(group)
|
||||
.click(function(ev) {
|
||||
ev.preventDefault();
|
||||
browser.runtime.sendMessage({
|
||||
action: 'add_credentials',
|
||||
args: [ _tab.credentials.username, _tab.credentials.password, _tab.credentials.url, group, groupUuid ]
|
||||
}).then(_verifyResult);
|
||||
});
|
||||
|
||||
if (hasChildren) {
|
||||
a.text('\u25BE ' + group);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
// Create the link list for group selection
|
||||
let depth = 0;
|
||||
for (const g of result.groups) {
|
||||
const a = createLink(g.name, g.uuid, g.children.length > 0);
|
||||
a.attr('id', 'root');
|
||||
|
||||
$('ul#list').append(a);
|
||||
addChildren(g, a, depth);
|
||||
}
|
||||
|
||||
$('.groups').show();
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-update').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('.groups').hide();
|
||||
$('ul#list').empty();
|
||||
|
||||
// Only one entry which could be updated
|
||||
if (_tab.credentials.list.length === 1) {
|
||||
|
|
@ -45,7 +141,7 @@ function _initialize(tab) {
|
|||
|
||||
browser.runtime.sendMessage({
|
||||
action: 'update_credentials',
|
||||
args: [_tab.credentials.list[0].uuid, _tab.credentials.username, _tab.credentials.password, _tab.credentials.url]
|
||||
args: [ _tab.credentials.list[0].uuid, _tab.credentials.username, _tab.credentials.password, _tab.credentials.url ]
|
||||
}).then(_verifyResult);
|
||||
} else {
|
||||
$('.credentials:first .username-new:first strong:first').text(_tab.credentials.username);
|
||||
|
|
@ -62,6 +158,7 @@ function _initialize(tab) {
|
|||
for (let i = 0; i < _tab.credentials.list.length; i++) {
|
||||
const $a = $('<a>')
|
||||
.attr('href', '#')
|
||||
.attr('class', 'list-group-item')
|
||||
.text(_tab.credentials.list[i].login + ' (' + _tab.credentials.list[i].name + ')')
|
||||
.data('entryId', i)
|
||||
.click(function(e) {
|
||||
|
|
@ -85,7 +182,7 @@ function _initialize(tab) {
|
|||
|
||||
// Show a notification if the user tries to update credentials using the old password
|
||||
if (credentials[entryId].password === _tab.credentials.password) {
|
||||
showNotification('Error: Credentials not updated. The password has not been changed.');
|
||||
showNotification(tr('popupRememberErrorPasswordNotChanged'));
|
||||
_close();
|
||||
return;
|
||||
}
|
||||
|
|
@ -101,8 +198,7 @@ function _initialize(tab) {
|
|||
$a.css('font-weight', 'bold');
|
||||
}
|
||||
|
||||
const $li = $('<li class=\"list-group-item\">').append($a);
|
||||
$('ul#list').append($li);
|
||||
$('ul#list').append($a);
|
||||
}
|
||||
|
||||
$('.credentials').show();
|
||||
|
|
@ -117,10 +213,10 @@ function _initialize(tab) {
|
|||
$('#btn-ignore').click(function(e) {
|
||||
browser.windows.getCurrent().then((win) => {
|
||||
browser.tabs.query({ 'active': true, 'currentWindow': true }).then((tabs) => {
|
||||
const tab = tabs[0];
|
||||
const currentTab = tabs[0];
|
||||
browser.runtime.getBackgroundPage().then((global) => {
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
action: 'ignore_site',
|
||||
browser.tabs.sendMessage(currentTab.id, {
|
||||
action: 'ignore-site',
|
||||
args: [ _tab.credentials.url ]
|
||||
});
|
||||
_close();
|
||||
|
|
@ -141,7 +237,7 @@ function _connectedDatabase(db) {
|
|||
|
||||
function _verifyResult(code) {
|
||||
if (code === 'error') {
|
||||
showNotification('Error: Credentials cannot be saved or updated.');
|
||||
showNotification(tr('popupRememberErrorCannotSaveCredentials'));
|
||||
}
|
||||
_close();
|
||||
}
|
||||
|
|
@ -158,6 +254,26 @@ function _close() {
|
|||
close();
|
||||
}
|
||||
|
||||
// Traverse the groups and ensure all paths are found
|
||||
const getDefaultGroup = function(groups, defaultGroup) {
|
||||
const getGroup = function(group, splitted, depth) {
|
||||
++depth;
|
||||
for (const g of group) {
|
||||
if (g.name === splitted[depth]) {
|
||||
if (splitted.length === (depth + 1)) {
|
||||
return [ g.name, g.uuid ];
|
||||
}
|
||||
return getGroup(g.children, splitted, depth);
|
||||
}
|
||||
}
|
||||
return [ '', '' ];
|
||||
};
|
||||
|
||||
let depth = -1;
|
||||
const splitted = defaultGroup.split('/');
|
||||
return getGroup(groups, splitted, depth);
|
||||
};
|
||||
|
||||
$(function() {
|
||||
browser.runtime.sendMessage({
|
||||
action: 'stack_add',
|
||||
|
|
|
|||
|
|
@ -32,20 +32,20 @@ Currently these messages are implemented:
|
|||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "change-public-keys",
|
||||
"publicKey": "<current public key>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "change-public-keys",
|
||||
"publicKey": "<current public key>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response (success):
|
||||
```javascript
|
||||
{
|
||||
"action": "change-public-keys",
|
||||
"version": "2.2.0",
|
||||
"publicKey": "<host public key>",
|
||||
"success": "true"
|
||||
"action": "change-public-keys",
|
||||
"version": "2.2.0",
|
||||
"publicKey": "<host public key>",
|
||||
"success": "true"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -53,26 +53,26 @@ Response (success):
|
|||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-databasehash"
|
||||
"action": "get-databasehash"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-databasehash",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "get-databasehash",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"action": "hash",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0"
|
||||
"action": "hash",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -80,30 +80,30 @@ Response message data (success, decrypted):
|
|||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "associate",
|
||||
"key": "<current public key>",
|
||||
"idKey": "<a new identification key>"
|
||||
"action": "associate",
|
||||
"key": "<current public key>",
|
||||
"idKey": "<a new identification key>"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "associate",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "associate",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0",
|
||||
"success": "true",
|
||||
"id": "testclient",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0",
|
||||
"success": "true",
|
||||
"id": "testclient",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -111,30 +111,30 @@ Response message data (success, decrypted):
|
|||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "test-associate",
|
||||
"id": "<saved database identifier>",
|
||||
"key": "<saved database public key>"
|
||||
"action": "test-associate",
|
||||
"id": "<saved database identifier>",
|
||||
"key": "<saved database public key>"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "test-associate",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "test-associate",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"version": "2.2.0",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"id": "testclient",
|
||||
"success": "true"
|
||||
"version": "2.2.0",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"id": "testclient",
|
||||
"success": "true"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -142,24 +142,24 @@ Response message data (success, decrypted):
|
|||
Request (no unencrypted message is needed):
|
||||
```javascript
|
||||
{
|
||||
"action": "generate-password",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "generate-password",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"version": "2.2.0",
|
||||
"entries": [
|
||||
{
|
||||
"login": 144,
|
||||
"password": "testclientpassword"
|
||||
}
|
||||
],
|
||||
"success": "true",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
"version": "2.2.0",
|
||||
"entries": [
|
||||
{
|
||||
"login": 144,
|
||||
"password": "testclientpassword"
|
||||
}
|
||||
],
|
||||
"success": "true",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -167,49 +167,49 @@ Response message data (success, decrypted):
|
|||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-logins",
|
||||
"url": "<snip>",
|
||||
"submitUrl": optional,
|
||||
"httpAuth": optional,
|
||||
"keys": [
|
||||
{
|
||||
"id": <connected_id>,
|
||||
"key": <connected_key>
|
||||
},
|
||||
...
|
||||
]
|
||||
"action": "get-logins",
|
||||
"url": "<snip>",
|
||||
"submitUrl": optional,
|
||||
"httpAuth": optional,
|
||||
"keys": [
|
||||
{
|
||||
"id": <connected_id>,
|
||||
"key": <connected_key>
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-logins",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "get-logins",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"count": "2",
|
||||
"entries" : [
|
||||
{
|
||||
"login": "user1",
|
||||
"name": "user1",
|
||||
"password": "passwd1"
|
||||
},
|
||||
{
|
||||
"login": "user2",
|
||||
"name": "user2",
|
||||
"password": "passwd2"
|
||||
}],
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"success": "true",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0"
|
||||
"count": "2",
|
||||
"entries" : [
|
||||
{
|
||||
"login": "user1",
|
||||
"name": "user1",
|
||||
"password": "passwd1"
|
||||
},
|
||||
{
|
||||
"login": "user2",
|
||||
"name": "user2",
|
||||
"password": "passwd2"
|
||||
}],
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"success": "true",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -217,36 +217,39 @@ Response message data (success, decrypted):
|
|||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "set-login",
|
||||
"url": "<snip>",
|
||||
"submitUrl": "<snip>",
|
||||
"id": "testclient",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"login": "user1",
|
||||
"password": "passwd1"
|
||||
"action": "set-login",
|
||||
"url": "<snip>",
|
||||
"submitUrl": "<snip>",
|
||||
"id": "testclient",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"login": "user1",
|
||||
"password": "passwd1",
|
||||
"group": "<group name>",
|
||||
"groupUuid": "<group UUID>",
|
||||
"uuid": "<entry UUID>"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "set-login",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "set-login",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"count": null,
|
||||
"entries" : null,
|
||||
"error": "",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"success": "true",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0"
|
||||
"count": null,
|
||||
"entries" : null,
|
||||
"error": "",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"success": "true",
|
||||
"hash": "29234e32274a32276e25666a42",
|
||||
"version": "2.2.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -254,26 +257,124 @@ Response message data (success, decrypted):
|
|||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "lock-database"
|
||||
"action": "lock-database"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "lock-database",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
"action": "lock-database",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success always returns an error, decrypted):
|
||||
```javascript
|
||||
{
|
||||
"action": "lock-database",
|
||||
"errorCode": 1,
|
||||
"error": "Database not opened",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
"action": "lock-database",
|
||||
"errorCode": 1,
|
||||
"error": "Database not opened",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
### get-database-groups
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-database-groups"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "get-database-groups",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```json
|
||||
{
|
||||
"defaultGroup": "<default group name>",
|
||||
"defaultGroupAlwaysAllow": false,
|
||||
"groups": [
|
||||
{
|
||||
"name": "Root",
|
||||
"uuid": "<group UUID>",
|
||||
"children": [
|
||||
{
|
||||
"name": "KeePassXC-Browser Passwords",
|
||||
"uuid": "<group UUID>",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "SecondRoot",
|
||||
"uuid": "<group UUID>",
|
||||
"children": [
|
||||
{
|
||||
"name": "Child",
|
||||
"uuid": "<group UUID>",
|
||||
"children": [
|
||||
{
|
||||
"name": "GrandChild",
|
||||
"uuid": "<group UUID>",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ThirdRoot",
|
||||
"uuid": "<group UUID>",
|
||||
"children": [
|
||||
{
|
||||
"name": "Child2",
|
||||
"uuid": "<group UUID>",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Child2",
|
||||
"uuid": "<group UUID>",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### create-new-group
|
||||
Unencrypted message:
|
||||
```javascript
|
||||
{
|
||||
"action": "create-new-group",
|
||||
"groupName": "<group name or path>"
|
||||
}
|
||||
```
|
||||
|
||||
Request:
|
||||
```javascript
|
||||
{
|
||||
"action": "create-new-group",
|
||||
"message": "<encrypted message>",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
|
||||
"clientID": "<clientID>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```json
|
||||
{
|
||||
"name": "<group name>",
|
||||
"uuid": "<group UUID>"
|
||||
}
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue