mirror of
https://github.com/balzack/databag.git
synced 2025-04-22 17:45:18 +00:00
encrypt and upload asset slices
This commit is contained in:
parent
e388d9ba42
commit
7782ace9c4
@ -56,6 +56,27 @@ export function updateChannelSubject(subject, contentKey) {
|
||||
return { subjectEncrypted, subjectIv };
|
||||
}
|
||||
|
||||
export function encryptBlock(block, contentKey) {
|
||||
const key = CryptoJS.enc.Hex.parse(contentKey);
|
||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
const encrypted = CryptoJS.AES.encrypt(block, key, { iv: iv });
|
||||
const blockEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
|
||||
const blockIv = iv.toString();
|
||||
|
||||
return { blockEncrypted, blockIv };
|
||||
}
|
||||
|
||||
export function decryptBlock(blockEncrypted, blockIv, contentKey) {
|
||||
const iv = CryptoJS.enc.Hex.parse(blockIv);
|
||||
const key = CryptoJS.enc.Hex.parse(contentKey);
|
||||
const enc = CryptoJS.enc.Base64.parse(blockEncrypted);
|
||||
const cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
|
||||
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
|
||||
const block = dec.toString(CryptoJS.enc.Utf8);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
export function decryptChannelSubject(subject, contentKey) {
|
||||
const { subjectEncrypted, subjectIv } = JSON.parse(subject);
|
||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { useState, useRef } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
const ENCRYPTED_BLOCK_SIZE = (128 * 1024); //110k
|
||||
|
||||
export function useUploadContext() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
@ -69,7 +71,8 @@ export function useUploadContext() {
|
||||
const controller = new AbortController();
|
||||
const entry = {
|
||||
index: index.current,
|
||||
url: `${host}/content/channels/${channelId}/topics/${topicId}/assets?contact=${token}`,
|
||||
baseUrl: `${host}/content/channels/${channelId}/topics/${topicId}/`,
|
||||
urlParams: `?contact=${token}`,
|
||||
files,
|
||||
assets: [],
|
||||
current: null,
|
||||
@ -91,7 +94,8 @@ export function useUploadContext() {
|
||||
const controller = new AbortController();
|
||||
const entry = {
|
||||
index: index.current,
|
||||
url: `/content/channels/${channelId}/topics/${topicId}/assets?agent=${token}`,
|
||||
baseUrl: `/content/channels/${channelId}/topics/${topicId}/`,
|
||||
urlParams: `?agent=${token}`,
|
||||
files,
|
||||
assets: [],
|
||||
current: null,
|
||||
@ -154,11 +158,33 @@ async function upload(entry, update, complete) {
|
||||
const file = entry.files.shift();
|
||||
entry.active = {};
|
||||
try {
|
||||
if (file.image) {
|
||||
if (file.encrypted) {
|
||||
const { size, getThumb, getEncryptedBlock, position } = file;
|
||||
const type = file.image ? 'image' : file.video ? 'video' : file.audio ? 'audio' : '';
|
||||
const thumb = getThumb(position);
|
||||
const parts = [];
|
||||
for (let pos = 0; pos < size; pos += ENCRYPTED_BLOCK_SIZE) {
|
||||
const { blockEncrypted, blockIv } = await getEncryptedBlock(pos, ENCRYPTED_BLOCK_SIZE);
|
||||
const partId = await axios.post(`${entry.baseUrl}block${entry.urlParams}`, blockEncrypted, {
|
||||
signal: entry.cancel.signal,
|
||||
onUploadProgress: (ev) => {
|
||||
const { loaded, total } = ev;
|
||||
const partLoaded = pos + Math.floor(blockEncrypted.length * loaded / total);
|
||||
entry.active = { partLoaded, size }
|
||||
update();
|
||||
}
|
||||
});
|
||||
parts.push({ blockIv, partId });
|
||||
}
|
||||
entry.assets.push({
|
||||
encrypted: { type, thumb, parts }
|
||||
});
|
||||
}
|
||||
else if (file.image) {
|
||||
const formData = new FormData();
|
||||
formData.append('asset', file.image);
|
||||
let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "ilg;photo"]));
|
||||
let asset = await axios.post(`${entry.url}&transforms=${transform}`, formData, {
|
||||
let asset = await axios.post(`${entry.baseUrl}assets${entry.urlParams}&transforms=${transform}`, formData, {
|
||||
signal: entry.cancel.signal,
|
||||
onUploadProgress: (ev) => {
|
||||
const { loaded, total } = ev;
|
||||
@ -178,7 +204,7 @@ async function upload(entry, update, complete) {
|
||||
formData.append('asset', file.video);
|
||||
let thumb = 'vthumb;video;' + file.position;
|
||||
let transform = encodeURIComponent(JSON.stringify(["vlq;video", "vhd;video", thumb]));
|
||||
let asset = await axios.post(`${entry.url}&transforms=${transform}`, formData, {
|
||||
let asset = await axios.post(`${entry.baseUrl}assets${entry.urlParams}&transforms=${transform}`, formData, {
|
||||
signal: entry.cancel.signal,
|
||||
onUploadProgress: (ev) => {
|
||||
const { loaded, total } = ev;
|
||||
@ -198,7 +224,7 @@ async function upload(entry, update, complete) {
|
||||
const formData = new FormData();
|
||||
formData.append('asset', file.audio);
|
||||
let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
|
||||
let asset = await axios.post(`${entry.url}&transforms=${transform}`, formData, {
|
||||
let asset = await axios.post(`${entry.baseUrl}assets${entry.urlParams}&transforms=${transform}`, formData, {
|
||||
signal: entry.cancel.signal,
|
||||
onUploadProgress: (ev) => {
|
||||
const { loaded, total } = ev;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useContext, useState, useRef, useEffect } from 'react';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { encryptTopicSubject } from 'context/sealUtil';
|
||||
import { encryptBlock, encryptTopicSubject } from 'context/sealUtil';
|
||||
import Resizer from "react-image-file-resizer";
|
||||
|
||||
export function useAddTopic(contentKey) {
|
||||
@ -64,20 +64,48 @@ export function useAddTopic(contentKey) {
|
||||
updateState({ enableImage, enableAudio, enableVideo });
|
||||
}, [conversation.state.channel?.data?.channelDetail]);
|
||||
|
||||
const setUrl = async (url, getThumb) => {
|
||||
if (contentKey) {
|
||||
const buffer = await url.arrayBuffer();
|
||||
const getEncryptedBlock = (pos, len) => {
|
||||
if (pos + len > buffer.byteLen) {
|
||||
return null;
|
||||
}
|
||||
const block = btoa(String.fromCharCode.apply(null, buffer.slice(pos, len)));
|
||||
return getEncryptedBlock(block, contentKey);
|
||||
}
|
||||
return { url, position: 0, label: '', encrypted: true, size: buffer.byteLength, getEncryptedBlock, getThumb };
|
||||
}
|
||||
else {
|
||||
return { url, position: 0, label: '', encrypted: false };
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
addImage: async (image) => {
|
||||
let url = URL.createObjectURL(image);
|
||||
addAsset({ image, url });
|
||||
const url = URL.createObjectURL(image);
|
||||
objects.current.push(url);
|
||||
const getThumb = async () => {
|
||||
return await getImageThumb(url);
|
||||
}
|
||||
const asset = setUrl(url, getThumb);
|
||||
addAsset({ image, ...asset });
|
||||
},
|
||||
addVideo: async (video) => {
|
||||
let url = URL.createObjectURL(video);
|
||||
addAsset({ video, url, position: 0 })
|
||||
const url = URL.createObjectURL(video);
|
||||
objects.current.push(url);
|
||||
const getThumb = async (position) => {
|
||||
return await getVideoThumb(url, position);
|
||||
}
|
||||
const asset = setUrl(url, getThumb);
|
||||
addAsset({ video, ...asset });
|
||||
},
|
||||
addAudio: (audio) => {
|
||||
let url = URL.createObjectURL(audio);
|
||||
addAsset({ audio, url, label: '' })
|
||||
addAudio: async (audio) => {
|
||||
const url = URL.createObjectURL(audio);
|
||||
objects.current.push(url);
|
||||
const getThumb = async () => { return null };
|
||||
const asset = setUrl(url, getThumb);
|
||||
addAsset({ audio, ...asset });
|
||||
},
|
||||
setLabel: (index, label) => {
|
||||
updateAsset(index, { label });
|
||||
@ -103,32 +131,19 @@ export function useAddTopic(contentKey) {
|
||||
updateState({ busy: true });
|
||||
const type = contentKey ? 'sealedtopic' : 'superbasictopic';
|
||||
const message = (assets) => {
|
||||
if (contentKey) {
|
||||
if (assets?.length) {
|
||||
console.log('assets not yet supported on sealed channels');
|
||||
}
|
||||
const message = {
|
||||
if (assets?.length) {
|
||||
return {
|
||||
assets,
|
||||
text: state.messageText,
|
||||
textColor: state.textColorSet ? state.textColor : null,
|
||||
textSize: state.textSizeSet ? state.textSize : null,
|
||||
}
|
||||
return encryptTopicSubject({ message }, contentKey);
|
||||
}
|
||||
else {
|
||||
if (assets?.length) {
|
||||
return {
|
||||
assets,
|
||||
text: state.messageText,
|
||||
textColor: state.textColorSet ? state.textColor : null,
|
||||
textSize: state.textSizeSet ? state.textSize : null,
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
text: state.messageText,
|
||||
textColor: state.textColorSet ? state.textColor : null,
|
||||
textSize: state.textSizeSet ? state.textSize : null,
|
||||
}
|
||||
return {
|
||||
text: state.messageText,
|
||||
textColor: state.textColorSet ? state.textColor : null,
|
||||
textSize: state.textSizeSet ? state.textSize : null,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user