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.Arrays;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.RNFetchBlob.RNFetchBlob;
|
|
||||||
|
|
||||||
import com.reactnativecommunity.webview.RNCWebViewManager;
|
import com.reactnativecommunity.webview.RNCWebViewManager;
|
||||||
|
|
||||||
import com.dylanvann.fastimage.FastImageOkHttpUrlLoader;
|
import com.dylanvann.fastimage.FastImageOkHttpUrlLoader;
|
||||||
|
@ -104,8 +102,6 @@ public class SSLPinningModule extends ReactContextBaseJavaModule implements KeyC
|
||||||
WebSocketModule.setCustomClientBuilder(new CustomClient());
|
WebSocketModule.setCustomClientBuilder(new CustomClient());
|
||||||
// Image networking react-native layer
|
// Image networking react-native layer
|
||||||
ReactOkHttpNetworkFetcher.setOkHttpClient(getOkHttpClient());
|
ReactOkHttpNetworkFetcher.setOkHttpClient(getOkHttpClient());
|
||||||
// RNFetchBlob networking layer
|
|
||||||
RNFetchBlob.applyCustomOkHttpClient(getOkHttpClient());
|
|
||||||
// RNCWebView onReceivedClientCertRequest
|
// RNCWebView onReceivedClientCertRequest
|
||||||
RNCWebViewManager.setCertificateAlias(data);
|
RNCWebViewManager.setCertificateAlias(data);
|
||||||
// FastImage Glide network layer
|
// FastImage Glide network layer
|
||||||
|
|
|
@ -13,8 +13,9 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
...sharedStyles.textRegular,
|
// jest error: TypeError: Cannot read property 'textRegular' of undefined
|
||||||
...sharedStyles.textAlignCenter
|
...sharedStyles?.textRegular,
|
||||||
|
...sharedStyles?.textAlignCenter
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
|
import { dequal } from 'dequal';
|
||||||
|
import moment from 'moment';
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
import moment from 'moment';
|
|
||||||
import { dequal } from 'dequal';
|
|
||||||
import FastImage from 'react-native-fast-image';
|
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 { IAttachment, TGetCustomEmoji } from '../../definitions';
|
||||||
import RCActivityIndicator from '../ActivityIndicator';
|
import { themes } from '../../lib/constants';
|
||||||
import Attachments from './Attachments';
|
import { fileDownloadAndPreview } from '../../lib/methods/helpers';
|
||||||
import { TSupportedThemes, useTheme } from '../../theme';
|
|
||||||
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
|
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';
|
import messageStyles from './styles';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
isDownloadActive,
|
isDownloadActive,
|
||||||
resumeMediaFile
|
resumeMediaFile
|
||||||
} from '../../lib/methods/handleMediaDownload';
|
} 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 EventEmitter from '../../lib/methods/helpers/events';
|
||||||
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
|
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
|
@ -24,7 +24,6 @@ import Markdown from '../markdown';
|
||||||
import BlurComponent from './Components/OverlayComponent';
|
import BlurComponent from './Components/OverlayComponent';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import Touchable from './Touchable';
|
import Touchable from './Touchable';
|
||||||
import { fileDownload } from './helpers/fileDownload';
|
|
||||||
import { DEFAULT_MESSAGE_HEIGHT } from './utils';
|
import { DEFAULT_MESSAGE_HEIGHT } from './utils';
|
||||||
|
|
||||||
const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])];
|
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 './keys';
|
||||||
export * from './links';
|
export * from './links';
|
||||||
export * from './localAuthentication';
|
export * from './localAuthentication';
|
||||||
export * from './localPath';
|
|
||||||
export * from './messagesStatus';
|
export * from './messagesStatus';
|
||||||
export * from './messageTypeLoad';
|
export * from './messageTypeLoad';
|
||||||
export * from './notifications';
|
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 { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||||
import { KJUR } from 'jsrsasign';
|
import { KJUR } from 'jsrsasign';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
@ -45,12 +44,12 @@ const verifyJWT = (jwt?: string): ISupportedVersionsData | null => {
|
||||||
|
|
||||||
export async function getServerInfo(server: string): Promise<TServerInfoResult> {
|
export async function getServerInfo(server: string): Promise<TServerInfoResult> {
|
||||||
try {
|
try {
|
||||||
const response = await RNFetchBlob.fetch('GET', `${server}/api/info`, {
|
const response = await fetch(`${server}/api/info`, {
|
||||||
...RocketChatSettings.customHeaders
|
...RocketChatSettings.customHeaders
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
const jsonRes: IApiServerInfo = response.json();
|
const serverInfo: IApiServerInfo = await response.json();
|
||||||
if (!jsonRes?.success) {
|
if (!serverInfo?.success) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: I18n.t('Not_RC_Server', { contact: I18n.t('Contact_your_server_admin') })
|
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
|
// 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 backend doesn't have supported versions or JWT is invalid, request from cloud
|
||||||
if (!supportedVersions) {
|
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
|
moment(new Date()).diff(serverRecord?.supportedVersionsUpdatedAt, 'hours') <= SV_CLOUD_UPDATE_INTERVAL
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
...jsonRes,
|
...serverInfo,
|
||||||
success: true
|
success: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -79,7 +78,7 @@ export async function getServerInfo(server: string): Promise<TServerInfoResult>
|
||||||
// Allows airgapped servers to use the app until enforcementStartDate
|
// Allows airgapped servers to use the app until enforcementStartDate
|
||||||
if (!cloudInfo) {
|
if (!cloudInfo) {
|
||||||
return {
|
return {
|
||||||
...jsonRes,
|
...serverInfo,
|
||||||
success: true
|
success: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -88,14 +87,14 @@ export async function getServerInfo(server: string): Promise<TServerInfoResult>
|
||||||
const supportedVersionsCloud = verifyJWT(cloudInfo?.signed);
|
const supportedVersionsCloud = verifyJWT(cloudInfo?.signed);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...jsonRes,
|
...serverInfo,
|
||||||
success: true,
|
success: true,
|
||||||
supportedVersions: supportedVersionsCloud
|
supportedVersions: supportedVersionsCloud
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...jsonRes,
|
...serverInfo,
|
||||||
success: true,
|
success: true,
|
||||||
supportedVersions
|
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 './askAndroidMediaPermissions';
|
||||||
export * from './emitter';
|
export * from './emitter';
|
||||||
export * from './parseJson';
|
export * from './parseJson';
|
||||||
|
export * from './fileDownload';
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import { FetchBlobResponse, StatefulPromise } from 'rn-fetch-blob';
|
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
|
|
||||||
import { IUpload, IUser, TUploadModel } from '../../definitions';
|
import { IUpload, IUser, TUploadModel } from '../../definitions';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import database from '../database';
|
import database from '../database';
|
||||||
|
import type { IFileUpload, Upload } from './helpers/fileUpload';
|
||||||
import FileUpload from './helpers/fileUpload';
|
import FileUpload from './helpers/fileUpload';
|
||||||
import { IFileUpload } from './helpers/fileUpload/interfaces';
|
|
||||||
import log from './helpers/log';
|
import log from './helpers/log';
|
||||||
|
|
||||||
const uploadQueue: { [index: string]: StatefulPromise<FetchBlobResponse> } = {};
|
const uploadQueue: { [index: string]: Upload } = {};
|
||||||
|
|
||||||
const getUploadPath = (path: string, rid: string) => `${path}-${rid}`;
|
const getUploadPath = (path: string, rid: string) => `${path}-${rid}`;
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ export function sendFileMessage(
|
||||||
server: string,
|
server: string,
|
||||||
user: Partial<Pick<IUser, 'id' | 'token'>>,
|
user: Partial<Pick<IUser, 'id' | 'token'>>,
|
||||||
isForceTryAgain?: boolean
|
isForceTryAgain?: boolean
|
||||||
): Promise<FetchBlobResponse | void> {
|
): Promise<void> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const { id, token } = user;
|
const { id, token } = user;
|
||||||
|
@ -121,7 +120,7 @@ export function sendFileMessage(
|
||||||
'X-User-Id': id
|
'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) => {
|
uploadQueue[uploadPath].uploadProgress(async (loaded: number, total: number) => {
|
||||||
try {
|
try {
|
||||||
|
@ -137,12 +136,11 @@ export function sendFileMessage(
|
||||||
|
|
||||||
uploadQueue[uploadPath].then(async response => {
|
uploadQueue[uploadPath].then(async response => {
|
||||||
if (response.respInfo.status >= 200 && response.respInfo.status < 400) {
|
if (response.respInfo.status >= 200 && response.respInfo.status < 400) {
|
||||||
// If response is all good...
|
|
||||||
try {
|
try {
|
||||||
await db.write(async () => {
|
await db.write(async () => {
|
||||||
await uploadRecord.destroyPermanently();
|
await uploadRecord.destroyPermanently();
|
||||||
});
|
});
|
||||||
resolve(response);
|
resolve();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
import RNFetchBlob from 'rn-fetch-blob';
|
|
||||||
|
|
||||||
export const getServerTimeSync = async (server: string) => {
|
export const getServerTimeSync = async (server: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await Promise.race([
|
const response = await Promise.race([fetch(`${server}/_timesync`), new Promise<undefined>(res => setTimeout(res, 2000))]);
|
||||||
RNFetchBlob.fetch('GET', `${server}/_timesync`),
|
const data = await response?.json();
|
||||||
new Promise<undefined>(res => setTimeout(res, 2000))
|
if (data?.data) {
|
||||||
]);
|
return parseInt(data.data);
|
||||||
if (response?.data) {
|
|
||||||
return parseInt(response.data);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import React from 'react';
|
||||||
import { PermissionsAndroid, useWindowDimensions, View } from 'react-native';
|
import { PermissionsAndroid, useWindowDimensions, View } from 'react-native';
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import { shallowEqual } from 'react-redux';
|
import { shallowEqual } from 'react-redux';
|
||||||
import RNFetchBlob from 'rn-fetch-blob';
|
import * as FileSystem from 'expo-file-system';
|
||||||
|
|
||||||
import { isImageBase64 } from '../lib/methods';
|
import { isImageBase64 } from '../lib/methods';
|
||||||
import RCActivityIndicator from '../containers/ActivityIndicator';
|
import RCActivityIndicator from '../containers/ActivityIndicator';
|
||||||
|
@ -18,7 +18,7 @@ import { IAttachment } from '../definitions';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { useAppSelector } from '../lib/hooks';
|
import { useAppSelector } from '../lib/hooks';
|
||||||
import { useAppNavigation, useAppRoute } from '../lib/hooks/navigation';
|
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 EventEmitter from '../lib/methods/helpers/events';
|
||||||
import { getUserSelector } from '../selectors/login';
|
import { getUserSelector } from '../selectors/login';
|
||||||
import { TNavigation } from '../stacks/stackType';
|
import { TNavigation } from '../stacks/stackType';
|
||||||
|
@ -177,11 +177,9 @@ const AttachmentView = (): React.ReactElement => {
|
||||||
} else {
|
} else {
|
||||||
filename = getFilename({ title: attachment.title, type: 'video', mimeType: video_type, url });
|
filename = getFilename({ title: attachment.title, type: 'video', mimeType: video_type, url });
|
||||||
}
|
}
|
||||||
const documentDir = `${RNFetchBlob.fs.dirs.DocumentDir}/`;
|
const file = await fileDownload(mediaAttachment, {}, filename);
|
||||||
const path = `${documentDir + filename}`;
|
await CameraRoll.save(file, { album: 'Rocket.Chat' });
|
||||||
const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment);
|
FileSystem.deleteAsync(file, { idempotent: true });
|
||||||
await CameraRoll.save(path, { album: 'Rocket.Chat' });
|
|
||||||
file.flush();
|
|
||||||
}
|
}
|
||||||
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
|
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -484,8 +484,6 @@ PODS:
|
||||||
- React
|
- React
|
||||||
- rn-extensions-share (2.4.1):
|
- rn-extensions-share (2.4.1):
|
||||||
- React
|
- React
|
||||||
- rn-fetch-blob (0.12.0):
|
|
||||||
- React-Core
|
|
||||||
- RNBootSplash (4.3.3):
|
- RNBootSplash (4.3.3):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNCAsyncStorage (1.17.11):
|
- RNCAsyncStorage (1.17.11):
|
||||||
|
@ -653,7 +651,6 @@ DEPENDENCIES:
|
||||||
- "ReactNativeART (from `../node_modules/@react-native-community/art`)"
|
- "ReactNativeART (from `../node_modules/@react-native-community/art`)"
|
||||||
- ReactNativeUiLib (from `../node_modules/react-native-ui-lib`)
|
- ReactNativeUiLib (from `../node_modules/react-native-ui-lib`)
|
||||||
- rn-extensions-share (from `../node_modules/rn-extensions-share`)
|
- 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`)
|
- RNBootSplash (from `../node_modules/react-native-bootsplash`)
|
||||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||||
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||||
|
@ -827,8 +824,6 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/react-native-ui-lib"
|
:path: "../node_modules/react-native-ui-lib"
|
||||||
rn-extensions-share:
|
rn-extensions-share:
|
||||||
:path: "../node_modules/rn-extensions-share"
|
:path: "../node_modules/rn-extensions-share"
|
||||||
rn-fetch-blob:
|
|
||||||
:path: "../node_modules/rn-fetch-blob"
|
|
||||||
RNBootSplash:
|
RNBootSplash:
|
||||||
:path: "../node_modules/react-native-bootsplash"
|
:path: "../node_modules/react-native-bootsplash"
|
||||||
RNCAsyncStorage:
|
RNCAsyncStorage:
|
||||||
|
@ -962,7 +957,6 @@ SPEC CHECKSUMS:
|
||||||
ReactNativeART: 78edc68dd4a1e675338cd0cd113319cf3a65f2ab
|
ReactNativeART: 78edc68dd4a1e675338cd0cd113319cf3a65f2ab
|
||||||
ReactNativeUiLib: 33521c0747ea376d292b62b6415e0f1d75bd3c10
|
ReactNativeUiLib: 33521c0747ea376d292b62b6415e0f1d75bd3c10
|
||||||
rn-extensions-share: 5fd84a80e6594706f0dfa1884f2d6d591b382cf5
|
rn-extensions-share: 5fd84a80e6594706f0dfa1884f2d6d591b382cf5
|
||||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
|
||||||
RNBootSplash: 7e91ea56c7010aae487489789dbe212e8c905a0c
|
RNBootSplash: 7e91ea56c7010aae487489789dbe212e8c905a0c
|
||||||
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
|
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
|
||||||
RNCClipboard: cc054ad1e8a33d2a74cd13e565588b4ca928d8fd
|
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('@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', () => ({
|
jest.mock('react-native-file-viewer', () => ({
|
||||||
open: jest.fn(() => null)
|
open: jest.fn(() => null)
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -137,7 +137,6 @@
|
||||||
"remove-markdown": "^0.3.0",
|
"remove-markdown": "^0.3.0",
|
||||||
"reselect": "4.0.0",
|
"reselect": "4.0.0",
|
||||||
"rn-extensions-share": "RocketChat/rn-extensions-share",
|
"rn-extensions-share": "RocketChat/rn-extensions-share",
|
||||||
"rn-fetch-blob": "^0.12.0",
|
|
||||||
"rn-root-view": "RocketChat/rn-root-view",
|
"rn-root-view": "RocketChat/rn-root-view",
|
||||||
"semver": "7.3.8",
|
"semver": "7.3.8",
|
||||||
"transliteration": "^2.3.5",
|
"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"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
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:
|
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"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
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"
|
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
|
||||||
integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==
|
integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==
|
||||||
|
|
||||||
|
|
||||||
bunyamin@^1.5.0:
|
bunyamin@^1.5.0:
|
||||||
version "1.5.2"
|
version "1.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/bunyamin/-/bunyamin-1.5.2.tgz#681db204c0b16531369d5c1f6c89dc8d760b7558"
|
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"
|
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||||
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
|
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:
|
glob@7.1.6, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
||||||
version "7.1.6"
|
version "7.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
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"
|
version "2.4.1"
|
||||||
resolved "https://codeload.github.com/RocketChat/rn-extensions-share/tar.gz/4d7c0e4c2f300e4fb116af7b7cc0dbbc8169150c"
|
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:
|
rn-host-detect@1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.2.0.tgz#8b0396fc05631ec60c1cb8789e5070cdb04d0da0"
|
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"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
string-width@^4.2.3:
|
string-width@^4.2.3:
|
||||||
|
name string-width-cjs
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
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"
|
ansi-regex "^4.1.0"
|
||||||
|
|
||||||
strip-ansi@^6.0.1:
|
strip-ansi@^6.0.1:
|
||||||
|
name strip-ansi-cjs
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
|
|
Loading…
Reference in New Issue