decrypting image media

This commit is contained in:
balzack 2024-12-30 23:12:37 -08:00
parent 032217cefb
commit 68e4492402
15 changed files with 10421 additions and 7164 deletions

View File

@ -1193,6 +1193,8 @@ PODS:
- React-utils (= 0.74.3)
- RNCClipboard (1.15.0):
- React-Core
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.21.2):
- DoubleConversion
- glog
@ -1420,6 +1422,7 @@ DEPENDENCIES:
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
@ -1551,6 +1554,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
RNCClipboard:
:path: "../node_modules/@react-native-clipboard/clipboard"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNImageCropPicker:
@ -1625,6 +1630,7 @@ SPEC CHECKSUMS:
React-utils: a06061b3887c702235d2dac92dacbd93e1ea079e
ReactCommon: f00e436b3925a7ae44dfa294b43ef360fbd8ccc4
RNCClipboard: 69ab8e51324d5b351f6ba72bbdb72478087a2c64
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 6fee3422fd8c81c5ee756fa72e3d1780e9943d9d
RNImageCropPicker: a536bb88eade8336e1d18fdeafa77dc893fbc42e
RNReanimated: 30ed0985f2b8dc16a76c23362cabe8dd5166b64f

View File

@ -23,6 +23,7 @@
"react": "18.2.0",
"react-dom": "^18.3.1",
"react-native": "0.74.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.19.0",
"react-native-image-crop-picker": "^0.41.2",
"react-native-keyboard-aware-scroll-view": "^0.9.5",

View File

@ -0,0 +1,31 @@
import { Media } from 'databag-client-sdk'
import RNFS from 'react-native-fs';
export class MediaFiles implements Media {
public async read(source: any): Promise<{ size: number, getData: (position: number, length: number)=>Promise<string>, close: ()=>Promise<void> }> {
const path = source;
const stat = await RNFS.stat(path);
const size = state.size;
const getData = async (position: number, length: number) => {
return await RNFS.read(path, length, position, 'base64');
}
const close = async ()=>{}
return { size, getData, close };
}
public async write(): Promise<{ setData: (data: string)=>Promise<void>, getUrl: ()=>Promise<string>, close: ()=>Promise<void> }> {
const path = RNFS.DocumentDirectoryPath + `/${Date.now()}.dat`
const setData = async (data: string) => {
await RNFS.appendFile(path, data, 'base64');
}
const getUrl = async () => {
return `${path}`
}
const close = async () => {
await RNFS.unlink(path);
}
return { setData, getUrl };
}
}

View File

@ -226,8 +226,8 @@ export function useContent() {
setTopic: (topic: string) => {
updateState({topic});
},
setFocus: (cardId: string | null, channelId: string) => {
app.actions.setFocus(cardId, channelId);
setFocus: async (cardId: string | null, channelId: string) => {
await app.actions.setFocus(cardId, channelId);
},
addTopic: async (sealed: boolean, subject: string, contacts: string[]) => {
const content = app.state.session.getContent()

View File

@ -3,7 +3,8 @@ import {DatabagSDK, Session, Focus} from 'databag-client-sdk';
import {SessionStore} from '../SessionStore';
import {NativeCrypto} from '../NativeCrypto';
import {LocalStore} from '../LocalStore';
const DATABAG_DB = 'db_v237.db';
import { MediaFiles } from '../MediaFiles'
const DATABAG_DB = 'db_v239.db';
const SETTINGS_DB = 'ls_v001.db';
const databag = new DatabagSDK(
@ -14,6 +15,7 @@ const databag = new DatabagSDK(
channelTypes: ['sealed', 'superbasic'],
},
new NativeCrypto(),
new MediaFiles(),
);
export function useAppContext() {
@ -117,9 +119,9 @@ export function useAppContext() {
const session = await sdk.current.access(node, secure, token, params);
updateState({session});
},
setFocus: (cardId: string | null, channelId: string) => {
setFocus: async (cardId: string | null, channelId: string) => {
if (state.session) {
const focus = state.session.setFocus(cardId, channelId);
const focus = await state.session.setFocus(cardId, channelId);
updateState({ focus });
}
},

View File

@ -21,4 +21,24 @@ export const styles = StyleSheet.create({
thumb: {
borderRadius: 4,
},
full: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
},
close: {
position: 'absolute',
top: 0,
right: 0,
},
closeIcon: {
backgroundColor: 'transparent',
},
progress: {
position: 'absolute',
bottom: '10%',
width: '50%',
},
});

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import { Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native'
import { Text } from 'react-native-paper'
import { SafeAreaView, Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native'
import { ProgressBar, IconButton } from 'react-native-paper'
import { useImageAsset } from './useImageAsset.hook';
import { MediaAsset } from '../../conversation/Conversation';
import { styles } from './ImageAsset.styled'
@ -21,10 +21,20 @@ export function ImageAsset({ topicId, asset }: { topicId: string, asset: MediaAs
}
}, [state.loaded]);
const showImage = () => {
setModal(true);
actions.loadImage();
};
const hideImage = () => {
setModal(false);
actions.unloadImage();
}
return (
<View style={styles.image}>
{ state.thumbUrl && (
<Pressable onPress={()=>setModal(true)}>
<Pressable onPress={showImage}>
<Animated.Image
style={[styles.thumb,{opacity},]}
resizeMode="contain"
@ -35,10 +45,30 @@ export function ImageAsset({ topicId, asset }: { topicId: string, asset: MediaAs
/>
</Pressable>
)}
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={modal} onRequestClose={() => setModal(false)}>
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={modal} onRequestClose={hideImage}>
<View style={styles.modal}>
<BlurView style={styles.blur} blurType="dark" blurAmount={2} reducedTransparencyFallbackColor="dark" />
<View style={{ width: 200, height: 200, backgroundColor: 'yellow' }} />
<BlurView style={styles.blur} blurType="dark" blurAmount={16} reducedTransparencyFallbackColor="dark" />
<Image
style={styles.full}
resizeMode="contain"
source={{ uri: state.thumbUrl }}
/>
{ state.dataUrl && (
<Image
style={styles.full}
resizeMode="contain"
onError={(err)=>console.log(err)}
source={{ uri: state.dataUrl }}
/>
)}
{ state.loading && (
<View style={styles.progress}>
<ProgressBar progress={state.loadPercent / 100} />
</View>
)}
<SafeAreaView style={styles.close}>
<IconButton style={styles.closeIcon} icon="close" compact="true" mode="contained" size={28} onPress={hideImage} />
</SafeAreaView>
</View>
</Modal>
</View>

File diff suppressed because it is too large Load Diff

View File

@ -245,8 +245,8 @@ export function useContent() {
setTopic: (topic: string) => {
updateState({ topic })
},
setFocus: (cardId: string | null, channelId: string) => {
app.actions.setFocus(cardId, channelId)
setFocus: async (cardId: string | null, channelId: string) => {
await app.actions.setFocus(cardId, channelId)
},
openTopic: async (cardId: string) => {
const content = app.state.session.getContent()

View File

@ -82,9 +82,9 @@ export function useAppContext() {
const session = await sdk.current.access(node, secure, token, params)
updateState({ session })
},
setFocus: (cardId: string | null, channelId: string) => {
setFocus: async (cardId: string | null, channelId: string) => {
if (state.session) {
const focus = state.session.setFocus(cardId, channelId);
const focus = async state.session.setFocus(cardId, channelId);
updateState({ focus });
}
},

View File

@ -9,7 +9,7 @@ export interface Session {
getContent(): Content;
getRing(): Ring;
setFocus(cardId: string | null, channelId: string): Focus;
setFocus(cardId: string | null, channelId: string): Promise<Focus>;
clearFocus(): void;
addStatusListener(ev: (status: string) => void): void;

View File

@ -682,7 +682,7 @@ export class ContactModule implements Contact {
this.emitter.emit('channel', { cardId, channels });
}
public setFocus(cardId: string, channelId: string): Focus {
public async setFocus(cardId: string, channelId: string): Promise<Focus> {
if (this.focus) {
this.focus.close();
}
@ -713,7 +713,7 @@ export class ContactModule implements Contact {
const guid = cardEntry.item.profile.guid;
const token = cardEntry.item.detail.token;
const revision = channelEntry.item.summary.revision;
const channelKey = channelEntry.item.channelKey;
const channelKey = await this.setChannelKey(channelEntry.item);
const sealEnabled = Boolean(this.seal);
const insecure = /^(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|:\d+$|$)){4}$/.test(node);
this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, cardId, channelId, this.guid, { node, secure: !insecure, token: `${guid}.${token}` }, channelKey, sealEnabled, revision, markRead, flagTopic);
@ -741,7 +741,7 @@ export class ContactModule implements Contact {
return this.focus;
}
public async clearFocus() {
public clearFocus() {
if (this.focus) {
this.focus.close();
this.focus = null;
@ -1095,6 +1095,18 @@ export class ContactModule implements Contact {
return null;
}
private async setChannelKey(item: ChannelItem) {
if (!item.channelKey && item.detail.dataType === 'sealed' && this.seal && this.crypto) {
try {
const { seals } = JSON.parse(item.detail.data);
item.channelKey = await this.getChannelKey(seals);
} catch (err) {
console.log(err);
}
}
return item.channelKey;
}
private async unsealChannelDetail(cardId: string, channelId: string, item: ChannelItem): Promise<boolean> {
if (item.unsealedDetail == null && item.detail.dataType === 'sealed' && this.seal && this.crypto) {
try {

View File

@ -941,6 +941,8 @@ export class FocusModule implements Focus {
}
public async setChannelKey(cardId: string | null, channelId: string, channelKey: string | null) {
console.log("!!!! SET CHANNEL KEY", cardId, channelId, channelKey);
if (cardId === this.cardId && channelId === this.channelId) {
this.channelKey = channelKey;
this.unsealAll = true;

View File

@ -155,15 +155,15 @@ export class SessionModule implements Session {
return this.ring;
}
public setFocus(cardId: string | null, channelId: string): Focus {
public async setFocus(cardId: string | null, channelId: string): Promise<Focus> {
if (cardId) {
return this.contact.setFocus(cardId, channelId);
return await this.contact.setFocus(cardId, channelId);
} else {
return this.stream.setFocus(channelId);
return await this.stream.setFocus(channelId);
}
}
public async clearFocus() {
public clearFocus() {
this.contact.clearFocus();
this.stream.clearFocus();
}

View File

@ -426,7 +426,7 @@ export class StreamModule {
}
}
public setFocus(channelId: string): Focus {
public async setFocus(channelId: string): Promise<Focus> {
const { node, secure, token, focus } = this;
if (focus) {
focus.close();
@ -446,7 +446,7 @@ export class StreamModule {
}
const entry = this.channelEntries.get(channelId);
const channelKey = entry ? entry.item.channelKey : null;
const channelKey = entry ? await this.setChannelKey(entry.item) : null;
const revision = entry ? entry.item.summary.revision : 0;
const sealEnabled = Boolean(this.seal);
this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, null, channelId, this.guid, { node, secure, token }, channelKey, sealEnabled, revision, markRead, flagTopic);
@ -602,6 +602,18 @@ export class StreamModule {
return channelEntry;
}
private async setChannelKey(item: ChannelItem) {
if (!item.channelKey && item.detail.dataType === 'sealed' && this.seal && this.crypto) {
try {
const { seals } = JSON.parse(item.detail.data);
item.channelKey = await this.getChannelKey(seals);
} catch (err) {
console.log(err);
}
}
return item.channelKey;
}
private async unsealChannelDetail(channelId: string, item: ChannelItem): Promise<boolean> {
if (item.unsealedDetail == null && item.detail.dataType === 'sealed' && this.seal && this.crypto) {
try {