General: Better validation for iframe event origins (#6856)
This commit is contained in:
parent
889d07823d
commit
7e789e6e77
@ -1,12 +1,13 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import type React from '../../lib/teact/teact';
|
import type React from '../../lib/teact/teact';
|
||||||
import { memo, useCallback, useEffect } from '../../lib/teact/teact';
|
import { memo, useCallback, useEffect, useRef } from '../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../global';
|
import { getActions, withGlobal } from '../../global';
|
||||||
|
|
||||||
import type { TabState } from '../../global/types';
|
import type { TabState } from '../../global/types';
|
||||||
|
|
||||||
import { getCanPostInChat } from '../../global/helpers';
|
import { getCanPostInChat } from '../../global/helpers';
|
||||||
import { selectChat, selectChatFullInfo } from '../../global/selectors';
|
import { selectChat, selectChatFullInfo } from '../../global/selectors';
|
||||||
|
import { isMessageFromIframe } from '../../util/browser/iframe';
|
||||||
|
|
||||||
import useInterval from '../../hooks/schedulers/useInterval';
|
import useInterval from '../../hooks/schedulers/useInterval';
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
@ -34,6 +35,7 @@ const GameModal: FC<OwnProps & StateProps> = ({ openedGame, gameTitle, canPost }
|
|||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
const { url, chatId, messageId } = openedGame || {};
|
const { url, chatId, messageId } = openedGame || {};
|
||||||
const isOpen = Boolean(url);
|
const isOpen = Boolean(url);
|
||||||
|
const frameRef = useRef<HTMLIFrameElement>();
|
||||||
|
|
||||||
const sendMessageAction = useSendMessageAction(chatId);
|
const sendMessageAction = useSendMessageAction(chatId);
|
||||||
useInterval(() => {
|
useInterval(() => {
|
||||||
@ -41,7 +43,10 @@ const GameModal: FC<OwnProps & StateProps> = ({ openedGame, gameTitle, canPost }
|
|||||||
}, isOpen && canPost ? PLAY_GAME_ACTION_INTERVAL : undefined);
|
}, isOpen && canPost ? PLAY_GAME_ACTION_INTERVAL : undefined);
|
||||||
|
|
||||||
const handleMessage = useCallback((event: MessageEvent<string>) => {
|
const handleMessage = useCallback((event: MessageEvent<string>) => {
|
||||||
if (!chatId || !messageId) return;
|
if (!chatId || !messageId || !isMessageFromIframe(event, frameRef.current)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data) as GameEvents;
|
const data = JSON.parse(event.data) as GameEvents;
|
||||||
if (data.eventType === 'share_score') {
|
if (data.eventType === 'share_score') {
|
||||||
@ -77,6 +82,7 @@ const GameModal: FC<OwnProps & StateProps> = ({ openedGame, gameTitle, canPost }
|
|||||||
>
|
>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<iframe
|
<iframe
|
||||||
|
ref={frameRef}
|
||||||
className="game-frame"
|
className="game-frame"
|
||||||
onLoad={handleLoad}
|
onLoad={handleLoad}
|
||||||
src={url}
|
src={url}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type { WebApp, WebAppInboundEvent, WebAppOutboundEvent } from '../../../.
|
|||||||
|
|
||||||
import { VERIFY_AGE_MIN_DEFAULT } from '../../../../config';
|
import { VERIFY_AGE_MIN_DEFAULT } from '../../../../config';
|
||||||
import { getWebAppKey } from '../../../../global/helpers';
|
import { getWebAppKey } from '../../../../global/helpers';
|
||||||
|
import { isMessageFromIframe } from '../../../../util/browser/iframe';
|
||||||
import { extractCurrentThemeParams } from '../../../../util/themeStyle';
|
import { extractCurrentThemeParams } from '../../../../util/themeStyle';
|
||||||
import { REM } from '../../../common/helpers/mediaDimensions';
|
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
@ -172,10 +173,8 @@ const useWebAppFrame = (
|
|||||||
if (ignoreEventsRef.current) {
|
if (ignoreEventsRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const contentWindow = ref.current?.contentWindow;
|
|
||||||
const sourceWindow = event.source as Window;
|
|
||||||
|
|
||||||
if (contentWindow !== sourceWindow) {
|
if (!isMessageFromIframe(event, ref.current)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import { memo, useCallback, useEffect, useRef } from '../../lib/teact/teact';
|
||||||
import { memo, useCallback, useEffect } from '../../lib/teact/teact';
|
|
||||||
import { getActions } from '../../global';
|
import { getActions } from '../../global';
|
||||||
|
|
||||||
import { TME_LINK_PREFIX } from '../../config';
|
import { TME_LINK_PREFIX } from '../../config';
|
||||||
|
import { isMessageFromIframe } from '../../util/browser/iframe';
|
||||||
|
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
|
|
||||||
@ -35,14 +35,19 @@ interface WebAppOpenTgLinkEvent {
|
|||||||
|
|
||||||
type IframeCallbackEvent = PaymentFormSubmitEvent | WebAppOpenTgLinkEvent;
|
type IframeCallbackEvent = PaymentFormSubmitEvent | WebAppOpenTgLinkEvent;
|
||||||
|
|
||||||
const ConfirmPayment: FC<OwnProps> = ({
|
const ConfirmPayment = ({
|
||||||
url, noRedirect, onClose, onPaymentFormSubmit,
|
url, noRedirect, onClose, onPaymentFormSubmit,
|
||||||
}) => {
|
}: OwnProps) => {
|
||||||
const { openTelegramLink } = getActions();
|
const { openTelegramLink } = getActions();
|
||||||
|
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
|
const frameRef = useRef<HTMLIFrameElement>();
|
||||||
|
|
||||||
const handleMessage = useCallback((event: MessageEvent<string>) => {
|
const handleMessage = useCallback((event: MessageEvent<string>) => {
|
||||||
|
if (!isMessageFromIframe(event, frameRef.current)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data) as IframeCallbackEvent;
|
const data = JSON.parse(event.data) as IframeCallbackEvent;
|
||||||
const { eventType, eventData } = data;
|
const { eventType, eventData } = data;
|
||||||
@ -76,6 +81,7 @@ const ConfirmPayment: FC<OwnProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="ConfirmPayment">
|
<div className="ConfirmPayment">
|
||||||
<iframe
|
<iframe
|
||||||
|
ref={frameRef}
|
||||||
src={url}
|
src={url}
|
||||||
title={lang('Checkout.WebConfirmation.Title')}
|
title={lang('Checkout.WebConfirmation.Title')}
|
||||||
allow="payment"
|
allow="payment"
|
||||||
|
|||||||
3
src/util/browser/iframe.ts
Normal file
3
src/util/browser/iframe.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function isMessageFromIframe(event: MessageEvent, iframe?: HTMLIFrameElement) {
|
||||||
|
return Boolean(iframe?.contentWindow && event.source === iframe.contentWindow);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user