mirror of
https://github.com/balzack/databag.git
synced 2025-02-15 21:19:16 +00:00
support e2e key handling in mobile
This commit is contained in:
parent
4a8c2f1776
commit
5f4b04adc6
@ -669,7 +669,7 @@ SPEC CHECKSUMS:
|
|||||||
FirebaseInstallations: 99d24bac0243cf8b0e96cf5426340d211f0bcc80
|
FirebaseInstallations: 99d24bac0243cf8b0e96cf5426340d211f0bcc80
|
||||||
FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5
|
FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5
|
||||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
|
||||||
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
|
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
|
||||||
GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7
|
GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7
|
||||||
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
|
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useState, useRef, useContext } from 'react';
|
import { useState, useRef, useContext } from 'react';
|
||||||
import { StoreContext } from 'context/StoreContext';
|
import { StoreContext } from 'context/StoreContext';
|
||||||
|
import { setAccountSeal } from 'api/setAccountSeal';
|
||||||
import { setAccountSearchable } from 'api/setAccountSearchable';
|
import { setAccountSearchable } from 'api/setAccountSearchable';
|
||||||
import { setAccountNotifications } from 'api/setAccountNotifications';
|
import { setAccountNotifications } from 'api/setAccountNotifications';
|
||||||
import { getAccountStatus } from 'api/getAccountStatus';
|
import { getAccountStatus } from 'api/getAccountStatus';
|
||||||
@ -78,6 +79,7 @@ export function useAccountContext() {
|
|||||||
updateState({ sealKey: key });
|
updateState({ sealKey: key });
|
||||||
},
|
},
|
||||||
unlockAccountSeal: async (key) => {
|
unlockAccountSeal: async (key) => {
|
||||||
|
const { guid } = session.current;
|
||||||
await store.actions.setAccountSealKey(guid, key);
|
await store.actions.setAccountSealKey(guid, key);
|
||||||
updateState({ sealKey: key });
|
updateState({ sealKey: key });
|
||||||
},
|
},
|
||||||
|
@ -41,6 +41,20 @@ export function ProfileBody({ navigation }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saveSeal = async () => {
|
||||||
|
try {
|
||||||
|
await actions.saveSeal();
|
||||||
|
actions.hideSealEdit();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
Alert.alert(
|
||||||
|
'Failed to Update Topic Sealing',
|
||||||
|
'Please try again.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const saveDetails = async () => {
|
const saveDetails = async () => {
|
||||||
try {
|
try {
|
||||||
await actions.saveDetails();
|
await actions.saveDetails();
|
||||||
@ -258,9 +272,6 @@ export function ProfileBody({ navigation }) {
|
|||||||
</View>
|
</View>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
animationType="fade"
|
animationType="fade"
|
||||||
transparent={true}
|
transparent={true}
|
||||||
@ -282,7 +293,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ !state.showSealUnlock && (
|
{ !state.showSealUnlock && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={state.sealUnlock} onChangeText={actions.setSealUnlock}
|
<TextInput style={styles.input} value={state.sealUnlock} onChangeText={actions.setSealUnlock}
|
||||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Seal Password"
|
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password for Seal"
|
||||||
placeholderTextColor={Colors.grey} />
|
placeholderTextColor={Colors.grey} />
|
||||||
<TouchableOpacity onPress={actions.showSealUnlock}>
|
<TouchableOpacity onPress={actions.showSealUnlock}>
|
||||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||||
@ -292,7 +303,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ state.showSealUnlock && (
|
{ state.showSealUnlock && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={state.sealUnlock} onChangeText={actions.setSealUnlock}
|
<TextInput style={styles.input} value={state.sealUnlock} onChangeText={actions.setSealUnlock}
|
||||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Seal Password"
|
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password for Seal"
|
||||||
placeholderTextColor={Colors.grey} />
|
placeholderTextColor={Colors.grey} />
|
||||||
<TouchableOpacity onPress={actions.hideSealUnlock}>
|
<TouchableOpacity onPress={actions.hideSealUnlock}>
|
||||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||||
@ -306,7 +317,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ !state.showSealPassword && (
|
{ !state.showSealPassword && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={state.sealPassword} onChangeText={actions.setSealPassword}
|
<TextInput style={styles.input} value={state.sealPassword} onChangeText={actions.setSealPassword}
|
||||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password Seal"
|
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password for Seal"
|
||||||
placeholderTextColor={Colors.grey} />
|
placeholderTextColor={Colors.grey} />
|
||||||
<TouchableOpacity onPress={actions.showSealPassword}>
|
<TouchableOpacity onPress={actions.showSealPassword}>
|
||||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||||
@ -316,7 +327,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ state.showSealPassword && (
|
{ state.showSealPassword && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={state.sealPassword} onChangeText={actions.setSealPassword}
|
<TextInput style={styles.input} value={state.sealPassword} onChangeText={actions.setSealPassword}
|
||||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password Seal"
|
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password for Seal"
|
||||||
placeholderTextColor={Colors.grey} />
|
placeholderTextColor={Colors.grey} />
|
||||||
<TouchableOpacity onPress={actions.hideSealPassword}>
|
<TouchableOpacity onPress={actions.hideSealPassword}>
|
||||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||||
@ -326,7 +337,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ !state.showSealConfirm && (
|
{ !state.showSealConfirm && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
|
<TextInput style={styles.input} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
|
||||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Confirm Seal"
|
autoCapitalize={'none'} secureTextEntry={true} placeholder="Confirm Password"
|
||||||
placeholderTextColor={Colors.grey} />
|
placeholderTextColor={Colors.grey} />
|
||||||
<TouchableOpacity onPress={actions.showSealConfirm}>
|
<TouchableOpacity onPress={actions.showSealConfirm}>
|
||||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||||
@ -336,7 +347,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ state.showSealConfirm && (
|
{ state.showSealConfirm && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
|
<TextInput style={styles.input} value={state.sealConfirm} onChangeText={actions.setSealConfirm}
|
||||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Confirm Seal"
|
autoCapitalize={'none'} secureTextEntry={false} placeholder="Confirm Password"
|
||||||
placeholderTextColor={Colors.grey} />
|
placeholderTextColor={Colors.grey} />
|
||||||
<TouchableOpacity onPress={actions.hideSealConfirm}>
|
<TouchableOpacity onPress={actions.hideSealConfirm}>
|
||||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||||
@ -356,6 +367,7 @@ export function ProfileBody({ navigation }) {
|
|||||||
{ state.sealMode === 'unlocked' && (
|
{ state.sealMode === 'unlocked' && (
|
||||||
<View style={styles.inputField}>
|
<View style={styles.inputField}>
|
||||||
<TextInput style={styles.input} value={'xxxxxxxx'} editable="false" secureTextEntry={true} />
|
<TextInput style={styles.input} value={'xxxxxxxx'} editable="false" secureTextEntry={true} />
|
||||||
|
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||||
<TouchableOpacity style={styles.sealUpdate} onPress={actions.updateSeal} />
|
<TouchableOpacity style={styles.sealUpdate} onPress={actions.updateSeal} />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@ -363,23 +375,39 @@ export function ProfileBody({ navigation }) {
|
|||||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
||||||
<Text>Cancel</Text>
|
<Text>Cancel</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
{ state.canSaveSeal && (
|
||||||
|
<>
|
||||||
{ state.sealMode !== 'unlocking' && (
|
{ state.sealMode !== 'unlocking' && (
|
||||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
<TouchableOpacity style={styles.save} onPress={saveSeal}>
|
||||||
<Text>Save</Text>
|
<Text style={styles.saveText}>Save</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
{ state.sealMode === 'unlocking' && (
|
{ state.sealMode === 'unlocking' && (
|
||||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
<TouchableOpacity style={styles.save} onPress={saveSeal}>
|
||||||
<Text>Unlock</Text>
|
<Text style={styles.saveText}>Unlock</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{ !state.canSaveSeal && (
|
||||||
|
<>
|
||||||
|
{ state.sealMode !== 'unlocking' && (
|
||||||
|
<View style={styles.disabled}>
|
||||||
|
<Text style={styles.disabledText}>Save</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
{ state.sealMode === 'unlocking' && (
|
||||||
|
<View style={styles.disabled}>
|
||||||
|
<Text style={styles.disabledText}>Unlock</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
animationType="fade"
|
animationType="fade"
|
||||||
transparent={true}
|
transparent={true}
|
||||||
@ -458,7 +486,6 @@ export function ProfileBody({ navigation }) {
|
|||||||
</View>
|
</View>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -140,8 +140,8 @@ export const styles = StyleSheet.create({
|
|||||||
sealUpdate: {
|
sealUpdate: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
height: '100%',
|
height: 36,
|
||||||
left: 0,
|
left: 8,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
sealable: {
|
sealable: {
|
||||||
|
@ -41,6 +41,7 @@ export function useProfileBody() {
|
|||||||
sealKey: null,
|
sealKey: null,
|
||||||
sealEnabled: false,
|
sealEnabled: false,
|
||||||
sealUnlocked: false,
|
sealUnlocked: false,
|
||||||
|
canSaveSeal: false,
|
||||||
|
|
||||||
sealEdit: false,
|
sealEdit: false,
|
||||||
sealMode: null,
|
sealMode: null,
|
||||||
@ -111,13 +112,10 @@ export function useProfileBody() {
|
|||||||
return encoded
|
return encoded
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const sealEnable = async () => {
|
||||||
sealTest: async () => {
|
|
||||||
console.log("SEAL TEST");
|
|
||||||
|
|
||||||
// generate key to encrypt private key
|
// generate key to encrypt private key
|
||||||
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
const aes = CryptoJS.PBKDF2('testpassword', salt, {
|
const aes = CryptoJS.PBKDF2(state.sealPassword, salt, {
|
||||||
keySize: 256 / 32,
|
keySize: 256 / 32,
|
||||||
iterations: 1024,
|
iterations: 1024,
|
||||||
});
|
});
|
||||||
@ -130,17 +128,91 @@ export function useProfileBody() {
|
|||||||
// encrypt private key
|
// encrypt private key
|
||||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
const privateKey = convertPem(crypto.getPrivateKey());
|
const privateKey = convertPem(crypto.getPrivateKey());
|
||||||
|
const publicKey = convertPem(crypto.getPublicKey());
|
||||||
const enc = CryptoJS.AES.encrypt(privateKey, aes, { iv: iv });
|
const enc = CryptoJS.AES.encrypt(privateKey, aes, { iv: iv });
|
||||||
|
|
||||||
const seal = {
|
const seal = {
|
||||||
passwordSalt: salt.toString(),
|
passwordSalt: salt.toString(),
|
||||||
privateKeyIv: iv.toString(),
|
privateKeyIv: iv.toString(),
|
||||||
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
||||||
publicKey: convertPem(crypto.getPublicKey()),
|
publicKey: publicKey,
|
||||||
}
|
}
|
||||||
console.log("SEAL:", seal);
|
const sealKey = {
|
||||||
|
public: publicKey,
|
||||||
|
private: privateKey,
|
||||||
|
}
|
||||||
|
await account.actions.setAccountSeal(seal, sealKey);
|
||||||
|
};
|
||||||
|
|
||||||
},
|
const sealDisable = async () => {
|
||||||
|
await account.actions.setAccountSeal({}, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sealUnlock = async () => {
|
||||||
|
// generate key to encrypt private key
|
||||||
|
const salt = CryptoJS.enc.Hex.parse(state.seal.passwordSalt);
|
||||||
|
const aes = CryptoJS.PBKDF2(state.sealUnlock, salt, {
|
||||||
|
keySize: 256 / 32,
|
||||||
|
iterations: 1024,
|
||||||
|
});
|
||||||
|
|
||||||
|
// decrypt private key
|
||||||
|
const iv = CryptoJS.enc.Hex.parse(state.seal.privateKeyIv);
|
||||||
|
const enc = CryptoJS.enc.Base64.parse(state.seal.privateKeyEncrypted)
|
||||||
|
let cipherParams = CryptoJS.lib.CipherParams.create({
|
||||||
|
ciphertext: enc,
|
||||||
|
iv: iv
|
||||||
|
});
|
||||||
|
const dec = CryptoJS.AES.decrypt(cipherParams, aes, { iv: iv });
|
||||||
|
|
||||||
|
// store unlocked seal
|
||||||
|
const sealKey = {
|
||||||
|
public: state.seal.publicKey,
|
||||||
|
private: dec.toString(CryptoJS.enc.Utf8),
|
||||||
|
};
|
||||||
|
await account.actions.unlockAccountSeal(sealKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sealUpdate = async () => {
|
||||||
|
// generate key to encrypt private key
|
||||||
|
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const aes = CryptoJS.PBKDF2(state.sealPassword, salt, {
|
||||||
|
keySize: 256 / 32,
|
||||||
|
iterations: 1024,
|
||||||
|
});
|
||||||
|
|
||||||
|
// encrypt private key
|
||||||
|
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||||
|
const enc = CryptoJS.AES.encrypt(state.sealKey.private, aes, { iv: iv });
|
||||||
|
|
||||||
|
// update account
|
||||||
|
const seal = {
|
||||||
|
passwordSalt: salt.toString(),
|
||||||
|
privateKeyIv: iv.toString(),
|
||||||
|
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
||||||
|
publicKey: state.sealKey.public,
|
||||||
|
}
|
||||||
|
const sealKey = { ...state.sealKey }
|
||||||
|
await account.actions.setAccountSeal(seal, sealKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (state.sealMode === 'unlocking' && state.sealUnlock != null && state.sealUnlock !== '') {
|
||||||
|
return updateState({ canSaveSeal: true });
|
||||||
|
}
|
||||||
|
if (state.sealMode === 'enabling' && state.sealPassword != null && state.sealPassword === state.sealConfirm) {
|
||||||
|
return updateState({ canSaveSeal: true });
|
||||||
|
}
|
||||||
|
if (state.sealMode === 'disabling' && state.sealDelete === 'delete') {
|
||||||
|
return updateState({ canSaveSeal: true });
|
||||||
|
}
|
||||||
|
if (state.sealMode === 'updating' && state.sealPassword != null && state.sealPassword === state.sealConfirm) {
|
||||||
|
return updateState({ canSaveSeal: true });
|
||||||
|
}
|
||||||
|
updateState({ canSaveSeal: false });
|
||||||
|
}, [state.sealMode, state.sealable, state.sealUnlock, state.sealPassword, state.sealConfirm, state.sealDelete]);
|
||||||
|
|
||||||
|
const actions = {
|
||||||
showSealEdit: () => {
|
showSealEdit: () => {
|
||||||
let sealMode = null;
|
let sealMode = null;
|
||||||
const sealable = state.sealEnabled;
|
const sealable = state.sealEnabled;
|
||||||
@ -153,7 +225,7 @@ export function useProfileBody() {
|
|||||||
else {
|
else {
|
||||||
sealMode = 'disabled';
|
sealMode = 'disabled';
|
||||||
}
|
}
|
||||||
updateState({ sealEdit: true, sealable, sealMode });
|
updateState({ sealEdit: true, sealable, sealMode, sealUnlock: null, sealPassword: null, sealConfirm: null, sealDelete: null });
|
||||||
},
|
},
|
||||||
hideSealEdit: () => {
|
hideSealEdit: () => {
|
||||||
updateState({ sealEdit: false });
|
updateState({ sealEdit: false });
|
||||||
@ -181,6 +253,23 @@ export function useProfileBody() {
|
|||||||
}
|
}
|
||||||
updateState({ sealable, sealMode });
|
updateState({ sealable, sealMode });
|
||||||
},
|
},
|
||||||
|
saveSeal: async () => {
|
||||||
|
if (state.sealMode === 'enabling') {
|
||||||
|
await sealEnable();
|
||||||
|
}
|
||||||
|
else if (state.sealMode === 'disabling') {
|
||||||
|
await sealDisable();
|
||||||
|
}
|
||||||
|
else if (state.sealMode === 'unlocking') {
|
||||||
|
await sealUnlock();
|
||||||
|
}
|
||||||
|
else if (state.sealMode === 'updating') {
|
||||||
|
await sealUpdate();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(state.sealMode);
|
||||||
|
}
|
||||||
|
},
|
||||||
showSealUnlock: () => {
|
showSealUnlock: () => {
|
||||||
updateState({ showSealUnlock: true });
|
updateState({ showSealUnlock: true });
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user