Add BIP39 validation for seed phrase recovery
Signed-off-by: yenda <eric@status.im>
This commit is contained in:
parent
b93e6d8d78
commit
3bcf7ecf29
|
@ -614,5 +614,6 @@ var TopLevel = {
|
|||
"multiAccountReset" : function () {},
|
||||
"multiAccountLoadAccount" : function () {},
|
||||
"multiAccountStoreAccount" : function () {},
|
||||
"multiAccountImportMnemonic" : function () {}
|
||||
"multiAccountImportMnemonic" : function () {},
|
||||
"validateMnemonic" : function () {}
|
||||
}
|
||||
|
|
|
@ -1253,4 +1253,26 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -601,6 +601,15 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(identicon:(NSString *)publicKey) {
|
|||
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
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
(defn sanitize-passphrase [s]
|
||||
(-> (string/trim s)
|
||||
(string/replace #"\s+" " ")))
|
||||
(string/replace #"[\s\n]+" " ")))
|
||||
|
||||
(defn passphrase->words [s]
|
||||
(when s
|
||||
|
|
|
@ -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]}
|
||||
|
@ -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}]
|
||||
|
|
|
@ -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))
|
|
@ -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
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
(: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]))
|
||||
|
||||
|
@ -10,9 +9,7 @@
|
|||
|
||||
|
||||
(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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": "디앱",
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue