support unsealing summary in webapp

This commit is contained in:
Roland Osborne 2022-12-16 14:36:40 -08:00
parent 8a6411ff21
commit cc7e8e4ad2
5 changed files with 136 additions and 51 deletions

View File

@ -1,6 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setContactChannelTopicSubject(server, token, channelId, topicId, data) { export async function setContactChannelTopicSubject(server, token, channelId, topicId, datatype, data) {
console.log(data);
let host = ""; let host = "";
if (server) { if (server) {
host = `https://${server}`; host = `https://${server}`;
@ -8,7 +9,7 @@ export async function setContactChannelTopicSubject(server, token, channelId, to
let subject = { data: JSON.stringify(data, (key, value) => { let subject = { data: JSON.stringify(data, (key, value) => {
if (value !== null) return value if (value !== null) return value
}), datatype: 'superbasictopic' }; }), datatype };
let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}/subject?contact=${token}&confirm=true`, let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}/subject?contact=${token}&confirm=true`,
{ method: 'PUT', body: JSON.stringify(subject) }); { method: 'PUT', body: JSON.stringify(subject) });

View File

@ -60,6 +60,20 @@ export function useCardContext() {
} }
} }
const unsealKey = (seals, sealKey) => {
let unsealedKey;
if (seals?.length) {
seals.forEach(seal => {
if (seal.publicKey === sealKey.public) {
let crypto = new JSEncrypt();
crypto.setPrivateKey(sealKey.private);
unsealedKey = crypto.decrypt(seal.sealedKey);
}
});
}
return unsealedKey;
};
const updateCards = async () => { const updateCards = async () => {
let delta = await getCards(access.current, revision.current); let delta = await getCards(access.current, revision.current);
for (let card of delta) { for (let card of delta) {
@ -159,6 +173,7 @@ export function useCardContext() {
let detail = await getContactChannelDetail(node, guid + "." + token, channel.id); let detail = await getContactChannelDetail(node, guid + "." + token, channel.id);
cur.data.channelDetail = detail; cur.data.channelDetail = detail;
} }
cur.data.unsealedChannel = null;
cur.data.detailRevision = channel.data.detailRevision; cur.data.detailRevision = channel.data.detailRevision;
} }
if (cur.data.topicRevision !== channel.data.topicRevision) { if (cur.data.topicRevision !== channel.data.topicRevision) {
@ -169,6 +184,7 @@ export function useCardContext() {
let summary = await getContactChannelSummary(node, guid + "." + token, channel.id); let summary = await getContactChannelSummary(node, guid + "." + token, channel.id);
cur.data.channelSummary = summary; cur.data.channelSummary = summary;
} }
cur.data.unsealedSummary = null;
cur.data.topicRevision = channel.data.topicRevision; cur.data.topicRevision = channel.data.topicRevision;
} }
cur.revision = channel.revision; cur.revision = channel.revision;
@ -274,27 +290,48 @@ export function useCardContext() {
return card.data.cardProfile.name; return card.data.cardProfile.name;
}, },
unsealChannelSubject: (cardId, channelId, sealKey) => { unsealChannelSubject: (cardId, channelId, sealKey) => {
const card = cards.current.get(cardId); try {
const channel = card.channels.get(channelId); const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.data); const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.data);
if (seals?.length) { const unsealedKey = unsealKey(seals, sealKey);
seals.forEach(seal => { if (unsealedKey) {
if (seal.publicKey === sealKey.public) { const iv = CryptoJS.enc.Hex.parse(subjectIv);
let crypto = new JSEncrypt(); const key = CryptoJS.enc.Hex.parse(unsealedKey);
crypto.setPrivateKey(sealKey.private); const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
const unsealedKey = crypto.decrypt(seal.sealedKey); let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const iv = CryptoJS.enc.Hex.parse(subjectIv); const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
const key = CryptoJS.enc.Hex.parse(unsealedKey); channel.data.unsealedChannel = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted); card.channels.set(channel.id, { ...channel });
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv }); cards.current.set(cardId, { ...card });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv }); updateState({ cards: cards.current });
channel.data.unsealedChannel = JSON.parse(dec.toString(CryptoJS.enc.Utf8)); }
card.channels.set(channel.id, { ...channel }); }
cards.current.set(cardId, { ...card }); catch(err) {
updateState({ cards: cards.current }); console.log(err);
} }
}); },
unsealChannelSummary: (cardId, channelId, sealKey) => {
try {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
const { seals } = JSON.parse(channel.data.channelDetail.data);
const { messageEncrypted, messageIv } = JSON.parse(channel.data.channelSummary.lastTopic.data);
const unsealedKey = unsealKey(seals, sealKey);
if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(messageIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey);
const enc = CryptoJS.enc.Base64.parse(messageEncrypted);
const cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
channel.data.unsealedSummary = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
card.channels.set(channel.id, { ...channel });
cards.current.set(cardId, { ...card });
updateState({ cards: cards.current });
}
}
catch(err) {
console.log(err);
} }
}, },
removeChannel: async (cardId, channelId) => { removeChannel: async (cardId, channelId) => {
@ -330,14 +367,12 @@ export function useCardContext() {
} }
}, },
setSealedChannelTopicSubject: async (cardId, channelId, topicId, data, sealKey) => { setSealedChannelTopicSubject: async (cardId, channelId, topicId, data, sealKey) => {
console.log("SETTING:", data, sealKey);
let { cardProfile, cardDetail } = cards.current.get(cardId).data; let { cardProfile, cardDetail } = cards.current.get(cardId).data;
let token = cardProfile.guid + '.' + cardDetail.token; let token = cardProfile.guid + '.' + cardDetail.token;
let node = cardProfile.node; let node = cardProfile.node;
const iv = CryptoJS.lib.WordArray.random(128 / 8); const iv = CryptoJS.lib.WordArray.random(128 / 8);
const key = CryptoJS.enc.Hex.parse(sealKey); const key = CryptoJS.enc.Hex.parse(sealKey);
const encrypted = CryptoJS.AES.encrypt(JSON.stringify(data), key, { iv: iv }); const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ message: data }), key, { iv: iv });
const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64) const messageEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
const messageIv = iv.toString(); const messageIv = iv.toString();
await setContactChannelTopicSubject(node, token, channelId, topicId, 'sealedtopic', { messageEncrypted, messageIv }); await setContactChannelTopicSubject(node, token, channelId, topicId, 'sealedtopic', { messageEncrypted, messageIv });

View File

@ -32,6 +32,20 @@ export function useChannelContext() {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const unsealKey = (seals, sealKey) => {
let unsealedKey;
if (seals?.length) {
seals.forEach(seal => {
if (seal.publicKey === sealKey.public) {
let crypto = new JSEncrypt();
crypto.setPrivateKey(sealKey.private);
unsealedKey = crypto.decrypt(seal.sealedKey);
}
});
}
return unsealedKey;
}
const updateChannels = async () => { const updateChannels = async () => {
let delta = await getChannels(access.current, revision.current); let delta = await getChannels(access.current, revision.current);
for (let channel of delta) { for (let channel of delta) {
@ -43,13 +57,12 @@ export function useChannelContext() {
if (cur.data.detailRevision !== channel.data.detailRevision) { if (cur.data.detailRevision !== channel.data.detailRevision) {
if (channel.data.channelDetail != null) { if (channel.data.channelDetail != null) {
cur.data.channelDetail = channel.data.channelDetail; cur.data.channelDetail = channel.data.channelDetail;
cur.data.unsealedSubject = null;
} }
else { else {
let detail = await getChannelDetail(access.current, channel.id); let detail = await getChannelDetail(access.current, channel.id);
cur.data.channelDetail = detail; cur.data.channelDetail = detail;
cur.data.unsealedChannel = null;
} }
cur.data.unsealedChannel = null;
cur.data.detailRevision = channel.data.detailRevision; cur.data.detailRevision = channel.data.detailRevision;
} }
if (cur.data.topicRevision !== channel.data.topicRevision) { if (cur.data.topicRevision !== channel.data.topicRevision) {
@ -60,6 +73,7 @@ export function useChannelContext() {
let summary = await getChannelSummary(access.current, channel.id); let summary = await getChannelSummary(access.current, channel.id);
cur.data.channelSummary = summary; cur.data.channelSummary = summary;
} }
cur.data.unsealedSummary = null;
cur.data.topicRevision = channel.data.topicRevision; cur.data.topicRevision = channel.data.topicRevision;
} }
cur.revision = channel.revision; cur.revision = channel.revision;
@ -131,25 +145,44 @@ export function useChannelContext() {
return await addChannel(access.current, 'sealed', cards, data); return await addChannel(access.current, 'sealed', cards, data);
}, },
unsealChannelSubject: (channelId, sealKey) => { unsealChannelSubject: (channelId, sealKey) => {
const channel = channels.current.get(channelId); try {
const channel = channels.current.get(channelId);
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.data); const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.data);
if (seals?.length) { const unsealedKey = unsealKey(seals, sealKey);
seals.forEach(seal => { if (unsealKey) {
if (seal.publicKey === sealKey.public) { const iv = CryptoJS.enc.Hex.parse(subjectIv);
let crypto = new JSEncrypt(); const key = CryptoJS.enc.Hex.parse(unsealedKey);
crypto.setPrivateKey(sealKey.private); const enc = CryptoJS.enc.Base64.parse(subjectEncrypted);
const unsealedKey = crypto.decrypt(seal.sealedKey); const cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const iv = CryptoJS.enc.Hex.parse(subjectIv); const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
const key = CryptoJS.enc.Hex.parse(unsealedKey); channel.data.unsealedChannel = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
const enc = CryptoJS.enc.Base64.parse(subjectEncrypted); channels.current.set(channel.id, { ...channel });
let cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv }); updateState({ channels: channels.current });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv }); }
channel.data.unsealedChannel = JSON.parse(dec.toString(CryptoJS.enc.Utf8)); }
channels.current.set(channel.id, { ...channel }); catch(err) {
updateState({ channels: channels.current }); console.log(err);
} }
}); },
unsealChannelSummary: (channelId, sealKey) => {
try {
const channel = channels.current.get(channelId);
const { seals } = JSON.parse(channel.data.channelDetail.data);
const { messageEncrypted, messageIv } = JSON.parse(channel.data.channelSummary.lastTopic.data);
const unsealedKey = unsealKey(seals, sealKey);
if (unsealKey) {
const iv = CryptoJS.enc.Hex.parse(messageIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey);
const enc = CryptoJS.enc.Base64.parse(messageEncrypted);
const cipher = CryptoJS.lib.CipherParams.create({ ciphertext: enc, iv: iv });
const dec = CryptoJS.AES.decrypt(cipher, key, { iv: iv });
channel.data.unsealedSummary = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
channels.current.set(channel.id, { ...channel });
updateState({ channels: channels.current });
}
}
catch(err) {
console.log(err);
} }
}, },
setChannelSubject: async (channelId, subject) => { setChannelSubject: async (channelId, subject) => {

View File

@ -209,6 +209,26 @@ export function useChannels() {
console.log(err); console.log(err);
} }
} }
if (chan.data.channelSummary?.lastTopic?.dataType === 'sealedtopic') {
try {
if (chan.data.unsealedSummary == null) {
if (chan.cardId) {
card.actions.unsealChannelSummary(chan.cardId, chan.id, account.state.sealKey);
}
else {
channel.actions.unsealChannelSummary(chan.id, account.state.sealKey);
}
}
else {
if (typeof chan.data.unsealedSummary.message.text === 'string') {
chan.message = chan.data.unsealedSummary.message.text;
}
}
}
catch (err) {
console.log(err)
}
}
if (typeof message === 'string') { if (typeof message === 'string') {
chan.message = message; chan.message = message;

View File

@ -86,8 +86,6 @@ export function useTopicItem(topic, sealed, sealKey) {
} }
else if (dataType === 'sealedtopic') { else if (dataType === 'sealedtopic') {
if (topic.data.unsealedMessage) { if (topic.data.unsealedMessage) {
console.log("UNSEALED MESSAGE", topic.data.unsealedMessage);
text = topic.data.unsealedMessage.message?.text; text = topic.data.unsealedMessage.message?.text;
sealed = false; sealed = false;
} }
@ -146,11 +144,9 @@ console.log("UNSEALED MESSAGE", topic.data.unsealedMessage);
updateState({ busy: true }); updateState({ busy: true });
try { try {
if (sealed) { if (sealed) {
console.log("SET SEALED");
await conversation.actions.setSealedTopicSubject(topic.id, {...state.message, text: editMessage.current }, sealKey); await conversation.actions.setSealedTopicSubject(topic.id, {...state.message, text: editMessage.current }, sealKey);
} }
else { else {
console.log("SET UNSEALED");
await conversation.actions.setTopicSubject(topic.id, await conversation.actions.setTopicSubject(topic.id,
{ ...state.message, text: editMessage.current, assets: state.assets }); { ...state.message, text: editMessage.current, assets: state.assets });
} }