This commit is contained in:
Sami Vänttinen 2026-03-09 22:30:23 +13:00 committed by GitHub
commit 7226e51d70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 97 additions and 4 deletions

View file

@ -874,6 +874,22 @@
"message": "Allow filling HTTP Basic Auth credentials",
"description": "Allow filling HTTP Basic Auth credentials checkbox text."
},
"optionsConnectionMethod": {
"message": "Connection method",
"description": "Connection method selection text."
},
"optionsConnectionMethodHelpText": {
"message": "If native messaging is blocked in your browser, you can switch to a direct WebSocket sonnection. The feature must be enabled from KeePassXC side to work. Browser restart is required.",
"description": "Connection method help text."
},
"optionsConnectionMethodNativeMessaging": {
"message": "Native messaging",
"description": "Native messaging option for Connection method."
},
"optionsConnectionMethodWebSocket": {
"message": "WebSocket",
"description": "WebSocket option for Connection method."
},
"optionsDebugLogging": {
"message": "Debug logging",
"description": "Debug logging checkbox text."

View file

@ -5,11 +5,12 @@ keepassClient.keySize = 24;
keepassClient.messageTimeout = 500; // Milliseconds
keepassClient.nativeHostName = 'org.keepassxc.keepassxc_browser';
keepassClient.nativePort = null;
keepassClient.webSocket = null;
const kpErrors = {
UNKNOWN_ERROR: 0,
DATABASE_NOT_OPENED: 1,
DATABASE_HASH_NOT_RECEIVED: 2,
DATABASE_HASH_NOT_RECEIVED: 2,
CLIENT_PUBLIC_KEY_NOT_RECEIVED: 3,
CANNOT_DECRYPT_MESSAGE: 4,
TIMEOUT_OR_NOT_CONNECTED: 5,
@ -157,7 +158,10 @@ class Message {
//--------------------------------------------------------------------------
keepassClient.sendNativeMessage = async function(request, enableTimeout = false, timeoutValue) {
if (!keepassClient.nativePort) {
if (page?.settings?.connectionMethod === ConnectionMethod.WEBSOCKET && !keepassClient.webSocket) {
logError('No WebSocket defined.');
return;
} else if (page?.settings?.connectionMethod === ConnectionMethod.NATIVE_MESSAGING && !keepassClient.nativePort) {
logError('No native messaging port defined.');
return;
}
@ -167,7 +171,11 @@ keepassClient.sendNativeMessage = async function(request, enableTimeout = false,
messageBuffer.addMessage(message);
});
keepassClient.nativePort.postMessage(request);
if (page?.settings?.connectionMethod === ConnectionMethod.WEBSOCKET) {
keepassClient.webSocket.send(JSON.stringify(request));
} else {
keepassClient.nativePort.postMessage(request);
}
const response = await message.promise;
@ -413,3 +421,42 @@ keepassClient.onNativeMessage = function(response) {
// Generic response handling
keepassClient.handleNativeMessage(response);
};
//--------------------------------------------------------------------------
// WebSocket related
//--------------------------------------------------------------------------
keepassClient.connectToWebSocket = async function() {
return new Promise((resolve, reject) => {
if (keepassClient.webSocket) {
keepassClient.webSocket.close();
}
console.log(`${EXTENSION_NAME}: Connecting to WebSocket`);
try {
keepassClient.webSocket = new WebSocket('ws://localhost:7580');
keepassClient.webSocket.addEventListener('close', (event) => {
logError('Close WebSocket:', event);
onDisconnected();
reject();
});
keepassClient.webSocket.addEventListener('error', (event) => {
logError('WebSocket error:', event);
onDisconnected();
reject();
});
keepassClient.webSocket.addEventListener('message', (event) => {
keepassClient.onNativeMessage(JSON.parse(event?.data));
});
keepassClient.webSocket.addEventListener('open', (event) => {
console.log(`${EXTENSION_NAME}: WebSocket connected`);
keepass.isConnected = true;
resolve();
});
} catch (e) {
keepassClient.webSocket = null;
onDisconnected();
}
});
};

View file

@ -822,7 +822,12 @@ keepass.disableAutomaticReconnect = function() {
};
keepass.reconnect = async function(tab = null, connectionTimeout = 1500) {
keepassClient.connectToNative();
if (page?.settings?.connectionMethod === ConnectionMethod.WEBSOCKET) {
await keepassClient.connectToWebSocket();
} else {
keepassClient.connectToNative();
}
keepass.generateNewKeyPair();
const keyChangeResult = await keepass
.changePublicKeys(tab, !!connectionTimeout, connectionTimeout)

View file

@ -1,5 +1,10 @@
'use strict';
const ConnectionMethod = {
NATIVE_MESSAGING: 'nativemessaging',
WEBSOCKET: 'websocket',
};
const defaultSettings = {
afterFillSorting: SORT_BY_MATCHING_CREDENTIALS_SETTING,
afterFillSortingTotp: SORT_BY_RELEVANT_ENTRY,
@ -15,6 +20,7 @@ const defaultSettings = {
checkUpdateKeePassXC: CHECK_UPDATE_NEVER,
clearCredentialsTimeout: 10,
colorTheme: 'system',
connectionMethod: ConnectionMethod.NATIVE_MESSAGING,
credentialSorting: SORT_BY_GROUP_AND_TITLE,
debugLogging: false,
defaultGroup: '',

View file

@ -537,6 +537,18 @@
<div class="form-text" data-i18n="optionsClearCredentialsTimeoutHelpText"></div>
</div>
<!-- Connection method -->
<div class="form-group col-sm-3 pb-2 py-2">
<label for="connectionMethod" class="form-label" data-i18n="optionsConnectionMethod"></label>
<select class="form-select form-select-sm col-md-3 col-lg-2" id="connectionMethod" data-i18n="[title]optionsConnectionMethodSelection">
<option value="nativemessaging" data-i18n="optionsConnectionMethodNativeMessaging"></option>
<option value="websocket" data-i18n="optionsConnectionMethodWebSocket"></option>
</select>
</div>
<div>
<span class="form-text text-muted" data-i18n="optionsConnectionMethodHelpText"></span>
</div>
<!-- Debug logging -->
<div class="form-group mt-2 pb-1">
<div class="form-check form-switch">

View file

@ -226,6 +226,13 @@ options.initGeneralSettings = async function() {
});
});
// Connection method
$('#tab-general-settings select#connectionMethod').value = options.settings['connectionMethod'];
$('#tab-general-settings select#connectionMethod').addEventListener('change', async function(e) {
options.settings['connectionMethod'] = e.currentTarget.value;
await options.saveSettings();
});
// Default group
$('#defaultGroupButton').addEventListener('click', async function() {
const value = $('#defaultGroup').value;