feat: remove rn-fetch-blob (#5669)
* feat: remove rn-fetch-blob * fix types * jest
This commit is contained in:
parent
0ffa528e2a
commit
02b3afda3c
|
@ -32,8 +32,6 @@ import android.security.KeyChainAliasCallback;
|
|||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.RNFetchBlob.RNFetchBlob;
|
||||
|
||||
import com.reactnativecommunity.webview.RNCWebViewManager;
|
||||
|
||||
import com.dylanvann.fastimage.FastImageOkHttpUrlLoader;
|
||||
|
@ -104,8 +102,6 @@ public class SSLPinningModule extends ReactContextBaseJavaModule implements KeyC
|
|||
WebSocketModule.setCustomClientBuilder(new CustomClient());
|
||||
// Image networking react-native layer
|
||||
ReactOkHttpNetworkFetcher.setOkHttpClient(getOkHttpClient());
|
||||
// RNFetchBlob networking layer
|
||||
RNFetchBlob.applyCustomOkHttpClient(getOkHttpClient());
|
||||
// RNCWebView onReceivedClientCertRequest
|
||||
RNCWebViewManager.setCertificateAlias(data);
|
||||
// FastImage Glide network layer
|
||||
|
|
|
@ -13,8 +13,9 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
text: {
|
||||
fontSize: 14,
|
||||
...sharedStyles.textRegular,
|
||||
...sharedStyles.textAlignCenter
|
||||
// jest error: TypeError: Cannot read property 'textRegular' of undefined
|
||||
...sharedStyles?.textRegular,
|
||||
...sharedStyles?.textAlignCenter
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { dequal } from 'dequal';
|
||||
import moment from 'moment';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import moment from 'moment';
|
||||
import { dequal } from 'dequal';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import Markdown from '../markdown';
|
||||
import openLink from '../../lib/methods/helpers/openLink';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../lib/constants';
|
||||
import MessageContext from './Context';
|
||||
import { fileDownloadAndPreview } from './helpers/fileDownload';
|
||||
import { IAttachment, TGetCustomEmoji } from '../../definitions';
|
||||
import RCActivityIndicator from '../ActivityIndicator';
|
||||
import Attachments from './Attachments';
|
||||
import { TSupportedThemes, useTheme } from '../../theme';
|
||||
import { themes } from '../../lib/constants';
|
||||
import { fileDownloadAndPreview } from '../../lib/methods/helpers';
|
||||
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
|
||||
import openLink from '../../lib/methods/helpers/openLink';
|
||||
import { TSupportedThemes, useTheme } from '../../theme';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import RCActivityIndicator from '../ActivityIndicator';
|
||||
import Markdown from '../markdown';
|
||||
import Attachments from './Attachments';
|
||||
import MessageContext from './Context';
|
||||
import Touchable from './Touchable';
|
||||
import messageStyles from './styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
isDownloadActive,
|
||||
resumeMediaFile
|
||||
} from '../../lib/methods/handleMediaDownload';
|
||||
import { isIOS } from '../../lib/methods/helpers';
|
||||
import { fileDownload, isIOS } from '../../lib/methods/helpers';
|
||||
import EventEmitter from '../../lib/methods/helpers/events';
|
||||
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
|
||||
import { useTheme } from '../../theme';
|
||||
|
@ -24,7 +24,6 @@ import Markdown from '../markdown';
|
|||
import BlurComponent from './Components/OverlayComponent';
|
||||
import MessageContext from './Context';
|
||||
import Touchable from './Touchable';
|
||||
import { fileDownload } from './helpers/fileDownload';
|
||||
import { DEFAULT_MESSAGE_HEIGHT } from './utils';
|
||||
|
||||
const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])];
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
import RNFetchBlob, { FetchBlobResponse } from 'rn-fetch-blob';
|
||||
import FileViewer from 'react-native-file-viewer';
|
||||
|
||||
import EventEmitter from '../../../../lib/methods/helpers/events';
|
||||
import { LISTENER } from '../../../Toast';
|
||||
import I18n from '../../../../i18n';
|
||||
import { DOCUMENTS_PATH, DOWNLOAD_PATH } from '../../../../lib/constants';
|
||||
import { IAttachment } from '../../../../definitions';
|
||||
|
||||
export const getLocalFilePathFromFile = (localPath: string, attachment: IAttachment): string => `${localPath}${attachment.title}`;
|
||||
|
||||
export const fileDownload = (url: string, attachment: IAttachment): Promise<FetchBlobResponse> => {
|
||||
const path = getLocalFilePathFromFile(DOWNLOAD_PATH, attachment);
|
||||
|
||||
const options = {
|
||||
path,
|
||||
timeout: 10000,
|
||||
indicator: true,
|
||||
overwrite: true,
|
||||
addAndroidDownloads: {
|
||||
path,
|
||||
notification: true,
|
||||
useDownloadManager: true
|
||||
}
|
||||
};
|
||||
|
||||
return RNFetchBlob.config(options).fetch('GET', url);
|
||||
};
|
||||
|
||||
export const fileDownloadAndPreview = async (url: string, attachment: IAttachment): Promise<void> => {
|
||||
try {
|
||||
const path = getLocalFilePathFromFile(DOCUMENTS_PATH, attachment);
|
||||
const file = await RNFetchBlob.config({
|
||||
timeout: 10000,
|
||||
indicator: true,
|
||||
path
|
||||
}).fetch('GET', url);
|
||||
|
||||
FileViewer.open(file.data, {
|
||||
showOpenWithDialog: true,
|
||||
showAppsSuggestions: true
|
||||
})
|
||||
.then(res => res)
|
||||
.catch(async () => {
|
||||
const file = await fileDownload(url, attachment);
|
||||
file
|
||||
? EventEmitter.emit(LISTENER, { message: I18n.t('Downloaded_file') })
|
||||
: EventEmitter.emit(LISTENER, { message: I18n.t('Error_Download_file') });
|
||||
});
|
||||
} catch (e) {
|
||||
EventEmitter.emit(LISTENER, { message: I18n.t('Error_Download_file') });
|
||||
}
|
||||
};
|
|
@ -6,7 +6,6 @@ export * from './environment';
|
|||
export * from './keys';
|
||||
export * from './links';
|
||||
export * from './localAuthentication';
|
||||
export * from './localPath';
|
||||
export * from './messagesStatus';
|
||||
export * from './messageTypeLoad';
|
||||
export * from './notifications';
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
|
||||
export const DOCUMENTS_PATH = `${RNFetchBlob.fs.dirs.DocumentDir}/`;
|
||||
export const DOWNLOAD_PATH = `${RNFetchBlob.fs.dirs.DownloadDir}/`;
|
|
@ -1,4 +1,3 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||
import { KJUR } from 'jsrsasign';
|
||||
import moment from 'moment';
|
||||
|
@ -45,12 +44,12 @@ const verifyJWT = (jwt?: string): ISupportedVersionsData | null => {
|
|||
|
||||
export async function getServerInfo(server: string): Promise<TServerInfoResult> {
|
||||
try {
|
||||
const response = await RNFetchBlob.fetch('GET', `${server}/api/info`, {
|
||||
const response = await fetch(`${server}/api/info`, {
|
||||
...RocketChatSettings.customHeaders
|
||||
});
|
||||
try {
|
||||
const jsonRes: IApiServerInfo = response.json();
|
||||
if (!jsonRes?.success) {
|
||||
const serverInfo: IApiServerInfo = await response.json();
|
||||
if (!serverInfo?.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: I18n.t('Not_RC_Server', { contact: I18n.t('Contact_your_server_admin') })
|
||||
|
@ -58,7 +57,7 @@ export async function getServerInfo(server: string): Promise<TServerInfoResult>
|
|||
}
|
||||
|
||||
// Makes use of signed JWT to get supported versions
|
||||
const supportedVersions = verifyJWT(jsonRes.supportedVersions?.signed);
|
||||
const supportedVersions = verifyJWT(serverInfo.supportedVersions?.signed);
|
||||
|
||||
// if backend doesn't have supported versions or JWT is invalid, request from cloud
|
||||
if (!supportedVersions) {
|
||||
|
@ -69,7 +68,7 @@ export async function getServerInfo(server: string): Promise<TServerInfoResult>
|
|||
moment(new Date()).diff(serverRecord?.supportedVersionsUpdatedAt, 'hours') <= SV_CLOUD_UPDATE_INTERVAL
|
||||
) {
|
||||
return {
|
||||
...jsonRes,
|
||||
...serverInfo,
|
||||
success: true
|
||||
};
|
||||
}
|
||||
|
@ -79,7 +78,7 @@ export async function getServerInfo(server: string): Promise<TServerInfoResult>
|
|||
// Allows airgapped servers to use the app until enforcementStartDate
|
||||
if (!cloudInfo) {
|
||||
return {
|
||||
...jsonRes,
|
||||
...serverInfo,
|
||||
success: true
|
||||
};
|
||||
}
|
||||
|
@ -88,14 +87,14 @@ export async function getServerInfo(server: string): Promise<TServerInfoResult>
|
|||
const supportedVersionsCloud = verifyJWT(cloudInfo?.signed);
|
||||
|
||||
return {
|
||||
...jsonRes,
|
||||
...serverInfo,
|
||||
success: true,
|
||||
supportedVersions: supportedVersionsCloud
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...jsonRes,
|
||||
...serverInfo,
|
||||
success: true,
|
||||
supportedVersions
|
||||
};
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import * as FileSystem from 'expo-file-system';
|
||||
import FileViewer from 'react-native-file-viewer';
|
||||
|
||||
import { LISTENER } from '../../../containers/Toast';
|
||||
import { IAttachment } from '../../../definitions';
|
||||
import i18n from '../../../i18n';
|
||||
import EventEmitter from './events';
|
||||
|
||||
export const getLocalFilePathFromFile = (localPath: string, attachment: IAttachment): string => `${localPath}${attachment.title}`;
|
||||
|
||||
export const fileDownload = async (url: string, attachment?: IAttachment, fileName?: string): Promise<string> => {
|
||||
let path = `${FileSystem.documentDirectory}`;
|
||||
if (fileName) {
|
||||
path = `${path}${fileName}`;
|
||||
}
|
||||
if (attachment) {
|
||||
path = `${path}${attachment.title}`;
|
||||
}
|
||||
const file = await FileSystem.downloadAsync(url, path);
|
||||
return file.uri;
|
||||
};
|
||||
|
||||
export const fileDownloadAndPreview = async (url: string, attachment: IAttachment): Promise<void> => {
|
||||
try {
|
||||
const file = await fileDownload(url, attachment);
|
||||
FileViewer.open(file, {
|
||||
showOpenWithDialog: true,
|
||||
showAppsSuggestions: true
|
||||
});
|
||||
} catch (e) {
|
||||
EventEmitter.emit(LISTENER, { message: i18n.t('Error_Download_file') });
|
||||
}
|
||||
};
|
|
@ -0,0 +1,66 @@
|
|||
export interface IFileUpload {
|
||||
name: string;
|
||||
uri?: string;
|
||||
type?: string;
|
||||
filename?: string;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export class Upload {
|
||||
public xhr: XMLHttpRequest;
|
||||
public formData: FormData;
|
||||
|
||||
constructor() {
|
||||
this.xhr = new XMLHttpRequest();
|
||||
this.formData = new FormData();
|
||||
}
|
||||
|
||||
public setupRequest(url: string, headers: { [key: string]: string }): void {
|
||||
this.xhr.open('POST', url);
|
||||
Object.keys(headers).forEach(key => {
|
||||
this.xhr.setRequestHeader(key, headers[key]);
|
||||
});
|
||||
}
|
||||
|
||||
public appendFile(item: IFileUpload): void {
|
||||
if (item.uri) {
|
||||
this.formData.append(item.name, {
|
||||
uri: item.uri,
|
||||
type: item.type,
|
||||
name: item.filename
|
||||
} as any);
|
||||
} else {
|
||||
this.formData.append(item.name, item.data);
|
||||
}
|
||||
}
|
||||
|
||||
public then(callback: (param: { respInfo: XMLHttpRequest }) => void): void {
|
||||
this.xhr.onload = () => callback({ respInfo: this.xhr });
|
||||
this.xhr.send(this.formData);
|
||||
}
|
||||
|
||||
public catch(callback: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null): void {
|
||||
this.xhr.onerror = callback;
|
||||
}
|
||||
|
||||
public uploadProgress(callback: (param: number, arg1: number) => any): void {
|
||||
this.xhr.upload.onprogress = ({ total, loaded }) => callback(loaded, total);
|
||||
}
|
||||
|
||||
public cancel(): Promise<void> {
|
||||
this.xhr.abort();
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
class FileUpload {
|
||||
public uploadFile(url: string, headers: { [x: string]: string }, data: IFileUpload[]) {
|
||||
const upload = new Upload();
|
||||
upload.setupRequest(url, headers);
|
||||
data.forEach(item => upload.appendFile(item));
|
||||
return upload;
|
||||
}
|
||||
}
|
||||
|
||||
const fileUpload = new FileUpload();
|
||||
export default fileUpload;
|
|
@ -1,60 +0,0 @@
|
|||
import { IFileUpload } from './interfaces';
|
||||
|
||||
class Upload {
|
||||
public xhr: XMLHttpRequest;
|
||||
|
||||
public formData: FormData;
|
||||
|
||||
constructor() {
|
||||
this.xhr = new XMLHttpRequest();
|
||||
this.formData = new FormData();
|
||||
}
|
||||
|
||||
then = (callback: (param: { respInfo: XMLHttpRequest }) => XMLHttpRequest) => {
|
||||
this.xhr.onload = () => callback({ respInfo: this.xhr });
|
||||
this.xhr.send(this.formData);
|
||||
};
|
||||
|
||||
catch = (callback: ((this: XMLHttpRequest, ev: ProgressEvent<EventTarget>) => any) | null) => {
|
||||
this.xhr.onerror = callback;
|
||||
};
|
||||
|
||||
uploadProgress = (callback: (param: number, arg1: number) => any) => {
|
||||
this.xhr.upload.onprogress = ({ total, loaded }) => callback(loaded, total);
|
||||
};
|
||||
|
||||
cancel = () => {
|
||||
this.xhr.abort();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
class FileUpload {
|
||||
fetch = (method: string, url: string, headers: { [x: string]: string }, data: IFileUpload[]) => {
|
||||
const upload = new Upload();
|
||||
upload.xhr.open(method, url);
|
||||
|
||||
Object.keys(headers).forEach(key => {
|
||||
upload.xhr.setRequestHeader(key, headers[key]);
|
||||
});
|
||||
|
||||
data.forEach(item => {
|
||||
if (item.uri) {
|
||||
upload.formData.append(item.name, {
|
||||
// @ts-ignore
|
||||
uri: item.uri,
|
||||
// @ts-ignore
|
||||
type: item.type,
|
||||
name: item.filename
|
||||
});
|
||||
} else {
|
||||
upload.formData.append(item.name, item.data);
|
||||
}
|
||||
});
|
||||
|
||||
return upload;
|
||||
};
|
||||
}
|
||||
|
||||
const fileUpload = new FileUpload();
|
||||
export default fileUpload;
|
|
@ -1,25 +0,0 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
|
||||
import { TMethods } from '../fetch';
|
||||
import { IFileUpload } from './interfaces';
|
||||
|
||||
class FileUpload {
|
||||
fetch = (method: TMethods, url: string, headers: { [key: string]: string }, data: IFileUpload[]) => {
|
||||
const formData = data.map(item => {
|
||||
if (item.uri) {
|
||||
return {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
filename: item.filename,
|
||||
data: RNFetchBlob.wrap(decodeURI(item.uri))
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
return RNFetchBlob.fetch(method, url, headers, formData);
|
||||
};
|
||||
}
|
||||
|
||||
const fileUpload = new FileUpload();
|
||||
export default fileUpload;
|
|
@ -1,7 +0,0 @@
|
|||
export interface IFileUpload {
|
||||
name: string;
|
||||
uri?: string;
|
||||
type?: string;
|
||||
filename?: string;
|
||||
data?: any;
|
||||
}
|
|
@ -18,3 +18,4 @@ export * from './image';
|
|||
export * from './askAndroidMediaPermissions';
|
||||
export * from './emitter';
|
||||
export * from './parseJson';
|
||||
export * from './fileDownload';
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { FetchBlobResponse, StatefulPromise } from 'rn-fetch-blob';
|
||||
import { Alert } from 'react-native';
|
||||
|
||||
import { IUpload, IUser, TUploadModel } from '../../definitions';
|
||||
import i18n from '../../i18n';
|
||||
import database from '../database';
|
||||
import type { IFileUpload, Upload } from './helpers/fileUpload';
|
||||
import FileUpload from './helpers/fileUpload';
|
||||
import { IFileUpload } from './helpers/fileUpload/interfaces';
|
||||
import log from './helpers/log';
|
||||
|
||||
const uploadQueue: { [index: string]: StatefulPromise<FetchBlobResponse> } = {};
|
||||
const uploadQueue: { [index: string]: Upload } = {};
|
||||
|
||||
const getUploadPath = (path: string, rid: string) => `${path}-${rid}`;
|
||||
|
||||
|
@ -48,7 +47,7 @@ export function sendFileMessage(
|
|||
server: string,
|
||||
user: Partial<Pick<IUser, 'id' | 'token'>>,
|
||||
isForceTryAgain?: boolean
|
||||
): Promise<FetchBlobResponse | void> {
|
||||
): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const { id, token } = user;
|
||||
|
@ -121,7 +120,7 @@ export function sendFileMessage(
|
|||
'X-User-Id': id
|
||||
};
|
||||
|
||||
uploadQueue[uploadPath] = FileUpload.fetch('POST', uploadUrl, headers, formData);
|
||||
uploadQueue[uploadPath] = FileUpload.uploadFile(uploadUrl, headers, formData);
|
||||
|
||||
uploadQueue[uploadPath].uploadProgress(async (loaded: number, total: number) => {
|
||||
try {
|
||||
|
@ -137,12 +136,11 @@ export function sendFileMessage(
|
|||
|
||||
uploadQueue[uploadPath].then(async response => {
|
||||
if (response.respInfo.status >= 200 && response.respInfo.status < 400) {
|
||||
// If response is all good...
|
||||
try {
|
||||
await db.write(async () => {
|
||||
await uploadRecord.destroyPermanently();
|
||||
});
|
||||
resolve(response);
|
||||
resolve();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
|
||||
export const getServerTimeSync = async (server: string) => {
|
||||
try {
|
||||
const response = await Promise.race([
|
||||
RNFetchBlob.fetch('GET', `${server}/_timesync`),
|
||||
new Promise<undefined>(res => setTimeout(res, 2000))
|
||||
]);
|
||||
if (response?.data) {
|
||||
return parseInt(response.data);
|
||||
const response = await Promise.race([fetch(`${server}/_timesync`), new Promise<undefined>(res => setTimeout(res, 2000))]);
|
||||
const data = await response?.json();
|
||||
if (data?.data) {
|
||||
return parseInt(data.data);
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
|
|
|
@ -6,7 +6,7 @@ import React from 'react';
|
|||
import { PermissionsAndroid, useWindowDimensions, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { shallowEqual } from 'react-redux';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
import { isImageBase64 } from '../lib/methods';
|
||||
import RCActivityIndicator from '../containers/ActivityIndicator';
|
||||
|
@ -18,7 +18,7 @@ import { IAttachment } from '../definitions';
|
|||
import I18n from '../i18n';
|
||||
import { useAppSelector } from '../lib/hooks';
|
||||
import { useAppNavigation, useAppRoute } from '../lib/hooks/navigation';
|
||||
import { formatAttachmentUrl, isAndroid } from '../lib/methods/helpers';
|
||||
import { formatAttachmentUrl, isAndroid, fileDownload } from '../lib/methods/helpers';
|
||||
import EventEmitter from '../lib/methods/helpers/events';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import { TNavigation } from '../stacks/stackType';
|
||||
|
@ -177,11 +177,9 @@ const AttachmentView = (): React.ReactElement => {
|
|||
} else {
|
||||
filename = getFilename({ title: attachment.title, type: 'video', mimeType: video_type, url });
|
||||
}
|
||||
const documentDir = `${RNFetchBlob.fs.dirs.DocumentDir}/`;
|
||||
const path = `${documentDir + filename}`;
|
||||
const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment);
|
||||
await CameraRoll.save(path, { album: 'Rocket.Chat' });
|
||||
file.flush();
|
||||
const file = await fileDownload(mediaAttachment, {}, filename);
|
||||
await CameraRoll.save(file, { album: 'Rocket.Chat' });
|
||||
FileSystem.deleteAsync(file, { idempotent: true });
|
||||
}
|
||||
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
|
||||
} catch (e) {
|
||||
|
|
|
@ -484,8 +484,6 @@ PODS:
|
|||
- React
|
||||
- rn-extensions-share (2.4.1):
|
||||
- React
|
||||
- rn-fetch-blob (0.12.0):
|
||||
- React-Core
|
||||
- RNBootSplash (4.3.3):
|
||||
- React-Core
|
||||
- RNCAsyncStorage (1.17.11):
|
||||
|
@ -653,7 +651,6 @@ DEPENDENCIES:
|
|||
- "ReactNativeART (from `../node_modules/@react-native-community/art`)"
|
||||
- ReactNativeUiLib (from `../node_modules/react-native-ui-lib`)
|
||||
- rn-extensions-share (from `../node_modules/rn-extensions-share`)
|
||||
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
|
||||
- RNBootSplash (from `../node_modules/react-native-bootsplash`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||
|
@ -827,8 +824,6 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native-ui-lib"
|
||||
rn-extensions-share:
|
||||
:path: "../node_modules/rn-extensions-share"
|
||||
rn-fetch-blob:
|
||||
:path: "../node_modules/rn-fetch-blob"
|
||||
RNBootSplash:
|
||||
:path: "../node_modules/react-native-bootsplash"
|
||||
RNCAsyncStorage:
|
||||
|
@ -962,7 +957,6 @@ SPEC CHECKSUMS:
|
|||
ReactNativeART: 78edc68dd4a1e675338cd0cd113319cf3a65f2ab
|
||||
ReactNativeUiLib: 33521c0747ea376d292b62b6415e0f1d75bd3c10
|
||||
rn-extensions-share: 5fd84a80e6594706f0dfa1884f2d6d591b382cf5
|
||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||
RNBootSplash: 7e91ea56c7010aae487489789dbe212e8c905a0c
|
||||
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
|
||||
RNCClipboard: cc054ad1e8a33d2a74cd13e565588b4ca928d8fd
|
||||
|
|
|
@ -29,18 +29,6 @@ jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock
|
|||
|
||||
jest.mock('@react-native-clipboard/clipboard', () => mockClipboard);
|
||||
|
||||
jest.mock('rn-fetch-blob', () => ({
|
||||
fs: {
|
||||
dirs: {
|
||||
DocumentDir: '/data/com.rocket.chat/documents',
|
||||
DownloadDir: '/data/com.rocket.chat/downloads'
|
||||
},
|
||||
exists: jest.fn(() => null)
|
||||
},
|
||||
fetch: jest.fn(() => null),
|
||||
config: jest.fn(() => null)
|
||||
}));
|
||||
|
||||
jest.mock('react-native-file-viewer', () => ({
|
||||
open: jest.fn(() => null)
|
||||
}));
|
||||
|
|
|
@ -137,7 +137,6 @@
|
|||
"remove-markdown": "^0.3.0",
|
||||
"reselect": "4.0.0",
|
||||
"rn-extensions-share": "RocketChat/rn-extensions-share",
|
||||
"rn-fetch-blob": "^0.12.0",
|
||||
"rn-root-view": "RocketChat/rn-root-view",
|
||||
"semver": "7.3.8",
|
||||
"transliteration": "^2.3.5",
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
diff --git a/node_modules/rn-fetch-blob/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/node_modules/rn-fetch-blob/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java
|
||||
index 602d51d..920d975 100644
|
||||
--- a/node_modules/rn-fetch-blob/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java
|
||||
+++ b/node_modules/rn-fetch-blob/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java
|
||||
@@ -38,7 +38,7 @@ import static com.RNFetchBlob.RNFetchBlobConst.GET_CONTENT_INTENT;
|
||||
|
||||
public class RNFetchBlob extends ReactContextBaseJavaModule {
|
||||
|
||||
- private final OkHttpClient mClient;
|
||||
+ static private OkHttpClient mClient;
|
||||
|
||||
static ReactApplicationContext RCTContext;
|
||||
private static LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
||||
@@ -75,6 +75,10 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
|
||||
});
|
||||
}
|
||||
|
||||
+ public static void applyCustomOkHttpClient(OkHttpClient client) {
|
||||
+ mClient = client;
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNFetchBlob";
|
||||
diff --git a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
||||
index cdbe6b1..04e5e7b 100644
|
||||
--- a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
||||
+++ b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m
|
||||
@@ -15,6 +15,9 @@
|
||||
#import "IOS7Polyfill.h"
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
+#import "SecureStorage.h"
|
||||
+#import <MMKV/MMKV.h>
|
||||
+
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ResponseFormat) {
|
||||
UTF8,
|
||||
@@ -450,16 +453,108 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen
|
||||
}
|
||||
}
|
||||
|
||||
-
|
||||
-- (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
|
||||
+-(NSURLCredential *)getUrlCredential:(NSURLAuthenticationChallenge *)challenge path:(NSString *)path password:(NSString *)password
|
||||
{
|
||||
- if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) {
|
||||
- completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
- } else {
|
||||
- completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
+ NSString *authMethod = [[challenge protectionSpace] authenticationMethod];
|
||||
+ SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
|
||||
+
|
||||
+ if ([authMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || path == nil || password == nil) {
|
||||
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||
+ } else if (path && password) {
|
||||
+ NSMutableArray *policies = [NSMutableArray array];
|
||||
+ [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)];
|
||||
+ SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
|
||||
+
|
||||
+ SecTrustResultType result;
|
||||
+ SecTrustEvaluate(serverTrust, &result);
|
||||
+
|
||||
+ if (![[NSFileManager defaultManager] fileExistsAtPath:path])
|
||||
+ {
|
||||
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||
+ }
|
||||
+
|
||||
+ NSData *p12data = [NSData dataWithContentsOfFile:path];
|
||||
+ NSDictionary* options = @{ (id)kSecImportExportPassphrase:password };
|
||||
+ CFArrayRef rawItems = NULL;
|
||||
+ OSStatus status = SecPKCS12Import((__bridge CFDataRef)p12data,
|
||||
+ (__bridge CFDictionaryRef)options,
|
||||
+ &rawItems);
|
||||
+
|
||||
+ if (status != noErr) {
|
||||
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||
+ }
|
||||
+
|
||||
+ NSArray* items = (NSArray*)CFBridgingRelease(rawItems);
|
||||
+ NSDictionary* firstItem = nil;
|
||||
+ if ((status == errSecSuccess) && ([items count]>0)) {
|
||||
+ firstItem = items[0];
|
||||
}
|
||||
+
|
||||
+ SecIdentityRef identity = (SecIdentityRef)CFBridgingRetain(firstItem[(id)kSecImportItemIdentity]);
|
||||
+ SecCertificateRef certificate = NULL;
|
||||
+ if (identity) {
|
||||
+ SecIdentityCopyCertificate(identity, &certificate);
|
||||
+ if (certificate) { CFRelease(certificate); }
|
||||
+ }
|
||||
+
|
||||
+ NSMutableArray *certificates = [[NSMutableArray alloc] init];
|
||||
+ [certificates addObject:CFBridgingRelease(certificate)];
|
||||
+
|
||||
+ return [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone];
|
||||
+ }
|
||||
+
|
||||
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||
+}
|
||||
+
|
||||
+- (NSString *)stringToHex:(NSString *)string
|
||||
+{
|
||||
+ char *utf8 = (char *)[string UTF8String];
|
||||
+ NSMutableString *hex = [NSMutableString string];
|
||||
+ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF];
|
||||
+
|
||||
+ return [[NSString stringWithFormat:@"%@", hex] lowercaseString];
|
||||
}
|
||||
|
||||
+-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
|
||||
+{
|
||||
+ NSString *host = challenge.protectionSpace.host;
|
||||
+
|
||||
+ // Read the clientSSL info from MMKV
|
||||
+ __block NSString *clientSSL;
|
||||
+ SecureStorage *secureStorage = [[SecureStorage alloc] init];
|
||||
+
|
||||
+ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31
|
||||
+ NSString *key = [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"]];
|
||||
+ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||
+
|
||||
+ if (key == NULL) {
|
||||
+ return completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential);
|
||||
+ }
|
||||
+
|
||||
+ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding];
|
||||
+ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess];
|
||||
+ clientSSL = [mmkv getStringForKey:host];
|
||||
+
|
||||
+ if ([clientSSL length] != 0) {
|
||||
+ NSData *data = [clientSSL dataUsingEncoding:NSUTF8StringEncoding];
|
||||
+ id dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
+ NSString *path = [dict objectForKey:@"path"];
|
||||
+ NSString *password = [dict objectForKey:@"password"];
|
||||
+ credential = [self getUrlCredential:challenge path:path password:password];
|
||||
+ }
|
||||
+
|
||||
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
|
||||
+}
|
||||
+
|
||||
+// - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
|
||||
+// {
|
||||
+// if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) {
|
||||
+// completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
+// } else {
|
||||
+// completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
|
||||
+// }
|
||||
+// }
|
||||
+
|
||||
|
||||
- (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
|
||||
{
|
28
yarn.lock
28
yarn.lock
|
@ -8171,11 +8171,6 @@ balanced-match@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
base-64@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb"
|
||||
integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==
|
||||
|
||||
base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
|
@ -8619,7 +8614,6 @@ builtins@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
|
||||
integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==
|
||||
|
||||
|
||||
bunyamin@^1.5.0:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/bunyamin/-/bunyamin-1.5.2.tgz#681db204c0b16531369d5c1f6c89dc8d760b7558"
|
||||
|
@ -12208,18 +12202,6 @@ glob-to-regexp@^0.3.0:
|
|||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
|
||||
|
||||
glob@7.0.6:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
|
||||
integrity sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.2"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@7.1.6, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
|
@ -18798,14 +18780,6 @@ rn-extensions-share@RocketChat/rn-extensions-share:
|
|||
version "2.4.1"
|
||||
resolved "https://codeload.github.com/RocketChat/rn-extensions-share/tar.gz/4d7c0e4c2f300e4fb116af7b7cc0dbbc8169150c"
|
||||
|
||||
rn-fetch-blob@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz#ec610d2f9b3f1065556b58ab9c106eeb256f3cba"
|
||||
integrity sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==
|
||||
dependencies:
|
||||
base-64 "0.1.0"
|
||||
glob "7.0.6"
|
||||
|
||||
rn-host-detect@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.2.0.tgz#8b0396fc05631ec60c1cb8789e5070cdb04d0da0"
|
||||
|
@ -19677,6 +19651,7 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
|
|||
strip-ansi "^6.0.0"
|
||||
|
||||
string-width@^4.2.3:
|
||||
name string-width-cjs
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
|
@ -19840,6 +19815,7 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
|||
ansi-regex "^4.1.0"
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
name strip-ansi-cjs
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
|
|
Loading…
Reference in New Issue