mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Merge pull request #1265 from keepassxreboot/feature/autotype_from_browser
Support for triggering Global Auto-Type
This commit is contained in:
commit
1579838617
9 changed files with 103 additions and 2 deletions
|
|
@ -31,6 +31,10 @@
|
|||
"message": "Fill attribute…",
|
||||
"description": "Context menu parent item for filling a custom attribute."
|
||||
},
|
||||
"contextMenuRequestGlobalAutoType": {
|
||||
"message": "Request Global Auto-Type",
|
||||
"description": "Global Auto-Type shortcut text."
|
||||
},
|
||||
"multipleCredentialsDetected": {
|
||||
"message": "HTTP authentication with multiple credentials detected. Click on the extension icon to choose the correct one.",
|
||||
"description": "Notification when HTTP Authentication has multiple credentials detected."
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ kpxcEvent.messageHandlers = {
|
|||
'popup_login': kpxcEvent.onLoginPopup,
|
||||
'reconnect': kpxcEvent.onReconnect,
|
||||
'remove_credentials_from_tab_information': kpxcEvent.onRemoveCredentialsFromTabInformation,
|
||||
'request_autotype': keepass.requestAutotype,
|
||||
'retrieve_credentials': page.retrieveCredentials,
|
||||
'show_default_browseraction': browserAction.showDefault,
|
||||
'update_credentials': keepass.updateCredentials,
|
||||
|
|
|
|||
|
|
@ -114,7 +114,8 @@ const contextMenuItems = [
|
|||
{ title: tr('contextMenuFillTOTP'), action: 'fill_totp' },
|
||||
{ title: tr('contextMenuFillAttribute'), id: 'fill_attribute', visible: false },
|
||||
{ title: tr('contextMenuShowPasswordGenerator'), action: 'show_password_generator' },
|
||||
{ title: tr('contextMenuSaveCredentials'), action: 'save_credentials' }
|
||||
{ title: tr('contextMenuSaveCredentials'), action: 'save_credentials' },
|
||||
{ title: tr('contextMenuRequestGlobalAutoType'), action: 'request_autotype' }
|
||||
];
|
||||
|
||||
const menuContexts = [ 'editable' ];
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ const kpActions = {
|
|||
DATABASE_UNLOCKED: 'database-unlocked',
|
||||
GET_DATABASE_GROUPS: 'get-database-groups',
|
||||
CREATE_NEW_GROUP: 'create-new-group',
|
||||
GET_TOTP: 'get-totp'
|
||||
GET_TOTP: 'get-totp',
|
||||
REQUEST_AUTOTYPE: 'request-autotype'
|
||||
};
|
||||
|
||||
const kpErrors = {
|
||||
|
|
@ -852,6 +853,50 @@ keepass.getTotp = async function(tab, args = []) {
|
|||
}
|
||||
};
|
||||
|
||||
keepass.requestAutotype = async function(tab, args = []) {
|
||||
if (!keepass.isConnected) {
|
||||
keepass.handleError(tab, kpErrors.TIMEOUT_OR_NOT_CONNECTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
const kpAction = kpActions.REQUEST_AUTOTYPE;
|
||||
const [ nonce, incrementedNonce ] = keepass.getNonces();
|
||||
const search = getTopLevelDomainFromUrl(args[0]);
|
||||
|
||||
const messageData = {
|
||||
action: kpAction,
|
||||
search: search
|
||||
};
|
||||
|
||||
const request = keepass.buildRequest(kpAction, keepass.encrypt(messageData, nonce), nonce, keepass.clientID);
|
||||
|
||||
try {
|
||||
const response = await keepass.sendNativeMessage(request);
|
||||
if (response.message && response.nonce) {
|
||||
const res = keepass.decrypt(response.message, response.nonce);
|
||||
if (!res) {
|
||||
keepass.handleError(tab, kpErrors.CANNOT_DECRYPT_MESSAGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
const message = nacl.util.encodeUTF8(res);
|
||||
const parsed = JSON.parse(message);
|
||||
|
||||
if (keepass.verifyResponse(parsed, incrementedNonce)) {
|
||||
return true;
|
||||
}
|
||||
} else if (response.error && response.errorCode) {
|
||||
keepass.handleError(tab, response.errorCode, response.error);
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (err) {
|
||||
console.log('requestAutotype failed: ', err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
keepass.generateNewKeyPair = function() {
|
||||
keepass.keyPair = nacl.box.keyPair();
|
||||
//console.log(nacl.util.encodeBase64(keepass.keyPair.publicKey) + ' ' + nacl.util.encodeBase64(keepass.keyPair.secretKey));
|
||||
|
|
|
|||
|
|
@ -140,6 +140,19 @@ const slashNeededForUrl = function(pattern) {
|
|||
return matchPattern.exec(pattern);
|
||||
};
|
||||
|
||||
// Returns the top level domain, e.g. https://another.example.co.uk -> example.co.uk
|
||||
// This is done because a top level domain will probably give better matches with Auto-Type than a full hostname.
|
||||
const getTopLevelDomainFromUrl = function(hostname) {
|
||||
const domainRegex = new RegExp(/(\w+).(com|net|org|edu|co)*(.\w+)$/g);
|
||||
const domainMatch = domainRegex.exec(hostname);
|
||||
|
||||
if (domainMatch) {
|
||||
return domainMatch[0];
|
||||
}
|
||||
|
||||
return hostname;
|
||||
};
|
||||
|
||||
function tr(key, params) {
|
||||
return browser.i18n.getMessage(key, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2114,6 +2114,8 @@ browser.runtime.onMessage.addListener(async function(req, sender) {
|
|||
await kpxc.retrieveCredentials(true);
|
||||
} else if (req.action === 'show_password_generator') {
|
||||
kpxcPasswordDialog.trigger();
|
||||
} else if (req.action === 'request_autotype') {
|
||||
sendMessage('request_autotype', [ window.location.hostname ]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@
|
|||
},
|
||||
"retrive_credentials_forced": {
|
||||
"description": "__MSG_popupReopenButton__"
|
||||
},
|
||||
"request_autotype": {
|
||||
"description": "__MSG_contextMenuRequestGlobalAutoType__"
|
||||
}
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
|
|
|
|||
|
|
@ -404,3 +404,21 @@ Response message data (success, decrypted):
|
|||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
||||
### request-autotype (KeePassXC 2.7.0 and newer)
|
||||
Request (no unencrypted message is needed):
|
||||
```json
|
||||
{
|
||||
"action": "request-autotype",
|
||||
"search": "<base domain of URL>"
|
||||
}
|
||||
```
|
||||
|
||||
Response message data (success, decrypted):
|
||||
```json
|
||||
{
|
||||
"version": "2.7.0",
|
||||
"success": "true",
|
||||
"nonce": "tZvLrBzkQ9GxXq9PvKJj4iAnfPT0VZ3Q"
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -43,6 +43,20 @@ async function testGeneral() {
|
|||
for (const m of matches) {
|
||||
assertRegex(siteMatch(m[0], m[1]), m[2], testCard, `siteMatch() for ${m[1]}`);
|
||||
}
|
||||
|
||||
// Base domain parsing (window.location.hostname)
|
||||
const domains = [
|
||||
[ 'another.example.co.uk', 'example.co.uk' ],
|
||||
[ 'www.example.com', 'example.com' ],
|
||||
[ 'test.net', 'test.net' ],
|
||||
[ 'so.many.subdomains.co.jp', 'subdomains.co.jp' ],
|
||||
[ 'test.site.example.com.au', 'example.com.au' ],
|
||||
[ '192.168.0.1', '192.168.0.1' ]
|
||||
];
|
||||
|
||||
for (const d of domains) {
|
||||
kpxcAssert(getTopLevelDomainFromUrl(d[0]), d[1], testCard, 'getBaseDomainFromUrl() for ' + d[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Input field matching (keepassxc-browser.js)
|
||||
|
|
|
|||
Loading…
Reference in a new issue