starting getContent, multiple file types
This commit is contained in:
parent
c67cb0deb4
commit
f373972911
|
@ -69,4 +69,8 @@ export interface IShareAttachment {
|
|||
canUpload: boolean;
|
||||
error?: any;
|
||||
uri: string;
|
||||
encryption?: {
|
||||
key: any;
|
||||
iv: string;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import { store } from '../store/auxStore';
|
|||
import { joinVectorData, randomPassword, splitVectorData, toString, utf8ToBuffer } from './utils';
|
||||
import { EncryptionRoom } from './index';
|
||||
import {
|
||||
IAttachment,
|
||||
IMessage,
|
||||
ISubscription,
|
||||
IUpload,
|
||||
|
@ -44,6 +45,7 @@ class Encryption {
|
|||
decrypt: Function;
|
||||
encrypt: Function;
|
||||
encryptText: Function;
|
||||
encryptFile: Function;
|
||||
encryptUpload: Function;
|
||||
importRoomKey: Function;
|
||||
};
|
||||
|
@ -514,6 +516,37 @@ class Encryption {
|
|||
return roomE2E.decrypt(message);
|
||||
};
|
||||
|
||||
encryptFile = async (rid: string, attachment: IAttachment) => {
|
||||
const db = database.active;
|
||||
const subCollection = db.get('subscriptions');
|
||||
|
||||
try {
|
||||
// Find the subscription
|
||||
const subRecord = await subCollection.find(rid);
|
||||
|
||||
// Subscription is not encrypted at the moment
|
||||
if (!subRecord.encrypted) {
|
||||
// Send a non encrypted message
|
||||
return attachment;
|
||||
}
|
||||
|
||||
// If the client is not ready
|
||||
if (!this.ready) {
|
||||
// Wait for ready status
|
||||
await this.establishing;
|
||||
}
|
||||
|
||||
const roomE2E = await this.getRoomInstance(rid);
|
||||
return roomE2E.encryptFile(rid, attachment);
|
||||
} catch {
|
||||
// Subscription not found
|
||||
// or client can't be initialized (missing password)
|
||||
}
|
||||
|
||||
// Send a non encrypted message
|
||||
return attachment;
|
||||
};
|
||||
|
||||
// Decrypt multiple messages
|
||||
decryptMessages = (messages: Partial<IMessage>[]) =>
|
||||
Promise.all(messages.map((m: Partial<IMessage>) => this.decryptMessage(m as IMessage)));
|
||||
|
|
|
@ -5,7 +5,7 @@ import ByteBuffer from 'bytebuffer';
|
|||
import parse from 'url-parse';
|
||||
|
||||
import getSingleMessage from '../methods/getSingleMessage';
|
||||
import { IMessage, IUpload, IUser } from '../../definitions';
|
||||
import { IMessage, IShareAttachment, IUpload, IUser } from '../../definitions';
|
||||
import Deferred from './helpers/deferred';
|
||||
import { debounce } from '../methods/helpers';
|
||||
import database from '../database';
|
||||
|
@ -15,6 +15,9 @@ import {
|
|||
bufferToB64,
|
||||
bufferToB64URI,
|
||||
bufferToUtf8,
|
||||
encryptAESCTR,
|
||||
exportAESCTR,
|
||||
generateAESCTRKey,
|
||||
joinVectorData,
|
||||
splitVectorData,
|
||||
toString,
|
||||
|
@ -269,6 +272,77 @@ export default class EncryptionRoom {
|
|||
return message;
|
||||
};
|
||||
|
||||
// Encrypt file
|
||||
encryptFile = async (rid: string, attachment: IShareAttachment) => {
|
||||
if (!this.ready) {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
try {
|
||||
const { path } = attachment;
|
||||
const vector = await SimpleCrypto.utils.randomBytes(16);
|
||||
const key = await generateAESCTRKey();
|
||||
const exportedKey = await exportAESCTR(key);
|
||||
const encryptedFile = await encryptAESCTR(path, exportedKey.k, bufferToB64(vector));
|
||||
|
||||
const getContent = async (_id: string, fileUrl: string) => {
|
||||
const attachments = [];
|
||||
let att = {
|
||||
title: attachment.filename,
|
||||
type: attachment.type,
|
||||
mime: attachment.type,
|
||||
size: attachment.size,
|
||||
description: attachment.description,
|
||||
encryption: {
|
||||
key: exportedKey,
|
||||
iv: bufferToB64(vector)
|
||||
}
|
||||
};
|
||||
if (/^image\/.+/.test(attachment.type)) {
|
||||
att = {
|
||||
...att,
|
||||
image_url: fileUrl,
|
||||
image_type: attachment.type,
|
||||
image_size: attachment.size
|
||||
};
|
||||
} else if (/^audio\/.+/.test(attachment.type)) {
|
||||
att = {
|
||||
...att,
|
||||
audio_url: fileUrl,
|
||||
audio_type: attachment.type,
|
||||
audio_size: attachment.size
|
||||
};
|
||||
} else if (/^video\/.+/.test(attachment.type)) {
|
||||
att = {
|
||||
...att,
|
||||
video_url: fileUrl,
|
||||
video_type: attachment.type,
|
||||
video_size: attachment.size
|
||||
};
|
||||
}
|
||||
attachments.push(att);
|
||||
|
||||
const data = EJSON.stringify({
|
||||
attachments
|
||||
});
|
||||
|
||||
return {
|
||||
algorithm: 'rc.v1.aes-sha2',
|
||||
ciphertext: await Encryption.encryptText(rid, data)
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
encryptedFile,
|
||||
getContent
|
||||
};
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return attachment;
|
||||
};
|
||||
|
||||
// Decrypt text
|
||||
decryptText = async (msg: string | ArrayBuffer) => {
|
||||
if (!msg) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
|||
import isEmpty from 'lodash/isEmpty';
|
||||
import RNFetchBlob, { FetchBlobResponse, StatefulPromise } from 'rn-fetch-blob';
|
||||
import { Alert } from 'react-native';
|
||||
import { sha256 } from 'js-sha256';
|
||||
|
||||
import { Encryption } from '../encryption';
|
||||
import { IUpload, IUser, TUploadModel } from '../../definitions';
|
||||
|
@ -45,59 +46,69 @@ export async function cancelUpload(item: TUploadModel, rid: string): Promise<voi
|
|||
}
|
||||
}
|
||||
|
||||
const createUploadRecord = async ({
|
||||
rid,
|
||||
fileInfo,
|
||||
tmid,
|
||||
isForceTryAgain
|
||||
}: {
|
||||
rid: string;
|
||||
fileInfo: IUpload;
|
||||
tmid: string | undefined;
|
||||
isForceTryAgain?: boolean;
|
||||
}) => {
|
||||
const db = database.active;
|
||||
const uploadsCollection = db.get('uploads');
|
||||
const uploadPath = getUploadPath(fileInfo.path, rid);
|
||||
let uploadRecord: TUploadModel;
|
||||
try {
|
||||
uploadRecord = await uploadsCollection.find(uploadPath);
|
||||
if (uploadRecord.id && !isForceTryAgain) {
|
||||
return Alert.alert(i18n.t('FileUpload_Error'), i18n.t('Upload_in_progress'));
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
await db.write(async () => {
|
||||
uploadRecord = await uploadsCollection.create(u => {
|
||||
u._raw = sanitizedRaw({ id: uploadPath }, uploadsCollection.schema);
|
||||
Object.assign(u, fileInfo);
|
||||
if (tmid) {
|
||||
u.tmid = tmid;
|
||||
}
|
||||
if (u.subscription) {
|
||||
u.subscription.id = rid;
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function sendFileMessage(
|
||||
rid: string,
|
||||
fileInfo: IUpload,
|
||||
tmid: string | undefined,
|
||||
server: string,
|
||||
user: Partial<Pick<IUser, 'id' | 'token'>>,
|
||||
isForceTryAgain?: boolean,
|
||||
getContent?: Function
|
||||
isForceTryAgain?: boolean
|
||||
): Promise<FetchBlobResponse | void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const { id, token } = user;
|
||||
|
||||
const uploadUrl = `${server}/api/v1/rooms.media/${rid}`;
|
||||
|
||||
fileInfo.rid = rid;
|
||||
|
||||
const db = database.active;
|
||||
const uploadsCollection = db.get('uploads');
|
||||
const uploadPath = getUploadPath(fileInfo.path, rid);
|
||||
let uploadRecord: TUploadModel;
|
||||
try {
|
||||
uploadRecord = await uploadsCollection.find(uploadPath);
|
||||
if (uploadRecord.id && !isForceTryAgain) {
|
||||
return Alert.alert(i18n.t('FileUpload_Error'), i18n.t('Upload_in_progress'));
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
await db.write(async () => {
|
||||
uploadRecord = await uploadsCollection.create(u => {
|
||||
u._raw = sanitizedRaw({ id: uploadPath }, uploadsCollection.schema);
|
||||
Object.assign(u, fileInfo);
|
||||
if (tmid) {
|
||||
u.tmid = tmid;
|
||||
}
|
||||
if (u.subscription) {
|
||||
u.subscription.id = rid;
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
return log(e);
|
||||
}
|
||||
}
|
||||
|
||||
// const encryptedFileInfo = await Encryption.encryptMessage(fileInfo);
|
||||
fileInfo.path = fileInfo.path.startsWith('file://') ? fileInfo.path.substring(7) : fileInfo.path;
|
||||
await createUploadRecord({ rid, fileInfo, tmid, isForceTryAgain });
|
||||
const encryptedFileInfo = await Encryption.encryptFile(rid, fileInfo);
|
||||
const { encryptedFile, getContent } = encryptedFileInfo;
|
||||
|
||||
const formData: IFileUpload[] = [];
|
||||
formData.push({
|
||||
name: 'file',
|
||||
type: fileInfo.type,
|
||||
filename: fileInfo.name || 'fileMessage',
|
||||
uri: fileInfo.path
|
||||
type: 'file',
|
||||
filename: sha256(fileInfo.name || 'fileMessage'),
|
||||
uri: encryptedFile
|
||||
});
|
||||
|
||||
// if (fileInfo.description) {
|
||||
|
@ -152,13 +163,12 @@ export function sendFileMessage(
|
|||
}
|
||||
return item;
|
||||
});
|
||||
const response = await RNFetchBlob.fetch('POST', uploadUrl, headers, data);
|
||||
const response = await RNFetchBlob.fetch('POST', `${server}/api/v1/rooms.media/${rid}`, headers, data);
|
||||
|
||||
const json = response.json();
|
||||
let content;
|
||||
if (getContent) {
|
||||
content = await getContent(json.file._id, json.file.url);
|
||||
console.log('🚀 ~ returnnewPromise ~ content:', content);
|
||||
}
|
||||
|
||||
const mediaConfirm = await fetch(`${server}/api/v1/rooms.mediaConfirm/${rid}/${json.file._id}`, {
|
||||
|
|
|
@ -5,9 +5,6 @@ import { Text, View } from 'react-native';
|
|||
import { connect } from 'react-redux';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import SimpleCrypto from 'react-native-simple-crypto';
|
||||
import EJSON from 'ejson';
|
||||
import { sha256 } from 'js-sha256';
|
||||
|
||||
import { IMessageComposerRef, MessageComposerContainer } from '../../containers/MessageComposer';
|
||||
import { InsideStackParamList } from '../../stacks/types';
|
||||
|
@ -38,8 +35,6 @@ import {
|
|||
import { sendFileMessage, sendMessage } from '../../lib/methods';
|
||||
import { hasPermission, isAndroid, canUploadFile, isReadOnly, isBlocked } from '../../lib/methods/helpers';
|
||||
import { RoomContext } from '../RoomView/context';
|
||||
import { Encryption } from '../../lib/encryption';
|
||||
import { bufferToB64, encryptAESCTR, exportAESCTR, generateAESCTRKey } from '../../lib/encryption/utils';
|
||||
|
||||
interface IShareViewState {
|
||||
selected: IShareAttachment;
|
||||
|
@ -257,70 +252,27 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
|||
// Send attachment
|
||||
if (attachments.length) {
|
||||
await Promise.all(
|
||||
attachments.map(async ({ filename: name, mime: type, description, size, canUpload }) => {
|
||||
attachments.map(({ filename: name, mime: type, description, size, path, canUpload }) => {
|
||||
if (!canUpload) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
try {
|
||||
const { path } = attachments[0];
|
||||
const vector = await SimpleCrypto.utils.randomBytes(16);
|
||||
const key = await generateAESCTRKey();
|
||||
const exportedKey = await exportAESCTR(key);
|
||||
const encryptedFile = await encryptAESCTR(path, exportedKey.k, bufferToB64(vector));
|
||||
|
||||
const getContent = async (_id: string, fileUrl: string) => {
|
||||
const attachments = [];
|
||||
|
||||
const attachment = {
|
||||
title: name,
|
||||
type: 'file',
|
||||
description,
|
||||
// title_link: fileUrl,
|
||||
// title_link_download: true,
|
||||
encryption: {
|
||||
key: exportedKey,
|
||||
iv: bufferToB64(vector)
|
||||
},
|
||||
image_url: fileUrl,
|
||||
image_type: type,
|
||||
image_size: size
|
||||
};
|
||||
attachments.push(attachment);
|
||||
|
||||
const data = EJSON.stringify({
|
||||
attachments
|
||||
});
|
||||
|
||||
return {
|
||||
algorithm: 'rc.v1.aes-sha2',
|
||||
ciphertext: await Encryption.encryptText(room.rid, data)
|
||||
};
|
||||
};
|
||||
|
||||
// Send the file message with the encrypted path
|
||||
return sendFileMessage(
|
||||
room.rid,
|
||||
{
|
||||
rid: room.rid,
|
||||
name: sha256(name),
|
||||
description,
|
||||
size,
|
||||
type: 'file',
|
||||
path: encryptedFile,
|
||||
store: 'Uploads',
|
||||
msg
|
||||
},
|
||||
thread?.id,
|
||||
server,
|
||||
{ id: user.id, token: user.token },
|
||||
undefined,
|
||||
getContent
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return Promise.reject(e);
|
||||
}
|
||||
return sendFileMessage(
|
||||
room.rid,
|
||||
{
|
||||
rid: room.rid,
|
||||
name,
|
||||
description,
|
||||
size,
|
||||
type,
|
||||
path,
|
||||
store: 'Uploads',
|
||||
msg
|
||||
},
|
||||
thread?.id,
|
||||
server,
|
||||
{ id: user.id, token: user.token }
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue