mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 20:49:16 +00:00
unsealing channel subject in mobile app
This commit is contained in:
parent
356ec4dc45
commit
fd086e2333
@ -33,6 +33,9 @@ import { removeContactChannelTopic } from 'api/removeContactChannelTopic';
|
|||||||
import { getContactChannelNotifications } from 'api/getContactChannelNotifications';
|
import { getContactChannelNotifications } from 'api/getContactChannelNotifications';
|
||||||
import { setContactChannelNotifications } from 'api/setContactChannelNotifications';
|
import { setContactChannelNotifications } from 'api/setContactChannelNotifications';
|
||||||
|
|
||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
import { JSEncrypt } from 'jsencrypt'
|
||||||
|
|
||||||
export function useCardContext() {
|
export function useCardContext() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
cards: new Map(),
|
cards: new Map(),
|
||||||
@ -595,6 +598,36 @@ export function useCardContext() {
|
|||||||
const { detail, profile } = getCardEntry(cardId);
|
const { detail, profile } = getCardEntry(cardId);
|
||||||
return await setContactChannelNotifications(profile.node, `${profile.guid}.${detail.token}`, channelId, notify);
|
return await setContactChannelNotifications(profile.node, `${profile.guid}.${detail.token}`, channelId, notify);
|
||||||
},
|
},
|
||||||
|
unsealChannelSubject: async (cardId, channelId, revision, sealKey) => {
|
||||||
|
try {
|
||||||
|
const { guid } = session.current;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
resync: (cardId) => {
|
resync: (cardId) => {
|
||||||
resync.current.push(cardId);
|
resync.current.push(cardId);
|
||||||
sync();
|
sync();
|
||||||
|
@ -334,6 +334,34 @@ export function useChannelContext() {
|
|||||||
const { server, appToken } = session.current;
|
const { server, appToken } = session.current;
|
||||||
return await setChannelNotifications(server, appToken, channelId, notify);
|
return await setChannelNotifications(server, appToken, channelId, notify);
|
||||||
},
|
},
|
||||||
|
unsealChannelSubject: async (channelId, revision, sealKey) => {
|
||||||
|
try {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await store.actions.setChannelItemUnsealedDetail(guid, channelId, revision, channel.unsealedDetail);
|
||||||
|
channels.current.set(channelId, { ...channel });
|
||||||
|
updateState({ channels: channels.current });
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState, useRef, useContext } from 'react';
|
import { useEffect, useState, useRef, useContext } from 'react';
|
||||||
import SQLite from "react-native-sqlite-storage";
|
import SQLite from "react-native-sqlite-storage";
|
||||||
|
|
||||||
const DATABAG_DB = 'databag_v064.db';
|
const DATABAG_DB = 'databag_v068.db';
|
||||||
|
|
||||||
export function useStoreContext() {
|
export function useStoreContext() {
|
||||||
const [state, setState] = useState({});
|
const [state, setState] = useState({});
|
||||||
@ -221,6 +221,9 @@ export function useStoreContext() {
|
|||||||
setChannelItemDetail: async (guid, channelId, revision, detail) => {
|
setChannelItemDetail: async (guid, channelId, revision, detail) => {
|
||||||
await db.current.executeSql(`UPDATE channel_${guid} set detail_revision=?, detail=?, unsealed_detail=null where channel_id=?`, [revision, encodeObject(detail), channelId]);
|
await db.current.executeSql(`UPDATE channel_${guid} set detail_revision=?, detail=?, unsealed_detail=null where channel_id=?`, [revision, encodeObject(detail), channelId]);
|
||||||
},
|
},
|
||||||
|
setChannelItemUnsealedDetail: async (guid, channelId, revision, unsealed) => {
|
||||||
|
await db.current.executeSql(`UPDATE channel_${guid} set unsealed_detail=? where detail_revision=? AND channel_id=?`, [encodeObject(unsealed), revision, channelId]);
|
||||||
|
},
|
||||||
setChannelItemSummary: async (guid, channelId, revision, summary) => {
|
setChannelItemSummary: async (guid, channelId, revision, summary) => {
|
||||||
await db.current.executeSql(`UPDATE channel_${guid} set topic_revision=?, summary=?, unsealed_summary=null where channel_id=?`, [revision, encodeObject(summary), channelId]);
|
await db.current.executeSql(`UPDATE channel_${guid} set topic_revision=?, summary=?, unsealed_summary=null where channel_id=?`, [revision, encodeObject(summary), channelId]);
|
||||||
},
|
},
|
||||||
@ -236,7 +239,7 @@ export function useStoreContext() {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
getChannelItems: async (guid) => {
|
getChannelItems: async (guid) => {
|
||||||
const values = await getAppValues(db.current, `SELECT channel_id, read_revision, revision, sync_revision, blocked, detail_revision, topic_revision, detail, summary FROM channel_${guid}`, []);
|
const values = await getAppValues(db.current, `SELECT channel_id, read_revision, revision, sync_revision, blocked, detail_revision, topic_revision, detail, unsealed_detail, summary, unsealed_summary FROM channel_${guid}`, []);
|
||||||
return values.map(channel => ({
|
return values.map(channel => ({
|
||||||
channelId: channel.channel_id,
|
channelId: channel.channel_id,
|
||||||
revision: channel.revision,
|
revision: channel.revision,
|
||||||
@ -254,7 +257,7 @@ export function useStoreContext() {
|
|||||||
|
|
||||||
|
|
||||||
getChannelTopicItems: async (guid, channelId) => {
|
getChannelTopicItems: async (guid, channelId) => {
|
||||||
const values = await getAppValues(db.current, `SELECT topic_id, revision, blocked, detail_revision, detail FROM channel_topic_${guid} WHERE channel_id=?`, [channelId]);
|
const values = await getAppValues(db.current, `SELECT topic_id, revision, blocked, detail_revision, detail, unsealed_detail FROM channel_topic_${guid} WHERE channel_id=?`, [channelId]);
|
||||||
return values.map(topic => ({
|
return values.map(topic => ({
|
||||||
topicId: topic.topic_id,
|
topicId: topic.topic_id,
|
||||||
revision: topic.revision,
|
revision: topic.revision,
|
||||||
@ -305,6 +308,9 @@ export function useStoreContext() {
|
|||||||
setCardChannelItemDetail: async (guid, cardId, channelId, revision, detail) => {
|
setCardChannelItemDetail: async (guid, cardId, channelId, revision, detail) => {
|
||||||
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]);
|
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) => {
|
||||||
|
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) => {
|
setCardChannelItemSummary: async (guid, cardId, channelId, revision, summary) => {
|
||||||
await db.current.executeSql(`UPDATE card_channel_${guid} set topic_revision=?, summary=?, unsealed_summary=null where card_id=? and channel_id=?`, [revision, encodeObject(summary), cardId, channelId]);
|
await db.current.executeSql(`UPDATE card_channel_${guid} set topic_revision=?, summary=?, unsealed_summary=null where card_id=? and channel_id=?`, [revision, encodeObject(summary), cardId, channelId]);
|
||||||
},
|
},
|
||||||
@ -320,7 +326,7 @@ export function useStoreContext() {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
getCardChannelItems: async (guid) => {
|
getCardChannelItems: async (guid) => {
|
||||||
const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, sync_revision, revision, blocked, detail_revision, topic_revision, detail, summary FROM card_channel_${guid}`, []);
|
const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, sync_revision, revision, blocked, detail_revision, topic_revision, detail, unsealed_detail, summary, unsealed_summary FROM card_channel_${guid}`, []);
|
||||||
return values.map(channel => ({
|
return values.map(channel => ({
|
||||||
cardId: channel.card_id,
|
cardId: channel.card_id,
|
||||||
channelId: channel.channel_id,
|
channelId: channel.channel_id,
|
||||||
@ -341,7 +347,7 @@ export function useStoreContext() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getCardChannelTopicItems: async (guid, cardId, channelId) => {
|
getCardChannelTopicItems: async (guid, cardId, channelId) => {
|
||||||
const values = await getAppValues(db.current, `SELECT topic_id, revision, blocked, detail_revision, detail FROM card_channel_topic_${guid} WHERE card_id=? AND channel_id=?`, [cardId, channelId]);
|
const values = await getAppValues(db.current, `SELECT topic_id, revision, blocked, detail_revision, detail, unsealed_detail FROM card_channel_topic_${guid} WHERE card_id=? AND channel_id=?`, [cardId, channelId]);
|
||||||
return values.map(topic => ({
|
return values.map(topic => ({
|
||||||
topicId: topic.topic_id,
|
topicId: topic.topic_id,
|
||||||
revision: topic.revision,
|
revision: topic.revision,
|
||||||
|
@ -3,6 +3,8 @@ import { TouchableOpacity } from 'react-native-gesture-handler';
|
|||||||
import { Logo } from 'utils/Logo';
|
import { Logo } from 'utils/Logo';
|
||||||
import { styles } from './ChannelItem.styled';
|
import { styles } from './ChannelItem.styled';
|
||||||
import { useChannelItem } from './useChannelItem.hook';
|
import { useChannelItem } from './useChannelItem.hook';
|
||||||
|
import Colors from 'constants/Colors';
|
||||||
|
import Ionicons from '@expo/vector-icons/MaterialCommunityIcons';
|
||||||
|
|
||||||
export function ChannelItem({ item, openConversation }) {
|
export function ChannelItem({ item, openConversation }) {
|
||||||
|
|
||||||
@ -12,7 +14,15 @@ export function ChannelItem({ item, openConversation }) {
|
|||||||
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={() => openConversation(item.cardId, item.channelId, item.revision)}>
|
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={() => openConversation(item.cardId, item.channelId, item.revision)}>
|
||||||
<Logo src={item.logo} width={32} height={32} radius={6} />
|
<Logo src={item.logo} width={32} height={32} radius={6} />
|
||||||
<View style={styles.detail}>
|
<View style={styles.detail}>
|
||||||
<Text style={styles.subject} numberOfLines={1} ellipsizeMode={'tail'}>{ item.subject }</Text>
|
<View style={styles.subject}>
|
||||||
|
{ item.locked && !item.unlocked && (
|
||||||
|
<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} />
|
||||||
|
)}
|
||||||
|
<Text style={styles.subjectText} numberOfLines={1} ellipsizeMode={'tail'}>{ item.subject }</Text>
|
||||||
|
</View>
|
||||||
<Text style={styles.message} numberOfLines={1} ellipsizeMode={'tail'}>{ item.message }</Text>
|
<Text style={styles.message} numberOfLines={1} ellipsizeMode={'tail'}>{ item.message }</Text>
|
||||||
</View>
|
</View>
|
||||||
{ item.updated && (
|
{ item.updated && (
|
||||||
|
@ -22,6 +22,13 @@ export const styles = StyleSheet.create({
|
|||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
},
|
},
|
||||||
subject: {
|
subject: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
subjectIcon: {
|
||||||
|
paddingRight: 4,
|
||||||
|
},
|
||||||
|
subjectText: {
|
||||||
color: Colors.text,
|
color: Colors.text,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
|
@ -133,8 +133,32 @@ export function useChannels() {
|
|||||||
logo = 'appstore';
|
logo = 'appstore';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let locked = false;
|
||||||
|
let unlocked = false;
|
||||||
let subject = null;
|
let subject = null;
|
||||||
if (item?.detail?.data) {
|
if (item?.detail?.dataType === 'sealed') {
|
||||||
|
locked = true;
|
||||||
|
if (state.sealable) {
|
||||||
|
try {
|
||||||
|
if (item.unsealedDetail == null) {
|
||||||
|
if (item.cardId) {
|
||||||
|
card.actions.unsealChannelSubject(item.cardId, item.channelId, item.detailRevision, account.state.sealKey);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
channel.actions.unsealChannelSubject(item.channelId, item.detailRevision, account.state.sealKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlocked = true;
|
||||||
|
subject = item.unsealedDetail.subject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
try {
|
try {
|
||||||
subject = JSON.parse(item?.detail?.data).subject;
|
subject = JSON.parse(item?.detail?.data).subject;
|
||||||
}
|
}
|
||||||
@ -170,7 +194,7 @@ export function useChannels() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { cardId: item.cardId, channelId: item.channelId, contacts, logo, subject, message, updated, revision: item.revision, timestamp: created, blocked: item.blocked === 1 };
|
return { cardId: item.cardId, channelId: item.channelId, contacts, logo, subject, locked, unlocked, message, updated, revision: item.revision, timestamp: created, blocked: item.blocked === 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -214,7 +238,7 @@ export function useChannels() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
updateState({ channels: sorted });
|
updateState({ channels: sorted });
|
||||||
}, [channel, card, state.filter]);
|
}, [channel, card, state.filter, state.sealable]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setSealed: (sealed) => {
|
setSealed: (sealed) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user