mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
unsealing messages in sealed conversation in webapp
This commit is contained in:
parent
c44bf282de
commit
faca16f748
@ -1,6 +1,6 @@
|
|||||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
export async function addChannelTopic(token, channelId, message, assets ): string {
|
export async function addChannelTopic(token, channelId, datatype, message, assets ): string {
|
||||||
|
|
||||||
if (message == null && (assets == null || assets.length === 0)) {
|
if (message == null && (assets == null || assets.length === 0)) {
|
||||||
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
|
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
|
||||||
@ -12,7 +12,7 @@ export async function addChannelTopic(token, channelId, message, assets ): strin
|
|||||||
else if (assets == null || assets.length === 0) {
|
else if (assets == null || assets.length === 0) {
|
||||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||||
if (value !== null) return value
|
if (value !== null) return value
|
||||||
}), datatype: 'superbasictopic' };
|
}), datatype };
|
||||||
|
|
||||||
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}&confirm=true`,
|
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}&confirm=true`,
|
||||||
{ method: 'POST', body: JSON.stringify(subject) });
|
{ method: 'POST', body: JSON.stringify(subject) });
|
||||||
@ -78,7 +78,7 @@ export async function addChannelTopic(token, channelId, message, assets ): strin
|
|||||||
|
|
||||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||||
if (value !== null) return value
|
if (value !== null) return value
|
||||||
}), datatype: 'superbasictopic' };
|
}), datatype };
|
||||||
|
|
||||||
let unconfirmed = await fetchWithTimeout(`/content/channels/${channelId}/topics/${slot.id}/subject?agent=${token}`,
|
let unconfirmed = await fetchWithTimeout(`/content/channels/${channelId}/topics/${slot.id}/subject?agent=${token}`,
|
||||||
{ method: 'PUT', body: JSON.stringify(subject) });
|
{ method: 'PUT', body: JSON.stringify(subject) });
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
export async function addContactChannelTopic(server, token, channelId, message, assets ) {
|
export async function addContactChannelTopic(server, token, channelId, datatype, message, assets ) {
|
||||||
let host = "";
|
let host = "";
|
||||||
if (server) {
|
if (server) {
|
||||||
host = `https://${server}`
|
host = `https://${server}`
|
||||||
@ -16,7 +16,7 @@ export async function addContactChannelTopic(server, token, channelId, message,
|
|||||||
else if (assets == null || assets.length === 0) {
|
else if (assets == null || assets.length === 0) {
|
||||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||||
if (value !== null) return value
|
if (value !== null) return value
|
||||||
}), datatype: 'superbasictopic' };
|
}), datatype };
|
||||||
|
|
||||||
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}&confirm=true`,
|
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}&confirm=true`,
|
||||||
{ method: 'POST', body: JSON.stringify(subject) });
|
{ method: 'POST', body: JSON.stringify(subject) });
|
||||||
@ -81,7 +81,7 @@ export async function addContactChannelTopic(server, token, channelId, message,
|
|||||||
|
|
||||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||||
if (value !== null) return value
|
if (value !== null) return value
|
||||||
}), datatype: 'superbasictopic' };
|
}), datatype };
|
||||||
|
|
||||||
let unconfirmed = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${slot.id}/subject?contact=${token}`,
|
let unconfirmed = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${slot.id}/subject?contact=${token}`,
|
||||||
{ method: 'PUT', body: JSON.stringify(subject) });
|
{ method: 'PUT', body: JSON.stringify(subject) });
|
||||||
|
@ -332,7 +332,7 @@ export function useCardContext() {
|
|||||||
let token = cardProfile.guid + '.' + cardDetail.token;
|
let token = cardProfile.guid + '.' + cardDetail.token;
|
||||||
let node = cardProfile.node;
|
let node = cardProfile.node;
|
||||||
if (files?.length) {
|
if (files?.length) {
|
||||||
const topicId = await addContactChannelTopic(node, token, channelId, null, null);
|
const topicId = await addContactChannelTopic(node, token, channelId, null, null, null);
|
||||||
upload.actions.addContactTopic(node, token, cardId, channelId, topicId, files, async (assets) => {
|
upload.actions.addContactTopic(node, token, cardId, channelId, topicId, files, async (assets) => {
|
||||||
message.assets = assets;
|
message.assets = assets;
|
||||||
await setContactChannelTopicSubject(node, token, channelId, topicId, message);
|
await setContactChannelTopicSubject(node, token, channelId, topicId, message);
|
||||||
@ -346,7 +346,7 @@ export function useCardContext() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await addContactChannelTopic(node, token, channelId, message, files);
|
await addContactChannelTopic(node, token, channelId, 'superbasictopic', message, files);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
resync.current.push(cardId);
|
resync.current.push(cardId);
|
||||||
@ -356,6 +356,17 @@ export function useCardContext() {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addSealedChannelTopic: async (cardId, channelId, sealKey, message) => {
|
||||||
|
let { cardProfile, cardDetail } = cards.current.get(cardId).data;
|
||||||
|
let token = cardProfile.guid + '.' + cardDetail.token;
|
||||||
|
let node = cardProfile.node;
|
||||||
|
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const key = CryptoJS.enc.Hex.parse(sealKey);
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ message }), key, { iv: iv });
|
||||||
|
const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
|
||||||
|
const messageIv = iv.toString();
|
||||||
|
await addContactChannelTopic(node, token, channelId, 'sealedtopic', { messageEncrypted, messageIv });
|
||||||
|
},
|
||||||
getChannel: (cardId, channelId) => {
|
getChannel: (cardId, channelId) => {
|
||||||
let card = cards.current.get(cardId);
|
let card = cards.current.get(cardId);
|
||||||
let channel = card.channels.get(channelId);
|
let channel = card.channels.get(channelId);
|
||||||
|
@ -202,7 +202,7 @@ export function useChannelContext() {
|
|||||||
},
|
},
|
||||||
addChannelTopic: async (channelId, message, files) => {
|
addChannelTopic: async (channelId, message, files) => {
|
||||||
if (files?.length) {
|
if (files?.length) {
|
||||||
const topicId = await addChannelTopic(access.current, channelId, null, null);
|
const topicId = await addChannelTopic(access.current, channelId, null, null, null);
|
||||||
upload.actions.addTopic(access.current, channelId, topicId, files, async (assets) => {
|
upload.actions.addTopic(access.current, channelId, topicId, files, async (assets) => {
|
||||||
message.assets = assets;
|
message.assets = assets;
|
||||||
await setChannelTopicSubject(access.current, channelId, topicId, message);
|
await setChannelTopicSubject(access.current, channelId, topicId, message);
|
||||||
@ -216,7 +216,7 @@ export function useChannelContext() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await addChannelTopic(access.current, channelId, message, files);
|
await addChannelTopic(access.current, channelId, 'superbasictopic', message, files);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await setChannels(null);
|
await setChannels(null);
|
||||||
@ -225,6 +225,14 @@ export function useChannelContext() {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addSealedChannelTopic: async (channelId, sealKey, message) => {
|
||||||
|
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const key = CryptoJS.enc.Hex.parse(sealKey);
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ message }), key, { iv: iv });
|
||||||
|
const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
|
||||||
|
const messageIv = iv.toString();
|
||||||
|
await addChannelTopic(access.current, channelId, 'sealedtopic', { messageEncrypted, messageIv });
|
||||||
|
},
|
||||||
getChannel: (channelId) => {
|
getChannel: (channelId) => {
|
||||||
return channels.current.get(channelId);
|
return channels.current.get(channelId);
|
||||||
},
|
},
|
||||||
|
@ -2,6 +2,8 @@ import { useEffect, useState, useRef, useContext } from 'react';
|
|||||||
import { ProfileContext } from 'context/ProfileContext';
|
import { ProfileContext } from 'context/ProfileContext';
|
||||||
import { CardContext } from 'context/CardContext';
|
import { CardContext } from 'context/CardContext';
|
||||||
import { ChannelContext } from 'context/ChannelContext';
|
import { ChannelContext } from 'context/ChannelContext';
|
||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
import { JSEncrypt } from 'jsencrypt'
|
||||||
|
|
||||||
export function useConversationContext() {
|
export function useConversationContext() {
|
||||||
const TOPIC_BATCH = 32;
|
const TOPIC_BATCH = 32;
|
||||||
@ -22,6 +24,7 @@ export function useConversationContext() {
|
|||||||
enabelAudio: null,
|
enabelAudio: null,
|
||||||
enableVideo: null,
|
enableVideo: null,
|
||||||
sealed: false,
|
sealed: false,
|
||||||
|
seals: null,
|
||||||
image: null,
|
image: null,
|
||||||
logoUrl: null,
|
logoUrl: null,
|
||||||
logoImg: null,
|
logoImg: null,
|
||||||
@ -55,6 +58,18 @@ export function useConversationContext() {
|
|||||||
setState((s) => ({ ...s, ...value }));
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSeals = (conversation) => {
|
||||||
|
try {
|
||||||
|
if (conversation.data.channelDetail.dataType === 'sealed') {
|
||||||
|
return JSON.parse(conversation.data.channelDetail.data).seals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const getSubject = (conversation) => {
|
const getSubject = (conversation) => {
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
return null;
|
return null;
|
||||||
@ -160,11 +175,13 @@ export function useConversationContext() {
|
|||||||
if(topic.data.topicDetail) {
|
if(topic.data.topicDetail) {
|
||||||
cur.data.topicDetail = topic.data.topicDetail;
|
cur.data.topicDetail = topic.data.topicDetail;
|
||||||
cur.data.detailRevision = topic.data.detailRevision;
|
cur.data.detailRevision = topic.data.detailRevision;
|
||||||
|
cur.data.unsealedMessage = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let slot = await getTopic(topic.id);
|
let slot = await getTopic(topic.id);
|
||||||
cur.data.topicDetail = slot.data.topicDetail;
|
cur.data.topicDetail = slot.data.topicDetail;
|
||||||
cur.data.detailRevision = slot.data.detailRevision;
|
cur.data.detailRevision = slot.data.detailRevision;
|
||||||
|
cur.data.unsealedMessage = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur.revision = topic.revision;
|
cur.revision = topic.revision;
|
||||||
@ -212,6 +229,7 @@ export function useConversationContext() {
|
|||||||
let contacts = getContacts(chan);
|
let contacts = getContacts(chan);
|
||||||
let subject = getSubject(chan);
|
let subject = getSubject(chan);
|
||||||
let members = getMembers(chan);
|
let members = getMembers(chan);
|
||||||
|
const seals = getSeals(chan);
|
||||||
const enableImage = chan?.data?.channelDetail?.enableImage;
|
const enableImage = chan?.data?.channelDetail?.enableImage;
|
||||||
const enableAudio = chan?.data?.channelDetail?.enableAudio;
|
const enableAudio = chan?.data?.channelDetail?.enableAudio;
|
||||||
const enableVideo = chan?.data?.channelDetail?.enableVideo;
|
const enableVideo = chan?.data?.channelDetail?.enableVideo;
|
||||||
@ -237,6 +255,7 @@ export function useConversationContext() {
|
|||||||
init: true,
|
init: true,
|
||||||
error: false,
|
error: false,
|
||||||
sealed,
|
sealed,
|
||||||
|
seals,
|
||||||
subject,
|
subject,
|
||||||
logoImg,
|
logoImg,
|
||||||
logoUrl,
|
logoUrl,
|
||||||
@ -337,6 +356,23 @@ export function useConversationContext() {
|
|||||||
return await channel.actions.removeChannel(channelId);
|
return await channel.actions.removeChannel(channelId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
unsealTopic: async (topicId, sealKey) => {
|
||||||
|
try {
|
||||||
|
const topic = topics.current.get(topicId);
|
||||||
|
const { messageEncrypted, messageIv } = JSON.parse(topic.data.topicDetail.data);
|
||||||
|
const iv = CryptoJS.enc.Hex.parse(messageIv);
|
||||||
|
const key = CryptoJS.enc.Hex.parse(sealKey);
|
||||||
|
const enc = CryptoJS.enc.Base64.parse(messageEncrypted);
|
||||||
|
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
|
||||||
|
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
|
||||||
|
topic.data.unsealedMessage = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||||
|
topics.current.set(topicId, topic);
|
||||||
|
updateState({ topics: topics.current });
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
removeTopic: async (topicId) => {
|
removeTopic: async (topicId) => {
|
||||||
const { cardId, channelId } = channelView.current;
|
const { cardId, channelId } = channelView.current;
|
||||||
if (cardId) {
|
if (cardId) {
|
||||||
|
@ -14,7 +14,7 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
|
|||||||
const thread = useRef(null);
|
const thread = useRef(null);
|
||||||
|
|
||||||
const topicRenderer = (topic) => {
|
const topicRenderer = (topic) => {
|
||||||
return (<TopicItem host={cardId == null} topic={topic} />)
|
return (<TopicItem host={cardId == null} topic={topic} sealKey={state.sealKey} />)
|
||||||
}
|
}
|
||||||
|
|
||||||
// an unfortunate cludge for the mobile browser
|
// an unfortunate cludge for the mobile browser
|
||||||
@ -107,7 +107,9 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="topic">
|
<div class="topic">
|
||||||
<AddTopic cardId={cardId} channelId={channelId} />
|
{ (!state.sealed || state.sealKey) && (
|
||||||
|
<AddTopic cardId={cardId} channelId={channelId} sealed={state.sealed} sealKey={state.sealKey} />
|
||||||
|
)}
|
||||||
{ state.uploadError && (
|
{ state.uploadError && (
|
||||||
<div class="upload-error">
|
<div class="upload-error">
|
||||||
{ state.display === 'small' && (
|
{ state.display === 'small' && (
|
||||||
|
@ -8,7 +8,7 @@ import { AudioFile } from './audioFile/AudioFile';
|
|||||||
import { VideoFile } from './videoFile/VideoFile';
|
import { VideoFile } from './videoFile/VideoFile';
|
||||||
import { Carousel } from 'carousel/Carousel';
|
import { Carousel } from 'carousel/Carousel';
|
||||||
|
|
||||||
export function AddTopic({ cardId, channelId }) {
|
export function AddTopic({ cardId, channelId, sealed, sealKey }) {
|
||||||
|
|
||||||
const { state, actions } = useAddTopic(cardId, channelId);
|
const { state, actions } = useAddTopic(cardId, channelId);
|
||||||
const attachImage = useRef(null);
|
const attachImage = useRef(null);
|
||||||
@ -26,7 +26,7 @@ export function AddTopic({ cardId, channelId }) {
|
|||||||
const addTopic = async () => {
|
const addTopic = async () => {
|
||||||
if (state.messageText || state.assets.length) {
|
if (state.messageText || state.assets.length) {
|
||||||
try {
|
try {
|
||||||
await actions.addTopic();
|
await actions.addTopic(sealed, sealKey);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -83,7 +83,7 @@ export function useAddTopic(cardId, channelId) {
|
|||||||
setTextSize: (value) => {
|
setTextSize: (value) => {
|
||||||
updateState({ textSizeSet: true, textSize: value });
|
updateState({ textSizeSet: true, textSize: value });
|
||||||
},
|
},
|
||||||
addTopic: async () => {
|
addTopic: async (sealed, sealKey) => {
|
||||||
if (!state.busy) {
|
if (!state.busy) {
|
||||||
try {
|
try {
|
||||||
updateState({ busy: true });
|
updateState({ busy: true });
|
||||||
@ -93,11 +93,21 @@ export function useAddTopic(cardId, channelId) {
|
|||||||
textSize: state.textSizeSet ? state.textSize : null,
|
textSize: state.textSizeSet ? state.textSize : null,
|
||||||
};
|
};
|
||||||
if (cardId) {
|
if (cardId) {
|
||||||
|
if (sealed) {
|
||||||
|
await card.actions.addSealedChannelTopic(cardId, channelId, sealKey, message, state.assets);
|
||||||
|
}
|
||||||
|
else {
|
||||||
await card.actions.addChannelTopic(cardId, channelId, message, state.assets);
|
await card.actions.addChannelTopic(cardId, channelId, message, state.assets);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (sealed) {
|
||||||
|
await channel.actions.addSealedChannelTopic(channelId, sealKey, message, state.assets);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
await channel.actions.addChannelTopic(channelId, message, state.assets);
|
await channel.actions.addChannelTopic(channelId, message, state.assets);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
updateState({ busy: false, messageText: null, textColor: '#444444', textColorSet: false,
|
updateState({ busy: false, messageText: null, textColor: '#444444', textColorSet: false,
|
||||||
textSize: 12, textSizeSet: false, assets: [] });
|
textSize: 12, textSizeSet: false, assets: [] });
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import { Space, Skeleton, Button, Modal, Input } from 'antd';
|
|||||||
import { ExclamationCircleOutlined, DeleteOutlined, EditOutlined, FireOutlined, PictureOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined, DeleteOutlined, EditOutlined, FireOutlined, PictureOutlined } from '@ant-design/icons';
|
||||||
import { Carousel } from 'carousel/Carousel';
|
import { Carousel } from 'carousel/Carousel';
|
||||||
|
|
||||||
export function TopicItem({ host, topic }) {
|
export function TopicItem({ host, topic, sealKey }) {
|
||||||
|
|
||||||
const { state, actions } = useTopicItem(topic);
|
const { state, actions } = useTopicItem(topic, sealKey);
|
||||||
|
|
||||||
let name = state.name ? state.name : state.handle;
|
let name = state.name ? state.name : state.handle;
|
||||||
let nameClass = state.name ? 'set' : 'unset';
|
let nameClass = state.name ? 'set' : 'unset';
|
||||||
@ -76,7 +76,7 @@ export function TopicItem({ host, topic }) {
|
|||||||
if (state.editing) {
|
if (state.editing) {
|
||||||
return (
|
return (
|
||||||
<div class="editing">
|
<div class="editing">
|
||||||
<Input.TextArea defaultValue={state.message?.text} placeholder="message"
|
<Input.TextArea defaultValue={state.text} placeholder="message"
|
||||||
style={{ resize: 'none', color: state.textColor, fontSize: state.textSize }}
|
style={{ resize: 'none', color: state.textColor, fontSize: state.textSize }}
|
||||||
onChange={(e) => actions.setEdit(e.target.value)} rows={3} bordered={false}/>
|
onChange={(e) => actions.setEdit(e.target.value)} rows={3} bordered={false}/>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
@ -88,7 +88,7 @@ export function TopicItem({ host, topic }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <div style={{ color: state.textColor, fontSize: state.textSize }}>{ state.message?.text }</div>
|
return <div style={{ color: state.textColor, fontSize: state.textSize }}>{ state.text }</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -103,9 +103,11 @@ export function TopicItem({ host, topic }) {
|
|||||||
<div class={nameClass}>{ name }</div>
|
<div class={nameClass}>{ name }</div>
|
||||||
<div>{ state.created }</div>
|
<div>{ state.created }</div>
|
||||||
</div>
|
</div>
|
||||||
|
{ !state.sealed && (
|
||||||
<div class="topic-options">
|
<div class="topic-options">
|
||||||
<Options />
|
<Options />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{ !state.confirmed && (
|
{ !state.confirmed && (
|
||||||
<div class="skeleton">
|
<div class="skeleton">
|
||||||
@ -130,7 +132,12 @@ export function TopicItem({ host, topic }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div class="message">
|
<div class="message">
|
||||||
|
{ !state.sealed && (
|
||||||
<Message />
|
<Message />
|
||||||
|
)}
|
||||||
|
{ state.sealed && (
|
||||||
|
<div class="sealed-message">sealed message</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -81,6 +81,11 @@ export const TopicItemWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sealed-message {
|
||||||
|
font-style: italic;
|
||||||
|
color: #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
.asset-placeholder {
|
.asset-placeholder {
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
|
@ -3,14 +3,14 @@ import { ConversationContext } from 'context/ConversationContext';
|
|||||||
import { ProfileContext } from 'context/ProfileContext';
|
import { ProfileContext } from 'context/ProfileContext';
|
||||||
import { CardContext } from 'context/CardContext';
|
import { CardContext } from 'context/CardContext';
|
||||||
|
|
||||||
export function useTopicItem(topic) {
|
export function useTopicItem(topic, sealKey) {
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
init: false,
|
init: false,
|
||||||
name: null,
|
name: null,
|
||||||
handle: null,
|
handle: null,
|
||||||
imageUrl: null,
|
imageUrl: null,
|
||||||
message: null,
|
text: null,
|
||||||
created: null,
|
created: null,
|
||||||
confirmed: false,
|
confirmed: false,
|
||||||
ready: false,
|
ready: false,
|
||||||
@ -39,6 +39,7 @@ export function useTopicItem(topic) {
|
|||||||
owner = true;
|
owner = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let text = null;
|
||||||
let textColor = '#444444';
|
let textColor = '#444444';
|
||||||
let textSize = 14;
|
let textSize = 14;
|
||||||
|
|
||||||
@ -47,16 +48,19 @@ export function useTopicItem(topic) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { status, transform, data } = topic.data.topicDetail;
|
const { status, transform, data, dataType } = topic.data.topicDetail;
|
||||||
let message;
|
let message;
|
||||||
|
let sealed = false;
|
||||||
let ready = false;
|
let ready = false;
|
||||||
let error = false;
|
let error = false;
|
||||||
let confirmed = false;
|
let confirmed = false;
|
||||||
let assets = [];
|
let assets = [];
|
||||||
if (status === 'confirmed') {
|
if (status === 'confirmed') {
|
||||||
confirmed = true;
|
confirmed = true;
|
||||||
|
if (dataType === 'superbasictopic') {
|
||||||
try {
|
try {
|
||||||
message = JSON.parse(data);
|
message = JSON.parse(data);
|
||||||
|
text = message.text;
|
||||||
if (message.textColor != null) {
|
if (message.textColor != null) {
|
||||||
textColor = message.textColor;
|
textColor = message.textColor;
|
||||||
}
|
}
|
||||||
@ -78,6 +82,18 @@ export function useTopicItem(topic) {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (dataType === 'sealedtopic') {
|
||||||
|
if (topic.data.unsealedMessage) {
|
||||||
|
text = topic.data.unsealedMessage.message.text;
|
||||||
|
sealed = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conversation.actions.unsealTopic(topic.id, sealKey);
|
||||||
|
sealed = true;
|
||||||
|
}
|
||||||
|
ready = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (profile.state.init && card.state.init && conversation.state.init) {
|
if (profile.state.init && card.state.init && conversation.state.init) {
|
||||||
const { guid, created } = topic.data.topicDetail;
|
const { guid, created } = topic.data.topicDetail;
|
||||||
@ -98,11 +114,11 @@ export function useTopicItem(topic) {
|
|||||||
|
|
||||||
if (profile.state.profile.guid === guid) {
|
if (profile.state.profile.guid === guid) {
|
||||||
const { name, handle, imageUrl } = profile.actions.getProfile();
|
const { name, handle, imageUrl } = profile.actions.getProfile();
|
||||||
updateState({ name, handle, imageUrl, status, message, transform, assets, confirmed, error, ready, created: createdStr, owner, textColor, textSize, topicId: topic.id, init: true });
|
updateState({ sealed, name, handle, imageUrl, status, text, transform, assets, confirmed, error, ready, created: createdStr, owner, textColor, textSize, topicId: topic.id, init: true });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const { name, handle, imageUrl } = card.actions.getCardProfileByGuid(guid);
|
const { name, handle, imageUrl } = card.actions.getCardProfileByGuid(guid);
|
||||||
updateState({ name, handle, imageUrl, status, message, transform, assets, confirmed, error, ready, created: createdStr, owner, textColor, textSize, topicId: topic.id, init: true });
|
updateState({ sealed, name, handle, imageUrl, status, text, transform, assets, confirmed, error, ready, created: createdStr, owner, textColor, textSize, topicId: topic.id, init: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [profile, card, conversation, topic]);
|
}, [profile, card, conversation, topic]);
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import { useContext, useState, useEffect } from 'react';
|
import { useContext, useState, useEffect } from 'react';
|
||||||
import { ViewportContext } from 'context/ViewportContext';
|
import { ViewportContext } from 'context/ViewportContext';
|
||||||
|
import { AccountContext } from 'context/AccountContext';
|
||||||
import { CardContext } from 'context/CardContext';
|
import { CardContext } from 'context/CardContext';
|
||||||
import { ChannelContext } from 'context/ChannelContext';
|
import { ChannelContext } from 'context/ChannelContext';
|
||||||
import { ConversationContext } from 'context/ConversationContext';
|
import { ConversationContext } from 'context/ConversationContext';
|
||||||
import { UploadContext } from 'context/UploadContext';
|
import { UploadContext } from 'context/UploadContext';
|
||||||
import { StoreContext } from 'context/StoreContext';
|
import { StoreContext } from 'context/StoreContext';
|
||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
import { JSEncrypt } from 'jsencrypt'
|
||||||
|
|
||||||
export function useConversation(cardId, channelId) {
|
export function useConversation(cardId, channelId) {
|
||||||
|
|
||||||
@ -19,8 +22,11 @@ export function useConversation(cardId, channelId) {
|
|||||||
uploadError: false,
|
uploadError: false,
|
||||||
uploadPercent: 0,
|
uploadPercent: 0,
|
||||||
error: false,
|
error: false,
|
||||||
|
sealed: false,
|
||||||
|
sealKey: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const account = useContext(AccountContext);
|
||||||
const viewport = useContext(ViewportContext);
|
const viewport = useContext(ViewportContext);
|
||||||
const card = useContext(CardContext);
|
const card = useContext(CardContext);
|
||||||
const channel = useContext(ChannelContext);
|
const channel = useContext(ChannelContext);
|
||||||
@ -36,6 +42,21 @@ export function useConversation(cardId, channelId) {
|
|||||||
updateState({ display: viewport.state.display });
|
updateState({ display: viewport.state.display });
|
||||||
}, [viewport]);
|
}, [viewport]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let sealKey;
|
||||||
|
const seals = conversation.state.seals;
|
||||||
|
if (seals?.length > 0) {
|
||||||
|
seals.forEach(seal => {
|
||||||
|
if (seal.publicKey === account.state.sealKey?.public) {
|
||||||
|
let crypto = new JSEncrypt();
|
||||||
|
crypto.setPrivateKey(account.state.sealKey.private);
|
||||||
|
sealKey = crypto.decrypt(seal.sealedKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateState({ sealed: conversation.state.sealed, sealKey });
|
||||||
|
}, [account.state.sealKey, conversation.state.seals, conversation.state.sealed]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let active = false;
|
let active = false;
|
||||||
let uploadError = false;
|
let uploadError = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user