Skip to content

Commit

Permalink
Add BIP39 validation for seed phrase recovery
Browse files Browse the repository at this point in the history
  • Loading branch information
acolytec3 committed Jan 6, 2020
1 parent b93e6d8 commit f309d6e
Show file tree
Hide file tree
Showing 14 changed files with 58 additions and 32 deletions.
3 changes: 2 additions & 1 deletion externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,5 +614,6 @@ var TopLevel = {
"multiAccountReset" : function () {},
"multiAccountLoadAccount" : function () {},
"multiAccountStoreAccount" : function () {},
"multiAccountImportMnemonic" : function () {}
"multiAccountImportMnemonic" : function () {},
"validateMnemonic" : function () {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1253,4 +1253,26 @@ Map<String, Object> getConstants() {
public void isDeviceRooted(final Callback callback) {
callback.invoke(rootedDevice);
}

@ReactMethod
public void validateMnemonic(final String seed, final Callback callback) {
Log.d(TAG, "validateMnemonic");
if (!checkAvailability()) {
callback.invoke(false);
return;
}

Runnable r = new Runnable() {
@Override
public void run() {
String resValidateMnemonic = Statusgo.validateMnemonic(seed);

Log.d(TAG, resValidateMnemonic);
callback.invoke(resValidateMnemonic);
}
};

StatusThreadPoolExecutor.getInstance().execute(r);
}
}

9 changes: 9 additions & 0 deletions modules/react-native-status/ios/RCTStatus/RCTStatus.m
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,15 @@ -(NSString *) prepareDirAndUpdateConfig:(NSString *)config {
return StatusgoIdenticon(publicKey);
}

RCT_EXPORT_METHOD(validateMnemonic:(NSString *)seed
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"validateMnemonic() method called");
#endif
NSString *result = StatusgoValidateMnemonic(seed);
callback(@[result]);
}

RCT_EXPORT_METHOD(identiconAsync:(NSString *)publicKey
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
Expand Down
2 changes: 1 addition & 1 deletion src/status_im/ethereum/mnemonic.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

(defn sanitize-passphrase [s]
(-> (string/trim s)
(string/replace #"\s+" " ")))
(string/replace #"[\s\n]+" " ")))

(defn passphrase->words [s]
(when s
Expand Down
23 changes: 16 additions & 7 deletions src/status_im/multiaccounts/recover/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
[root-key multiaccounts]
(contains? multiaccounts (:key-uid root-key)))

(re-frame/reg-fx
::validate-mnemonic
(fn [[passphrase callback]]
(status/validate-mnemonic passphrase callback)))

(defn check-phrase-warnings [recovery-phrase]
(cond (string/blank? recovery-phrase) :required-field
(not (mnemonic/valid-words? recovery-phrase)) :recovery-phrase-invalid
(not (mnemonic/status-generated-phrase? recovery-phrase)) :recovery-phrase-unknown-words))
(cond (string/blank? recovery-phrase) :required-field))

(fx/defn set-phrase
{:events [:multiaccounts.recover/passphrase-input-changed]}
Expand Down Expand Up @@ -160,15 +163,21 @@
(navigation/navigate-to-cofx :recover-multiaccount-enter-phrase nil)))

(fx/defn proceed-to-import-mnemonic
{:events [:multiaccounts.recover/enter-phrase-next-pressed]}
[{:keys [db] :as cofx}]
{:events [:multiaccounts.recover/phrase-validated]}
[{:keys [db] :as cofx} phrase-warnings]
(let [{:keys [password passphrase]} (:intro-wizard db)]
(if (check-phrase-warnings passphrase)
(if-not (string/blank? (:error (types/json->clj phrase-warnings)))
(popover/show-popover cofx {:view :custom-seed-phrase})
(when (mnemonic/valid-length? passphrase)
{::import-multiaccount {:passphrase passphrase
{::import-multiaccount {:passphrase (mnemonic/sanitize-passphrase passphrase)
:password password}}))))

(fx/defn seed-phrase-next-pressed
{:events [:multiaccounts.recover/enter-phrase-next-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [passphrase]} (:intro-wizard db)]
{::validate-mnemonic [passphrase #(re-frame/dispatch [:multiaccounts.recover/phrase-validated %])]}))

(fx/defn continue-to-import-mnemonic
{:events [::continue-pressed]}
[{:keys [db] :as cofx}]
Expand Down
6 changes: 6 additions & 0 deletions src/status_im/native_module/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,9 @@
[seed callback]
(log/debug "[native-module] gfycat-identicon-async")
(.generateAliasAndIdenticonAsync (status) seed callback))

(defn validate-mnemonic
"Validate that a mnemonic conforms to BIP39 dictionary/checksum standards"
[mnemonic callback]
(log/debug "[native-module] validate-mnemonic")
(.validateMnemonic (status) mnemonic callback))
8 changes: 1 addition & 7 deletions src/status_im/ui/screens/multiaccounts/recover/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,9 @@
:line-height 22}}
(i18n/label :t/custom-seed-phrase-text-1)
[{:style {:color colors/black}}
(i18n/label :t/custom-seed-phrase-text-2)]
(i18n/label :t/custom-seed-phrase-text-3)
[{:style {:color colors/black}}
(i18n/label :t/custom-seed-phrase-text-4)]]]
(i18n/label :t/custom-seed-phrase-text-2)]]]
[react/view {:margin-vertical 24
:align-items :center}
[button/button {:on-press #(re-frame/dispatch [::multiaccounts.recover/continue-pressed])
:accessibility-label :continue-custom-seed-phrase
:label (i18n/label :t/continue)}]
[button/button {:on-press #(re-frame/dispatch [:hide-popover])
:accessibility-label :cancel-custom-seed-phrase
:type :secondary
Expand Down
5 changes: 1 addition & 4 deletions test/cljs/status_im/test/multiaccounts/recover/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.multiaccounts.recover.core :as models]
[status-im.multiaccounts.create.core :as multiaccounts.create]
[clojure.string :as string]
[status-im.utils.security :as security]
[status-im.i18n :as i18n]))

;;;; helpers


(deftest check-phrase-warnings
(is (nil? (models/check-phrase-warnings "monkey monkey monkey monkey monkey monkey monkey monkey monkey monkey monkey monkey")))
(is (nil? (models/check-phrase-warnings "game buzz method pretty olympic fat quit display velvet unveil marine crater")))
(is (= :recovery-phrase-unknown-words (models/check-phrase-warnings "game buzz method pretty zeus fat quit display velvet unveil marine crater"))))
(is (= :required-field (models/check-phrase-warnings ""))))

;;;; handlers

Expand Down
2 changes: 0 additions & 2 deletions translations/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,6 @@
"custom-seed-phrase": "عبارة البذور المخصصة",
"custom-seed-phrase-text-1": "هذا يبدو وكأنه عبارة أولية مخصصة ولا يتطابق مع قاموس Status. هذا يمكن أن يعني أيضا",
"custom-seed-phrase-text-2": "بعض الكلمات بها أخطاء إملائية.",
"custom-seed-phrase-text-3": "إذا كان الأمر كذلك ، فسوف ينتهي إنشاء",
"custom-seed-phrase-text-4": "حساب جديد",
"dapp": "ÐApp",
"dapp-would-like-to-connect-wallet": "ترغب في الاتصال",
"dapps": "ÐApps",
Expand Down
2 changes: 0 additions & 2 deletions translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1116,8 +1116,6 @@
"custom-seed-phrase": "Custom seed phrase",
"custom-seed-phrase-text-1": "This looks like a custom seed phrase and doesn't match the Status dictionary. This could also mean ",
"custom-seed-phrase-text-2": "some words are misspelled.",
"custom-seed-phrase-text-3": " If so, you'll end up creating a",
"custom-seed-phrase-text-4": " new account",
"to-enable-biometric": "To enable {{bio-type-label}}, your must save your password on the unlock screen",
"ok-save-pass": "OK, save password",
"lock-app-with": "Lock app with",
Expand Down
2 changes: 0 additions & 2 deletions translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,6 @@
"custom-seed-phrase": "Phrase de récupération personnalisée",
"custom-seed-phrase-text-1": "Cela ressemble à une phrase de récupération personnalisée et ne correspond pas au dictionnaire de Status. Cela pourrait aussi signifier",
"custom-seed-phrase-text-2": "certains mots sont mal orthographiés.",
"custom-seed-phrase-text-3": "Si c'est le cas, vous allez créer un",
"custom-seed-phrase-text-4": "nouveau compte",
"dapp": "ÐApp",
"dapp-would-like-to-connect-wallet": "souhaite se connecter à votre portefeuille",
"dapps": "ÐApps",
Expand Down
2 changes: 0 additions & 2 deletions translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,6 @@
"custom-seed-phrase": "Frase di recupero personalizzata",
"custom-seed-phrase-text-1": "Sembra una frase seed personalizzata e non corrisponde al dizionario di Status. Questo potrebbe anche significare",
"custom-seed-phrase-text-2": "alcune parole sono scritte male.",
"custom-seed-phrase-text-3": "In tal caso, finirai per creare un",
"custom-seed-phrase-text-4": "Nuovo account",
"dapp": "ÐApp",
"dapp-would-like-to-connect-wallet": "vorrebbe connettersi a",
"dapps": "ÐApps",
Expand Down
2 changes: 0 additions & 2 deletions translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,6 @@
"custom-seed-phrase": "커스텀 시드 구문",
"custom-seed-phrase-text-1": "커스텀 시드 구문이 스테이터스 딕셔너리와 일치하지 않습니다. 또한",
"custom-seed-phrase-text-2": "일부 단어의 철자가 잘못되었을 수 있습니다.",
"custom-seed-phrase-text-3": " 이 경우",
"custom-seed-phrase-text-4": "새 계정을 생성하게 됩니다.",
"dapp": "디앱",
"dapp-would-like-to-connect-wallet": "(이)가 사용자 다음에 연결합니다",
"dapps": "디앱",
Expand Down
2 changes: 0 additions & 2 deletions translations/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,6 @@
"custom-seed-phrase": "自定义助记词",
"custom-seed-phrase-text-1": "这好像是一个自定义的助记词,与“Status”字库不匹配。这也可能意味着",
"custom-seed-phrase-text-2": "有些单词拼写错误。",
"custom-seed-phrase-text-3": "如果是这样,您最终将创建一个",
"custom-seed-phrase-text-4": "新账户",
"dapp": "ÐApp",
"dapp-would-like-to-connect-wallet": "想要连接到",
"dapps": "ÐApp",
Expand Down

0 comments on commit f309d6e

Please sign in to comment.