[#8502] recover key to keycard

Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2019-07-01 20:21:44 +03:00
parent e28202521f
commit a2da4dec63
No known key found for this signature in database
GPG Key ID: 43D1DAF5AD39C927
6 changed files with 240 additions and 116 deletions

View File

@ -282,11 +282,6 @@
;; accounts recover module ;; accounts recover module
(handlers/register-handler-fx
:accounts.recover.ui/recover-account-button-pressed
(fn [cofx _]
(hardwallet/navigate-to-recover-method cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:accounts.recover.ui/passphrase-input-changed :accounts.recover.ui/passphrase-input-changed
(fn [cofx [_ recovery-phrase]] (fn [cofx [_ recovery-phrase]]
@ -1171,11 +1166,6 @@
{:db (assoc-in db [:hardwallet :setup-step] :begin)} {:db (assoc-in db [:hardwallet :setup-step] :begin)}
(navigation/navigate-to-cofx :hardwallet-setup nil)))) (navigation/navigate-to-cofx :hardwallet-setup nil))))
(handlers/register-handler-fx
:hardwallet/load-pairing-screen
(fn [cofx _]
(hardwallet/load-pairing-screen cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet/load-generating-mnemonic-screen :hardwallet/load-generating-mnemonic-screen
(fn [cofx _] (fn [cofx _]

View File

@ -302,6 +302,18 @@
(navigation/navigate-to-cofx cofx :keycard-onboarding-recovery-phrase nil) (navigation/navigate-to-cofx cofx :keycard-onboarding-recovery-phrase nil)
(navigation/navigate-to-cofx cofx :keycard-onboarding-recovery-phrase-confirm-word1 nil))) (navigation/navigate-to-cofx cofx :keycard-onboarding-recovery-phrase-confirm-word1 nil)))
(fx/defn proceed-with-generating-key
[{:keys [db] :as cofx}]
(let [pin (or (get-in db [:hardwallet :secrets :pin])
(vector->string (get-in db [:hardwallet :pin :current])))]
(if (empty? pin)
(fx/merge cofx
{:db (assoc-in db [:hardwallet :pin] {:enter-step :current
:on-verified :hardwallet/generate-and-load-key
:current []})}
(navigation/navigate-to-cofx :keycard-onboarding-pin nil))
(load-finishing-screen cofx))))
(fx/defn recovery-phrase-confirm-word-next-pressed (fx/defn recovery-phrase-confirm-word-next-pressed
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/next-pressed {:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/next-pressed
:keycard.onboarding.recovery-phrase-confirm-word.ui/input-submitted]} :keycard.onboarding.recovery-phrase-confirm-word.ui/input-submitted]}
@ -314,16 +326,7 @@
(fx/merge cofx (fx/merge cofx
(recovery-phrase-next-word) (recovery-phrase-next-word)
(navigation/navigate-to-cofx :keycard-onboarding-recovery-phrase-confirm-word2 nil)) (navigation/navigate-to-cofx :keycard-onboarding-recovery-phrase-confirm-word2 nil))
(let [pin (or (get-in db [:hardwallet :secrets :pin]) (proceed-with-generating-key cofx))
(vector->string (get-in db [:hardwallet :pin :current])))]
(if (empty? pin)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin] {:enter-step :current
:on-verified :hardwallet/generate-and-load-key
:current []}))}
(navigation/navigate-to-cofx :keycard-onboarding-pin nil))
(load-finishing-screen cofx))))
{:db (assoc-in db [:hardwallet :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))}))) {:db (assoc-in db [:hardwallet :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
(fx/defn recovery-phrase-confirm-word-input-changed (fx/defn recovery-phrase-confirm-word-input-changed
@ -357,7 +360,7 @@
(when (= card-state :blank) (when (= card-state :blank)
(show-no-keycard-applet-alert)) (show-no-keycard-applet-alert))
(when (and (= card-state :account) (when (and (= card-state :account)
(= flow :create)) (#{:create :recovery} flow))
(show-keycard-has-account-alert))) (show-keycard-has-account-alert)))
{:db db'}))) {:db db'})))
@ -390,14 +393,37 @@
(navigation/navigate-to-cofx :hardwallet-authentication-method nil)) (navigation/navigate-to-cofx :hardwallet-authentication-method nil))
(accounts.create/intro-wizard cofx false))) (accounts.create/intro-wizard cofx false)))
(fx/defn navigate-to-recover-method (fx/defn navigate-to-enter-mnemonic
{:events [:accounts.recover.ui/recover-account-button-pressed]}
[{:keys [db] :as cofx}] [{:keys [db] :as cofx}]
(if (hardwallet-supported? cofx) (if (hardwallet-supported? cofx)
(fx/merge cofx (fx/merge cofx
{:db (assoc-in db [:hardwallet :flow] :import)} {:db (assoc-in db [:hardwallet :flow] :recovery)}
(navigation/navigate-to-cofx :hardwallet-authentication-method nil)) (navigation/navigate-to-cofx :keycard-recovery-enter-mnemonic nil))
(accounts.recover/navigate-to-recover-account-screen cofx))) (accounts.recover/navigate-to-recover-account-screen cofx)))
(fx/defn recovery-keycard-selected
{:events [:recovery.ui/keycard-option-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:hardwallet :flow] :recovery)
:hardwallet/check-nfc-enabled nil
:hardwallet/register-card-events nil}
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
;NOTE to be removed when Recovery flow will be implemented
(fx/defn enter-mnemonic-next-button-pressed
{:events [:keycard.recovery.enter-mnemonic.ui/input-submitted
:keycard.recovery.enter-mnemonic.ui/next-pressed]}
[cofx]
(recovery-keycard-selected cofx))
;NOTE to be removed when Recovery flow will be implemented
(fx/defn enter-mnemonic-input-changed
{:events [:keycard.recovery.enter-mnemonic.ui/input-changed]}
[{:keys [db]} input]
{:db (assoc-in db [:hardwallet :secrets :mnemonic] input)})
(fx/defn password-option-pressed (fx/defn password-option-pressed
[{:keys [db] :as cofx}] [{:keys [db] :as cofx}]
(if (= (get-in db [:hardwallet :flow]) :create) (if (= (get-in db [:hardwallet :flow]) :create)
@ -591,11 +617,13 @@
(fx/defn keycard-option-pressed (fx/defn keycard-option-pressed
{:events [:onboarding.ui/keycard-option-pressed]} {:events [:onboarding.ui/keycard-option-pressed]}
[cofx] [{:keys [db] :as cofx}]
(fx/merge cofx (let [flow (get-in db [:hardwallet :flow] :create)]
{:hardwallet/check-nfc-enabled nil (fx/merge cofx
:hardwallet/register-card-events nil} {:db (assoc-in db [:hardwallet :flow] flow)
(navigation/navigate-to-cofx :keycard-onboarding-intro nil))) :hardwallet/check-nfc-enabled nil
:hardwallet/register-card-events nil}
(navigation/navigate-to-cofx :keycard-onboarding-intro nil))))
(fx/defn begin-setup-pressed (fx/defn begin-setup-pressed
{:events [:keycard.onboarding.intro.ui/begin-setup-pressed]} {:events [:keycard.onboarding.intro.ui/begin-setup-pressed]}
@ -823,8 +851,10 @@
card-connected? (get-in db [:hardwallet :card-connected?])] card-connected? (get-in db [:hardwallet :card-connected?])]
(fx/merge cofx (fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/pair)} {:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/pair)}
(when card-connected?
(pair* password))
(if card-connected? (if card-connected?
(pair* password) (navigation/navigate-to-cofx :keycard-onboarding-pairing nil)
(navigation/navigate-to-cofx :keycard-onboarding-connection-lost nil))))) (navigation/navigate-to-cofx :keycard-onboarding-connection-lost nil)))))
(fx/defn pair-code-next-button-pressed (fx/defn pair-code-next-button-pressed
@ -838,8 +868,7 @@
{:db (-> db {:db (-> db
(assoc-in [:hardwallet :setup-step] :import-account) (assoc-in [:hardwallet :setup-step] :import-account)
(assoc-in [:hardwallet :secrets :paired-on] paired-on))} (assoc-in [:hardwallet :secrets :paired-on] paired-on))}
(pair)) (pair)))))
(navigation/navigate-to-cofx :keycard-onboarding-pairing nil))))
(fx/defn return-back-from-nfc-settings [{:keys [db]}] (fx/defn return-back-from-nfc-settings [{:keys [db]}]
(when (= (:view-id db) (when (= (:view-id db)
@ -938,6 +967,7 @@
(update-in [:hardwallet :pin] merge {:status nil (update-in [:hardwallet :pin] merge {:status nil
:error-label nil}))} :error-label nil}))}
(when-not (contains? #{:hardwallet/unpair (when-not (contains? #{:hardwallet/unpair
:hardwallet/generate-and-load-key
:hardwallet/remove-key-with-unpair :hardwallet/remove-key-with-unpair
:hardwallet/unpair-and-delete} on-verified) :hardwallet/unpair-and-delete} on-verified)
(get-application-info pairing nil)) (get-application-info pairing nil))
@ -1343,7 +1373,7 @@
(assoc-in [:hardwallet :card-state] :init) (assoc-in [:hardwallet :card-state] :init)
(assoc-in [:hardwallet :on-card-connected] nil) (assoc-in [:hardwallet :on-card-connected] nil)
(assoc-in [:hardwallet :setup-step] :secret-keys) (assoc-in [:hardwallet :setup-step] :secret-keys)
(assoc-in [:hardwallet :secrets] secrets'))} (update-in [:hardwallet :secrets] merge secrets'))}
(navigation/navigate-to-cofx :keycard-onboarding-puk-code nil)))) (navigation/navigate-to-cofx :keycard-onboarding-puk-code nil))))
(def on-init-card-success on-install-applet-and-init-card-success) (def on-init-card-success on-install-applet-and-init-card-success)
@ -1392,6 +1422,8 @@
(assoc-in [:hardwallet :secrets :paired-on] paired-on))} (assoc-in [:hardwallet :secrets :paired-on] paired-on))}
(when account (when account
(set-account-pairing account pairing paired-on)) (set-account-pairing account pairing paired-on))
(when (= flow :recovery)
(proceed-with-generating-key))
(when (= flow :create) (when (= flow :create)
(generate-mnemonic))))) (generate-mnemonic)))))

View File

@ -16,6 +16,13 @@
(fn [db] (fn [db]
(get-in db [:hardwallet :flow]))) (get-in db [:hardwallet :flow])))
(re-frame/reg-sub
:hardwallet-flow-steps
(fn [db]
(case (get-in db [:hardwallet :flow])
:recovery "2"
"3")))
(re-frame/reg-sub (re-frame/reg-sub
:hardwallet-pair-code :hardwallet-pair-code
(fn [db] (fn [db]

View File

@ -66,73 +66,76 @@
[react/text {:style {:color colors/blue}} [react/text {:style {:color colors/blue}}
(i18n/label :t/begin-set-up)]]]]]]) (i18n/label :t/begin-set-up)]]]]]])
(defn start [] (defview start []
[react/view styles/container (letsubs [flow [:hardwallet-flow]]
[toolbar/toolbar [react/view styles/container
{:transparent? true [toolbar/toolbar
:style {:margin-top 32}} {:transparent? true
toolbar/default-nav-back :style {:margin-top 32}}
nil] toolbar/default-nav-back
[react/scroll-view nil]
[react/view {:flex 1 [react/scroll-view
:flex-direction :column [react/view {:flex 1
:justify-content :space-between :flex-direction :column
:align-items :center} :justify-content :space-between
[react/view {:flex-direction :column :align-items :center}
:align-items :center} [react/view {:flex-direction :column
[react/view {:margin-top 16} :align-items :center}
[react/text {:style {:typography :header [react/view {:margin-top 16}
:text-align :center}} [react/text {:style {:typography :header
(i18n/label :t/keycard-onboarding-start-header)]] :text-align :center}}
[react/view {:margin-top 16 (i18n/label :t/keycard-onboarding-start-header)]]
:width 311} [react/view {:margin-top 16
[react/text {:style {:font-size 15 :width 311}
:line-height 22 [react/text {:style {:color colors/gray
:color colors/gray :text-align :center}}
:text-align :center}} (i18n/label :t/keycard-onboarding-start-text)]]
(i18n/label :t/keycard-onboarding-start-text)]] [react/view {:margin-top 20
[react/view {:margin-top 20 :width "80%"}
:width "80%"} (for [[number header text] [["1"
(for [[number header text] [["1" (i18n/label :t/keycard-onboarding-start-step1)
(i18n/label :t/keycard-onboarding-start-step1) (i18n/label :t/keycard-onboarding-start-step1-text)]
(i18n/label :t/keycard-onboarding-start-step1-text)] ["2"
["2" (i18n/label :t/keycard-onboarding-start-step2)
(i18n/label :t/keycard-onboarding-start-step2) (i18n/label :t/keycard-onboarding-start-step2-text)]
(i18n/label :t/keycard-onboarding-start-step2-text)] (when (not= flow :recovery)
["3" ["3"
(i18n/label :t/keycard-onboarding-start-step3) (i18n/label :t/keycard-onboarding-start-step3)
(i18n/label :t/keycard-onboarding-start-step3-text)]]] (i18n/label :t/keycard-onboarding-start-step3-text)])]]
^{:key number} [react/view {:flex-direction :row (when number
:margin-top 15} ^{:key number} [react/view {:flex-direction :row
[react/view {:border-width 1 :margin-top 15}
:border-radius 20 [react/view {:border-width 1
:border-color colors/gray-light :border-radius 20
:align-items :center :border-color colors/gray-light
:justify-content :center :align-items :center
:width 40 :justify-content :center
:height 40} :width 40
[react/text {:style {:typography :title}} :height 40}
number]] [react/text {:style {:typography :title}}
[react/view {:align-items :flex-start number]]
:justify-content :flex-start [react/view {:align-items :flex-start
:margin-left 11} :justify-content :flex-start
[react/view :margin-left 11}
[react/text {:style {:typography :main-medium}} [react/view
header]] [react/text {:style {:typography :main-medium}}
[react/view header]]
[react/text {:style {:color colors/gray [react/view
:padding-right 35}} [react/text {:style {:color colors/gray
text]]]])]] :padding-right 35}}
[react/view {:margin-bottom 12 text]]]]))]]
:align-items :center [react/view {:margin-bottom 12
:justify-content :center} :margin-top (if (= flow :recovery) 20 0)
[react/image {:source (resources/get-image :keycard-phone) :align-items :center
:resize-mode :center :justify-content :center}
:style {:width 160 [react/image {:source (resources/get-image :keycard-phone)
:height 170}}]]]]]) :resize-mode :center
:style {:width 160
:height 170}}]]]]]))
(defview puk-code [] (defview puk-code []
(letsubs [secrets [:hardwallet-secrets]] (letsubs [secrets [:hardwallet-secrets]
steps [:hardwallet-flow-steps]]
[react/view styles/container [react/view styles/container
[toolbar/toolbar [toolbar/toolbar
{:transparent? true {:transparent? true
@ -142,7 +145,8 @@
:style {:padding-left 21}} :style {:padding-left 21}}
(i18n/label :t/cancel)] (i18n/label :t/cancel)]
[react/text {:style {:color colors/gray}} [react/text {:style {:color colors/gray}}
"Step 2 of 3"]] (i18n/label :t/step-i-of-n {:step "2"
:number steps})]]
[react/scroll-view {:content-container-style {:flex-grow 1 [react/scroll-view {:content-container-style {:flex-grow 1
:justify-content :space-between}} :justify-content :space-between}}
[react/view {:flex 1 [react/view {:flex 1
@ -239,10 +243,8 @@
(i18n/label title-label)]] (i18n/label title-label)]]
[react/view {:margin-top 16 [react/view {:margin-top 16
:width 311} :width 311}
[react/text {:style {:font-size 15 [react/text {:style {:color colors/gray
:line-height 22 :text-align :center}}
:color colors/gray
:text-align :center}}
(i18n/label :t/this-will-take-few-seconds)]]] (i18n/label :t/this-will-take-few-seconds)]]]
[react/view {:flex 1 [react/view {:flex 1
:align-items :center :align-items :center
@ -252,10 +254,8 @@
:style {:width 160 :style {:width 160
:height 170}}] :height 170}}]
[react/view {:margin-top 10} [react/view {:margin-top 10}
[react/text {:style {:text-align :center [react/text {:style {:text-align :center
:color colors/gray :color colors/gray}}
:font-size 15
:line-height 22}}
(i18n/label :t/hold-card)]]]]]) (i18n/label :t/hold-card)]]]]])
(defn preparing [] (defn preparing []
@ -331,7 +331,40 @@
:margin-bottom 30}} :margin-bottom 30}}
(i18n/label :t/open-nfc-settings)]]]]]) (i18n/label :t/open-nfc-settings)]]]]])
(def pin pin.views/create-pin) (defview pin []
(letsubs [pin [:hardwallet/pin]
enter-step [:hardwallet/pin-enter-step]
status [:hardwallet/pin-status]
error-label [:hardwallet/pin-error-label]
steps [:hardwallet-flow-steps]]
[react/view styles/container
[toolbar/toolbar
{:transparent? true
:style {:margin-top 32}}
[toolbar/nav-text
{:handler #(re-frame/dispatch [:keycard.onboarding.ui/cancel-pressed])
:style {:padding-left 21}}
(i18n/label :t/cancel)]
[react/text {:style {:color colors/gray}}
(i18n/label :t/step-i-of-n {:number steps
:step 1})]]
[react/view {:flex 1
:flex-direction :column
:justify-content :space-between
:align-items :center}
[react/view {:flex-direction :column
:align-items :center}
[react/view {:margin-top 16}
[react/text {:style {:typography :header
:text-align :center}}
(i18n/label (if (= :original enter-step)
:t/intro-wizard-title4
:t/intro-wizard-title5))]]]
[status-im.ui.screens.hardwallet.pin.views/pin-view
{:pin pin
:status status
:error-label error-label
:step enter-step}]]]))
(defview recovery-phrase [] (defview recovery-phrase []
(letsubs [mnemonic [:hardwallet-mnemonic]] (letsubs [mnemonic [:hardwallet-mnemonic]]
@ -344,7 +377,8 @@
:style {:padding-left 21}} :style {:padding-left 21}}
(i18n/label :t/cancel)] (i18n/label :t/cancel)]
[react/text {:style {:color colors/gray}} [react/text {:style {:color colors/gray}}
"Step 3 of 3"]] (i18n/label :t/step-i-of-n {:step "3"
:number "3"})]]
[react/scroll-view {:content-container-style {:flex-grow 1 [react/scroll-view {:content-container-style {:flex-grow 1
:justify-content :space-between}} :justify-content :space-between}}
[react/view {:flex-direction :column [react/view {:flex-direction :column
@ -366,12 +400,13 @@
[react/text {:style {:color colors/blue}} [react/text {:style {:color colors/blue}}
(i18n/label :t/learn-more)]]]]] (i18n/label :t/learn-more)]]]]]
[react/view [react/view {:padding-horizontal 24}
[react/view [react/view
(for [[i row] mnemonic] (for [[i row] mnemonic]
^{:key (str "row" i)} ^{:key (str "row" i)}
[react/view {:flex-direction :row [react/view {:flex-direction :row
:margin-top 12} :justify-content :center
:margin-top 12}
(for [[i word] row] (for [[i word] row]
^{:key (str "word" i)} ^{:key (str "word" i)}
[react/view {:flex-direction :row [react/view {:flex-direction :row
@ -413,7 +448,8 @@
:style {:padding-left 21}} :style {:padding-left 21}}
(i18n/label :t/cancel)] (i18n/label :t/cancel)]
[react/text {:style {:color colors/gray}} [react/text {:style {:color colors/gray}}
"Step 3 of 3"]] (i18n/label :t/step-i-of-n {:step "3"
:number "3"})]]
[react/view {:flex 1 [react/view {:flex 1
:flex-direction :column :flex-direction :column
:justify-content :space-between :justify-content :space-between
@ -474,7 +510,8 @@
:style {:padding-left 21}} :style {:padding-left 21}}
(i18n/label :t/cancel)] (i18n/label :t/cancel)]
[react/text {:style {:color colors/gray}} [react/text {:style {:color colors/gray}}
"Step 3 of 3"]] (i18n/label :t/step-i-of-n {:step "3"
:number "3"})]]
[react/view {:flex 1 [react/view {:flex 1
:flex-direction :column :flex-direction :column
:justify-content :space-between :justify-content :space-between
@ -514,3 +551,58 @@
:label (i18n/label :t/pair-card) :label (i18n/label :t/pair-card)
:disabled? (empty? pair-code) :disabled? (empty? pair-code)
:forward? true}]]]]])) :forward? true}]]]]]))
;NOTE temporary screen, to be removed after Recovery will be implemented
(defview enter-mnemonic []
(letsubs [mnemonic [:hardwallet-mnemonic]]
[react/view styles/container
[toolbar/toolbar
{:transparent? true
:style {:margin-top 32}}
[toolbar/nav-text
{:handler #(re-frame/dispatch [:keycard.onboarding.ui/cancel-pressed])
:style {:padding-left 21}}
(i18n/label :t/cancel)]
[react/text {:style {:color colors/gray}}
(i18n/label :t/step-i-of-n {:step "1"
:number "2"})]]
[react/view {:flex 1
:flex-direction :column
:justify-content :space-between
:align-items :center}
[react/view {:flex-direction :column
:align-items :center}
[react/view {:margin-top 16}
[react/text {:style {:typography :header
:text-align :center}}
"Enter your seed phrase"]]
[react/view {:margin-top 16
:width "85%"
:align-items :center}
[react/text {:style {:color colors/gray
:text-align :center}}
"Enter your seed phrase, separate the words by single spaces"]]]
[react/view
[text-input/text-input-with-label
{:on-change-text #(re-frame/dispatch [:keycard.recovery.enter-mnemonic.ui/input-changed %])
:auto-focus true
:on-submit-editing #(re-frame/dispatch [:keycard.recovery.enter-mnemonic.ui/input-submitted])
:placeholder nil
:height 125
:multiline true
:auto-correct false
:container {:background-color :white}
:style {:background-color :white
:typography :header}}]]
[react/view {:flex-direction :row
:justify-content :space-between
:align-items :center
:width "100%"
:height 86}
[react/view]
[react/view {:margin-right 20}
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:keycard.recovery.enter-mnemonic.ui/next-pressed])
:label (i18n/label :t/next)
:disabled? (empty? mnemonic)
:forward? true}]]]]]))

View File

@ -26,7 +26,8 @@
:keycard-onboarding-nfc-on :keycard-onboarding-nfc-on
:keycard-onboarding-recovery-phrase :keycard-onboarding-recovery-phrase
:keycard-onboarding-recovery-phrase-confirm-word1 :keycard-onboarding-recovery-phrase-confirm-word1
:keycard-onboarding-recovery-phrase-confirm-word2}) :keycard-onboarding-recovery-phrase-confirm-word2
:keycard-recovery-enter-mnemonic})
(defn login-stack [view-id] (defn login-stack [view-id]
{:name :login-stack {:name :login-stack
@ -66,6 +67,7 @@
:keycard-onboarding-nfc-on :keycard-onboarding-nfc-on
:keycard-onboarding-recovery-phrase :keycard-onboarding-recovery-phrase
:keycard-onboarding-recovery-phrase-confirm-word1 :keycard-onboarding-recovery-phrase-confirm-word1
:keycard-onboarding-recovery-phrase-confirm-word2) :keycard-onboarding-recovery-phrase-confirm-word2
:keycard-recovery-enter-mnemonic)
(assoc :name :intro-stack) (assoc :name :intro-stack)
(assoc :config {:initialRouteName :intro}))) (assoc :config {:initialRouteName :intro})))

View File

@ -96,6 +96,7 @@
:keycard-onboarding-recovery-phrase keycard.onboarding/recovery-phrase :keycard-onboarding-recovery-phrase keycard.onboarding/recovery-phrase
:keycard-onboarding-recovery-phrase-confirm-word1 keycard.onboarding/recovery-phrase-confirm-word :keycard-onboarding-recovery-phrase-confirm-word1 keycard.onboarding/recovery-phrase-confirm-word
:keycard-onboarding-recovery-phrase-confirm-word2 keycard.onboarding/recovery-phrase-confirm-word :keycard-onboarding-recovery-phrase-confirm-word2 keycard.onboarding/recovery-phrase-confirm-word
:keycard-recovery-enter-mnemonic keycard.onboarding/enter-mnemonic
:home home/home-wrapper :home home/home-wrapper
:chat chat/chat :chat chat/chat
:select-chat chat/select-chat :select-chat chat/select-chat