mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Merge pull request #1886 from keepassxreboot/fix/transfer_iframe_messages_without_postmessage
Transfer iframe messages without postMessage()
This commit is contained in:
commit
0563e73f55
4 changed files with 104 additions and 118 deletions
|
|
@ -220,6 +220,11 @@ kpxcEvent.hideTroubleshootingGuideAlert = async function(tab) {
|
|||
await kpxcEvent.onSaveSettings(tab, settings);
|
||||
};
|
||||
|
||||
// Bounce message back to all frames
|
||||
kpxcEvent.sendBackToTabs = async function(tab, args = []) {
|
||||
await browser.tabs.sendMessage(tab.id, { action: 'frame_message', args: args });
|
||||
};
|
||||
|
||||
// All methods named in this object have to be declared BEFORE this!
|
||||
kpxcEvent.messageHandlers = {
|
||||
'add_credentials': keepass.addCredentials,
|
||||
|
|
@ -231,6 +236,7 @@ kpxcEvent.messageHandlers = {
|
|||
'enable_automatic_reconnect': keepass.enableAutomaticReconnect,
|
||||
'disable_automatic_reconnect': keepass.disableAutomaticReconnect,
|
||||
'fill_http_auth': page.fillHttpAuth,
|
||||
'frame_message': kpxcEvent.sendBackToTabs,
|
||||
'generate_password': keepass.generatePassword,
|
||||
'get_color_theme': kpxcEvent.getColorTheme,
|
||||
'get_connected_database': kpxcEvent.onGetConnectedDatabase,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ kpxcSites.exceptionFound = function(identifier) {
|
|||
|
||||
if (document.location.origin === 'https://idmsa.apple.com'
|
||||
&& ((typeof identifier === 'string' && identifier === 'password_text_field')
|
||||
|| [ 'password', 'form-row', 'show-password' ].every(c => identifier.contains(c)))) {
|
||||
|| (typeof identifier === 'object' && [ 'password', 'form-row', 'show-password' ].every(c => identifier.contains(c))))) {
|
||||
return true;
|
||||
} else if (document.location.origin.startsWith('https://signin.ebay.')
|
||||
&& (identifier === 'null' || identifier.value === 'null' || identifier === 'pass')) {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ kpxcCustomLoginFieldsBanner.create = async function() {
|
|||
= kpxc.settings[DEFINED_CUSTOM_FIELDS] && kpxc.settings[DEFINED_CUSTOM_FIELDS][location]
|
||||
? 'inline-block' : 'none';
|
||||
if (window.self !== window.top && kpxcCustomLoginFieldsBanner.buttons.clearData.style.display === 'inline-block') {
|
||||
sendMessageToParent('enable_clear_data_button');
|
||||
sendMessageToParent(undefined, 'enable_clear_data_button');
|
||||
}
|
||||
|
||||
initColorTheme(banner);
|
||||
|
|
@ -147,14 +147,6 @@ kpxcCustomLoginFieldsBanner.create = async function() {
|
|||
if (!kpxcCustomLoginFieldsBanner.created) {
|
||||
window.self.document.body.appendChild(wrapper);
|
||||
kpxcCustomLoginFieldsBanner.created = true;
|
||||
|
||||
if (window.self === window.top) {
|
||||
// Listen messages from iframes
|
||||
window.addEventListener('message', handleTopWindowMessage, false);
|
||||
} else {
|
||||
// Listen messages from top window
|
||||
window.addEventListener('message', handleParentWindowMessage, false);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', kpxcCustomLoginFieldsBanner.keyDown);
|
||||
|
|
@ -191,7 +183,7 @@ kpxcCustomLoginFieldsBanner.usernameButtonClicked = function(e) {
|
|||
kpxcCustomLoginFieldsBanner.prepareUsernameSelection();
|
||||
kpxcCustomLoginFieldsBanner.buttons.confirm.disabled = true;
|
||||
|
||||
sendMessageToFrames('username_button_clicked');
|
||||
sendMessageToFrames(e, 'username_button_clicked');
|
||||
};
|
||||
|
||||
kpxcCustomLoginFieldsBanner.passwordButtonClicked = function(e) {
|
||||
|
|
@ -209,7 +201,7 @@ kpxcCustomLoginFieldsBanner.passwordButtonClicked = function(e) {
|
|||
kpxcCustomLoginFieldsBanner.preparePasswordSelection();
|
||||
kpxcCustomLoginFieldsBanner.buttons.confirm.disabled = true;
|
||||
|
||||
sendMessageToFrames('password_button_clicked');
|
||||
sendMessageToFrames(e, 'password_button_clicked');
|
||||
};
|
||||
|
||||
kpxcCustomLoginFieldsBanner.totpButtonClicked = function(e) {
|
||||
|
|
@ -227,7 +219,7 @@ kpxcCustomLoginFieldsBanner.totpButtonClicked = function(e) {
|
|||
kpxcCustomLoginFieldsBanner.prepareTOTPSelection();
|
||||
kpxcCustomLoginFieldsBanner.buttons.confirm.disabled = true;
|
||||
|
||||
sendMessageToFrames('totp_button_clicked');
|
||||
sendMessageToFrames(e, 'totp_button_clicked');
|
||||
};
|
||||
|
||||
kpxcCustomLoginFieldsBanner.stringFieldsButtonClicked = function(e) {
|
||||
|
|
@ -248,7 +240,7 @@ kpxcCustomLoginFieldsBanner.stringFieldsButtonClicked = function(e) {
|
|||
kpxcCustomLoginFieldsBanner.prepareStringFieldSelection();
|
||||
kpxcCustomLoginFieldsBanner.buttons.confirm.disabled = true;
|
||||
|
||||
sendMessageToFrames('string_field_button_clicked');
|
||||
sendMessageToFrames(e, 'string_field_button_clicked');
|
||||
};
|
||||
|
||||
kpxcCustomLoginFieldsBanner.closeButtonClicked = function(e) {
|
||||
|
|
@ -258,7 +250,7 @@ kpxcCustomLoginFieldsBanner.closeButtonClicked = function(e) {
|
|||
|
||||
kpxcCustomLoginFieldsBanner.destroy();
|
||||
|
||||
sendMessageToFrames('close_button_clicked');
|
||||
sendMessageToFrames(e, 'close_button_clicked');
|
||||
};
|
||||
|
||||
// Updates the possible selections if the page content has been changed
|
||||
|
|
@ -281,7 +273,7 @@ kpxcCustomLoginFieldsBanner.updateFieldSelections = function() {
|
|||
};
|
||||
|
||||
// Reset selections
|
||||
kpxcCustomLoginFieldsBanner.reset = function() {
|
||||
kpxcCustomLoginFieldsBanner.reset = function(e) {
|
||||
kpxcCustomLoginFieldsBanner.resetSelection();
|
||||
|
||||
kpxcCustomLoginFieldsBanner.buttons.confirm.disabled = true;
|
||||
|
|
@ -291,11 +283,11 @@ kpxcCustomLoginFieldsBanner.reset = function() {
|
|||
|
||||
kpxcCustomLoginFieldsBanner.enableAllButtons();
|
||||
|
||||
sendMessageToFrames('reset_button_clicked');
|
||||
sendMessageToFrames(e, 'reset_button_clicked');
|
||||
};
|
||||
|
||||
// Confirm and save the selections
|
||||
kpxcCustomLoginFieldsBanner.confirm = async function() {
|
||||
kpxcCustomLoginFieldsBanner.confirm = async function(e) {
|
||||
if (!kpxc.settings[DEFINED_CUSTOM_FIELDS]) {
|
||||
kpxc.settings[DEFINED_CUSTOM_FIELDS] = {};
|
||||
}
|
||||
|
|
@ -354,11 +346,11 @@ kpxcCustomLoginFieldsBanner.confirm = async function() {
|
|||
}
|
||||
|
||||
kpxcCustomLoginFieldsBanner.destroy();
|
||||
sendMessageToFrames('confirm_button_clicked');
|
||||
sendMessageToFrames(e, 'confirm_button_clicked');
|
||||
};
|
||||
|
||||
// Clears the previously saved data from settings
|
||||
kpxcCustomLoginFieldsBanner.clearData = async function() {
|
||||
kpxcCustomLoginFieldsBanner.clearData = async function(e) {
|
||||
const location = kpxc.getDocumentLocation();
|
||||
delete kpxc.settings[DEFINED_CUSTOM_FIELDS][location];
|
||||
|
||||
|
|
@ -367,7 +359,7 @@ kpxcCustomLoginFieldsBanner.clearData = async function() {
|
|||
|
||||
kpxcCustomLoginFieldsBanner.buttons.clearData.style.display = 'none';
|
||||
|
||||
sendMessageToFrames('clear_data_button_clicked');
|
||||
sendMessageToFrames(e, 'clear_data_button_clicked');
|
||||
};
|
||||
|
||||
// Resets all selections and marked fields
|
||||
|
|
@ -477,7 +469,7 @@ kpxcCustomLoginFieldsBanner.selectField = function(fieldType) {
|
|||
kpxcCustomLoginFieldsBanner.backToStart();
|
||||
|
||||
kpxcCustomLoginFieldsBanner.buttons[fieldType].classList.add(GRAY_BUTTON_CLASS);
|
||||
sendMessageToParent(`${fieldType}_selected`, kpxcCustomLoginFieldsBanner.selection[fieldType]);
|
||||
sendMessageToParent(e, `${fieldType}_selected`, kpxcCustomLoginFieldsBanner.selection[fieldType]);
|
||||
};
|
||||
|
||||
kpxcCustomLoginFieldsBanner.markFields();
|
||||
|
|
@ -502,7 +494,7 @@ kpxcCustomLoginFieldsBanner.selectStringFields = function() {
|
|||
field.onclick = undefined;
|
||||
|
||||
kpxcCustomLoginFieldsBanner.buttons.stringFields.classList.add(GRAY_BUTTON_CLASS);
|
||||
sendMessageToParent('string_field_selected', kpxcCustomLoginFieldsBanner.selection.fields);
|
||||
sendMessageToParent(e, 'string_field_selected', kpxcCustomLoginFieldsBanner.selection.fields);
|
||||
};
|
||||
|
||||
kpxcCustomLoginFieldsBanner.markFields();
|
||||
|
|
@ -626,6 +618,83 @@ kpxcCustomLoginFieldsBanner.getNonSelectedElements = function() {
|
|||
return kpxcCustomLoginFieldsBanner.chooser.querySelectorAll(kpxcCustomLoginFieldsBanner.nonSelectedElementsPattern);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// IFrame support
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Handles messages sent from iframes to the top window
|
||||
kpxcCustomLoginFieldsBanner.handleTopWindowMessage = function(args) {
|
||||
if (!kpxcCustomLoginFieldsBanner.created) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = args?.[2];
|
||||
const selection = args?.[3];
|
||||
|
||||
if (message === 'username_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.username = selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (message === 'password_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.password = selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (message === 'totp_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.totp = selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (message === 'string_field_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.stringFields = selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (message === 'enable_clear_data_button') {
|
||||
kpxcCustomLoginFieldsBanner.buttons.clearData.style.display = 'inline-block';
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Banner button clicks from the top window
|
||||
kpxcCustomLoginFieldsBanner.handleParentWindowMessage = function(args) {
|
||||
if (!kpxcCustomLoginFieldsBanner.created) {
|
||||
return;
|
||||
}
|
||||
|
||||
const e = {};
|
||||
e.isTrusted = args?.[1];
|
||||
const message = args?.[2];
|
||||
|
||||
if (message === 'username_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.usernameButtonClicked(e);
|
||||
} else if (message === 'password_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.passwordButtonClicked(e);
|
||||
} else if (message === 'totp_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.totpButtonClicked(e);
|
||||
} else if (message === 'string_field_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.stringFieldsButtonClicked(e);
|
||||
} else if (message === 'reset_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.reset();
|
||||
} else if (message === 'close_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.closeButtonClicked(e);
|
||||
} else if (message === 'confirm_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.confirm();
|
||||
} else if (message === 'clear_data_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.clearData();
|
||||
}
|
||||
};
|
||||
|
||||
// Sends messages to all iframes. Works only from the top window.
|
||||
const sendMessageToFrames = async function(e, message) {
|
||||
if (window.self === window.top) {
|
||||
await sendMessage('frame_message', [ 'frame_request_to_frames', e?.isTrusted, message ]);
|
||||
}
|
||||
};
|
||||
|
||||
// Sends message to parent window. Works only from iframes.
|
||||
const sendMessageToParent = async function(e, message, selection) {
|
||||
if (window.self !== window.top) {
|
||||
await sendMessage('frame_message', [ 'frame_request_to_parent', e?.isTrusted, message, selection ]);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helper functions
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const removeContent = function(pattern) {
|
||||
const elems = kpxcCustomLoginFieldsBanner.chooser.querySelectorAll(pattern);
|
||||
for (const e of elems) {
|
||||
|
|
@ -666,98 +735,3 @@ const dataStepToString = function() {
|
|||
return tr('defineStringField');
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// IFrame support
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// A simple check for top-level-domain
|
||||
const topLevelDomainMatches = function(host) {
|
||||
if (!host) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const originUrl = new URL(host);
|
||||
const frameUrl = new URL(window.self.document.location.origin);
|
||||
const urlParts = originUrl.host.split('.');
|
||||
const dotCount = urlParts.length - 1;
|
||||
|
||||
// Simple host like google.com, check directly
|
||||
if (dotCount < 1) {
|
||||
return false;
|
||||
} else if (dotCount === 1) {
|
||||
return frameUrl.host.includes(originUrl.host);
|
||||
}
|
||||
|
||||
// Get the top-level-domain using counts of '.' but backwards, max 3.
|
||||
// A basic host is like idmsa.apple.com, a more complex one like www.bbva.com.ar.
|
||||
const index = Math.min(dotCount, 3);
|
||||
const subDomain = `${urlParts[dotCount - index]}.`;
|
||||
const topLevelDomain = originUrl.host.substring(originUrl.host.indexOf(subDomain) + subDomain.length);
|
||||
|
||||
return frameUrl.host.includes(topLevelDomain);
|
||||
};
|
||||
|
||||
// Handles messages sent from iframes to the top window
|
||||
const handleTopWindowMessage = function(e) {
|
||||
if (!topLevelDomainMatches(e.origin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.data.message === 'username_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.username = e.data.selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (e.data.message === 'password_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.password = e.data.selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (e.data.message === 'totp_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.totp = e.data.selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (e.data.message === 'string_field_selected') {
|
||||
kpxcCustomLoginFieldsBanner.selection.stringFields = e.data.selection;
|
||||
kpxcCustomLoginFieldsBanner.setSelectedField();
|
||||
} else if (e.data.message === 'enable_clear_data_button') {
|
||||
kpxcCustomLoginFieldsBanner.buttons.clearData.style.display = 'inline-block';
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Banner button clicks from the top window
|
||||
const handleParentWindowMessage = function(e) {
|
||||
if (!topLevelDomainMatches(e.origin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.data === 'username_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.usernameButtonClicked(e);
|
||||
} else if (e.data === 'password_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.passwordButtonClicked(e);
|
||||
} else if (e.data === 'totp_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.totpButtonClicked(e);
|
||||
} else if (e.data === 'string_field_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.stringFieldsButtonClicked(e);
|
||||
} else if (e.data === 'reset_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.reset();
|
||||
} else if (e.data === 'close_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.closeButtonClicked(e);
|
||||
} else if (e.data === 'confirm_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.confirm();
|
||||
} else if (e.data === 'clear_data_button_clicked') {
|
||||
kpxcCustomLoginFieldsBanner.clearData();
|
||||
}
|
||||
};
|
||||
|
||||
// Sends messages to all iframes. Works only from the top window.
|
||||
const sendMessageToFrames = function(message) {
|
||||
if (window.self === window.top) {
|
||||
for (var i = 0; i < window.frames.length; i++) {
|
||||
frames[i].postMessage(message, '*');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Sends message to parent window. Works only from iframes.
|
||||
const sendMessageToParent = function(message, selection) {
|
||||
if (window.self !== window.top) {
|
||||
window.top.postMessage({ message, selection }, '*');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -864,6 +864,12 @@ browser.runtime.onMessage.addListener(async function(req, sender) {
|
|||
} else if (req.action === 'fill_attribute' && req.args) {
|
||||
await kpxc.receiveCredentialsIfNecessary();
|
||||
kpxcFill.fillAttributeToActiveElementWith(req.args);
|
||||
} else if (req.action === 'frame_message') {
|
||||
if (req.args?.[0] === 'frame_request_to_frames' && window.self !== window.top) {
|
||||
kpxcCustomLoginFieldsBanner.handleParentWindowMessage(req.args);
|
||||
} else if (req.args?.[0] === 'frame_request_to_parent' && window.self === window.top) {
|
||||
kpxcCustomLoginFieldsBanner.handleTopWindowMessage(req.args);
|
||||
}
|
||||
} else if (req.action === 'ignore_site') {
|
||||
kpxc.ignoreSite(req.args);
|
||||
} else if (req.action === 'redetect_fields') {
|
||||
|
|
|
|||
Loading…
Reference in a new issue