starting upload poc
This commit is contained in:
parent
09bc78c068
commit
fe1ea5678c
|
@ -43,6 +43,7 @@ class Encryption {
|
||||||
handshake: Function;
|
handshake: Function;
|
||||||
decrypt: Function;
|
decrypt: Function;
|
||||||
encrypt: Function;
|
encrypt: Function;
|
||||||
|
encryptText: Function;
|
||||||
encryptFile: Function;
|
encryptFile: Function;
|
||||||
decryptFile: Function;
|
decryptFile: Function;
|
||||||
encryptUpload: Function;
|
encryptUpload: Function;
|
||||||
|
@ -446,6 +447,11 @@ class Encryption {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
encryptText = async (rid: string, text: string) => {
|
||||||
|
const roomE2E = await this.getRoomInstance(rid);
|
||||||
|
return roomE2E.encryptText(text);
|
||||||
|
};
|
||||||
|
|
||||||
// Encrypt a message
|
// Encrypt a message
|
||||||
encryptMessage = async (message: IMessage | IUpload) => {
|
encryptMessage = async (message: IMessage | IUpload) => {
|
||||||
const { rid } = message;
|
const { rid } = message;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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 RNFetchBlob, { FetchBlobResponse, StatefulPromise } from 'rn-fetch-blob';
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
|
|
||||||
import { Encryption } from '../encryption';
|
import { Encryption } from '../encryption';
|
||||||
|
@ -51,13 +51,14 @@ export function sendFileMessage(
|
||||||
tmid: string | undefined,
|
tmid: string | undefined,
|
||||||
server: string,
|
server: string,
|
||||||
user: Partial<Pick<IUser, 'id' | 'token'>>,
|
user: Partial<Pick<IUser, 'id' | 'token'>>,
|
||||||
isForceTryAgain?: boolean
|
isForceTryAgain?: boolean,
|
||||||
|
getContent?: Function
|
||||||
): Promise<FetchBlobResponse | void> {
|
): Promise<FetchBlobResponse | void> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const { id, token } = user;
|
const { id, token } = user;
|
||||||
|
|
||||||
const uploadUrl = `${server}/api/v1/rooms.upload/${rid}`;
|
const uploadUrl = `${server}/api/v1/rooms.media/${rid}`;
|
||||||
|
|
||||||
fileInfo.rid = rid;
|
fileInfo.rid = rid;
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ export function sendFileMessage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedFileInfo = await Encryption.encryptMessage(fileInfo);
|
// const encryptedFileInfo = await Encryption.encryptMessage(fileInfo);
|
||||||
|
|
||||||
const formData: IFileUpload[] = [];
|
const formData: IFileUpload[] = [];
|
||||||
formData.push({
|
formData.push({
|
||||||
|
@ -99,38 +100,38 @@ export function sendFileMessage(
|
||||||
uri: fileInfo.path
|
uri: fileInfo.path
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fileInfo.description) {
|
// if (fileInfo.description) {
|
||||||
formData.push({
|
// formData.push({
|
||||||
name: 'description',
|
// name: 'description',
|
||||||
data: encryptedFileInfo.description
|
// data: encryptedFileInfo.description
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (fileInfo.msg) {
|
// if (fileInfo.msg) {
|
||||||
formData.push({
|
// formData.push({
|
||||||
name: 'msg',
|
// name: 'msg',
|
||||||
data: fileInfo.msg
|
// data: fileInfo.msg
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (tmid) {
|
// if (tmid) {
|
||||||
formData.push({
|
// formData.push({
|
||||||
name: 'tmid',
|
// name: 'tmid',
|
||||||
data: tmid
|
// data: tmid
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const { version: serverVersion } = store.getState().server;
|
// const { version: serverVersion } = store.getState().server;
|
||||||
if (encryptedFileInfo.t === E2E_MESSAGE_TYPE && compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '6.8.0')) {
|
// if (encryptedFileInfo.t === E2E_MESSAGE_TYPE && compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '6.8.0')) {
|
||||||
formData.push({
|
// formData.push({
|
||||||
name: 't',
|
// name: 't',
|
||||||
data: encryptedFileInfo.t
|
// data: encryptedFileInfo.t
|
||||||
});
|
// });
|
||||||
formData.push({
|
// formData.push({
|
||||||
name: 'e2e',
|
// name: 'e2e',
|
||||||
data: encryptedFileInfo.e2e
|
// data: encryptedFileInfo.e2e
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
...RocketChatSettings.customHeaders,
|
...RocketChatSettings.customHeaders,
|
||||||
|
@ -139,61 +140,110 @@ export function sendFileMessage(
|
||||||
'X-User-Id': id
|
'X-User-Id': id
|
||||||
};
|
};
|
||||||
|
|
||||||
uploadQueue[uploadPath] = FileUpload.fetch('POST', uploadUrl, headers, formData);
|
try {
|
||||||
|
const data = formData.map(item => {
|
||||||
uploadQueue[uploadPath].uploadProgress(async (loaded: number, total: number) => {
|
if (item.uri) {
|
||||||
try {
|
return {
|
||||||
await db.write(async () => {
|
name: item.name,
|
||||||
await uploadRecord.update(u => {
|
type: item.type,
|
||||||
u.progress = Math.floor((loaded / total) * 100);
|
filename: item.filename,
|
||||||
});
|
data: RNFetchBlob.wrap(decodeURI(item.uri))
|
||||||
});
|
};
|
||||||
} catch (e) {
|
|
||||||
log(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
} catch (e) {
|
|
||||||
log(e);
|
|
||||||
}
|
}
|
||||||
} else {
|
return item;
|
||||||
try {
|
});
|
||||||
await db.write(async () => {
|
console.log('🚀 ~ data ~ data:', data);
|
||||||
await uploadRecord.update(u => {
|
const response = await RNFetchBlob.fetch('POST', uploadUrl, headers, data);
|
||||||
u.error = true;
|
console.log(response);
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
log(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
reject(response);
|
|
||||||
} catch (e) {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
uploadQueue[uploadPath].catch(async error => {
|
const json = response.json();
|
||||||
try {
|
console.log('🚀 ~ returnnewPromise ~ json:', json);
|
||||||
await db.write(async () => {
|
|
||||||
await uploadRecord.update(u => {
|
console.log('🚀 ~ returnnewPromise ~ getContent:', getContent);
|
||||||
u.error = true;
|
let content;
|
||||||
});
|
if (getContent) {
|
||||||
});
|
content = await getContent(json.file._id, json.file.url);
|
||||||
} catch (e) {
|
console.log('🚀 ~ returnnewPromise ~ content:', content);
|
||||||
log(e);
|
|
||||||
}
|
}
|
||||||
reject(error);
|
|
||||||
});
|
const mediaConfirm = await fetch(`${server}/api/v1/rooms.mediaConfirm/${rid}/${json.file._id}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({
|
||||||
|
msg: fileInfo.msg,
|
||||||
|
tmid: fileInfo.tmid,
|
||||||
|
description: fileInfo.description,
|
||||||
|
t: fileInfo.t,
|
||||||
|
content
|
||||||
|
})
|
||||||
|
});
|
||||||
|
console.log('🚀 ~ returnnewPromise ~ mediaConfirm :', mediaConfirm);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// uploadQueue[uploadPath] = FileUpload.fetch('POST', uploadUrl, headers, formData);
|
||||||
|
|
||||||
|
// uploadQueue[uploadPath].uploadProgress(async (loaded: number, total: number) => {
|
||||||
|
// try {
|
||||||
|
// await db.write(async () => {
|
||||||
|
// await uploadRecord.update(u => {
|
||||||
|
// u.progress = Math.floor((loaded / total) * 100);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// } catch (e) {
|
||||||
|
// log(e);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// uploadQueue[uploadPath].then(async response => {
|
||||||
|
// // If response is all good...
|
||||||
|
// if (response.respInfo.status >= 200 && response.respInfo.status < 400) {
|
||||||
|
// try {
|
||||||
|
// console.log('🚀 ~ returnnewPromise ~ response:', response);
|
||||||
|
// console.log('🚀 ~ returnnewPromise ~ response:', response.data);
|
||||||
|
// // if (getContent) {
|
||||||
|
// // const content = getContent(response.json().file._id, response.json().file.url);
|
||||||
|
// // console.log('🚀 ~ returnnewPromise ~ content:', content);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// await db.write(async () => {
|
||||||
|
// await uploadRecord.destroyPermanently();
|
||||||
|
// });
|
||||||
|
// resolve(response);
|
||||||
|
// } catch (e) {
|
||||||
|
// log(e);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// try {
|
||||||
|
// await db.write(async () => {
|
||||||
|
// await uploadRecord.update(u => {
|
||||||
|
// u.error = true;
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// } catch (e) {
|
||||||
|
// log(e);
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// reject(response);
|
||||||
|
// } catch (e) {
|
||||||
|
// reject(e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// uploadQueue[uploadPath].catch(async error => {
|
||||||
|
// try {
|
||||||
|
// await db.write(async () => {
|
||||||
|
// await uploadRecord.update(u => {
|
||||||
|
// u.error = true;
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// } catch (e) {
|
||||||
|
// log(e);
|
||||||
|
// }
|
||||||
|
// reject(error);
|
||||||
|
// });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { connect } from 'react-redux';
|
||||||
import ShareExtension from 'rn-extensions-share';
|
import ShareExtension from 'rn-extensions-share';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import SimpleCrypto from 'react-native-simple-crypto';
|
import SimpleCrypto from 'react-native-simple-crypto';
|
||||||
|
import EJSON from 'ejson';
|
||||||
|
|
||||||
import { IMessageComposerRef, MessageComposerContainer } from '../../containers/MessageComposer';
|
import { IMessageComposerRef, MessageComposerContainer } from '../../containers/MessageComposer';
|
||||||
import { InsideStackParamList } from '../../stacks/types';
|
import { InsideStackParamList } from '../../stacks/types';
|
||||||
|
@ -37,7 +38,15 @@ import { sendFileMessage, sendMessage } from '../../lib/methods';
|
||||||
import { hasPermission, isAndroid, canUploadFile, isReadOnly, isBlocked } from '../../lib/methods/helpers';
|
import { hasPermission, isAndroid, canUploadFile, isReadOnly, isBlocked } from '../../lib/methods/helpers';
|
||||||
import { RoomContext } from '../RoomView/context';
|
import { RoomContext } from '../RoomView/context';
|
||||||
import { Encryption } from '../../lib/encryption';
|
import { Encryption } from '../../lib/encryption';
|
||||||
import { b64URIToBuffer, decryptAESCTR, encryptAESCTR, exportAESCTR, generateAESCTRKey } from '../../lib/encryption/utils';
|
import {
|
||||||
|
Base64,
|
||||||
|
b64URIToBuffer,
|
||||||
|
bufferToB64,
|
||||||
|
decryptAESCTR,
|
||||||
|
encryptAESCTR,
|
||||||
|
exportAESCTR,
|
||||||
|
generateAESCTRKey
|
||||||
|
} from '../../lib/encryption/utils';
|
||||||
|
|
||||||
interface IShareViewState {
|
interface IShareViewState {
|
||||||
selected: IShareAttachment;
|
selected: IShareAttachment;
|
||||||
|
@ -252,64 +261,101 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { path } = attachments[0];
|
// Send attachment
|
||||||
const vector = await SimpleCrypto.utils.randomBytes(16);
|
if (attachments.length) {
|
||||||
const key = await generateAESCTRKey();
|
console.log('🚀 ~ ShareView ~ send= ~ attachments:', attachments);
|
||||||
|
await Promise.all(
|
||||||
|
attachments.map(async ({ filename: name, mime: type, description, size, canUpload }) => {
|
||||||
|
if (!canUpload) {
|
||||||
|
return Promise.resolve(); // Resolve immediately if upload is not allowed
|
||||||
|
}
|
||||||
|
|
||||||
const exportedKey = exportAESCTR(key);
|
try {
|
||||||
console.log('🚀 ~ ShareView ~ send= ~ exportedKey:', exportedKey, exportedKey.k);
|
const { path } = attachments[0]; // Consider if you need a specific attachment or iterate over each
|
||||||
|
const vector = await SimpleCrypto.utils.randomBytes(16);
|
||||||
|
const key = await generateAESCTRKey();
|
||||||
|
|
||||||
const exportedKeyArrayBuffer = b64URIToBuffer(exportedKey.k);
|
const exportedKey = await exportAESCTR(key);
|
||||||
console.log('🚀 ~ ShareView ~ send= ~ exportedKeyArrayBuffer:', exportedKeyArrayBuffer);
|
console.log('🚀 ~ ShareView ~ send= ~ exportedKey:', exportedKey, exportedKey.k);
|
||||||
|
|
||||||
const encryptedFile = await encryptAESCTR(path, exportedKeyArrayBuffer, vector);
|
const exportedKeyArrayBuffer = b64URIToBuffer(exportedKey.k);
|
||||||
console.log('🚀 ~ ShareView ~ send= ~ encryptedFile:', encryptedFile);
|
console.log('🚀 ~ ShareView ~ send= ~ exportedKeyArrayBuffer:', exportedKeyArrayBuffer);
|
||||||
|
|
||||||
const decryptedFile = await decryptAESCTR(encryptedFile, exportedKeyArrayBuffer, vector);
|
const encryptedFile = await encryptAESCTR(path, exportedKeyArrayBuffer, vector);
|
||||||
console.log('🚀 ~ ShareView ~ send= ~ decryptedFile:', decryptedFile);
|
console.log('🚀 ~ ShareView ~ send= ~ encryptedFile:', encryptedFile);
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
const decryptedFile = await decryptAESCTR(encryptedFile, exportedKeyArrayBuffer, vector);
|
||||||
|
console.log('🚀 ~ ShareView ~ send= ~ decryptedFile:', decryptedFile);
|
||||||
|
|
||||||
|
const getContent = async (_id: string, fileUrl: string) => {
|
||||||
|
console.log('🚀 ~ ShareView ~ getContent ~ _id:', _id, fileUrl);
|
||||||
|
const attachments = [];
|
||||||
|
console.log('🚀 ~ ShareView ~ getContent ~ attachment.encryption.exportedKey:', vector, exportedKey);
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
console.log('🚀 ~ ShareView ~ getContent ~ attachments:', attachments, data);
|
||||||
|
|
||||||
|
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,
|
||||||
|
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); // Ensure that errors are propagated
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Send text message
|
||||||
|
} else if (text.length) {
|
||||||
|
await sendMessage(room.rid, text, thread?.id, { id: user.id, token: user.token } as IUser);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
if (!this.isShareExtension) {
|
||||||
|
const text = this.messageComposerRef.current?.getText();
|
||||||
|
this.finishShareView(text, this.state.selectedMessages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try {
|
|
||||||
// // Send attachment
|
|
||||||
// if (attachments.length) {
|
|
||||||
// console.log('🚀 ~ ShareView ~ send= ~ attachments:', attachments);
|
|
||||||
// await Promise.all(
|
|
||||||
// attachments.map(async ({ filename: name, mime: type, description, size, path, canUpload }) => {
|
|
||||||
// if (canUpload) {
|
|
||||||
// return sendFileMessage(
|
|
||||||
// room.rid,
|
|
||||||
// {
|
|
||||||
// rid: room.rid,
|
|
||||||
// name,
|
|
||||||
// description,
|
|
||||||
// size,
|
|
||||||
// type,
|
|
||||||
// path,
|
|
||||||
// store: 'Uploads',
|
|
||||||
// msg
|
|
||||||
// },
|
|
||||||
// thread?.id,
|
|
||||||
// server,
|
|
||||||
// { id: user.id, token: user.token }
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// return Promise.resolve();
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Send text message
|
|
||||||
// } else if (text.length) {
|
|
||||||
// await sendMessage(room.rid, text, thread?.id, { id: user.id, token: user.token } as IUser);
|
|
||||||
// }
|
|
||||||
// } catch {
|
|
||||||
// if (!this.isShareExtension) {
|
|
||||||
// const text = this.messageComposerRef.current?.getText();
|
|
||||||
// this.finishShareView(text, this.state.selectedMessages);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if it's share extension this should close
|
// if it's share extension this should close
|
||||||
if (this.isShareExtension) {
|
if (this.isShareExtension) {
|
||||||
sendLoadingEvent({ visible: false });
|
sendLoadingEvent({ visible: false });
|
||||||
|
|
Loading…
Reference in New Issue