mirror of
https://gitea.com/gitea/gitea-mirror.git
synced 2026-05-01 01:04:19 +00:00
Harden render iframe open-link handling (#36811)
This PR hardens the handling of the “open-link” action in render iframes (external rendering iframes). It prevents iframes from triggering unsafe or unintended redirects or opening new windows via postMessage. Additionally, it improves iframe height reporting to reduce scrollbar and height mismatch issues, and adds unit test coverage. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -1,23 +1,46 @@
|
||||
import {generateElemId, queryElemChildren} from '../utils/dom.ts';
|
||||
import {isDarkTheme} from '../utils.ts';
|
||||
|
||||
function safeRenderIframeLink(link: any): string | null {
|
||||
try {
|
||||
const url = new URL(`${link}`, window.location.href);
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
||||
console.error(`Unsupported link protocol: ${link}`);
|
||||
return null;
|
||||
}
|
||||
return url.href;
|
||||
} catch (e) {
|
||||
console.error(`Failed to parse link: ${link}, error: ${e}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// This function is only designed for "open-link" command from iframe, is not suitable for other contexts.
|
||||
// Because other link protocols are directly handled by the iframe, but not here.
|
||||
// Arguments can be any type & any value, they are from "message" event's data which is not controlled by us.
|
||||
export function navigateToIframeLink(unsafeLink: any, target: any) {
|
||||
const linkHref = safeRenderIframeLink(unsafeLink);
|
||||
if (linkHref === null) return;
|
||||
if (target === '_blank') {
|
||||
window.open(linkHref, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
// treat all other targets including ("_top", "_self", etc.) as same tab navigation
|
||||
window.location.assign(linkHref);
|
||||
}
|
||||
|
||||
async function loadRenderIframeContent(iframe: HTMLIFrameElement) {
|
||||
const iframeSrcUrl = iframe.getAttribute('data-src')!;
|
||||
if (!iframe.id) iframe.id = generateElemId('gitea-iframe-');
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
if (e.source !== iframe.contentWindow) return;
|
||||
if (!e.data?.giteaIframeCmd || e.data?.giteaIframeId !== iframe.id) return;
|
||||
const cmd = e.data.giteaIframeCmd;
|
||||
if (cmd === 'resize') {
|
||||
// TODO: sometimes the reported iframeHeight is not the size we need, need to figure why. Example: openapi swagger.
|
||||
// As a workaround, add some pixels here.
|
||||
iframe.style.height = `${e.data.iframeHeight + 2}px`;
|
||||
iframe.style.height = `${e.data.iframeHeight}px`;
|
||||
} else if (cmd === 'open-link') {
|
||||
if (e.data.anchorTarget === '_blank') {
|
||||
window.open(e.data.openLink, '_blank');
|
||||
} else {
|
||||
window.location.href = e.data.openLink;
|
||||
}
|
||||
navigateToIframeLink(e.data.openLink, e.data.anchorTarget);
|
||||
} else {
|
||||
throw new Error(`Unknown gitea iframe cmd: ${cmd}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user