* Fix 60879
* Address feedback
* Address feedback
* Add tests
(cherry picked from commit 7f21754b78)
Co-authored-by: Daniel Espino García <larkox@gmail.com>
This commit is contained in:
parent
298666755c
commit
6d7370972d
11 changed files with 57 additions and 17 deletions
|
|
@ -51,7 +51,7 @@ const Document = forwardRef<DocumentRef, DocumentProps>(({canDownloadFiles, chil
|
|||
let exists = false;
|
||||
|
||||
try {
|
||||
path = decodeURIComponent(file.localPath || '');
|
||||
path = file.localPath || '';
|
||||
if (path) {
|
||||
exists = await fileExists(path);
|
||||
}
|
||||
|
|
@ -103,7 +103,7 @@ const Document = forwardRef<DocumentRef, DocumentProps>(({canDownloadFiles, chil
|
|||
|
||||
const openDocument = useCallback(async () => {
|
||||
if (!didCancel && !preview) {
|
||||
let path = decodeURIComponent(file.localPath || '');
|
||||
let path = file.localPath || '';
|
||||
let exists = false;
|
||||
if (path) {
|
||||
exists = await fileExists(path);
|
||||
|
|
@ -116,7 +116,7 @@ const Document = forwardRef<DocumentRef, DocumentProps>(({canDownloadFiles, chil
|
|||
setPreview(true);
|
||||
setStatusBarColor('dark-content');
|
||||
FileViewer.open(path!.replace('file://', ''), {
|
||||
displayName: decodeURIComponent(file.name),
|
||||
displayName: file.name,
|
||||
onDismiss: onDonePreviewingFile,
|
||||
showOpenWithDialog: true,
|
||||
showAppsSuggestions: true,
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ const FileInfo = ({disabled, file, channelName, showDate, onPress}: FileInfoProp
|
|||
ellipsizeMode='tail'
|
||||
style={style.fileName}
|
||||
>
|
||||
{decodeURIComponent(file.name.trim())}
|
||||
{file.name.trim()}
|
||||
</Text>
|
||||
<View style={style.fileDownloadContainer}>
|
||||
{channelName &&
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import {calculateDimensions, getViewPortWidth, isGifTooLarge} from '@utils/image
|
|||
import {getMarkdownImageSize} from '@utils/markdown';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {secureGetFromRecord} from '@utils/types';
|
||||
import {normalizeProtocol, tryOpenURL} from '@utils/url';
|
||||
import {normalizeProtocol, safeDecodeURIComponent, tryOpenURL} from '@utils/url';
|
||||
|
||||
import type {GalleryItemType} from '@typings/screens/gallery';
|
||||
|
||||
|
|
@ -89,8 +89,8 @@ const MarkdownImage = ({
|
|||
const uri = source.startsWith('/') ? serverUrl + source : source;
|
||||
|
||||
const fileInfo = useMemo(() => {
|
||||
const link = decodeURIComponent(uri);
|
||||
let filename = parseUrl(link.substr(link.lastIndexOf('/'))).pathname.replace('/', '');
|
||||
const decodedLink = safeDecodeURIComponent(uri);
|
||||
let filename = parseUrl(decodedLink.substr(decodedLink.lastIndexOf('/'))).pathname.replace('/', '');
|
||||
let extension = metadata?.format || filename.split('.').pop();
|
||||
if (extension === filename) {
|
||||
const ext = filename.indexOf('.') === -1 ? '.png' : filename.substring(filename.lastIndexOf('.'));
|
||||
|
|
@ -105,7 +105,7 @@ const MarkdownImage = ({
|
|||
has_preview_image: true,
|
||||
mime_type: lookupMimeType(filename),
|
||||
post_id: postId,
|
||||
uri: link,
|
||||
uri,
|
||||
width: originalSize.width,
|
||||
height: originalSize.height,
|
||||
} as FileInfo;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {fileToGalleryItem, openGalleryAtIndex} from '@utils/gallery';
|
|||
import {generateId} from '@utils/general';
|
||||
import {calculateDimensions, isGifTooLarge} from '@utils/images';
|
||||
import {secureGetFromRecord} from '@utils/types';
|
||||
import {safeDecodeURIComponent} from '@utils/url';
|
||||
|
||||
import type {GalleryItemType} from '@typings/screens/gallery';
|
||||
|
||||
|
|
@ -58,8 +59,9 @@ const MarkTableImage = ({disabled, imagesMetadata, location, postId, serverURL,
|
|||
const getFileInfo = () => {
|
||||
const height = metadata?.height || 0;
|
||||
const width = metadata?.width || 0;
|
||||
const link = decodeURIComponent(getImageSource());
|
||||
let filename = parseUrl(link.substr(link.lastIndexOf('/'))).pathname.replace('/', '');
|
||||
const uri = getImageSource();
|
||||
const decodedLink = safeDecodeURIComponent(uri);
|
||||
let filename = parseUrl(decodedLink.substring(decodedLink.lastIndexOf('/'))).pathname.replace('/', '');
|
||||
let extension = filename.split('.').pop();
|
||||
|
||||
if (extension === filename) {
|
||||
|
|
@ -74,7 +76,7 @@ const MarkTableImage = ({disabled, imagesMetadata, location, postId, serverURL,
|
|||
extension,
|
||||
has_preview_image: true,
|
||||
post_id: postId,
|
||||
uri: link,
|
||||
uri,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ const BookmarkFile = ({channelId, close, disabled, initialFile, maxFileSize, set
|
|||
ellipsizeMode='tail'
|
||||
style={styles.filename}
|
||||
>
|
||||
{decodeURIComponent(file.name.trim())}
|
||||
{file.name.trim()}
|
||||
</Text>
|
||||
{info}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -159,13 +159,13 @@ const ChannelBookmarkAddOrEdit = ({
|
|||
...(bookmark || emptyBookmark),
|
||||
owner_id: ownerId,
|
||||
channel_id: channelId,
|
||||
display_name: decodeURIComponent(f.name),
|
||||
display_name: f.name,
|
||||
type: 'file',
|
||||
file_id: f.id,
|
||||
};
|
||||
setBookmarkToSave(b);
|
||||
setFile(f);
|
||||
}, [bookmark, channelId, ownerId]);
|
||||
}, [bookmark, channelId, ownerId, setBookmarkToSave]);
|
||||
|
||||
const setBookmarkDisplayName = useCallback((displayName: string) => {
|
||||
if (bookmark) {
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction, gallery
|
|||
actionToExecute({
|
||||
code: 200,
|
||||
ok: true,
|
||||
data: {path},
|
||||
data: {path: path.replace('file://', '')},
|
||||
});
|
||||
} else {
|
||||
if (item.type === 'avatar') {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import Permissions from 'react-native-permissions';
|
|||
import {dismissBottomSheet} from '@screens/navigation';
|
||||
import {extractFileInfo, lookupMimeType} from '@utils/file';
|
||||
import {logWarning} from '@utils/log';
|
||||
import {safeDecodeURIComponent} from '@utils/url';
|
||||
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
|
|
@ -128,7 +129,7 @@ export default class FilePickerUtil {
|
|||
const type = file.type || lookupMimeType(uri);
|
||||
let fileName = file.fileName;
|
||||
if (type.includes('video/') && uri) {
|
||||
fileName = decodeURIComponent(uri.split('\\').pop()?.split('/').pop() || '');
|
||||
fileName = safeDecodeURIComponent(uri.split('\\').pop()?.split('/').pop() || '');
|
||||
}
|
||||
|
||||
if (uri) {
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ export async function extractFileInfo(files: Array<Asset | DocumentPickerRespons
|
|||
} else {
|
||||
const localPath = file.uri || '';
|
||||
try {
|
||||
const fileInfo = await getInfoAsync(decodeURIComponent(localPath), {size: true});
|
||||
const fileInfo = await getInfoAsync(localPath, {size: true});
|
||||
if ('size' in fileInfo) {
|
||||
outFile.size = fileInfo.size || 0;
|
||||
outFile.name = localPath.substring(localPath.lastIndexOf('/') + 1);
|
||||
|
|
|
|||
29
app/utils/url/index.test.ts
Normal file
29
app/utils/url/index.test.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import {safeDecodeURIComponent} from './index';
|
||||
|
||||
describe('safeDecodeURIComponent', () => {
|
||||
test('should decode a valid URI component', () => {
|
||||
const encoded = 'Hello%20World';
|
||||
const decoded = safeDecodeURIComponent(encoded);
|
||||
expect(decoded).toBe('Hello World');
|
||||
});
|
||||
|
||||
test('should return the input if it is not a valid URI component', () => {
|
||||
const invalidEncoded = '%E0%A4%A';
|
||||
const result = safeDecodeURIComponent(invalidEncoded);
|
||||
expect(result).toBe(invalidEncoded);
|
||||
});
|
||||
|
||||
test('should decode a complex URI component', () => {
|
||||
const encoded = 'Hello%20World%21%20How%20are%20you%3F';
|
||||
const decoded = safeDecodeURIComponent(encoded);
|
||||
expect(decoded).toBe('Hello World! How are you?');
|
||||
});
|
||||
|
||||
test('should return empty string if input is empty', () => {
|
||||
const encoded = '';
|
||||
const decoded = safeDecodeURIComponent(encoded);
|
||||
expect(decoded).toBe('');
|
||||
});
|
||||
});
|
||||
|
|
@ -252,3 +252,11 @@ export function extractFilenameFromUrl(url: string) {
|
|||
const uri = urlParse(url);
|
||||
return uri.pathname.split('/').pop();
|
||||
}
|
||||
|
||||
export function safeDecodeURIComponent(v: string) {
|
||||
try {
|
||||
return decodeURIComponent(v);
|
||||
} catch {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue