File: Show warning before downloading HTML (#6145)

This commit is contained in:
zubiden 2025-08-29 08:57:50 +02:00 committed by Alexander Zinchuk
parent 17dd4d47b0
commit 452929ad35
12 changed files with 89 additions and 63 deletions

View File

@ -6,7 +6,6 @@ import { getActions } from '../../global';
import type { ApiDocument, ApiMessage } from '../../api/types'; import type { ApiDocument, ApiMessage } from '../../api/types';
import type { ObserveFn } from '../../hooks/useIntersectionObserver'; import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import { SVG_EXTENSIONS } from '../../config';
import { import {
getDocumentMediaHash, getDocumentMediaHash,
getMediaFormat, getMediaFormat,
@ -14,6 +13,7 @@ import {
getMediaTransferState, getMediaTransferState,
isDocumentVideo, isDocumentVideo,
} from '../../global/helpers'; } from '../../global/helpers';
import { isIpRevealingMedia } from '../../util/media/ipRevealingMedia';
import { getDocumentExtension, getDocumentHasPreview } from './helpers/documentInfo'; import { getDocumentExtension, getDocumentHasPreview } from './helpers/documentInfo';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
@ -41,7 +41,7 @@ type OwnProps = {
sender?: string; sender?: string;
autoLoadFileMaxSizeMb?: number; autoLoadFileMaxSizeMb?: number;
isDownloading?: boolean; isDownloading?: boolean;
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
onCancelUpload?: () => void; onCancelUpload?: () => void;
onMediaClick?: () => void; onMediaClick?: () => void;
} & ({ } & ({
@ -67,7 +67,7 @@ const Document = ({
sender, sender,
isSelected, isSelected,
isSelectable, isSelectable,
shouldWarnAboutSvg, shouldWarnAboutFiles,
isDownloading, isDownloading,
message, message,
onCancelUpload, onCancelUpload,
@ -79,10 +79,10 @@ const Document = ({
const ref = useRef<HTMLDivElement>(); const ref = useRef<HTMLDivElement>();
const lang = useOldLang(); const lang = useOldLang();
const [isSvgDialogOpen, openSvgDialog, closeSvgDialog] = useFlag(); const [isFileIpDialogOpen, openFileIpDialog, closeFileIpDialog] = useFlag();
const [shouldNotWarnAboutSvg, setShouldNotWarnAboutSvg] = useState(false); const [shouldNotWarnAboutFiles, setShouldNotWarnAboutFiles] = useState(false);
const { fileName, size, timestamp } = document; const { fileName, size, timestamp, mimeType } = document;
const extension = getDocumentExtension(document) || ''; const extension = getDocumentExtension(document) || '';
const isIntersecting = useIsIntersecting(ref, observeIntersection); const isIntersecting = useIsIntersecting(ref, observeIntersection);
@ -150,17 +150,17 @@ const Document = ({
return; return;
} }
if (SVG_EXTENSIONS.has(extension) && shouldWarnAboutSvg) { if (isIpRevealingMedia({ mimeType, extension }) && shouldWarnAboutFiles) {
openSvgDialog(); openFileIpDialog();
return; return;
} }
handleDownload(); handleDownload();
}); });
const handleSvgConfirm = useLastCallback(() => { const handleFileIpConfirm = useLastCallback(() => {
setSharedSettingOption({ shouldWarnAboutSvg: !shouldNotWarnAboutSvg }); setSharedSettingOption({ shouldWarnAboutFiles: !shouldNotWarnAboutFiles });
closeSvgDialog(); closeFileIpDialog();
handleDownload(); handleDownload();
}); });
@ -191,16 +191,16 @@ const Document = ({
onDateClick={onDateClick ? handleDateClick : undefined} onDateClick={onDateClick ? handleDateClick : undefined}
/> />
<ConfirmDialog <ConfirmDialog
isOpen={isSvgDialogOpen} isOpen={isFileIpDialogOpen}
onClose={closeSvgDialog} onClose={closeFileIpDialog}
confirmHandler={handleSvgConfirm} confirmHandler={handleFileIpConfirm}
> >
{lang('lng_launch_svg_warning')} {lang('lng_launch_svg_warning')}
<Checkbox <Checkbox
className="dialog-checkbox" className="dialog-checkbox"
checked={shouldNotWarnAboutSvg} checked={shouldNotWarnAboutFiles}
label={lang('lng_launch_exe_dont_ask')} label={lang('lng_launch_exe_dont_ask')}
onCheck={setShouldNotWarnAboutSvg} onCheck={setShouldNotWarnAboutFiles}
/> />
</ConfirmDialog> </ConfirmDialog>
</> </>

View File

@ -44,7 +44,7 @@ const FileResults: FC<OwnProps & StateProps> = ({
globalMessagesByChatId, globalMessagesByChatId,
foundIds, foundIds,
activeDownloads, activeDownloads,
shouldWarnAboutSvg, shouldWarnAboutFiles,
}) => { }) => {
const { const {
searchMessagesGlobal, searchMessagesGlobal,
@ -117,7 +117,7 @@ const FileResults: FC<OwnProps & StateProps> = ({
sender={getSenderName(lang, message, chatsById, usersById)} sender={getSenderName(lang, message, chatsById, usersById)}
className="scroll-item" className="scroll-item"
isDownloading={getIsDownloading(activeDownloads, message.content.document!)} isDownloading={getIsDownloading(activeDownloads, message.content.document!)}
shouldWarnAboutSvg={shouldWarnAboutSvg} shouldWarnAboutFiles={shouldWarnAboutFiles}
observeIntersection={observeIntersectionForMedia} observeIntersection={observeIntersectionForMedia}
onDateClick={handleMessageFocus} onDateClick={handleMessageFocus}
/> />

View File

@ -18,7 +18,7 @@ export type StateProps = {
searchChatId?: string; searchChatId?: string;
activeDownloads: TabState['activeDownloads']; activeDownloads: TabState['activeDownloads'];
isChatProtected?: boolean; isChatProtected?: boolean;
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
}; };
export function createMapStateToProps(type: ApiGlobalMessageSearchType) { export function createMapStateToProps(type: ApiGlobalMessageSearchType) {
@ -30,7 +30,7 @@ export function createMapStateToProps(type: ApiGlobalMessageSearchType) {
fetchingStatus, resultsByType, chatId, fetchingStatus, resultsByType, chatId,
} = tabState.globalSearch; } = tabState.globalSearch;
const { shouldWarnAboutSvg } = selectSharedSettings(global); const { shouldWarnAboutFiles } = selectSharedSettings(global);
// One component is used for two different types of results. // One component is used for two different types of results.
// The differences between them are only in the isVoice property. // The differences between them are only in the isVoice property.
@ -53,7 +53,7 @@ export function createMapStateToProps(type: ApiGlobalMessageSearchType) {
searchChatId: chatId, searchChatId: chatId,
activeDownloads, activeDownloads,
isChatProtected: chatId ? selectChat(global, chatId)?.isProtected : undefined, isChatProtected: chatId ? selectChat(global, chatId)?.isProtected : undefined,
shouldWarnAboutSvg, shouldWarnAboutFiles,
}; };
}; };
} }

View File

@ -11,8 +11,8 @@ import {
selectCanDownloadSelectedMessages, selectCanDownloadSelectedMessages,
selectCanForwardMessages, selectCanForwardMessages,
selectCanReportSelectedMessages, selectCurrentChat, selectCanReportSelectedMessages, selectCurrentChat,
selectCurrentMessageList, selectHasProtectedMessage, selectCurrentMessageList, selectHasIpRevealingMedia,
selectHasSvg, selectHasProtectedMessage,
selectSelectedMessagesCount, selectSelectedMessagesCount,
selectTabState, selectTabState,
} from '../../global/selectors'; } from '../../global/selectors';
@ -50,8 +50,8 @@ type StateProps = {
hasProtectedMessage?: boolean; hasProtectedMessage?: boolean;
isAnyModalOpen?: boolean; isAnyModalOpen?: boolean;
selectedMessageIds?: number[]; selectedMessageIds?: number[];
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
hasSvgs?: boolean; hasIpRevealingMedia?: boolean;
}; };
const MessageSelectToolbar: FC<OwnProps & StateProps> = ({ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
@ -68,8 +68,8 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
hasProtectedMessage, hasProtectedMessage,
isAnyModalOpen, isAnyModalOpen,
selectedMessageIds, selectedMessageIds,
shouldWarnAboutSvg, shouldWarnAboutFiles,
hasSvgs, hasIpRevealingMedia,
}) => { }) => {
const { const {
exitMessageSelectMode, exitMessageSelectMode,
@ -85,8 +85,8 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
useCopySelectedMessages(isActive); useCopySelectedMessages(isActive);
const [isSvgDialogOpen, openSvgDialog, closeSvgDialog] = useFlag(); const [isFileIpDialogOpen, openFileIpDialog, closeFileIpDialog] = useFlag();
const [shouldNotWarnAboutSvg, setShouldNotWarnAboutSvg] = useState(false); const [shouldNotWarnAboutFiles, setShouldNotWarnAboutFiles] = useState(false);
const handleExitMessageSelectMode = useLastCallback(() => { const handleExitMessageSelectMode = useLastCallback(() => {
exitMessageSelectMode(); exitMessageSelectMode();
@ -128,17 +128,17 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
}); });
const handleMessageDownload = useLastCallback(() => { const handleMessageDownload = useLastCallback(() => {
if (shouldWarnAboutSvg && hasSvgs) { if (shouldWarnAboutFiles && hasIpRevealingMedia) {
openSvgDialog(); openFileIpDialog();
return; return;
} }
handleDownload(); handleDownload();
}); });
const handleSvgConfirm = useLastCallback(() => { const handleFileIpConfirm = useLastCallback(() => {
setSharedSettingOption({ shouldWarnAboutSvg: !shouldNotWarnAboutSvg }); setSharedSettingOption({ shouldWarnAboutFiles: !shouldNotWarnAboutFiles });
closeSvgDialog(); closeFileIpDialog();
handleDownload(); handleDownload();
}); });
@ -223,16 +223,16 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
</div> </div>
</div> </div>
<ConfirmDialog <ConfirmDialog
isOpen={isSvgDialogOpen} isOpen={isFileIpDialogOpen}
onClose={closeSvgDialog} onClose={closeFileIpDialog}
confirmHandler={handleSvgConfirm} confirmHandler={handleFileIpConfirm}
> >
{lang('lng_launch_svg_warning')} {lang('lng_launch_svg_warning')}
<Checkbox <Checkbox
className="dialog-checkbox" className="dialog-checkbox"
checked={shouldNotWarnAboutSvg} checked={shouldNotWarnAboutFiles}
label={lang('lng_launch_exe_dont_ask')} label={lang('lng_launch_exe_dont_ask')}
onCheck={setShouldNotWarnAboutSvg} onCheck={setShouldNotWarnAboutFiles}
/> />
</ConfirmDialog> </ConfirmDialog>
</> </>
@ -242,7 +242,7 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global): StateProps => { (global): StateProps => {
const tabState = selectTabState(global); const tabState = selectTabState(global);
const { shouldWarnAboutSvg } = selectSharedSettings(global); const { shouldWarnAboutFiles } = selectSharedSettings(global);
const chat = selectCurrentChat(global); const chat = selectCurrentChat(global);
const { type: messageListType, chatId } = selectCurrentMessageList(global) || {}; const { type: messageListType, chatId } = selectCurrentMessageList(global) || {};
@ -253,7 +253,8 @@ export default memo(withGlobal<OwnProps>(
const { messageIds: selectedMessageIds } = tabState.selectedMessages || {}; const { messageIds: selectedMessageIds } = tabState.selectedMessages || {};
const hasProtectedMessage = chatId ? selectHasProtectedMessage(global, chatId, selectedMessageIds) : false; const hasProtectedMessage = chatId ? selectHasProtectedMessage(global, chatId, selectedMessageIds) : false;
const canForward = !isSchedule && chatId ? selectCanForwardMessages(global, chatId, selectedMessageIds) : false; const canForward = !isSchedule && chatId ? selectCanForwardMessages(global, chatId, selectedMessageIds) : false;
const hasSvgs = selectedMessageIds && chatId ? selectHasSvg(global, chatId, selectedMessageIds) : false; const hasIpRevealingMedia = selectedMessageIds && chatId
? selectHasIpRevealingMedia(global, chatId, selectedMessageIds) : false;
const isShareMessageModalOpen = tabState.isShareMessageModalShown; const isShareMessageModalOpen = tabState.isShareMessageModalShown;
const isAnyModalOpen = Boolean(isShareMessageModalOpen || tabState.requestedDraft const isAnyModalOpen = Boolean(isShareMessageModalOpen || tabState.requestedDraft
|| tabState.requestedAttachBotInChat || tabState.requestedAttachBotInstall || tabState.reportModal || tabState.requestedAttachBotInChat || tabState.requestedAttachBotInstall || tabState.reportModal
@ -270,8 +271,8 @@ export default memo(withGlobal<OwnProps>(
selectedMessageIds, selectedMessageIds,
hasProtectedMessage, hasProtectedMessage,
isAnyModalOpen, isAnyModalOpen,
shouldWarnAboutSvg, shouldWarnAboutFiles,
hasSvgs, hasIpRevealingMedia,
}; };
}, },
)(MessageSelectToolbar)); )(MessageSelectToolbar));

View File

@ -310,7 +310,7 @@ type StateProps = {
webPageStory?: ApiTypeStory; webPageStory?: ApiTypeStory;
isConnected: boolean; isConnected: boolean;
isLoadingComments?: boolean; isLoadingComments?: boolean;
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
senderBoosts?: number; senderBoosts?: number;
tags?: Record<ApiReactionKey, ApiSavedReactionTag>; tags?: Record<ApiReactionKey, ApiSavedReactionTag>;
canTranscribeVoice?: boolean; canTranscribeVoice?: boolean;
@ -438,7 +438,7 @@ const Message: FC<OwnProps & StateProps> = ({
webPageStory, webPageStory,
isConnected, isConnected,
getIsMessageListReady, getIsMessageListReady,
shouldWarnAboutSvg, shouldWarnAboutFiles,
senderBoosts, senderBoosts,
tags, tags,
canTranscribeVoice, canTranscribeVoice,
@ -1261,7 +1261,7 @@ const Message: FC<OwnProps & StateProps> = ({
onMediaClick={handleDocumentClick} onMediaClick={handleDocumentClick}
onCancelUpload={handleCancelUpload} onCancelUpload={handleCancelUpload}
isDownloading={isDownloading} isDownloading={isDownloading}
shouldWarnAboutSvg={shouldWarnAboutSvg} shouldWarnAboutFiles={shouldWarnAboutFiles}
/> />
)} )}
{storyData && !isStoryMention && ( {storyData && !isStoryMention && (
@ -1430,7 +1430,7 @@ const Message: FC<OwnProps & StateProps> = ({
isConnected={isConnected} isConnected={isConnected}
lastPlaybackTimestamp={lastPlaybackTimestamp} lastPlaybackTimestamp={lastPlaybackTimestamp}
backgroundEmojiId={messageColorPeer?.color?.backgroundEmojiId} backgroundEmojiId={messageColorPeer?.color?.backgroundEmojiId}
shouldWarnAboutSvg={shouldWarnAboutSvg} shouldWarnAboutFiles={shouldWarnAboutFiles}
autoLoadFileMaxSizeMb={autoLoadFileMaxSizeMb} autoLoadFileMaxSizeMb={autoLoadFileMaxSizeMb}
onAudioPlay={handleAudioPlay} onAudioPlay={handleAudioPlay}
onMediaClick={handleMediaClick} onMediaClick={handleMediaClick}
@ -1884,7 +1884,7 @@ export default memo(withGlobal<OwnProps>(
const webPage = selectFullWebPageFromMessage(global, message); const webPage = selectFullWebPageFromMessage(global, message);
const { shouldWarnAboutSvg } = selectSharedSettings(global); const { shouldWarnAboutFiles } = selectSharedSettings(global);
const isChatWithUser = isUserId(chatId); const isChatWithUser = isUserId(chatId);
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
@ -2085,7 +2085,7 @@ export default memo(withGlobal<OwnProps>(
isLoadingComments: repliesThreadInfo?.isCommentsInfo isLoadingComments: repliesThreadInfo?.isCommentsInfo
&& loadingThread?.loadingChatId === repliesThreadInfo?.originChannelId && loadingThread?.loadingChatId === repliesThreadInfo?.originChannelId
&& loadingThread?.loadingMessageId === repliesThreadInfo?.originMessageId, && loadingThread?.loadingMessageId === repliesThreadInfo?.originMessageId,
shouldWarnAboutSvg, shouldWarnAboutFiles,
...(isOutgoing && { outgoingStatus: selectOutgoingStatus(global, message, messageListType === 'scheduled') }), ...(isOutgoing && { outgoingStatus: selectOutgoingStatus(global, message, messageListType === 'scheduled') }),
...(typeof uploadProgress === 'number' && { uploadProgress }), ...(typeof uploadProgress === 'number' && { uploadProgress }),
...(isFocused && { ...(isFocused && {

View File

@ -55,7 +55,7 @@ type OwnProps = {
backgroundEmojiId?: string; backgroundEmojiId?: string;
theme: ThemeKey; theme: ThemeKey;
story?: ApiTypeStory; story?: ApiTypeStory;
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
autoLoadFileMaxSizeMb?: number; autoLoadFileMaxSizeMb?: number;
lastPlaybackTimestamp?: number; lastPlaybackTimestamp?: number;
observeIntersectionForLoading?: ObserveFn; observeIntersectionForLoading?: ObserveFn;
@ -84,7 +84,7 @@ const WebPage: FC<OwnProps & StateProps> = ({
story, story,
theme, theme,
backgroundEmojiId, backgroundEmojiId,
shouldWarnAboutSvg, shouldWarnAboutFiles,
autoLoadFileMaxSizeMb, autoLoadFileMaxSizeMb,
lastPlaybackTimestamp, lastPlaybackTimestamp,
observeIntersectionForLoading, observeIntersectionForLoading,
@ -286,7 +286,7 @@ const WebPage: FC<OwnProps & StateProps> = ({
onMediaClick={onDocumentClick} onMediaClick={onDocumentClick}
onCancelUpload={onCancelMediaTransfer} onCancelUpload={onCancelMediaTransfer}
isDownloading={isDownloading} isDownloading={isDownloading}
shouldWarnAboutSvg={shouldWarnAboutSvg} shouldWarnAboutFiles={shouldWarnAboutFiles}
/> />
)} )}
{stickers && ( {stickers && (

View File

@ -146,7 +146,7 @@ type StateProps = {
isChatProtected?: boolean; isChatProtected?: boolean;
nextProfileTab?: ProfileTabType; nextProfileTab?: ProfileTabType;
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
similarChannels?: string[]; similarChannels?: string[];
similarBots?: string[]; similarBots?: string[];
botPreviewMedia?: ApiBotPreviewMedia[]; botPreviewMedia?: ApiBotPreviewMedia[];
@ -212,7 +212,7 @@ const Profile: FC<OwnProps & StateProps> = ({
isChatProtected, isChatProtected,
nextProfileTab, nextProfileTab,
animationLevel, animationLevel,
shouldWarnAboutSvg, shouldWarnAboutFiles,
similarChannels, similarChannels,
similarBots, similarBots,
isCurrentUserPremium, isCurrentUserPremium,
@ -693,7 +693,7 @@ const Profile: FC<OwnProps & StateProps> = ({
observeIntersection={observeIntersectionForMedia} observeIntersection={observeIntersectionForMedia}
onDateClick={handleMessageFocus} onDateClick={handleMessageFocus}
message={messagesById[id]} message={messagesById[id]}
shouldWarnAboutSvg={shouldWarnAboutSvg} shouldWarnAboutFiles={shouldWarnAboutFiles}
/> />
)) ))
) : resultType === 'links' ? ( ) : resultType === 'links' ? (
@ -955,7 +955,7 @@ export default memo(withGlobal<OwnProps>(
const userFullInfo = selectUserFullInfo(global, chatId); const userFullInfo = selectUserFullInfo(global, chatId);
const messagesById = selectChatMessages(global, chatId); const messagesById = selectChatMessages(global, chatId);
const { animationLevel, shouldWarnAboutSvg } = selectSharedSettings(global); const { animationLevel, shouldWarnAboutFiles } = selectSharedSettings(global);
const { currentType: mediaSearchType, resultsByType } = selectCurrentSharedMediaSearch(global) || {}; const { currentType: mediaSearchType, resultsByType } = selectCurrentSharedMediaSearch(global) || {};
const { foundIds } = (resultsByType && mediaSearchType && resultsByType[mediaSearchType]) || {}; const { foundIds } = (resultsByType && mediaSearchType && resultsByType[mediaSearchType]) || {};
@ -1040,7 +1040,7 @@ export default memo(withGlobal<OwnProps>(
nextProfileTab: selectTabState(global).nextProfileTab, nextProfileTab: selectTabState(global).nextProfileTab,
forceScrollProfileTab: selectTabState(global).forceScrollProfileTab, forceScrollProfileTab: selectTabState(global).forceScrollProfileTab,
animationLevel, animationLevel,
shouldWarnAboutSvg, shouldWarnAboutFiles,
similarChannels: similarChannelIds, similarChannels: similarChannelIds,
similarBots: similarBotsIds, similarBots: similarBotsIds,
botPreviewMedia, botPreviewMedia,

View File

@ -330,7 +330,7 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
shouldAllowHttpTransport: untypedCached.settings.byKey.shouldAllowHttpTransport, shouldAllowHttpTransport: untypedCached.settings.byKey.shouldAllowHttpTransport,
shouldCollectDebugLogs: untypedCached.settings.byKey.shouldCollectDebugLogs, shouldCollectDebugLogs: untypedCached.settings.byKey.shouldCollectDebugLogs,
shouldDebugExportedSenders: untypedCached.settings.byKey.shouldDebugExportedSenders, shouldDebugExportedSenders: untypedCached.settings.byKey.shouldDebugExportedSenders,
shouldWarnAboutSvg: untypedCached.settings.byKey.shouldWarnAboutSvg, shouldWarnAboutFiles: untypedCached.settings.byKey.shouldWarnAboutFiles,
}; };
} }
@ -351,6 +351,11 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
if (!cached.appConfig) { if (!cached.appConfig) {
cached.appConfig = initialState.appConfig; cached.appConfig = initialState.appConfig;
} }
if (untypedCached.sharedState?.settings?.shouldWarnAboutSvg) {
cached.sharedState.settings.shouldWarnAboutFiles = true;
untypedCached.sharedState.settings.shouldWarnAboutSvg = undefined;
}
} }
function updateCache(force?: boolean) { function updateCache(force?: boolean) {

View File

@ -88,7 +88,7 @@ export const INITIAL_SHARED_STATE: SharedState = {
isConnectionStatusMinimized: true, isConnectionStatusMinimized: true,
canDisplayChatInTitle: true, canDisplayChatInTitle: true,
shouldAllowHttpTransport: true, shouldAllowHttpTransport: true,
shouldWarnAboutSvg: true, shouldWarnAboutFiles: true,
}, },
isInitial: true, isInitial: true,
}; };

View File

@ -24,13 +24,14 @@ import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
import { import {
ANONYMOUS_USER_ID, GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID, ANONYMOUS_USER_ID, GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID,
SVG_EXTENSIONS, WEB_APP_PLATFORM, WEB_APP_PLATFORM,
} from '../../config'; } from '../../config';
import { IS_TRANSLATION_SUPPORTED } from '../../util/browser/windowEnvironment'; import { IS_TRANSLATION_SUPPORTED } from '../../util/browser/windowEnvironment';
import { isUserId } from '../../util/entities/ids'; import { isUserId } from '../../util/entities/ids';
import { getCurrentTabId } from '../../util/establishMultitabRole'; import { getCurrentTabId } from '../../util/establishMultitabRole';
import { findLast } from '../../util/iteratees'; import { findLast } from '../../util/iteratees';
import { getMessageKey, isLocalMessageId } from '../../util/keys/messageKey'; import { getMessageKey, isLocalMessageId } from '../../util/keys/messageKey';
import { isIpRevealingMedia } from '../../util/media/ipRevealingMedia';
import { MEMO_EMPTY_ARRAY } from '../../util/memo'; import { MEMO_EMPTY_ARRAY } from '../../util/memo';
import { getServerTime } from '../../util/serverTime'; import { getServerTime } from '../../util/serverTime';
import { getDocumentExtension } from '../../components/common/helpers/documentInfo'; import { getDocumentExtension } from '../../components/common/helpers/documentInfo';
@ -1305,7 +1306,7 @@ export function selectCanForwardMessages<T extends GlobalState>(global: T, chatI
&& (message.isForwardingAllowed || isServiceNotificationMessage(message))); && (message.isForwardingAllowed || isServiceNotificationMessage(message)));
} }
export function selectHasSvg<T extends GlobalState>(global: T, chatId: string, messageIds: number[]) { export function selectHasIpRevealingMedia<T extends GlobalState>(global: T, chatId: string, messageIds: number[]) {
const messages = selectChatMessages(global, chatId); const messages = selectChatMessages(global, chatId);
return messageIds return messageIds
@ -1319,7 +1320,7 @@ export function selectHasSvg<T extends GlobalState>(global: T, chatId: string, m
const extension = getDocumentExtension(document); const extension = getDocumentExtension(document);
if (!extension) return false; if (!extension) return false;
return SVG_EXTENSIONS.has(extension); return isIpRevealingMedia({ mimeType: document.mimeType, extension });
}); });
} }

View File

@ -27,6 +27,6 @@ export interface SharedSettings {
shouldAllowHttpTransport?: boolean; shouldAllowHttpTransport?: boolean;
shouldCollectDebugLogs?: boolean; shouldCollectDebugLogs?: boolean;
shouldDebugExportedSenders?: boolean; shouldDebugExportedSenders?: boolean;
shouldWarnAboutSvg?: boolean; shouldWarnAboutFiles?: boolean;
shouldSkipWebAppCloseConfirmation: boolean; shouldSkipWebAppCloseConfirmation: boolean;
} }

View File

@ -0,0 +1,19 @@
import { SVG_EXTENSIONS } from '../../config';
const UNSAFE_MIME_TYPES = new Set(['text/html', 'image/svg+xml']);
const UNSAFE_EXTENSIONS = new Set([
...SVG_EXTENSIONS,
'htm', 'html', 'svg', 'm4v', 'm3u', 'm3u8', 'xhtml', 'xml',
]);
export function isIpRevealingMedia({ mimeType, extension }: { mimeType?: string; extension: string }) {
if (mimeType && UNSAFE_MIME_TYPES.has(mimeType)) {
return true;
}
if (UNSAFE_EXTENSIONS.has(extension)) {
return true;
}
return false;
}