From 5d6d5495110d121956fec1f56c222b921fba4fe0 Mon Sep 17 00:00:00 2001 From: Dmitry Novotochinov Date: Tue, 30 Apr 2019 13:52:14 +0300 Subject: [PATCH] [#7927] import keycard account to new device Signed-off-by: Dmitry Novotochinov --- src/status_im/events.cljs | 27 ++++- src/status_im/hardwallet/card.cljs | 13 +- src/status_im/hardwallet/core.cljs | 112 ++++++++++++++---- .../ui/screens/hardwallet/pin/views.cljs | 2 + .../ui/screens/hardwallet/setup/views.cljs | 31 +++++ translations/en.json | 4 +- 6 files changed, 160 insertions(+), 29 deletions(-) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 90fc3173d3..0baea155f3 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -1229,7 +1229,7 @@ (handlers/register-handler-fx :hardwallet.ui/pair-code-next-button-pressed (fn [cofx] - (hardwallet/pair cofx))) + (hardwallet/pair-code-next-button-pressed cofx))) (handlers/register-handler-fx :hardwallet.ui/recovery-phrase-next-button-pressed @@ -1366,6 +1366,31 @@ (fn [cofx _] (hardwallet/proceed-to-generate-mnemonic cofx))) +(handlers/register-handler-fx + :hardwallet.ui/import-account-back-button-pressed + (fn [cofx _] + (hardwallet/import-account-back-button-pressed cofx))) + +(handlers/register-handler-fx + :hardwallet.ui/import-account-next-button-pressed + (fn [cofx _] + (hardwallet/import-account-next-button-pressed cofx))) + +(handlers/register-handler-fx + :hardwallet/load-importing-account-screen + (fn [cofx _] + (hardwallet/load-importing-account-screen cofx))) + +(handlers/register-handler-fx + :hardwallet/import-account + (fn [cofx _] + (hardwallet/import-account cofx))) + +(handlers/register-handler-fx + :hardwallet/verify-pin + (fn [cofx _] + (hardwallet/verify-pin cofx))) + (handlers/register-handler-fx :hardwallet/generate-mnemonic (fn [cofx _] diff --git a/src/status_im/hardwallet/card.cljs b/src/status_im/hardwallet/card.cljs index 2641104721..26fec3b934 100644 --- a/src/status_im/hardwallet/card.cljs +++ b/src/status_im/hardwallet/card.cljs @@ -111,7 +111,7 @@ (defn verify-pin [{:keys [pin pairing]}] - (when (and pairing pin) + (when (and pairing (not-empty pin)) (.. keycard (verifyPin pairing pin) (then #(re-frame/dispatch [:hardwallet.callback/on-verify-pin-success %])) @@ -163,11 +163,12 @@ (catch #(re-frame/dispatch [:hardwallet.callback/on-delete-error (error-object->map %)]))))) (defn get-keys - [{:keys [pairing pin]}] - (.. keycard - (getKeys pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-get-keys-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-get-keys-error (error-object->map %)])))) + [{:keys [pairing pin on-success]}] + (when (and pairing (not-empty pin)) + (.. keycard + (getKeys pairing pin) + (then #(re-frame/dispatch [(or on-success :hardwallet.callback/on-get-keys-success) %])) + (catch #(re-frame/dispatch [:hardwallet.callback/on-get-keys-error (error-object->map %)]))))) (defn sign [{:keys [pairing pin hash]}] diff --git a/src/status_im/hardwallet/core.cljs b/src/status_im/hardwallet/core.cljs index b32f084f64..c5f4ce1f0f 100644 --- a/src/status_im/hardwallet/core.cljs +++ b/src/status_im/hardwallet/core.cljs @@ -92,20 +92,12 @@ :cancel-button-text "" :confirm-button-text :t/okay}}) -(fx/defn show-keycard-has-account-alert - [{:keys [db] :as cofx}] - (fx/merge cofx - {:db (assoc-in db [:hardwallet :setup-step] nil) - :utils/show-confirmation {:title nil - :content (i18n/label :t/keycard-has-account-on-it) - :cancel-button-text "" - :confirm-button-text :t/okay}})) - (defn- card-state->setup-step [state] (case state :not-paired :pair :no-pairing-slots :no-slots :init :card-ready + :account :import-account :begin)) (defn- get-card-state @@ -140,23 +132,39 @@ [{:keys [db]} card-state] {:db (assoc-in db [:hardwallet :setup-step] (card-state->setup-step card-state))}) +(fx/defn show-keycard-has-account-alert + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (assoc-in db [:hardwallet :setup-step] nil) + :utils/show-confirmation {:title nil + :content (i18n/label :t/keycard-has-account-on-it) + :cancel-button-text "" + :confirm-button-text :t/okay}})) + (fx/defn check-card-state [{:keys [db] :as cofx}] (let [app-info (get-in db [:hardwallet :application-info]) - card-state (get-card-state app-info) + flow (get-in db [:hardwallet :flow]) + instance-uid (:instance-uid app-info) + pairing (get-pairing db instance-uid) + app-info' (if pairing (assoc app-info :paired? true) app-info) + card-state (get-card-state app-info') setup-running? (boolean (get-in db [:hardwallet :setup-step])) db' (assoc-in db [:hardwallet :card-state] card-state)] (if setup-running? (fx/merge cofx {:db db'} (set-setup-step card-state) - (if (contains? #{:init :pre-init} card-state) + (if (or (contains? #{:init :pre-init} card-state) + (and (= :account card-state) + (= :import flow))) (navigation/navigate-to-cofx :hardwallet-setup nil) (when-not (= :not-paired card-state) (navigation/navigate-to-cofx :hardwallet-authentication-method nil))) (when (= card-state :blank) (show-no-keycard-applet-alert)) - (when (= card-state :account) + (when (and (= card-state :account) + (= flow :create)) (show-keycard-has-account-alert))) {:db db'}))) @@ -307,10 +315,13 @@ [{:keys [db] :as cofx} info on-success] (let [info' (js->clj info :keywordize-keys true) {:keys [pin-retry-counter puk-retry-counter instance-uid]} info' - connect-screen? (= (:view-id db) :hardwallet-connect) + view-id (:view-id db) + connect-screen? (contains? #{:hardwallet-connect + :hardwallet-connect-sign + :hardwallet-connect-settings} view-id) {:keys [card-state on-card-read]} (:hardwallet db) on-success' (or on-success on-card-read) - accounts-screen? (= :accounts (:view-id db)) + accounts-screen? (= :accounts view-id) auto-login? (and accounts-screen? (not= on-success :hardwallet/auto-login)) setup-starting? (= :begin (get-in db [:hardwallet :setup-step])) @@ -580,16 +591,29 @@ (dispatch-event :hardwallet/pair) (navigation/navigate-to-cofx :hardwallet-connect nil))))) +(fx/defn pair* [_ password] + {:hardwallet/pair {:password password}}) + (fx/defn pair [{:keys [db] :as cofx}] (let [{:keys [password]} (get-in cofx [:db :hardwallet :secrets]) card-connected? (get-in db [:hardwallet :card-connected?])] - (if card-connected? - {:hardwallet/pair {:password password}} - (fx/merge cofx - {:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/pair)} + (fx/merge cofx + {:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/pair)} + (if card-connected? + (pair* password) (navigation/navigate-to-cofx :hardwallet-connect nil))))) +(fx/defn pair-code-next-button-pressed + [{:keys [db] :as cofx}] + (let [pairing (get-in db [:hardwallet :secrets :pairing]) + paired-on (get-in db [:hardwallet :secrets :paired-on] (utils.datetime/timestamp))] + (if pairing + {:db (-> db + (assoc-in [:hardwallet :setup-step] :import-account) + (assoc-in [:hardwallet :secrets :paired-on] paired-on))} + (pair cofx)))) + (fx/defn return-back-from-nfc-settings [{:keys [db]}] (when (contains? #{:hardwallet-connect :hardwallet-connect-sign @@ -801,7 +825,7 @@ (defn- unblock-pin [{:keys [db] :as cofx}] - (let [puk (vector->string (get-in cofx [:db :hardwallet :pin :puk])) + (let [puk (vector->string (get-in db [:hardwallet :pin :puk])) instance-uid (get-in db [:hardwallet :application-info :instance-uid]) card-connected? (get-in db [:hardwallet :card-connected?]) pairing (get-pairing db instance-uid)] @@ -899,6 +923,34 @@ :hardwallet-connect-sign) nil))))) +(fx/defn import-account + [{:keys [db] :as cofx}] + (let [{:keys [pairing]} (get-in db [:hardwallet :secrets]) + instance-uid (get-in db [:hardwallet :application-info :instance-uid]) + pairing' (or pairing (get-pairing db instance-uid)) + pin (vector->string (get-in db [:hardwallet :pin :import-account]))] + (fx/merge cofx + {:db (-> db + (assoc-in [:hardwallet :keycard-instance-uid] instance-uid) + (assoc-in [:hardwallet :secrets] {:pairing pairing' + :paired-on (utils.datetime/timestamp)})) + :hardwallet/get-keys {:pairing pairing' + :pin pin + :on-success :hardwallet.callback/on-generate-and-load-key-success}}))) + +(fx/defn load-importing-account-screen + [{:keys [db] :as cofx}] + (let [card-connected? (get-in db [:hardwallet :card-connected?])] + (fx/merge cofx + {:db (-> db + (assoc-in [:hardwallet :on-card-connected] :hardwallet/load-importing-account-screen) + (assoc-in [:hardwallet :setup-step] :importing-account))} + (when card-connected? + (import-account)) + (navigation/navigate-to-cofx (if card-connected? + :hardwallet-setup + :hardwallet-connect) nil)))) + ; PIN enter steps: ; login - PIN is used to login ; sign - PIN for transaction sign @@ -908,6 +960,7 @@ (fx/defn process-pin-input [{:keys [db]}] (let [enter-step (get-in db [:hardwallet :pin :enter-step]) + setup-step (get-in db [:hardwallet :setup-step]) pin (get-in db [:hardwallet :pin enter-step]) numbers-entered (count pin)] (cond-> {:db (assoc-in db [:hardwallet :pin :status] nil)} @@ -925,6 +978,11 @@ (= default-pin (vector->string pin))) (pin-enter-error :t/cannot-use-default-pin) + (and (= setup-step :import-account) + (= enter-step :import-account) + (= pin-code-length numbers-entered)) + (load-importing-account-screen) + (and (= enter-step :current) (= pin-code-length numbers-entered)) (verify-pin) @@ -1193,6 +1251,17 @@ {:db (assoc-in db [:hardwallet :secrets :mnemonic] mnemonic)} (load-loading-keys-screen))))) +(fx/defn import-account-back-button-pressed + [cofx] + (navigation/navigate-to-cofx cofx :hardwallet-authentication-method nil)) + +(fx/defn import-account-next-button-pressed + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (-> db + (assoc-in [:hardwallet :pin :enter-step] :import-account))} + (navigation/navigate-to-cofx :enter-pin-login nil))) + (fx/defn generate-and-load-key [{:keys [db] :as cofx}] (let [{:keys [mnemonic pairing pin]} (get-in db [:hardwallet :secrets]) @@ -1233,7 +1302,8 @@ wallet-address instance-uid encryption-public-key]} (js->clj data :keywordize-keys true) - whisper-public-key' (str "0x" whisper-public-key)] + whisper-public-key' (str "0x" whisper-public-key) + instance-uid' (get-in db [:hardwallet :keycard-instance-uid])] (fx/merge cofx {:db (-> db (assoc-in [:hardwallet :whisper-public-key] whisper-public-key') @@ -1241,7 +1311,7 @@ (assoc-in [:hardwallet :whisper-address] whisper-address) (assoc-in [:hardwallet :wallet-address] wallet-address) (assoc-in [:hardwallet :encryption-public-key] encryption-public-key) - (assoc-in [:hardwallet :keycard-instance-uid] instance-uid) + (assoc-in [:hardwallet :keycard-instance-uid] (or instance-uid' instance-uid)) (assoc-in [:hardwallet :on-card-connected] nil) (update :hardwallet dissoc :recovery-phrase) (update-in [:hardwallet :secrets] dissoc :pin :puk :password) diff --git a/src/status_im/ui/screens/hardwallet/pin/views.cljs b/src/status_im/ui/screens/hardwallet/pin/views.cljs index fd6eeecbb4..75121a7df5 100644 --- a/src/status_im/ui/screens/hardwallet/pin/views.cljs +++ b/src/status_im/ui/screens/hardwallet/pin/views.cljs @@ -147,12 +147,14 @@ :title-label (case step :current :t/current-pin :login :t/current-pin + :import-account :t/current-pin :original :t/create-a-pin :confirmation :t/repeat-pin :t/current-pin) :description-label (case step :current :t/current-pin-description :sign :t/current-pin-description + :import-account :t/current-pin-description :login :t/login-pin-description :t/new-pin-description) :step step diff --git a/src/status_im/ui/screens/hardwallet/setup/views.cljs b/src/status_im/ui/screens/hardwallet/setup/views.cljs index 2a49ddc95b..73ed5b8b90 100644 --- a/src/status_im/ui/screens/hardwallet/setup/views.cljs +++ b/src/status_im/ui/screens/hardwallet/setup/views.cljs @@ -91,6 +91,24 @@ {:on-press #(re-frame/dispatch [:hardwallet.ui/card-ready-next-button-pressed]) :forward? true}]]]]])) +(defn- import-account [] + [react/view styles/card-ready-container + [react/view styles/card-ready-inner-container + [react/view (assoc styles/center-container :margin-top 68) + [react/text {:style styles/center-title-text} + (i18n/label :t/card-is-paired)] + [react/text {:style styles/estimated-time-text} + (i18n/label :t/ready-to-import-keycard-account)]] + [react/view]] + [react/view styles/back-and-next-buttons-container + [components.common/bottom-button + {:on-press #(re-frame/dispatch [:hardwallet.ui/import-account-back-button-pressed]) + :back? true + :label (i18n/label :t/back)}] + [components.common/bottom-button + {:on-press #(re-frame/dispatch [:hardwallet.ui/import-account-next-button-pressed]) + :forward? true}]]]) + (defview display-recovery-phrase [] (letsubs [mnemonic [:hardwallet-mnemonic]] (let [mnemonic-vec (vec (map-indexed vector (clojure.string/split mnemonic #" ")))] @@ -419,6 +437,17 @@ :estimated-time-seconds 30 :step-number 3}]) +(defn- importing-account [] + [react/view styles/loading-view-container + [react/view styles/center-container + [react/text {:style styles/center-title-text} + (i18n/label :t/importing-keycard-account)] + [react/text {:style styles/estimated-time-text} + (i18n/label :t/this-will-take-few-seconds)]] + [react/view styles/waiting-indicator-container + [react/activity-indicator {:animating true + :size :large}]]]) + (defn- content [step] (case step :begin [begin] @@ -438,6 +467,8 @@ :recovery-phrase-confirm-word1 [recovery-phrase-confirm-word step] :recovery-phrase-confirm-word2 [recovery-phrase-confirm-word step] :error [error] + :import-account [import-account] + :importing-account [importing-account] [begin])) (defview hardwallet-setup [] diff --git a/translations/en.json b/translations/en.json index 4132317d3c..62e36c3cc7 100644 --- a/translations/en.json +++ b/translations/en.json @@ -843,6 +843,8 @@ "generating-mnemonic": "Generating mnemonic phrase", "next-step-generating-mnemonic": "Next step is generating mnemonic phrase for your card", "next-step-entering-mnemonic": "Next step is entering mnemonic phrase to import your account", + "importing-keycard-account": "Importing keycard account", + "ready-to-import-keycard-account": "We are ready to import keycard account", "this-will-take-few-seconds": "This will take a few seconds", "finishing-card-setup": "Finishing card setup", "finishing-card-setup-steps": "> Loading keys to the card\n> Generating account", @@ -891,7 +893,7 @@ "enter-pair-code": "Enter pair code", "enter-pair-code-description": "SECURITY NOTE: Use only the code you wrote down during card setup.", "no-pairing-slots-available": "This card is already paired to 5 devices and cannot pair to this one. Please use one of the paired devices, log in with this card and free up pairing slots on the card", - "keycard-has-account-on-it": "This card has already an account on it. If you wish to change it, login first and reset your card.", + "keycard-has-account-on-it": "This card has already an account on it. If you wish to change it, login first and reset your card. If you want to import keycard account, please use \"Add existing account\"", "card-already-linked": "Card is already linked to another account", "keycard-unauthorized-operation": "You're unauthorized to perform this operation.\n Please tap valid card and try again.", "no-account-on-card": "No account on this card",