support updating sealed channels subjects in mobile app

This commit is contained in:
balzack 2022-12-14 17:12:57 -08:00
parent d7cd2bd018
commit 6ee1ebef14
7 changed files with 47 additions and 13 deletions

View File

@ -669,7 +669,7 @@ SPEC CHECKSUMS:
FirebaseInstallations: 99d24bac0243cf8b0e96cf5426340d211f0bcc80
FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431

View File

@ -1,8 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelSubject(server, token, channelId, subject ) {
let data = { subject };
let params = { dataType: 'superbasic', data: JSON.stringify(data) };
export async function setChannelSubject(server, token, channelId, dataType, data ) {
let params = { dataType, data: JSON.stringify(data) };
let channel = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/subject?agent=${token}`, { method: 'PUT', body: JSON.stringify(params)} );
checkResponse(channel);
return await channel.json();

View File

@ -273,9 +273,30 @@ export function useChannelContext() {
const { server, appToken } = session.current;
return await setChannelTopicSubject(server, appToken, channelId, topicId, data);
},
setSubject: async (channelId, data) => {
setSubject: async (channelId, subject) => {
const { server, appToken } = session.current;
return await setChannelSubject(server, appToken, channelId, data);
return await setChannelSubject(server, appToken, channelId, 'superbasic', { subject });
},
setSealedSubject: async (channelId, subject, sealKey) => {
const { server, appToken } = session.current;
const channel = channels.current.get(channelId);
let { seals, subjectEncrypted, subjectIv } = 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 key = CryptoJS.enc.Hex.parse(unsealedKey);
const iv = CryptoJS.lib.WordArray.random(128 / 8);
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ subject }), key, { iv: iv });
subjectEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
subjectIv = iv.toString();
}
});
const data = { subjectEncrypted, subjectIv, seals };
return await setChannelSubject(server, appToken, channelId, 'sealed', data);
},
remove: async (channelId) => {
const { server, appToken } = session.current;

View File

@ -333,7 +333,8 @@ export function useConversationContext() {
locked = true;
unlocked = item.unsealedDetail != null;
if (item.unsealedDetail?.subject) {
subject = item.unsealedDetail.subject;
topic = item.unsealedDetail.subject;
subject = topic;
}
try {
seals = JSON.parse(item.detail.data).seals;
@ -440,6 +441,15 @@ export function useConversationContext() {
await channel.actions.setSubject(channelId, subject);
}
},
setSealedSubject: async (subject, sealKey) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
throw new Error("can only set hosted channel subjects");
}
await channel.actions.setSealedSubject(channelId, subject, sealKey);
}
},
remove: async () => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;

View File

@ -19,7 +19,7 @@ export function ChannelItem({ item, openConversation }) {
<Ionicons name="lock" style={styles.subjectIcon} size={16} color={Colors.text} />
)}
{ item.locked && item.unlocked && (
<Ionicons name="lock-open-variant-outline" style={styles.subjectIcon} size={16} color={Colors.text} />
<Ionicons name="lock-open-variant-outline" style={styles.subjectIcon} size={16} color={Colors.grey} />
)}
<Text style={styles.subjectText} numberOfLines={1} ellipsizeMode={'tail'}>{ item.subject }</Text>
</View>

View File

@ -136,7 +136,7 @@ export function DetailsBody({ channel, clearConversation }) {
<MatIcons name="lock-open-variant-outline" style={styles.subjectIcon} size={16} color={Colors.text} />
)}
<Text style={styles.subjectText} numberOfLines={1} ellipsizeMode={'tail'}>{ state.subject }</Text>
{ !state.hostId && (
{ !state.hostId && (!state.locked || state.sealable) && (
<TouchableOpacity onPress={actions.showEditSubject}>
<AntIcons name="edit" size={16} color={Colors.text} />
</TouchableOpacity>
@ -166,7 +166,7 @@ export function DetailsBody({ channel, clearConversation }) {
<Text style={styles.buttonText}>Report Topic</Text>
</TouchableOpacity>
)}
{ !state.hostId && (
{ !state.hostId && !state.locked && (
<TouchableOpacity style={styles.button} onPress={actions.showEditMembers}>
<Text style={styles.buttonText}>Edit Membership</Text>
</TouchableOpacity>

View File

@ -20,7 +20,6 @@ export function useDetails() {
locked: false,
unlocked: false,
sealable: false,
});
const account = useContext(AccountContext);
@ -37,7 +36,7 @@ export function useDetails() {
if (account.state.sealKey && conversation.state.seals) {
conversation.state.seals.forEach(seal => {
if (seal.publicKey === account.state.sealKey.public) {
sealabel = true;
sealable = true;
}
});
}
@ -72,7 +71,12 @@ export function useDetails() {
updateState({ subjectUpdate });
},
saveSubject: async () => {
if (state.locked) {
await conversation.actions.setSealedSubject(state.subjectUpdate, account.state.sealKey);
}
else {
await conversation.actions.setSubject(state.subjectUpdate);
}
},
remove: async () => {
await conversation.actions.remove();