mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 12:39:17 +00:00
adding e2e key management in mobile app
This commit is contained in:
parent
32e2479793
commit
4a8c2f1776
@ -669,7 +669,7 @@ SPEC CHECKSUMS:
|
||||
FirebaseInstallations: 99d24bac0243cf8b0e96cf5426340d211f0bcc80
|
||||
FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
|
||||
GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7
|
||||
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
|
||||
|
7
app/mobile/src/api/setAccountSeal.js
Normal file
7
app/mobile/src/api/setAccountSeal.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function setAccountSeal(server, token, seal) {
|
||||
let res = await fetchWithTimeout(`https://${server}/account/seal?agent=${token}`, { method: 'PUT', body: JSON.stringify(seal) })
|
||||
checkResponse(res);
|
||||
}
|
||||
|
@ -48,8 +48,9 @@ export function useAccountContext() {
|
||||
setSession: async (access) => {
|
||||
const { guid, server, appToken } = access;
|
||||
const status = await store.actions.getAccountStatus(guid);
|
||||
const sealKey = await store.actions.getAccountSealKey(guid);
|
||||
const revision = await store.actions.getAccountRevision(guid);
|
||||
updateState({ status });
|
||||
updateState({ status, sealKey });
|
||||
setRevision.current = revision;
|
||||
curRevision.current = revision;
|
||||
session.current = access;
|
||||
@ -70,6 +71,16 @@ export function useAccountContext() {
|
||||
const { server, appToken } = session.current;
|
||||
await setAccountSearchable(server, appToken, flag);
|
||||
},
|
||||
setAccountSeal: async (seal, key) => {
|
||||
const { guid, server, appToken } = session.current;
|
||||
await setAccountSeal(server, appToken, seal);
|
||||
await store.actions.setAccountSealKey(guid, key);
|
||||
updateState({ sealKey: key });
|
||||
},
|
||||
unlockAccountSeal: async (key) => {
|
||||
await store.actions.setAccountSealKey(guid, key);
|
||||
updateState({ sealKey: key });
|
||||
},
|
||||
setLogin: async (username, password) => {
|
||||
const { server, appToken } = session.current;
|
||||
await setAccountLogin(server, appToken, username, password);
|
||||
|
@ -76,6 +76,14 @@ export function useStoreContext() {
|
||||
const dataId = `${guid}_status`;
|
||||
await db.current.executeSql("INSERT OR REPLACE INTO app (key, value) values (?, ?);", [dataId, encodeObject(status)]);
|
||||
},
|
||||
getAccountSealKey: async (guid) => {
|
||||
const dataId = `${guid}_sealkey`;
|
||||
return await getAppValue(db.current, dataId, {});
|
||||
},
|
||||
setAccountSealKey: async (guid, key) => {
|
||||
const dataId = `${guid}_sealkey`;
|
||||
await db.current.executeSql("INSERT OR REPLACE INTO app (key, value) values (?, ?);", [dataId, encodeObject(key)]);
|
||||
},
|
||||
getAccountRevision: async (guid) => {
|
||||
const dataId = `${guid}_accountRevision`;
|
||||
return await getAppValue(db.current, dataId, null);
|
||||
|
@ -143,10 +143,12 @@ export function ProfileBody({ navigation }) {
|
||||
</TouchableOpacity>
|
||||
<Switch style={styles.visibleSwitch} value={state.pushEnabled} onValueChange={setNotifications} trackColor={styles.switch}/>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.link} onPress={actions.sealTest}>
|
||||
<Text style={styles.linkText}>Test Seal</Text>
|
||||
<TouchableOpacity style={styles.link} onPress={actions.showSealEdit}>
|
||||
<Ionicons name="setting" size={14} color={Colors.primary} />
|
||||
<Text style={styles.linkText}>Sealed Topics</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.link} onPress={actions.showLoginEdit}>
|
||||
<Ionicons name="lock" size={14} color={Colors.primary} />
|
||||
<Text style={styles.linkText}>Change Login</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.link} onPress={actions.showBlockedCards}>
|
||||
@ -256,6 +258,128 @@ export function ProfileBody({ navigation }) {
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
|
||||
|
||||
|
||||
<Modal
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
visible={state.sealEdit}
|
||||
supportedOrientations={['portrait', 'landscape']}
|
||||
onRequestClose={actions.hideSealEdit}
|
||||
>
|
||||
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
|
||||
<View style={styles.editContainer}>
|
||||
<Text style={styles.editHeader}>Sealed Topics:</Text>
|
||||
<View style={styles.sealable}>
|
||||
<TouchableOpacity onPress={() => actions.setSealable(!state.sealable)} activeOpacity={1}>
|
||||
<Text style={styles.sealableText}>Enable Sealed Topics</Text>
|
||||
</TouchableOpacity>
|
||||
<Switch style={styles.sealableSwitch} value={state.sealable} onValueChange={actions.setSealable} trackColor={styles.switch}/>
|
||||
</View>
|
||||
{ state.sealMode === 'unlocking' && (
|
||||
<>
|
||||
{ !state.showSealUnlock && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.sealUnlock} onChangeText={actions.setSealUnlock}
|
||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Seal Password"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
<TouchableOpacity onPress={actions.showSealUnlock}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ state.showSealUnlock && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.sealUnlock} onChangeText={actions.setSealUnlock}
|
||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Seal Password"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
<TouchableOpacity onPress={actions.hideSealUnlock}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{ (state.sealMode === 'updating' || state.sealMode === 'enabling') && (
|
||||
<>
|
||||
{ !state.showSealPassword && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.sealPassword} onChangeText={actions.setSealPassword}
|
||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password Seal"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
<TouchableOpacity onPress={actions.showSealPassword}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ state.showSealPassword && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.sealPassword} onChangeText={actions.setSealPassword}
|
||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password Seal"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
<TouchableOpacity onPress={actions.hideSealPassword}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ !state.showSealConfirm && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
|
||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Confirm Seal"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
<TouchableOpacity onPress={actions.showSealConfirm}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ state.showSealConfirm && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
|
||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Confirm Seal"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
<TouchableOpacity onPress={actions.hideSealConfirm}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{ state.sealMode === 'disabling' && (
|
||||
<View style={styles.inputField}>
|
||||
<Ionicons style={styles.warn} name="exclamationcircleo" size={18} color="#888888" />
|
||||
<TextInput style={styles.input} value={state.sealDelete} onChangeText={actions.setSealDelete}
|
||||
autoCapitalize={'none'} placeholder="Type 'delete' to remove sealing key"
|
||||
placeholderTextColor={Colors.grey} />
|
||||
</View>
|
||||
)}
|
||||
{ state.sealMode === 'unlocked' && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={'xxxxxxxx'} editable="false" secureTextEntry={true} />
|
||||
<TouchableOpacity style={styles.sealUpdate} onPress={actions.updateSeal} />
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.editControls}>
|
||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
||||
<Text>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
{ state.sealMode !== 'unlocking' && (
|
||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
||||
<Text>Save</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ state.sealMode === 'unlocking' && (
|
||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
||||
<Text>Unlock</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
|
||||
|
||||
|
||||
<Modal
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
|
@ -14,6 +14,10 @@ export const styles = StyleSheet.create({
|
||||
icon: {
|
||||
paddingTop: 2,
|
||||
},
|
||||
warn: {
|
||||
paddingTop: 2,
|
||||
paddingRight: 8,
|
||||
},
|
||||
wrapper: {
|
||||
backgroundColor: Colors.formBackground,
|
||||
},
|
||||
@ -133,6 +137,27 @@ export const styles = StyleSheet.create({
|
||||
fontSize: 16,
|
||||
color: Colors.text,
|
||||
},
|
||||
sealUpdate: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
height: '100%',
|
||||
left: 0,
|
||||
width: '100%',
|
||||
},
|
||||
sealable: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingBottom: 8,
|
||||
},
|
||||
sealableText: {
|
||||
fontSize: 16,
|
||||
color: Colors.text,
|
||||
},
|
||||
sealableSwitch: {
|
||||
transform: [{ scaleX: .7 }, { scaleY: .7 }],
|
||||
},
|
||||
visible: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
@ -282,8 +307,11 @@ export const styles = StyleSheet.create({
|
||||
},
|
||||
link: {
|
||||
marginTop: 16,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
linkText: {
|
||||
paddingLeft: 8,
|
||||
color: Colors.primary,
|
||||
},
|
||||
delete: {
|
||||
|
@ -36,6 +36,22 @@ export function useProfileBody() {
|
||||
blockedMessages: false,
|
||||
tabbed: null,
|
||||
disconnected: false,
|
||||
|
||||
seal: null,
|
||||
sealKey: null,
|
||||
sealEnabled: false,
|
||||
sealUnlocked: false,
|
||||
|
||||
sealEdit: false,
|
||||
sealMode: null,
|
||||
sealable: false,
|
||||
sealUnlock: null,
|
||||
showSealUnlock: false,
|
||||
sealPassword: null,
|
||||
showSealPassword: false,
|
||||
sealConfirm: null,
|
||||
showSealConfirm: false,
|
||||
sealDelete: null,
|
||||
});
|
||||
|
||||
const app = useContext(AppContext);
|
||||
@ -66,8 +82,11 @@ export function useProfileBody() {
|
||||
}, [profile]);
|
||||
|
||||
useEffect(() => {
|
||||
const { searchable, pushEnabled } = account.state.status;
|
||||
updateState({ searchable, pushEnabled });
|
||||
const { searchable, pushEnabled, seal } = account.state.status;
|
||||
const sealKey = account.state.sealKey;
|
||||
const sealEnabled = seal?.publicKey != null;
|
||||
const sealUnlocked = seal?.publicKey === sealKey?.public && sealKey?.private && sealKey?.public;
|
||||
updateState({ searchable, pushEnabled, seal, sealKey, sealEnabled, sealUnlocked });
|
||||
}, [account]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -122,6 +141,79 @@ export function useProfileBody() {
|
||||
console.log("SEAL:", seal);
|
||||
|
||||
},
|
||||
showSealEdit: () => {
|
||||
let sealMode = null;
|
||||
const sealable = state.sealEnabled;
|
||||
if (state.sealEnabled && !state.sealUnlocked) {
|
||||
sealMode = 'unlocking';
|
||||
}
|
||||
else if (state.sealEnabled && state.sealUnlocked) {
|
||||
sealMode = 'unlocked';
|
||||
}
|
||||
else {
|
||||
sealMode = 'disabled';
|
||||
}
|
||||
updateState({ sealEdit: true, sealable, sealMode });
|
||||
},
|
||||
hideSealEdit: () => {
|
||||
updateState({ sealEdit: false });
|
||||
},
|
||||
setSealable: (sealable) => {
|
||||
let sealMode = null;
|
||||
if (sealable !== state.sealEnabled) {
|
||||
if (sealable) {
|
||||
sealMode = 'enabling';
|
||||
}
|
||||
else {
|
||||
sealMode = 'disabling';
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (state.sealEnabled && !state.sealUnlocked) {
|
||||
sealMode = 'unlocking';
|
||||
}
|
||||
else if (state.sealEnabled && state.sealUnlocked) {
|
||||
sealMode = 'unlocked';
|
||||
}
|
||||
else {
|
||||
sealMode = 'disabled';
|
||||
}
|
||||
}
|
||||
updateState({ sealable, sealMode });
|
||||
},
|
||||
showSealUnlock: () => {
|
||||
updateState({ showSealUnlock: true });
|
||||
},
|
||||
hideSealUnlock: () => {
|
||||
updateState({ showSealUnlock: false });
|
||||
},
|
||||
setSealUnlock: (sealUnlock) => {
|
||||
updateState({ sealUnlock });
|
||||
},
|
||||
showSealPassword: () => {
|
||||
updateState({ showSealPassword: true });
|
||||
},
|
||||
hideSealPassword: () => {
|
||||
updateState({ showSealPassword: false });
|
||||
},
|
||||
setSealPassword: (sealPassword) => {
|
||||
updateState({ sealPassword });
|
||||
},
|
||||
showSealConfirm: () => {
|
||||
updateState({ showSealConfirm: true });
|
||||
},
|
||||
hideSealConfirm: () => {
|
||||
updateState({ showSealConfirm: false });
|
||||
},
|
||||
setSealConfirm: (sealConfirm) => {
|
||||
updateState({ sealConfirm });
|
||||
},
|
||||
setSealDelete: (sealDelete) => {
|
||||
updateState({ sealDelete });
|
||||
},
|
||||
updateSeal: () => {
|
||||
updateState({ sealMode: 'updating' });
|
||||
},
|
||||
logout: () => {
|
||||
app.actions.logout();
|
||||
navigate('/');
|
||||
|
Loading…
Reference in New Issue
Block a user