Skip to content

Commit

Permalink
rework validation
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitryn committed Aug 13, 2019
1 parent 1b37891 commit 71fbd73
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 61 deletions.
7 changes: 7 additions & 0 deletions src/status_im/ethereum/mnemonic.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
(defn valid-word-counts? [v]
(boolean (valid-word-counts (count v))))

(defn words-count [s]
(if (empty? s)
nil
(-> s
passphrase->words
count)))

(defn- valid-word? [s]
(re-matches #"^[A-z]+$" s))

Expand Down
46 changes: 31 additions & 15 deletions src/status_im/multiaccounts/recover/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
(defn check-phrase-errors [recovery-phrase]
(cond (string/blank? recovery-phrase) :required-field
(not (mnemonic/valid-words? recovery-phrase)) :recovery-phrase-invalid
(not (mnemonic/valid-length? recovery-phrase)) :recovery-phrase-wrong-length))
(not (mnemonic/valid-length? recovery-phrase)) :recovery-phrase-wrong-length
(not (mnemonic/status-generated-phrase? recovery-phrase)) :recovery-phrase-unknown-words))

(defn check-phrase-warnings [recovery-phrase]
(when (not (mnemonic/status-generated-phrase? recovery-phrase))
:recovery-phrase-unknown-words))
(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))

(defn recover-multiaccount! [masked-passphrase password]
(status/recover-multiaccount
Expand All @@ -43,18 +45,24 @@
(fx/defn set-phrase
[{:keys [db]} masked-recovery-phrase]
(let [recovery-phrase (security/safe-unmask-data masked-recovery-phrase)]
{:db (update db :multiaccounts/recover assoc
:passphrase (string/lower-case recovery-phrase)
:passphrase-warning nil
:passphrase-error nil
:passphrase-valid? (not (check-phrase-errors recovery-phrase)))}))
(fx/merge
{:db (update db :multiaccounts/recover assoc
:passphrase (string/lower-case recovery-phrase)
:passphrase-error nil
:next-button-disabled? (or (empty? recovery-phrase)
(not (mnemonic/valid-length? recovery-phrase))))})))

(fx/defn validate-phrase
[{:keys [db]}]
(let [recovery-phrase (get-in db [:multiaccounts/recover :passphrase])]
{:db (update db :multiaccounts/recover assoc
:passphrase-error (check-phrase-errors recovery-phrase)
:passphrase-warning (check-phrase-warnings recovery-phrase))}))
:passphrase-error (check-phrase-errors recovery-phrase))}))

(fx/defn validate-phrase-for-warnings
[{:keys [db]}]
(let [recovery-phrase (get-in db [:multiaccounts/recover :passphrase])]
{:db (update db :multiaccounts/recover assoc
:passphrase-error (check-phrase-warnings recovery-phrase))}))

(fx/defn set-password
[{:keys [db]} masked-password]
Expand Down Expand Up @@ -183,7 +191,8 @@
{:events [:recover.ui/enter-phrase-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:dispatch [:bottom-sheet/hide-sheet]}
{:db (assoc db :multiaccounts/recover {:next-button-disabled? true})
:dispatch [:bottom-sheet/hide-sheet]}
(navigation/navigate-to-cofx :recover-multiaccount-enter-phrase nil)))

(fx/defn prepare-to-recover
Expand All @@ -203,10 +212,9 @@

(fx/defn proceed-to-import-mnemonic
[{:keys [db] :as cofx}]
(let [{:keys [passphrase-error passphrase-warning]} (:multiaccounts/recover db)
(let [{:keys [passphrase-error]} (:multiaccounts/recover db)
node-started? (= :started (:node/status db))]
(when (and (nil? passphrase-warning)
(nil? passphrase-error))
(when (nil? passphrase-error)
(if node-started?
(import-mnemonic cofx)
(prepare-to-recover cofx)))))
Expand Down Expand Up @@ -260,17 +268,25 @@
(navigation/navigate-to-cofx :keycard-welcome nil))
{:db (assoc-in db [:multiaccounts/recover :password-error] :password_error1)})))

(fx/defn count-words
[{:keys [db]}]
(let [passphrase (get-in db [:multiaccounts/recover :passphrase])]
{:db (assoc-in db [:multiaccounts/recover :words-count]
(mnemonic/words-count passphrase))}))

(fx/defn run-validation
[{:keys [db] :as cofx}]
(let [passphrase (get-in db [:multiaccounts/recover :passphrase])]
(when (= (last passphrase) " ")
(validate-phrase cofx))))
(fx/merge cofx
(validate-phrase-for-warnings)))))

(fx/defn enter-phrase-input-changed
{:events [:recover.enter-passphrase.ui/input-changed]}
[cofx input]
(fx/merge cofx
(set-phrase input)
(count-words)
(run-validation)))

(fx/defn enter-password-input-changed
Expand Down
50 changes: 30 additions & 20 deletions src/status_im/ui/screens/multiaccounts/recover/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
:as views])
(:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[goog.functions :refer [debounce]]
[status-im.ui.components.text-input.view :as text-input]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
Expand Down Expand Up @@ -129,7 +128,11 @@
:content-height 130})

(defview enter-phrase []
(letsubs [{:keys [passphrase processing? passphrase-error passphrase-warning]} [:get-recover-multiaccount]]
(letsubs [{:keys [passphrase
processing?
passphrase-error
words-count
next-button-disabled?]} [:get-recover-multiaccount]]
[react/keyboard-avoiding-view {:flex 1
:justify-content :space-between
:background-color colors/white}
Expand All @@ -153,19 +156,12 @@
[react/text {:style {:typography :header
:text-align :center}}
(i18n/label :t/multiaccounts-recover-enter-phrase-title)]]
[react/view {:margin-top 16
:width "85%"
:align-items :center}
[react/text {:style {:color colors/gray
:text-align :center}}
(i18n/label :t/multiaccounts-recover-enter-phrase-text)]]
[react/view {:margin-top 16}
[text-input/text-input-with-label
{:on-change-text #(re-frame/dispatch [:recover.enter-passphrase.ui/input-changed (security/mask-data %)])
:auto-focus true
:on-submit-editing #(re-frame/dispatch [:recover.enter-passphrase.ui/input-submitted])
:error (cond passphrase-error (i18n/label passphrase-error)
passphrase-warning (i18n/label passphrase-warning))
:error (when passphrase-error (i18n/label passphrase-error))
:placeholder nil
:height 125
:multiline true
Expand All @@ -175,7 +171,26 @@
:style {:background-color :white
:text-align :center
:font-size 16
:font-weight "700"}}]]]
:font-weight "700"}}]]
[react/view {:align-items :center
:margin-top 38}
(when words-count
[react/view {:flex-direction :row
:align-items :flex-end}
(when-not next-button-disabled?
[vector-icons/tiny-icon :tiny-icons/tiny-check])
[react/text {:style {:font-size 14
:padding-left 4
:text-align :center
:color colors/black}}
(i18n/label-pluralize words-count :t/words-n)]])]
(when next-button-disabled?
[react/view {:margin-top 38
:align-items :center}
[react/text {:style {:color colors/black
:font-size 14
:text-align :center}}
(i18n/label :t/multiaccounts-recover-enter-phrase-text)]])]
(when processing?
[react/view
[react/activity-indicator {:size :large
Expand All @@ -195,7 +210,7 @@
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:recover.enter-passphrase.ui/next-pressed])
:label (i18n/label :t/next)
:disabled? (empty? passphrase)
:disabled? next-button-disabled?
:forward? true}]])]]]))

(defview success []
Expand Down Expand Up @@ -307,10 +322,7 @@
:forward? true}]]]]]))

(defview enter-password []
(letsubs [{:keys [password-error password-valid?]} [:get-recover-multiaccount]
validate-password (debounce
#(re-frame/dispatch [:multiaccounts.recover.ui/password-input-blured])
500)]
(letsubs [{:keys [password password-error]} [:get-recover-multiaccount]]
[react/keyboard-avoiding-view {:flex 1
:justify-content :space-between
:background-color colors/white}
Expand Down Expand Up @@ -342,9 +354,7 @@
(i18n/label :t/password-description)]]
[react/view {:margin-top 16}
[text-input/text-input-with-label
{:on-change-text #(do
(re-frame/dispatch [:recover.enter-password.ui/input-changed (security/mask-data %)])
(validate-password))
{:on-change-text #(re-frame/dispatch [:recover.enter-password.ui/input-changed (security/mask-data %)])
:auto-focus true
:on-submit-editing #(re-frame/dispatch [:recover.enter-password.ui/input-submitted])
:secure-text-entry true
Expand All @@ -370,7 +380,7 @@
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:recover.enter-password.ui/next-pressed])
:label (i18n/label :t/next)
:disabled? (not password-valid?)
:disabled? (empty? password)
:forward? true}]]]]]))

(defview confirm-password []
Expand Down
42 changes: 17 additions & 25 deletions test/cljs/status_im/test/multiaccounts/recover/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -42,43 +42,35 @@
;;;; handlers

(deftest set-phrase
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty olympic fat quit display velvet unveil marine crater"
:passphrase-warning nil
:passphrase-error nil
:passphrase-valid? true}}}
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty olympic fat quit display velvet unveil marine crater"
:passphrase-error nil
:next-button-disabled? false}}}
(models/set-phrase {:db {}} (security/mask-data "game buzz method pretty olympic fat quit display velvet unveil marine crater"))))
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty olympic fat quit display velvet unveil marine crater"
:passphrase-warning nil
:passphrase-error nil
:passphrase-valid? true}}}
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty olympic fat quit display velvet unveil marine crater"
:passphrase-error nil
:next-button-disabled? false}}}
(models/set-phrase {:db {}} (security/mask-data "Game buzz method pretty Olympic fat quit DISPLAY velvet unveil marine crater"))))
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty zeus fat quit display velvet unveil marine crater"
:passphrase-warning nil
:passphrase-error nil
:passphrase-valid? true}}}
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty zeus fat quit display velvet unveil marine crater"
:passphrase-error nil
:next-button-disabled? false}}}
(models/set-phrase {:db {}} (security/mask-data "game buzz method pretty zeus fat quit display velvet unveil marine crater"))))
(is (= {:db {:multiaccounts/recover {:passphrase " game\t buzz method pretty olympic fat quit\t display velvet unveil marine crater "
:passphrase-warning nil
:passphrase-error nil
:passphrase-valid? true}}}
(is (= {:db {:multiaccounts/recover {:passphrase " game\t buzz method pretty olympic fat quit\t display velvet unveil marine crater "
:passphrase-error nil
:next-button-disabled? false}}}
(models/set-phrase {:db {}} (security/mask-data " game\t buzz method pretty olympic fat quit\t display velvet unveil marine crater "))))
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty 1234 fat quit display velvet unveil marine crater"
:passphrase-warning nil
:passphrase-error nil
:passphrase-valid? false}}}
(is (= {:db {:multiaccounts/recover {:passphrase "game buzz method pretty 1234 fat quit display velvet unveil marine crater"
:passphrase-error nil
:next-button-disabled? false}}}
(models/set-phrase {:db {}} (security/mask-data "game buzz method pretty 1234 fat quit display velvet unveil marine crater")))))

(deftest validate-phrase
(is (= {:db {:multiaccounts/recover {:passphrase-error nil
:passphrase-warning nil
:passphrase "game buzz method pretty olympic fat quit display velvet unveil marine crater"}}}
(models/validate-phrase {:db {:multiaccounts/recover {:passphrase "game buzz method pretty olympic fat quit display velvet unveil marine crater"}}})))
(is (= {:db {:multiaccounts/recover {:passphrase-error nil
:passphrase-warning :recovery-phrase-unknown-words
:passphrase "game buzz method pretty zeus fat quit display velvet unveil marine crater"}}}
(is (= {:db {:multiaccounts/recover {:passphrase-error :recovery-phrase-unknown-words
:passphrase "game buzz method pretty zeus fat quit display velvet unveil marine crater"}}}
(models/validate-phrase {:db {:multiaccounts/recover {:passphrase "game buzz method pretty zeus fat quit display velvet unveil marine crater"}}})))
(is (= {:db {:multiaccounts/recover {:passphrase-error :recovery-phrase-invalid
:passphrase-warning :recovery-phrase-unknown-words
:passphrase "game buzz method pretty 1234 fat quit display velvet unveil marine crater"}}}
(models/validate-phrase {:db {:multiaccounts/recover {:passphrase "game buzz method pretty 1234 fat quit display velvet unveil marine crater"}}}))))

Expand Down
6 changes: 5 additions & 1 deletion translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,11 @@
"enter-seed-phrase": "Enter Seed phrase",
"recover-with-keycard": "Recover with Keycard",
"multiaccounts-recover-enter-phrase-title": "Enter your seed phrase",
"multiaccounts-recover-enter-phrase-text": "Enter your seed phrase, separate the words by single spaces",
"multiaccounts-recover-enter-phrase-text": "Enter 12, 15, 18, 21 or 24 words.\nSeperate words by a single space.",
"words-n": {
"one": "1 word",
"other": "{{count}} words"
},
"re-encrypt-key": "Re-encrypt your key",
"recovery-success-text": "You will have to create a new code or password to re-encrypt your key"
}

0 comments on commit 71fbd73

Please sign in to comment.