Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Mobile Vault Decryptor Functionality #3346

Merged
merged 12 commits into from
Nov 16, 2021
13 changes: 11 additions & 2 deletions app/components/Views/ImportFromSeed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ import TermsAndConditions from '../TermsAndConditions';
import zxcvbn from 'zxcvbn';
import Icon from 'react-native-vector-icons/FontAwesome';
import Device from '../../../util/device';
import { failedSeedPhraseRequirements, isValidMnemonic, parseSeedPhrase } from '../../../util/validators';
import {
failedSeedPhraseRequirements,
isValidMnemonic,
parseSeedPhrase,
parseVaultValue,
} from '../../../util/validators';
import { OutlinedTextField } from 'react-native-material-textfield';
import {
SEED_PHRASE_HINTS,
Expand Down Expand Up @@ -243,7 +248,11 @@ class ImportFromSeed extends PureComponent {

onPressImport = async () => {
const { loading, seed, password, confirmPassword } = this.state;
const parsedSeed = parseSeedPhrase(seed);

const vaultSeed = await parseVaultValue(password, seed);
const parsedSeed = parseSeedPhrase(vaultSeed || seed);
//Set the seed state with a valid parsed seed phrase (handle vault scenario)
this.setState({ seed: parsedSeed });

if (loading) return;
InteractionManager.runAfterInteractions(() => {
Expand Down
25 changes: 25 additions & 0 deletions app/util/validators/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
import { ethers } from 'ethers';
import { confusables } from 'unicode-confusables';
import Encryptor from '../../core/Encryptor';

export const failedSeedPhraseRequirements = (seed) => {
const wordCount = seed.split(/\s/u).length;
return wordCount % 3 !== 0 || wordCount > 24 || wordCount < 12;
};

/**
* This method validates and decyrpts a raw vault. Only works with iOS/Android vaults!
* The extension uses different cryptography for the vault.
* @param {string} password - users password related to vault
* @param {string} vault - exported from ios/android filesytem
* @returns seed phrase from vault
*/
export const parseVaultValue = async (password, vault) => {
let vaultSeed;

if (vault[0] === '{' && vault[vault.length - 1] === '}')
try {
const seedObject = JSON.parse(vault);
if (seedObject?.cipher && seedObject?.salt && seedObject?.iv && seedObject?.lib) {
const encryptor = new Encryptor();
const result = await encryptor.decrypt(password, vault);
vaultSeed = result[0]?.data?.mnemonic;
}
} catch (error) {
//No-op
}
return vaultSeed;
};

export const parseSeedPhrase = (seedPhrase) => (seedPhrase || '').trim().toLowerCase().match(/\w+/gu)?.join(' ') || '';

export const { isValidMnemonic } = ethers.utils;
Expand Down