Merge branch 'develop'

This commit is contained in:
varjolintu 2017-11-13 15:45:20 +02:00
commit 75e1e1a2f8
11 changed files with 79 additions and 105 deletions

View file

@ -1,3 +1,9 @@
0.4.0 (13-11-2017)
=========================
- Fixed showing context menu on password fields with Firefox
- Ignore XML files on content scripts (Firefox shows them incorrectly)
- UDP features removed as KeePassXC switched them to Unix domain sockets and named pipes
0.3.9 (04-11-2017)
=========================
- Removed incorrect timeout waiting on init

View file

@ -1,13 +1,13 @@
# keepassxc-browser
Chrome extension for [KeePassXC](https://keepassxc.org/) with Native Messaging.
Browser extension for [KeePassXC](https://keepassxc.org/) with Native Messaging.
This is a heavily forked version of [pfn](https://github.com/pfn)'s [chromeIPass](https://github.com/pfn/passifox).
Some changes merged also from [smorks'](https://github.com/smorks/keepasshttp-connector) KeePassHttp-Connector fork.
For testing purposes, please use following unofficial KeePassXC [release's](https://github.com/varjolintu/keepassxc/releases).
For testing purposes, please use only the following unofficial KeePassXC [release's](https://github.com/varjolintu/keepassxc/releases).
Get the extension for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/) or [Chrome/Chromium](https://chrome.google.com/webstore/detail/keepassxc-browser/iopaggbpplllidnfmcghoonnokmjoicf).
The extension is supported with Firefox 55 and newer. If you want to load it as a temporary plugin with Firefox 54 you can just change the minimum version from the manifest file before loading it.
The extension is supported with Firefox 55 and newer. If you want to load it as a temporary plugin with Firefox 54 or ESR you can just change the minimum version from the manifest file before loading it.
Please thee this [wiki page](hhttps://github.com/varjolintu/keepassxc-browser/wiki/Connecting-the-database-with-keepassxc-browser) for instructions how to configure this KeePassXC fork in order to connect the database correctly.
@ -17,10 +17,11 @@ There are two methods which you can use keepassxc-browser to connect to KeePassX
1. keepassxc-browser communicates directly with KeePassXC via stdin/stdout. This method launches KeePassXC every time you start the browser and closes when you exit.
This can cause unsaved changes not to be saved. If you use this method it's important to enable `Automatically save after every change` from KeePassXC's preferences.
2. keepassxc-browser communicated with KeePassXC through [keepassxc-proxy](https://github.com/varjolintu/keepassxc-proxy) or [keepassxc-proxy-rust](https://github.com/varjolintu/keepassxc-proxy-rust). The proxy handles listening stdin/stdout
2. keepassxc-browser communicated with KeePassXC through [keepassxc-proxy](https://github.com/varjolintu/keepassxc-proxy). The proxy handles listening stdin/stdout
and transfers these messages through Unix domain sockets / named pipes to KeePassXC. This means KeePassXC can be used and started normally without inteference from
Native Messaging API. keepassxc-browser starts only the proxy application and there's no risk of shutting down KeePassXC or losing any unsaved changes. keepassxc-proxy
is still under development. If you want, you are free to write your own proxy that handles the traffic.
is still under development. If you want, you are free to write your own proxy that handles the traffic. You don't need to install keepassxc-proxy separately. It is
included in the latest KeePassXC fork. Use it if you want to make your own proxy or improve/extend it.
## Improvements
The following improvements and features have been made after the fork. At this point some features are only available with the KeePassXC fork:
@ -77,4 +78,4 @@ Feel free to support this project:
- Donate via [PayPal](https://paypal.me/varjolintu)
- Donate via Bitcoin: 1LHbD69CcmpLW5hjUXs2MGJhw3GxwqLdw3
Also consider donating to [KeePassXC](https://flattr.com/submit/auto?fid=x7yqz0&url=https%3A%2F%2Fkeepassxc.org) and passifox teams [(1)](https://github.com/smorks/passifox),[(2)](https://github.com/projectgus/passifox),[(3)](https://github.com/pfn/passifox). They are doing great job.
Also consider donating to [KeePassXC](https://flattr.com/submit/auto?fid=x7yqz0&url=https%3A%2F%2Fkeepassxc.org) and passifox teams [(1)](https://github.com/smorks/passifox),[(2)](https://github.com/pfn/passifox). They are doing great job.

View file

@ -128,17 +128,24 @@ kpxcEvent.onSaveSettings = function(callback, tab, settings) {
});
};
kpxcEvent.onGetStatus = function(callback, tab) {
keepass.testAssociation((response) => {
if (!response) {
kpxcEvent.showStatus(false, tab, callback);
return;
}
kpxcEvent.onGetStatus = function(callback, tab, internalPoll = false) {
// When internalPoll is true the event is triggered from content script in intervals -> don't poll KeePassXC
if (!internalPoll) {
keepass.testAssociation((response) => {
if (!response) {
kpxcEvent.showStatus(false, tab, callback);
return;
}
keepass.isConfigured().then((configured) => {
kpxcEvent.showStatus(configured, tab, callback);
});
}, tab, true);
} else {
keepass.isConfigured().then((configured) => {
kpxcEvent.showStatus(configured, tab, callback);
});
}, tab, true);
}
};
kpxcEvent.onReconnect = function(callback, tab) {

View file

@ -92,17 +92,23 @@ if (browser.webRequest.onAuthRequired) {
browser.runtime.onMessage.addListener(kpxcEvent.onMessage);
const contextMenuItems = [
{title: 'Fill &User + Pass', action: 'fill_user_pass'},
{title: 'Fill &Pass Only', action: 'fill_pass_only'},
{title: 'Show Password &Generator Icons', action: 'activate_password_generator'},
{title: '&Save credentials', action: 'remember_credentials'}
{title: 'Fill User + Pass', action: 'fill_user_pass'},
{title: 'Fill Pass Only', action: 'fill_pass_only'},
{title: 'Show Password Generator Icons', action: 'activate_password_generator'},
{title: 'Save credentials', action: 'remember_credentials'}
];
let menuContexts = ['editable'];
if (isFirefox()) {
menuContexts.push('password');
}
// Create context menu items
for (const item of contextMenuItems) {
browser.contextMenus.create({
title: item.title,
contexts: [ 'editable' ],
contexts: menuContexts,
onclick: (info, tab) => {
browser.tabs.sendMessage(tab.id, {
action: item.action

View file

@ -160,7 +160,7 @@ keepass.updateCredentials = function(callback, tab, entryId, username, password,
const request = {
action: kpAction,
message: keepass.encrypt(messageData, nonce),
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -221,7 +221,7 @@ keepass.retrieveCredentials = function(callback, tab, url, submiturl, forceCallb
const request = {
action: kpAction,
message: keepass.encrypt(messageData, nonce),
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -285,7 +285,7 @@ keepass.generatePassword = function(callback, tab, forceCallback) {
const request = {
action: kpAction,
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -334,7 +334,7 @@ keepass.associate = function(callback, tab) {
page.tabs[tab.id].errorMessage = null;
const kpAction = kpActions.ASSOCIATE;
const key = keepass.b64e(keepass.keyPair.publicKey);
const key = nacl.util.encodeBase64(keepass.keyPair.publicKey);
const nonce = nacl.randomBytes(keepass.keySize);
const messageData = {
@ -345,7 +345,7 @@ keepass.associate = function(callback, tab) {
const request = {
action: kpAction,
message: keepass.encrypt(messageData, nonce),
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -427,7 +427,7 @@ keepass.testAssociation = function(callback, tab, enableTimeout = false) {
const request = {
action: kpAction,
message: keepass.encrypt(messageData, nonce),
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -494,7 +494,7 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) {
const request = {
action: kpAction,
message: encrypted,
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -545,19 +545,19 @@ keepass.getDatabaseHash = function(callback, tab, enableTimeout = false) {
keepass.changePublicKeys = function(tab, enableTimeout = false) {
return new Promise((resolve, reject) => {
if (!keepass.isConnected) {
keepass.handleError(tab, kpErrors.TIMEOUT_OR_NOT_CONNECTED);
reject(false);
}
const kpAction = kpActions.CHANGE_PUBLIC_KEYS;
const key = keepass.b64e(keepass.keyPair.publicKey);
const key = nacl.util.encodeBase64(keepass.keyPair.publicKey);
let nonce = nacl.randomBytes(keepass.keySize);
nonce = keepass.b64e(nonce);
keepass.clientID = keepass.b64e(nacl.randomBytes(keepass.keySize));
nonce = nacl.util.encodeBase64(nonce);
keepass.clientID = nacl.util.encodeBase64(nacl.randomBytes(keepass.keySize));
const request = {
action: kpAction,
publicKey: key,
proxyPort: (page.settings.port ? page.settings.port : 19700),
nonce: nonce,
clientID: keepass.clientID
};
@ -573,7 +573,7 @@ keepass.changePublicKeys = function(tab, enableTimeout = false) {
}
else {
keepass.isKeePassXCAvailable = true;
console.log('Server public key: ' + keepass.b64e(keepass.serverPublicKey));
console.log('Server public key: ' + nacl.util.encodeBase64(keepass.serverPublicKey));
}
resolve(true);
});
@ -597,7 +597,7 @@ keepass.lockDatabase = function(tab) {
const request = {
action: kpAction,
message: keepass.encrypt(messageData, nonce),
nonce: keepass.b64e(nonce),
nonce: nacl.util.encodeBase64(nonce),
clientID: keepass.clientID
};
@ -627,12 +627,12 @@ keepass.lockDatabase = function(tab) {
keepass.generateNewKeyPair = function() {
keepass.keyPair = nacl.box.keyPair();
//console.log(keepass.b64e(keepass.keyPair.publicKey) + ' ' + keepass.b64e(keepass.keyPair.secretKey));
//console.log(nacl.util.encodeBase64(keepass.keyPair.publicKey) + ' ' + nacl.util.encodeBase64(keepass.keyPair.secretKey));
};
keepass.isConfigured = function() {
return new Promise((resolve, reject) => {
if (typeof(keepass.databaseHash) === 'undefined' || keepass.databaseHash === 'no-hash') {
if (typeof(keepass.databaseHash) === 'undefined') {
keepass.getDatabaseHash((hash) => {
resolve(hash in keepass.keyRing);
});
@ -810,13 +810,14 @@ keepass.verifyKeyResponse = function(response, key, nonce) {
}
let reply = false;
if (keepass.b64d(nonce).length !== nacl.secretbox.nonceLength)
if (nacl.util.decodeBase64(nonce).length !== nacl.secretbox.nonceLength) {
return false;
}
reply = (response.nonce === nonce);
if (response.publicKey) {
keepass.serverPublicKey = keepass.b64d(response.publicKey);
keepass.serverPublicKey = nacl.util.decodeBase64(response.publicKey);
reply = true;
}
@ -832,8 +833,9 @@ keepass.verifyResponse = function(response, nonce, id) {
keepass.associated.hash = keepass.databaseHash;
if (keepass.b64d(response.nonce).length !== nacl.secretbox.nonceLength)
if (nacl.util.decodeBase64(response.nonce).length !== nacl.secretbox.nonceLength) {
return false;
}
keepass.associated.value = (response.nonce === nonce);
@ -856,14 +858,6 @@ keepass.handleError = function(tab, errorCode, errorMessage = '') {
}
};
keepass.b64e = function(d) {
return nacl.util.encodeBase64(d);
};
keepass.b64d = function(d) {
return nacl.util.decodeBase64(d);
};
keepass.getCryptoKey = function() {
let dbkey = null;
let dbid = null;
@ -890,15 +884,15 @@ keepass.encrypt = function(input, nonce) {
if (keepass.serverPublicKey) {
const message = nacl.box(messageData, nonce, keepass.serverPublicKey, keepass.keyPair.secretKey);
if (message) {
return keepass.b64e(message);
return nacl.util.encodeBase64(message);
}
}
return '';
};
keepass.decrypt = function(input, nonce, toStr) {
const m = keepass.b64d(input);
const n = keepass.b64d(nonce);
const m = nacl.util.decodeBase64(input);
const n = nacl.util.decodeBase64(nonce);
const res = nacl.box.open(m, n, keepass.serverPublicKey, keepass.keyPair.secretKey);
return res;
};

View file

@ -4,8 +4,7 @@ const defaultSettings = {
autoFillAndSend: true,
usePasswordGenerator: true,
autoFillSingleEntry: false,
autoRetrieveCredentials: true,
proxyPort: '19700'
autoRetrieveCredentials: true
};
var page = {};
@ -35,9 +34,6 @@ page.initSettings = function() {
if (!('autoRetrieveCredentials' in page.settings)) {
page.settings.autoRetrieveCredentials = defaultSettings.autoRetrieveCredentials;
}
if (!('port' in page.settings)) {
page.settings.port = defaultSettings.proxyPort;
}
browser.storage.local.set({'settings': page.settings});
resolve();
});

View file

@ -396,7 +396,6 @@ cipPassword.callbackPasswordCopied = function(bool) {
cipPassword.callbackGeneratedPassword = function(entries) {
if (entries && entries.length >= 1) {
console.log(entries[0]);
jQuery('#cip-genpw-btn-clipboard:first').removeClass('btn-success');
jQuery('input#cip-genpw-textfield-password:first').val(entries[0].password);
if (isNaN(entries[0].login)) {
@ -408,7 +407,7 @@ cipPassword.callbackGeneratedPassword = function(entries) {
}
else {
if (jQuery('div#cip-genpw-error:first').length === 0) {
jQuery('button#cip-genpw-btn-generate:first').after('<div style=\'block\' id=\'cip-genpw-error\'>Cannot receive generated password.<br />Is your version of KeePassXC up-to-date?<br /><br /><a href=\'https://keepassxc.org\'>Please visit the KeePassXC homepage</a></div>');
jQuery('button#cip-genpw-btn-generate:first').after('<div style=\'block\' id=\'cip-genpw-error\'>Cannot receive generated password.<br />Is KeePassXC opened?<br /></div>');
jQuery('input#cip-genpw-textfield-password:first').parent().hide();
jQuery('input#cip-genpw-checkbox-next-field:first').parent('label').hide();
jQuery('button#cip-genpw-btn-generate').hide();
@ -1117,21 +1116,15 @@ cip.init = function() {
};
cip.detectNewActiveFields = function() {
const hiddenFields = cipFields.getHiddenFieldCount();
// If hidden fields aren't detected, setInterval is being looped in each frame of the page
//if (hiddenFields > 0) {
const divDetect = setInterval(function() {
const fields = cipFields.getAllFields();
if (fields.length > 1) {
cip.initCredentialFields(true);
clearInterval(divDetect);
}
}, 1000);
//}
const divDetect = setInterval(function() {
const fields = cipFields.getAllFields();
if (fields.length > 1) {
cip.initCredentialFields(true);
clearInterval(divDetect);
}
}, 1000);
};
// Try to do this in a way that database value if checked without polling the KeePassXC.. too many messages jumping around
// Switch credentials if database is changed or closed
cip.detectDatabaseChange = function() {
let dbDetectInterval = setInterval(function() {
@ -1148,7 +1141,8 @@ cip.detectDatabaseChange = function() {
// Switch back to default popup
browser.runtime.sendMessage({
action: 'get_status'
action: 'get_status',
args: [ true ] // Set polling to true, this is an internal function call
});
} else {
if (response.new !== 'no-hash' && response.new !== response.old) {

View file

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "keepassxc-browser",
"version": "0.3.9",
"version": "0.4.0",
"description": "KeePassXC integration for modern web browsers",
"author": "Sami Vänttinen",
"icons": {
@ -41,6 +41,9 @@
"matches": [
"<all_urls>"
],
"exclude_matches": [
"*://*/*.xml"
],
"js": [
"browser-polyfill.min.js",
"global.js",
@ -67,8 +70,8 @@
"fill-password": {
"description": "Insert a password",
"suggested_key": {
"default": "Ctrl+Shift+P",
"mac": "Command+Shift+P"
"default": "Alt+Shift+P",
"mac": "Alt+Shift+P"
}
}
},

View file

@ -84,24 +84,6 @@
</span>
</div>
</p>
<p>
<div class="form-group">
<label for="port">UDP port for proxy applications:</label>
<div class="control-group">
<div class="input-append">
<input type="number" id="port" placeholder="19700" value="19700" />
<button class="btn btn-sm btn-primary" id="portButton" type="button"><span class="glyphicon glyphicon-floppy-disk"></span> Save</button>
</div>
<span class="help-inline">
Change the port if you have trouble with running KeePassXC on the default port.
<br />
You have to set the same port number in KeePassXC options.
<br />
Default: 19700
</span>
</div>
</div>
</p>
<hr />
<p>
<div class="checkbox">

View file

@ -88,24 +88,10 @@ options.initGeneralSettings = function() {
}).then(options.showKeePassXCVersions);
});
$('#port').val(options.settings['port']);
$('#blinkTimeout').val(options.settings['blinkTimeout']);
$('#blinkMinTimeout').val(options.settings['blinkMinTimeout']);
$('#allowedRedirect').val(options.settings['allowedRedirect']);
$('#portButton').click(function() {
const port = $.trim($('#port').val());
const portNumber = Number(port);
if (isNaN(port) || portNumber < 1025 || portNumber > 99999) {
$('#port').closest('.control-group').addClass('error');
alert('The port number has to be in range 1025 - 99999.\nNothing saved!');
return;
}
options.settings['port'] = String(portNumber);
options.saveSetting('port');
});
$('#blinkTimeoutButton').click(function(){
const blinkTimeout = $.trim($('#blinkTimeout').val());
const blinkTimeoutval = Number(blinkTimeout);

View file

@ -34,7 +34,6 @@ Request:
{
"action": "change-public-keys",
"publicKey": "<current public key>",
"proxyPort": "<UDP port for proxy applications>",
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q",
"clientID": "<clientID>"
}
@ -250,4 +249,4 @@ Response message data (success always returns an error, decrypted):
"error": "Database not opened",
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
}
```
```