mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29: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
|
||||
FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
|
||||
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
|
||||
GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7
|
||||
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useState, useRef, useContext } from 'react';
|
||||
import { StoreContext } from 'context/StoreContext';
|
||||
import { setAccountSeal } from 'api/setAccountSeal';
|
||||
import { setAccountSearchable } from 'api/setAccountSearchable';
|
||||
import { setAccountNotifications } from 'api/setAccountNotifications';
|
||||
import { getAccountStatus } from 'api/getAccountStatus';
|
||||
@ -78,6 +79,7 @@ export function useAccountContext() {
|
||||
updateState({ sealKey: key });
|
||||
},
|
||||
unlockAccountSeal: async (key) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.setAccountSealKey(guid, 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 () => {
|
||||
try {
|
||||
await actions.saveDetails();
|
||||
@ -258,9 +272,6 @@ export function ProfileBody({ navigation }) {
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
|
||||
|
||||
|
||||
<Modal
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
@ -282,7 +293,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ !state.showSealUnlock && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
<TouchableOpacity onPress={actions.showSealUnlock}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
@ -292,7 +303,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ state.showSealUnlock && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
<TouchableOpacity onPress={actions.hideSealUnlock}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
@ -306,7 +317,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ !state.showSealPassword && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
<TouchableOpacity onPress={actions.showSealPassword}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
@ -316,7 +327,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ state.showSealPassword && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
<TouchableOpacity onPress={actions.hideSealPassword}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
@ -326,7 +337,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ !state.showSealConfirm && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
<TouchableOpacity onPress={actions.showSealConfirm}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
@ -336,7 +347,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ state.showSealConfirm && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
<TouchableOpacity onPress={actions.hideSealConfirm}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
@ -356,6 +367,7 @@ export function ProfileBody({ navigation }) {
|
||||
{ state.sealMode === 'unlocked' && (
|
||||
<View style={styles.inputField}>
|
||||
<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} />
|
||||
</View>
|
||||
)}
|
||||
@ -363,23 +375,39 @@ export function ProfileBody({ navigation }) {
|
||||
<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.canSaveSeal && (
|
||||
<>
|
||||
{ state.sealMode !== 'unlocking' && (
|
||||
<TouchableOpacity style={styles.save} onPress={saveSeal}>
|
||||
<Text style={styles.saveText}>Save</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ state.sealMode === 'unlocking' && (
|
||||
<TouchableOpacity style={styles.save} onPress={saveSeal}>
|
||||
<Text style={styles.saveText}>Unlock</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{ state.sealMode === 'unlocking' && (
|
||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideSealEdit}>
|
||||
<Text>Unlock</Text>
|
||||
</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>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
|
||||
|
||||
|
||||
<Modal
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
@ -458,7 +486,6 @@ export function ProfileBody({ navigation }) {
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
@ -140,8 +140,8 @@ export const styles = StyleSheet.create({
|
||||
sealUpdate: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
height: '100%',
|
||||
left: 0,
|
||||
height: 36,
|
||||
left: 8,
|
||||
width: '100%',
|
||||
},
|
||||
sealable: {
|
||||
|
@ -41,7 +41,8 @@ export function useProfileBody() {
|
||||
sealKey: null,
|
||||
sealEnabled: false,
|
||||
sealUnlocked: false,
|
||||
|
||||
canSaveSeal: false,
|
||||
|
||||
sealEdit: false,
|
||||
sealMode: null,
|
||||
sealable: false,
|
||||
@ -111,36 +112,107 @@ export function useProfileBody() {
|
||||
return encoded
|
||||
};
|
||||
|
||||
const sealEnable = 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,
|
||||
});
|
||||
|
||||
// generate rsa key for sealing channel, delay for activity indicator
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
const crypto = new JSEncrypt({ default_key_size: 2048 });
|
||||
const key = crypto.getKey();
|
||||
|
||||
// encrypt private key
|
||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
const privateKey = convertPem(crypto.getPrivateKey());
|
||||
const publicKey = convertPem(crypto.getPublicKey());
|
||||
const enc = CryptoJS.AES.encrypt(privateKey, aes, { iv: iv });
|
||||
|
||||
const seal = {
|
||||
passwordSalt: salt.toString(),
|
||||
privateKeyIv: iv.toString(),
|
||||
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
||||
publicKey: publicKey,
|
||||
}
|
||||
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 = {
|
||||
sealTest: async () => {
|
||||
console.log("SEAL TEST");
|
||||
|
||||
// generate key to encrypt private key
|
||||
const salt = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
const aes = CryptoJS.PBKDF2('testpassword', salt, {
|
||||
keySize: 256 / 32,
|
||||
iterations: 1024,
|
||||
});
|
||||
|
||||
// generate rsa key for sealing channel, delay for activity indicator
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
const crypto = new JSEncrypt({ default_key_size: 2048 });
|
||||
const key = crypto.getKey();
|
||||
|
||||
// encrypt private key
|
||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
const privateKey = convertPem(crypto.getPrivateKey());
|
||||
const enc = CryptoJS.AES.encrypt(privateKey, aes, { iv: iv });
|
||||
|
||||
const seal = {
|
||||
passwordSalt: salt.toString(),
|
||||
privateKeyIv: iv.toString(),
|
||||
privateKeyEncrypted: enc.ciphertext.toString(CryptoJS.enc.Base64),
|
||||
publicKey: convertPem(crypto.getPublicKey()),
|
||||
}
|
||||
console.log("SEAL:", seal);
|
||||
|
||||
},
|
||||
showSealEdit: () => {
|
||||
let sealMode = null;
|
||||
const sealable = state.sealEnabled;
|
||||
@ -153,7 +225,7 @@ export function useProfileBody() {
|
||||
else {
|
||||
sealMode = 'disabled';
|
||||
}
|
||||
updateState({ sealEdit: true, sealable, sealMode });
|
||||
updateState({ sealEdit: true, sealable, sealMode, sealUnlock: null, sealPassword: null, sealConfirm: null, sealDelete: null });
|
||||
},
|
||||
hideSealEdit: () => {
|
||||
updateState({ sealEdit: false });
|
||||
@ -181,6 +253,23 @@ export function useProfileBody() {
|
||||
}
|
||||
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: () => {
|
||||
updateState({ showSealUnlock: true });
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user