mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 00:50:03 +00:00
unsealing topic messages in mobile app
This commit is contained in:
parent
faca16f748
commit
b43a26b240
@ -1,6 +1,6 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function addChannelTopic(server, token, channelId, message, assets ): string {
|
||||
export async function addChannelTopic(server, token, channelId, messageType, message, assets ): string {
|
||||
|
||||
if (message == null && (assets == null || assets.length === 0)) {
|
||||
let topic = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics?agent=${token}`,
|
||||
@ -12,7 +12,7 @@ export async function addChannelTopic(server, token, channelId, message, assets
|
||||
else if (assets == null || assets.length === 0) {
|
||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||
if (value !== null) return value
|
||||
}), datatype: 'superbasictopic' };
|
||||
}), datatype: messageType };
|
||||
|
||||
let topic = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics?agent=${token}&confirm=true`,
|
||||
{ method: 'POST', body: JSON.stringify(subject) });
|
||||
@ -78,7 +78,7 @@ export async function addChannelTopic(server, token, channelId, message, assets
|
||||
|
||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||
if (value !== null) return value
|
||||
}), datatype: 'superbasictopic' };
|
||||
}), datatype: messageType };
|
||||
|
||||
let unconfirmed = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics/${slot.id}/subject?agent=${token}`,
|
||||
{ method: 'PUT', body: JSON.stringify(subject) });
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function addContactChannelTopic(server, token, channelId, message, assets ) {
|
||||
export async function addContactChannelTopic(server, token, channelId, messageType, message, assets ) {
|
||||
if (message == null && (assets == null || assets.length === 0)) {
|
||||
let topic = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics?contact=${token}`,
|
||||
{ method: 'POST', body: JSON.stringify({}) });
|
||||
@ -11,7 +11,7 @@ export async function addContactChannelTopic(server, token, channelId, message,
|
||||
else if (assets == null || assets.length === 0) {
|
||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||
if (value !== null) return value
|
||||
}), datatype: 'superbasictopic' };
|
||||
}), datatype: messageType };
|
||||
|
||||
let topic = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics?contact=${token}&confirm=true`,
|
||||
{ method: 'POST', body: JSON.stringify(subject) });
|
||||
@ -76,7 +76,7 @@ export async function addContactChannelTopic(server, token, channelId, message,
|
||||
|
||||
let subject = { data: JSON.stringify(message, (key, value) => {
|
||||
if (value !== null) return value
|
||||
}), datatype: 'superbasictopic' };
|
||||
}), datatype: messageType };
|
||||
|
||||
let unconfirmed = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics/${slot.id}/subject?contact=${token}`,
|
||||
{ method: 'PUT', body: JSON.stringify(subject) });
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function setChannelTopicSubject(server, token, channelId, topicId, data) {
|
||||
export async function setChannelTopicSubject(server, token, channelId, topicId, dataType, data) {
|
||||
let subject = { data: JSON.stringify(data, (key, value) => {
|
||||
if (value !== null) return value
|
||||
}), datatype: 'superbasictopic' };
|
||||
}), datatype: dataType };
|
||||
|
||||
let channel = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics/${topicId}/subject?agent=${token}&confirm=true`,
|
||||
{ method: 'PUT', body: JSON.stringify(subject) });
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function setContactChannelTopicSubject(server, token, channelId, topicId, data) {
|
||||
export async function setContactChannelTopicSubject(server, token, channelId, topicId, dataType, data) {
|
||||
let subject = { data: JSON.stringify(data, (key, value) => {
|
||||
if (value !== null) return value
|
||||
}), datatype: 'superbasictopic' };
|
||||
}), datatype: dataType };
|
||||
|
||||
let channel = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/topics/${topicId}/subject?contact=${token}&confirm=true`,
|
||||
{ method: 'PUT', body: JSON.stringify(subject) });
|
||||
|
@ -553,10 +553,10 @@ export function useCardContext() {
|
||||
const node = profile.node;
|
||||
const token = `${profile.guid}.${detail.token}`;
|
||||
if (files?.length > 0) {
|
||||
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) => {
|
||||
message.assets = assets;
|
||||
await setContactChannelTopicSubject(node, token, channelId, topicId, message);
|
||||
await setContactChannelTopicSubject(node, token, channelId, topicId, 'superbasictopic', message);
|
||||
}, async () => {
|
||||
try {
|
||||
await removeContactChannelTopic(node, token, channelId, topicId);
|
||||
@ -567,13 +567,28 @@ export function useCardContext() {
|
||||
});
|
||||
}
|
||||
else {
|
||||
await addContactChannelTopic(node, token, channelId, message, []);
|
||||
await addContactChannelTopic(node, token, channelId, 'superbasictopic', message, []);
|
||||
}
|
||||
},
|
||||
addSealedChannelTopic: async (cardId, channelId, message, sealKey) => {
|
||||
const { detail, profile } = getCardEntry(cardId);
|
||||
const node = profile.node;
|
||||
const token = `${profile.guid}.${detail.token}`;
|
||||
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 });
|
||||
},
|
||||
setChannelTopicSubject: async (cardId, channelId, topicId, data) => {
|
||||
const { detail, profile } = getCardEntry(cardId);
|
||||
return await setContactChannelTopicSubject(profile.node, `${profile.guid}.${detail.token}`, channelId, topicId, data);
|
||||
},
|
||||
setChannelTopicUnsealedDetail: async (cardId, channelId, topicId, revision, unsealed) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.setCardChannelTopicItemUnsealedDetail(guid, cardId, channelId, revision, unsealed);
|
||||
},
|
||||
removeChannel: async (cardId, channelId) => {
|
||||
const { detail, profile } = getCardEntry(cardId);
|
||||
return await removeContactChannel(profile.node, `${profile.guid}.${detail.token}`, channelId);
|
||||
@ -604,25 +619,31 @@ export function useCardContext() {
|
||||
const card = cards.current.get(cardId);
|
||||
const channel = card.channels.get(channelId);
|
||||
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.detail.data);
|
||||
seals.forEach(seal => {
|
||||
if (seal.publicKey === sealKey.public) {
|
||||
let crypto = new JSEncrypt();
|
||||
crypto.setPrivateKey(sealKey.private);
|
||||
const unsealedKey = crypto.decrypt(seal.sealedKey);
|
||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
||||
const key = CryptoJS.enc.Hex.parse(unsealedKey);
|
||||
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
|
||||
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
|
||||
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
|
||||
if (revision === channel.detailRevision) {
|
||||
channel.unsealedDetail = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||
let unsealed = false;
|
||||
if (seals?.length) {
|
||||
seals.forEach(seal => {
|
||||
if (seal.publicKey === sealKey.public) {
|
||||
let crypto = new JSEncrypt();
|
||||
crypto.setPrivateKey(sealKey.private);
|
||||
const unsealedKey = crypto.decrypt(seal.sealedKey);
|
||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
||||
const key = CryptoJS.enc.Hex.parse(unsealedKey);
|
||||
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
|
||||
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
|
||||
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
|
||||
if (revision === channel.detailRevision) {
|
||||
channel.unsealedDetail = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||
unsealed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (unsealed) {
|
||||
await store.actions.setCardChannelItemUnsealedDetail(guid, cardId, channelId, revision, channel.unsealedDetail);
|
||||
card.channels.set(channelId, { ...channel });
|
||||
cards.current.set(cardId, { ...card });
|
||||
updateState({ cards: cards.current });
|
||||
}
|
||||
});
|
||||
await store.actions.setCardChannelItemUnsealedDetail(guid, cardId, channelId, revision, channel.unsealedDetail);
|
||||
card.channels.set(channelId, { ...channel });
|
||||
cards.current.set(cardId, { ...card });
|
||||
updateState({ cards: cards.current });
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
|
@ -252,10 +252,10 @@ export function useChannelContext() {
|
||||
addTopic: async (channelId, message, files) => {
|
||||
const { server, appToken } = session.current;
|
||||
if (files?.length > 0) {
|
||||
const topicId = await addChannelTopic(server, appToken, channelId, null, null);
|
||||
const topicId = await addChannelTopic(server, appToken, channelId, null, null, null);
|
||||
upload.actions.addTopic(server, appToken, channelId, topicId, files, async (assets) => {
|
||||
message.assets = assets;
|
||||
await setChannelTopicSubject(server, appToken, channelId, topicId, message);
|
||||
await setChannelTopicSubject(server, appToken, channelId, topicId, 'superbasictopic', message);
|
||||
}, async () => {
|
||||
try {
|
||||
await removeChannelTopic(server, appToken, channelId, topicId);
|
||||
@ -266,13 +266,26 @@ export function useChannelContext() {
|
||||
});
|
||||
}
|
||||
else {
|
||||
await addChannelTopic(server, appToken, channelId, message, []);
|
||||
await addChannelTopic(server, appToken, channelId, 'superbasictopic', message, []);
|
||||
}
|
||||
},
|
||||
addSealedTopic: async (channelId, message, sealKey) => {
|
||||
const { server, appToken } = session.current;
|
||||
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(server, appToken, channelId, 'sealedtopic', { messageEncrypted, messageIv });
|
||||
},
|
||||
setTopicSubject: async (channelId, topicId, data) => {
|
||||
const { server, appToken } = session.current;
|
||||
return await setChannelTopicSubject(server, appToken, channelId, topicId, data);
|
||||
},
|
||||
setTopicUnsealedDetail: async (channelId, topicId, revision, unsealed) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.setChannelTopicItemUnsealedDetail(guid, channelId, topicId, revision, unsealed);
|
||||
},
|
||||
setSubject: async (channelId, subject) => {
|
||||
const { server, appToken } = session.current;
|
||||
return await setChannelSubject(server, appToken, channelId, 'superbasic', { subject });
|
||||
@ -360,24 +373,30 @@ export function useChannelContext() {
|
||||
const { guid } = session.current;
|
||||
const channel = channels.current.get(channelId);
|
||||
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.detail.data);
|
||||
seals.forEach(seal => {
|
||||
if (seal.publicKey === sealKey.public) {
|
||||
let crypto = new JSEncrypt();
|
||||
crypto.setPrivateKey(sealKey.private);
|
||||
const unsealedKey = crypto.decrypt(seal.sealedKey);
|
||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
||||
const key = CryptoJS.enc.Hex.parse(unsealedKey);
|
||||
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
|
||||
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
|
||||
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
|
||||
if (revision === channel.detailRevision) {
|
||||
channel.unsealedDetail = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||
if (seals?.length) {
|
||||
let unsealed = false;
|
||||
seals.forEach(seal => {
|
||||
if (seal.publicKey === sealKey.public) {
|
||||
let crypto = new JSEncrypt();
|
||||
crypto.setPrivateKey(sealKey.private);
|
||||
const unsealedKey = crypto.decrypt(seal.sealedKey);
|
||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
||||
const key = CryptoJS.enc.Hex.parse(unsealedKey);
|
||||
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
|
||||
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
|
||||
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
|
||||
if (revision === channel.detailRevision) {
|
||||
channel.unsealedDetail = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||
unsealed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (unsealed) {
|
||||
await store.actions.setChannelItemUnsealedDetail(guid, channelId, revision, channel.unsealedDetail);
|
||||
channels.current.set(channelId, { ...channel });
|
||||
updateState({ channels: channels.current });
|
||||
}
|
||||
});
|
||||
await store.actions.setChannelItemUnsealedDetail(guid, channelId, revision, channel.unsealedDetail);
|
||||
channels.current.set(channelId, { ...channel });
|
||||
updateState({ channels: channels.current });
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
|
@ -5,6 +5,8 @@ import { CardContext } from 'context/CardContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import moment from 'moment';
|
||||
import CryptoJS from 'crypto-js';
|
||||
import { JSEncrypt } from 'jsencrypt'
|
||||
|
||||
export function useConversationContext() {
|
||||
const [state, setState] = useState({
|
||||
@ -432,6 +434,46 @@ export function useConversationContext() {
|
||||
sync();
|
||||
}
|
||||
},
|
||||
addSealedTopic: async (message, sealKey) => {
|
||||
if (conversationId.current) {
|
||||
const { cardId, channelId } = conversationId.current;
|
||||
if (cardId) {
|
||||
await card.actions.addSealedChannelTopic(cardId, channelId, message, sealKey);
|
||||
}
|
||||
else {
|
||||
await channel.actions.addSealedTopic(channelId, message, sealKey);
|
||||
}
|
||||
force.current = true;
|
||||
sync();
|
||||
}
|
||||
},
|
||||
unsealTopic: async (topicId, sealKey) => {
|
||||
console.log("UNSEAL TOPIC");
|
||||
try {
|
||||
const topic = topics.current.get(topicId);
|
||||
const { messageEncrypted, messageIv } = JSON.parse(topic.detail.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.unsealedDetail = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
|
||||
topics.current.set(topicId, { ...topic });
|
||||
updateState({ topics: topics.current });
|
||||
|
||||
const { cardId, channelId } = conversationId.current;
|
||||
if (cardId) {
|
||||
await card.actions.setChannelTopicUnsealedDetail(cardId, channelId, topic.topicId, topic.detailRevision, topic.unsealedDetial);
|
||||
}
|
||||
else {
|
||||
console.log("channel topic", topic);
|
||||
await channel.actions.setTopicUnsealedDetail(channelId, topic.topicId, topic.detailRevision, topic.unsealedDetail);
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
setSubject: async (subject) => {
|
||||
if (conversationId.current) {
|
||||
const { cardId, channelId } = conversationId.current;
|
||||
|
@ -271,6 +271,10 @@ export function useStoreContext() {
|
||||
const { id, revision, data } = topic;
|
||||
await db.current.executeSql(`INSERT OR REPLACE INTO channel_topic_${guid} (channel_id, topic_id, revision, detail_revision, detail, unsealed_detail) values (?, ?, ?, ?, ?, null);`, [channelId, id, revision, data.detailRevision, encodeObject(data.topicDetail)]);
|
||||
},
|
||||
setChannelTopicItemUnsealedDetail: async (guid, channelId, topicId, revision, unsealed) => {
|
||||
console.log("SAVING:", channelId, revision, unsealed);
|
||||
await db.current.executeSql(`UPDATE channel_topic_${guid} set unsealed_detail=? where detail_revision=? AND channel_id=? AND topic_id=?`, [encodeObject(unsealed), revision, channelId, topicId]);
|
||||
},
|
||||
clearChannelTopicItem: async (guid, channelId, topicId) => {
|
||||
await db.current.executeSql(`DELETE FROM channel_topic_${guid} WHERE channel_id=? and topic_id=?`, [channelId, topicId]);
|
||||
},
|
||||
@ -309,6 +313,7 @@ export function useStoreContext() {
|
||||
await db.current.executeSql(`UPDATE card_channel_${guid} set detail_revision=?, detail=?, unsealed_detail=null where card_id=? and channel_id=?`, [revision, encodeObject(detail), cardId, channelId]);
|
||||
},
|
||||
setCardChannelItemUnsealedDetail: async (guid, cardId, channelId, revision, unsealed) => {
|
||||
console.log("SAVING:", cardId, channelId, revision, unsealed);
|
||||
await db.current.executeSql(`UPDATE card_channel_${guid} set unsealed_detail=? where detail_revision=? AND card_id=? AND channel_id=?`, [encodeObject(unsealed), revision, cardId, channelId]);
|
||||
},
|
||||
setCardChannelItemSummary: async (guid, cardId, channelId, revision, summary) => {
|
||||
@ -361,6 +366,9 @@ export function useStoreContext() {
|
||||
const { id, revision, data } = topic;
|
||||
await db.current.executeSql(`INSERT OR REPLACE INTO card_channel_topic_${guid} (card_id, channel_id, topic_id, revision, detail_revision, detail, unsealed_detail) values (?, ?, ?, ?, ?, ?, null);`, [cardId, channelId, id, revision, data.detailRevision, encodeObject(data.topicDetail)]);
|
||||
},
|
||||
setCardChannelTopicItemUnsealedDetail: async (guid, cardId, channelId, topicId, revision, unsealed) => {
|
||||
await db.current.executeSql(`UPDATE card_channel_topic_${guid} set unsealed_detail=? where detail_revision=? AND card_id=? AND channel_id=? AND topic_id=?`, [encodeObject(unsealed), revision, cardId, channelId, topicId]);
|
||||
},
|
||||
clearCardChannelTopicItem: async (guid, cardId, channelId, topicId) => {
|
||||
await db.current.executeSql(`DELETE FROM card_channel_topic_${guid} WHERE card_id=? and channel_id=? and topic_id=?`, [cardId, channelId, topicId]);
|
||||
},
|
||||
|
@ -100,7 +100,8 @@ export function ConversationBody() {
|
||||
maintainVisibleContentPosition={ state.latched ? null : { minIndexForVisibile: 2, } }
|
||||
inverted={true}
|
||||
renderItem={({item}) => <TopicItem item={item} focused={item.topicId === state.focus}
|
||||
focus={() => actions.setFocus(item.topicId)} hosting={state.host == null}
|
||||
focus={() => actions.setFocus(item.topicId)} hosting={state.host == null}
|
||||
sealed={state.sealed} sealKey={state.sealKey}
|
||||
remove={actions.removeTopic} update={actions.editTopic} block={actions.blockTopic}
|
||||
report={actions.reportTopic} />}
|
||||
keyExtractor={item => item.topicId}
|
||||
@ -112,7 +113,9 @@ export function ConversationBody() {
|
||||
</View>
|
||||
)}
|
||||
<View>
|
||||
<AddTopic />
|
||||
{ (!state.locked || state.sealKey) && (
|
||||
<AddTopic sealed={state.locked} sealKey={state.sealKey} />
|
||||
)}
|
||||
<View style={styles.latchbar}>
|
||||
{ !state.latched && (
|
||||
<TouchableOpacity style={styles.latch} onPress={latch}>
|
||||
|
@ -13,9 +13,9 @@ import { ImageFile } from './imageFile/ImageFile';
|
||||
import DocumentPicker from 'react-native-document-picker'
|
||||
import ColorPicker from 'react-native-wheel-color-picker'
|
||||
|
||||
export function AddTopic() {
|
||||
export function AddTopic({ sealed, sealKey }) {
|
||||
|
||||
const { state, actions } = useAddTopic();
|
||||
const { state, actions } = useAddTopic(sealed, sealKey);
|
||||
const message = useRef();
|
||||
|
||||
const addImage = async () => {
|
||||
@ -132,22 +132,24 @@ export function AddTopic() {
|
||||
onSubmitEditing={sendMessage} returnKeyType="send"
|
||||
autoCapitalize="sentences" placeholder="New Message" multiline={true} />
|
||||
<View style={styles.addButtons}>
|
||||
{ state.enableImage && (
|
||||
{ !sealed && state.enableImage && (
|
||||
<TouchableOpacity style={styles.addButton} onPress={addImage}>
|
||||
<AntIcons name="picture" size={20} color={Colors.text} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ state.enableVideo && (
|
||||
{ !sealed && state.enableVideo && (
|
||||
<TouchableOpacity style={styles.addButton} onPress={addVideo}>
|
||||
<MaterialIcons name="video-outline" size={24} color={Colors.text} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ state.enableAudio && (
|
||||
{ !sealed && state.enableAudio && (
|
||||
<TouchableOpacity style={styles.addButton} onPress={addAudio}>
|
||||
<MaterialIcons name="music-box-outline" size={20} color={Colors.text} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<View style={styles.divider} />
|
||||
{ !sealed && (
|
||||
<View style={styles.divider} />
|
||||
)}
|
||||
<TouchableOpacity style={styles.addButton} onPress={actions.showFontSize}>
|
||||
<MaterialIcons name="format-size" size={20} color={Colors.text} />
|
||||
</TouchableOpacity>
|
||||
|
@ -3,7 +3,7 @@ import { ConversationContext } from 'context/ConversationContext';
|
||||
import { Image } from 'react-native';
|
||||
import Colors from 'constants/Colors';
|
||||
|
||||
export function useAddTopic(cardId, channelId) {
|
||||
export function useAddTopic(sealed, sealKey) {
|
||||
|
||||
const [state, setState] = useState({
|
||||
message: null,
|
||||
@ -112,7 +112,12 @@ export function useAddTopic(cardId, channelId) {
|
||||
textColor: state.colorSet ? state.color : null,
|
||||
textSize: state.sizeSet ? state.size : null,
|
||||
};
|
||||
await conversation.actions.addTopic(message, state.assets);
|
||||
if (sealed) {
|
||||
await conversation.actions.addSealedTopic(message, sealKey);
|
||||
}
|
||||
else {
|
||||
await conversation.actions.addTopic(message, state.assets);
|
||||
}
|
||||
updateState({ busy: false, assets: [], message: null,
|
||||
size: 'medium', sizeSet: false, textSize: 14,
|
||||
color: Colors.text, colorSet: false,
|
||||
|
@ -15,9 +15,9 @@ import Carousel from 'react-native-snap-carousel';
|
||||
import GestureRecognizer from 'react-native-swipe-gestures';
|
||||
import avatar from 'images/avatar.png';
|
||||
|
||||
export function TopicItem({ item, focused, focus, hosting, remove, update, block, report }) {
|
||||
export function TopicItem({ item, focused, focus, hosting, sealed, sealKey, remove, update, block, report }) {
|
||||
|
||||
const { state, actions } = useTopicItem(item, hosting);
|
||||
const { state, actions } = useTopicItem(item, hosting, remove, sealed, sealKey);
|
||||
|
||||
const erase = () => {
|
||||
Alert.alert(
|
||||
@ -163,9 +163,12 @@ export function TopicItem({ item, focused, focus, hosting, remove, update, block
|
||||
<MatIcons name="weather-cloudy-alert" size={32} color={Colors.alert} />
|
||||
</View>
|
||||
)}
|
||||
{ state.message && (
|
||||
{ state.message && !state.sealed && (
|
||||
<Text style={{ ...styles.message, fontSize: state.fontSize, color: state.fontColor }}>{ state.message }</Text>
|
||||
)}
|
||||
{ state.sealed && (
|
||||
<Text style={ styles.sealed }>sealed message</Text>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{ state.status !== 'confirmed' && (
|
||||
|
@ -47,6 +47,12 @@ export const styles = StyleSheet.create({
|
||||
status: {
|
||||
paddingLeft: 52,
|
||||
},
|
||||
sealed: {
|
||||
paddingRight: 16,
|
||||
paddingLeft: 52,
|
||||
color: Colors.grey,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
focused: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import moment from 'moment';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import Colors from 'constants/Colors';
|
||||
|
||||
export function useTopicItem(item, hosting, remove) {
|
||||
export function useTopicItem(item, hosting, remove, sealed, sealKey) {
|
||||
|
||||
const [state, setState] = useState({
|
||||
name: null,
|
||||
@ -25,6 +26,7 @@ export function useTopicItem(item, hosting, remove) {
|
||||
deletable: false,
|
||||
});
|
||||
|
||||
const conversation = useContext(ConversationContext);
|
||||
const profile = useContext(ProfileContext);
|
||||
const card = useContext(CardContext);
|
||||
const dimensions = useWindowDimensions();
|
||||
@ -38,8 +40,8 @@ export function useTopicItem(item, hosting, remove) {
|
||||
}, [dimensions]);
|
||||
|
||||
useEffect(() => {
|
||||
const { topicId, detail } = item;
|
||||
const { guid, data, status, transform } = detail;
|
||||
const { topicId, detail, unsealedDetail } = item;
|
||||
const { guid, dataType, data, status, transform } = detail;
|
||||
|
||||
let name, nameSet, known, logo;
|
||||
const identity = profile.state?.profile;
|
||||
@ -87,29 +89,59 @@ export function useTopicItem(item, hosting, remove) {
|
||||
}
|
||||
}
|
||||
|
||||
let parsed, message, assets, fontSize, fontColor;
|
||||
try {
|
||||
parsed = JSON.parse(data);
|
||||
message = parsed.text;
|
||||
assets = parsed.assets;
|
||||
if (parsed.textSize === 'small') {
|
||||
fontSize = 10;
|
||||
let parsed, sealed, message, assets, fontSize, fontColor;
|
||||
if (dataType === 'superbasictopic') {
|
||||
try {
|
||||
sealed = false;
|
||||
parsed = JSON.parse(data);
|
||||
message = parsed.text;
|
||||
assets = parsed.assets;
|
||||
if (parsed.textSize === 'small') {
|
||||
fontSize = 10;
|
||||
}
|
||||
else if (parsed.textSize === 'large') {
|
||||
fontSize = 20;
|
||||
}
|
||||
else {
|
||||
fontSize = 14;
|
||||
}
|
||||
if (parsed.textColor) {
|
||||
fontColor = parsed.textColor;
|
||||
}
|
||||
else {
|
||||
fontColor = Colors.text;
|
||||
}
|
||||
}
|
||||
else if (parsed.textSize === 'large') {
|
||||
fontSize = 20;
|
||||
}
|
||||
else {
|
||||
fontSize = 14;
|
||||
}
|
||||
if (parsed.textColor) {
|
||||
fontColor = parsed.textColor;
|
||||
}
|
||||
else {
|
||||
fontColor = Colors.text;
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
else if (dataType === 'sealedtopic') {
|
||||
if (unsealedDetail) {
|
||||
sealed = false;
|
||||
parsed = unsealedDetail.message;
|
||||
message = parsed?.text;
|
||||
if (parsed?.textSize === 'small') {
|
||||
fontSize = 10;
|
||||
}
|
||||
else if (parsed?.textSize === 'large') {
|
||||
fontSize = 20;
|
||||
}
|
||||
else {
|
||||
fontSize = 14;
|
||||
}
|
||||
if (parsed?.textColor) {
|
||||
fontColor = parsed?.textColor;
|
||||
}
|
||||
else {
|
||||
fontColor = Colors.text;
|
||||
}
|
||||
}
|
||||
else {
|
||||
conversation.actions.unsealTopic(topicId, sealKey);
|
||||
sealed = true;
|
||||
}
|
||||
}
|
||||
catch (err) { }
|
||||
|
||||
|
||||
let timestamp;
|
||||
const date = new Date(item.detail.created * 1000);
|
||||
@ -128,7 +160,7 @@ export function useTopicItem(item, hosting, remove) {
|
||||
const editable = detail.guid === identity.guid && parsed;
|
||||
const deletable = editable || hosting;
|
||||
|
||||
updateState({ logo, name, nameSet, known, message, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message });
|
||||
updateState({ logo, name, nameSet, known, sealed, message, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message });
|
||||
}, [card, item]);
|
||||
|
||||
const actions = {
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { useRef, useState, useEffect, useContext } from 'react';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { AccountContext } from 'context/AccountContext';
|
||||
import CryptoJS from 'crypto-js';
|
||||
import { JSEncrypt } from 'jsencrypt'
|
||||
|
||||
export function useConversation() {
|
||||
|
||||
@ -18,15 +21,33 @@ export function useConversation() {
|
||||
init: false,
|
||||
error: false,
|
||||
keyboard: false,
|
||||
locked: false,
|
||||
sealKey: null,
|
||||
});
|
||||
|
||||
const delay = useRef(null);
|
||||
const conversation = useContext(ConversationContext);
|
||||
const account = useContext(AccountContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let sealKey;
|
||||
const { locked, seals } = conversation.state;
|
||||
if (seals?.length) {
|
||||
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({ locked, sealKey });
|
||||
}, [conversation.state.locked, conversation.state.seals, account.state.sealKey])
|
||||
|
||||
useEffect(() => {
|
||||
const { error, subject, logo, topics, host, init } = conversation.state;
|
||||
const items = Array.from(topics.values());
|
||||
@ -42,7 +63,7 @@ export function useConversation() {
|
||||
return -1;
|
||||
});
|
||||
const filtered = sorted.filter(item => !(item.blocked === 1));
|
||||
updateState({ topics, subject, logo, host, error, topics: filtered });
|
||||
updateState({ subject, logo, host, error, topics: filtered });
|
||||
if (init) {
|
||||
clearTimeout(delay.current);
|
||||
updateState({ init: true });
|
||||
|
Loading…
Reference in New Issue
Block a user