unseal channel subject in webapp

This commit is contained in:
Roland Osborne 2022-12-13 14:25:35 -08:00
parent 5cf74e9793
commit 76ce83f0c0
7 changed files with 83 additions and 12 deletions

View File

@ -5,7 +5,7 @@ export async function getChannels(token, revision) {
if (revision != null) { if (revision != null) {
param += `&channelRevision=${revision}` param += `&channelRevision=${revision}`
} }
let types = encodeURIComponent(JSON.stringify([ 'superbasic' ])); let types = encodeURIComponent(JSON.stringify([ 'sealed', 'superbasic' ]));
param += `&types=${types}` param += `&types=${types}`
let channels = await fetchWithTimeout('/content/channels' + param, { method: 'GET' }); let channels = await fetchWithTimeout('/content/channels' + param, { method: 'GET' });
checkResponse(channels) checkResponse(channels)

View File

@ -13,7 +13,7 @@ export async function getContactChannels(server, token, viewRevision, channelRev
if (channelRevision != null) { if (channelRevision != null) {
param += '&channelRevision=' + channelRevision param += '&channelRevision=' + channelRevision
} }
let types = encodeURIComponent(JSON.stringify([ 'superbasic' ])); let types = encodeURIComponent(JSON.stringify([ 'sealed', 'superbasic' ]));
param += `&types=${types}` param += `&types=${types}`
let channels = await fetchWithTimeout(`${host}/content/channels${param}`, { method: 'GET' }); let channels = await fetchWithTimeout(`${host}/content/channels${param}`, { method: 'GET' });
checkResponse(channels) checkResponse(channels)

View File

@ -23,6 +23,8 @@ import { getContactChannelTopicAssetUrl } from 'api/getContactChannelTopicAssetU
import { addCard } from 'api/addCard'; import { addCard } from 'api/addCard';
import { removeCard } from 'api/removeCard'; import { removeCard } from 'api/removeCard';
import { UploadContext } from 'context/UploadContext'; import { UploadContext } from 'context/UploadContext';
import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt'
export function useCardContext() { export function useCardContext() {
const [state, setState] = useState({ const [state, setState] = useState({
@ -271,6 +273,28 @@ export function useCardContext() {
} }
return card.data.cardProfile.name; return card.data.cardProfile.name;
}, },
unsealChannelSubject: (cardId, channelId, sealKey) => {
const card = cards.current.get(cardId);
const channel = card.channels.get(channelId);
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.data.channelDetail.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 });
channel.data.unsealedChannel = JSON.parse(dec.toString(CryptoJS.enc.Utf8));
card.channels.set(channel.id, { ...channel });
cards.current.set(cardId, { ...card });
updateState({ cards: cards.current });
}
});
},
removeChannel: async (cardId, channelId) => { removeChannel: async (cardId, channelId) => {
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;

View File

@ -43,10 +43,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.unsealedSubject = null;
} }
cur.data.detailRevision = channel.data.detailRevision; cur.data.detailRevision = channel.data.detailRevision;
} }
@ -128,6 +130,11 @@ export function useChannelContext() {
const data = { subjectEncrypted, subjectIv, seals }; const data = { subjectEncrypted, subjectIv, seals };
return await addChannel(access.current, 'sealed', cards, data); return await addChannel(access.current, 'sealed', cards, data);
}, },
unsealChannelSubject: (channelId, sealKey) => {
console.log("unseal: ", channelId);
let sealed = channels.current.get(channelId);
console.log(sealed);
},
setChannelSubject: async (channelId, subject) => { setChannelSubject: async (channelId, subject) => {
return await setChannelSubject(access.current, channelId, subject); return await setChannelSubject(access.current, channelId, subject);
}, },

View File

@ -116,7 +116,7 @@ export function AccountAccess() {
)} )}
{ state.sealMode === 'unlocking' && ( { state.sealMode === 'unlocking' && (
<div class="sealPassword"> <div class="sealPassword">
<Input placeholder="Password" spellCheck="false" onChange={(e) => actions.setSealUnlock(e.target.value)} <Input.Password placeholder="Password" spellCheck="false" onChange={(e) => actions.setSealUnlock(e.target.value)}
prefix={<LockOutlined />} /> prefix={<LockOutlined />} />
</div> </div>
)} )}

View File

@ -1,7 +1,7 @@
import { Tooltip } from 'antd'; import { Tooltip } from 'antd';
import { ChannelItemWrapper, Markup } from './ChannelItem.styled'; import { ChannelItemWrapper, Markup } from './ChannelItem.styled';
import { Logo } from 'logo/Logo'; import { Logo } from 'logo/Logo';
import { AppstoreFilled, SolutionOutlined } from '@ant-design/icons'; import { AppstoreFilled, SolutionOutlined, UnlockOutlined, LockFilled } from '@ant-design/icons';
export function ChannelItem({ item, openChannel, active }) { export function ChannelItem({ item, openChannel, active }) {
@ -32,7 +32,15 @@ export function ChannelItem({ item, openChannel, active }) {
<Logo url={item.logo} width={32} height={32} radius={8} /> <Logo url={item.logo} width={32} height={32} radius={8} />
</div> </div>
<div class="details"> <div class="details">
<div class="subject">{ item.subject }</div> <div class="subject">
{ item.locked && !item.unlocked && (
<LockFilled style={{ paddingRight: 8 }}/>
)}
{ item.locked && item.unlocked && (
<UnlockOutlined style={{ paddingRight: 8 }}/>
)}
<span>{ item.subject }</span>
</div>
<div class="message">{ item.message }</div> <div class="message">{ item.message }</div>
</div> </div>
{ item.updated && ( { item.updated && (
@ -46,7 +54,15 @@ export function ChannelItem({ item, openChannel, active }) {
<AppstoreFilled /> <AppstoreFilled />
</div> </div>
<div class="details"> <div class="details">
<div class="subject">{ item.subject }</div> <div class="subject">
{ item.locked && !item.unlocked && (
<LockFilled style={{ paddingRight: 8 }}/>
)}
{ item.locked && item.unlocked && (
<UnlockOutlined style={{ paddingRight: 8 }}/>
)}
<span>{ item.subject }</span>
</div>
<div class="message">{ item.message }</div> <div class="message">{ item.message }</div>
</div> </div>
{ item.updated && ( { item.updated && (

View File

@ -153,12 +153,36 @@ export function useChannels() {
const setSubject = (chan) => { const setSubject = (chan) => {
let subject = ""; let subject = "";
if (chan.data.channelDetail?.data) { if (chan.data.channelDetail.dataType === 'sealed') {
try { chan.locked = chan.data.channelDetail.dataType === 'sealed'
subject = JSON.parse(chan.data.channelDetail?.data).subject; if (state.sealable) {
try {
if (chan.data.unsealedChannel == null) {
if (chan.cardId) {
card.actions.unsealChannelSubject(chan.cardId, chan.id, account.state.sealKey);
}
else {
channel.actions.unsealChannelSubject(chan.id, account.state.sealKey);
}
}
else {
chan.unlocked = true;
subject = chan.data.unsealedChannel.subject;
}
}
catch (err) {
console.log(err)
}
} }
catch (err) { }
console.log(err); else {
if (chan.data.channelDetail?.data) {
try {
subject = JSON.parse(chan.data.channelDetail?.data).subject;
}
catch (err) {
console.log(err);
}
} }
} }
if (!subject) { if (!subject) {
@ -223,7 +247,7 @@ export function useChannels() {
updateState({ channels: filtered }); updateState({ channels: filtered });
// eslint-disable-next-line // eslint-disable-next-line
}, [channel, card, store, filter]); }, [channel, card, store, filter, state.sealable]);
useEffect(() => { useEffect(() => {
updateState({ display: viewport.state.display }); updateState({ display: viewport.state.display });