"use client"; import { Box, Stack, Text, Title } from "@mantine/core"; import { IconBrowserOff, IconProtocol } from "@tabler/icons-react"; import { objectEntries } from "@homarr/common"; import { useI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; import classes from "./component.module.css"; export default function IFrameWidget({ options, isEditMode }: WidgetComponentProps<"iframe">) { const t = useI18n(); const { embedUrl, allowScrolling, ...permissions } = options; const allowedPermissions = getAllowedPermissions(permissions); const sandboxFlags = getSandboxFlags(permissions); if (embedUrl.trim() === "") return ; if (!isSupportedProtocol(embedUrl)) { return ; } return ( ); } const supportedProtocols = ["http", "https"]; const isSupportedProtocol = (url: string) => { try { const parsedUrl = new URL(url); return supportedProtocols.map((protocol) => `${protocol}:`).includes(`${parsedUrl.protocol}`); } catch { return false; } }; const NoUrl = () => { const t = useI18n(); return ( {t("widget.iframe.error.noUrl")} ); }; const UnsupportedProtocol = () => { const t = useI18n(); return ( {t("widget.iframe.error.unsupportedProtocol", { supportedProtocols: supportedProtocols.map((protocol) => protocol).join(", "), })} ); }; const getAllowedPermissions = ( permissions: Omit["options"], "embedUrl" | "allowScrolling">, ) => { return ( objectEntries(permissions) .filter(([_key, value]) => value) // * means it applies to all origins .map(([key]) => `${permissionMapping[key]} *`) .join("; ") ); }; const getSandboxFlags = ( permissions: Omit["options"], "embedUrl" | "allowScrolling">, ) => { const baseSandbox = [ "allow-scripts", "allow-same-origin", "allow-forms", "allow-popups", "allow-top-navigation-by-user-activation", ]; if (permissions.allowFullScreen) { baseSandbox.push("allow-presentation"); } if (permissions.allowPayment) { baseSandbox.push("allow-popups-to-escape-sandbox"); } if (permissions.allowModals) { baseSandbox.push("allow-modals"); } return baseSandbox; }; const permissionMapping = { allowAutoPlay: "autoplay", allowCamera: "camera", allowFullScreen: "fullscreen", allowGeolocation: "geolocation", allowMicrophone: "microphone", allowPayment: "payment", allowModals: "allow-modals", } satisfies Record["options"], "embedUrl" | "allowScrolling">, string>;