From 5101d4d6a5143890280ed2ed1a050b543122a5cf Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Mon, 6 Jul 2020 15:08:26 +0300 Subject: [PATCH] [keycard] Allow to restore kk multiacc using pairing --- src/status_im/hardwallet/sign.cljs | 2 + .../hardwallet/simulated_keycard.cljs | 210 +++++++++++++----- src/status_im/hardwallet/test_menu.cljs | 1 + src/status_im/signing/keycard.cljs | 2 +- .../ui/screens/hardwallet/setup/subs.cljs | 5 +- 5 files changed, 165 insertions(+), 55 deletions(-) diff --git a/src/status_im/hardwallet/sign.cljs b/src/status_im/hardwallet/sign.cljs index 504d17d821..e4a79c55d7 100644 --- a/src/status_im/hardwallet/sign.cljs +++ b/src/status_im/hardwallet/sign.cljs @@ -19,6 +19,7 @@ keycard-match? (= keycard-instance-uid instance-uid) hash (get-in db [:hardwallet :hash]) data (get-in db [:hardwallet :data]) + typed? (get-in db [:hardwallet :typed?]) pin (common/vector->string (get-in db [:hardwallet :pin :sign])) from (get-in db [:signing/tx :from :address]) path (reduce @@ -35,6 +36,7 @@ :hardwallet/sign {:hash (ethereum/naked-address hash) :data data :pairing pairing + :typed? typed? :pin pin :path path}} (fx/merge cofx diff --git a/src/status_im/hardwallet/simulated_keycard.cljs b/src/status_im/hardwallet/simulated_keycard.cljs index a76c3ff8d0..dc835f8f17 100644 --- a/src/status_im/hardwallet/simulated_keycard.cljs +++ b/src/status_im/hardwallet/simulated_keycard.cljs @@ -9,7 +9,8 @@ [status-im.utils.utils :as utils] [status-im.i18n :as i18n] [clojure.string :as string] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [status-im.multiaccounts.create.core :as multiaccounts.create])) (def initial-state {:card-connected? false @@ -36,6 +37,23 @@ :key-uid (get-in @re-frame.db/app-db [:multiaccounts/login :key-uid])}) (connect-card)) +(def initialization (atom false)) + +(defn connect-pairing-card [] + (reset! initialization false) + (swap! state assoc :application-info + {:free-pairing-slots 5 + :app-version "2.2" + :secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e", + :instance-uid "1b360b10a9a68b7d494e8f059059f118" + :paired? true + :has-master-key? true + :initialized? true + :pin-retry-counter 3 + :puk-retry-counter 5 + :key-uid "0x16839e8b1b8a395acb18100c7e2b161701c225adf31eefa02114099b4d81a30b"}) + (connect-card)) + (defn disconnect-card [] (swap! state assoc :card-connected? false) (doseq [callback (vals (get @state :on-card-disconnected))] @@ -45,7 +63,8 @@ (reset! state initial-state)) (defn- later [f] - (utils/set-timeout f 500)) + (when f + (utils/set-timeout f 500))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -88,6 +107,7 @@ (def kk1-password "000000") (def default-puk "000000000000") (defn init-card [{:keys [pin on-success]}] + (reset! initialization true) (swap! state assoc :application-info {:free-pairing-slots 5 :app-version "2.2" @@ -107,48 +127,84 @@ (def kk1-pair "ADEol+GCD67EO7zU6ko0DNK7XrNs9w2+h9GxcibNY4yf") +(def derived-acc (atom nil)) + +(defn multiaccount->keys [pin data] + (let [{:keys [selected-id multiaccounts root-key derived]} + data + + {:keys [id address public-key derived key-uid]} + (or (->> multiaccounts + (filter #(= (:id %) selected-id)) + first) + (assoc root-key :derived derived)) + + whisper (get derived constants/path-whisper-keyword) + wallet (get derived constants/path-default-wallet-keyword) + wallet-root (get derived constants/path-wallet-root-keyword) + password (ethereum/sha3 pin) + response {:key-uid key-uid + :encryption-public-key password + :address address + :whisper-public-key (:public-key whisper) + :instance-uid "1b360b10a9a68b7d494e8f059059f118" + :wallet-root-public-key (:public-key wallet-root) + :wallet-root-address (:address wallet-root) + :whisper-address (:address whisper) + :public-key public-key + :whisper-private-key "34bc7d0c258c4f2ac1dac4fd6c55c9478bac1f4a9d8b9f1152c8551ab7187b43" + :wallet-address (:address wallet) + :wallet-public-key (:public-key wallet)}] + [id response])) + (defn pair [{:keys [password on-success]}] + (when (and (not @initialization) + (not @derived-acc)) + (status/multiaccount-import-mnemonic + "night fortune spider version version armed amused winner matter tonight cave flag" + nil + (fn [result] + (let [{:keys [id] :as root-data} + (multiaccounts.create/normalize-multiaccount-data-keys + (types/json->clj result))] + (status-im.native-module.core/multiaccount-derive-addresses + id + [constants/path-wallet-root + constants/path-eip1581 + constants/path-whisper + constants/path-default-wallet] + (fn [result] + (let [derived-data (multiaccounts.create/normalize-derived-data-keys + (types/json->clj result)) + public-key (get-in derived-data [constants/path-whisper-keyword :public-key])] + (status/gfycat-identicon-async + public-key + (fn [name photo-path] + (let [derived-data-extended + (update derived-data + constants/path-whisper-keyword + merge {:name name :photo-path photo-path})] + (reset! derived-acc + {:root-key root-data + :derived derived-data-extended}))))))))))) (when (= password kk1-password) - (later #(on-success kk1-pair)))) + (later #(on-success (str (rand-int 10000000)))))) (defn generate-and-load-key - [{:keys [pin pairing on-success]}] - (when (and (= pin (get @state :pin)) - (= pairing kk1-pair)) - (let [{:keys [selected-id multiaccounts root-key derived]} - (:intro-wizard @re-frame.db/app-db) - - {:keys [id address public-key derived key-uid]} - (or (->> multiaccounts - (filter #(= (:id %) selected-id)) - first) - (assoc root-key :derived derived)) - - whisper (get derived constants/path-whisper-keyword) - wallet (get derived constants/path-default-wallet-keyword) - wallet-root (get derived constants/path-wallet-root-keyword) - password (ethereum/sha3 pin) - response {:key-uid key-uid - :encryption-public-key (ethereum/sha3 pin) - :address address - :whisper-public-key (:public-key whisper) - :instance-uid "1b360b10a9a68b7d494e8f059059f118" - :wallet-root-public-key (:public-key wallet-root) - :wallet-root-address (:address wallet-root) - :whisper-address (:address whisper) - :public-key public-key - :whisper-private-key "34bc7d0c258c4f2ac1dac4fd6c55c9478bac1f4a9d8b9f1152c8551ab7187b43" - :wallet-address (:address wallet) - :wallet-public-key (:public-key wallet)}] + [{:keys [pin on-success]}] + (when (= pin (get @state :pin)) + (let [[id response] (multiaccount->keys + pin + (:intro-wizard @re-frame.db/app-db))] (log/debug "[simulated kk] generate-and-load-key response" response) (status/multiaccount-store-derived id - key-uid + (:key-uid response) [constants/path-wallet-root constants/path-eip1581 constants/path-whisper constants/path-default-wallet] - password + (ethereum/sha3 pin) #(on-success response))))) (defn unblock-pin @@ -168,9 +224,8 @@ #js {:code "EUNSPECIFIED" :message "Unexpected error SW, 0x63C2"}))))) -(defn verify-pin [{:keys [pin pairing on-success on-failure]}] - (if (and (= pairing kk1-pair) - (= pin (get @state :pin))) +(defn verify-pin [{:keys [pin on-success on-failure]}] + (if (= pin (get @state :pin)) (later #(on-success 3)) (do (swap! state update-in @@ -242,9 +297,20 @@ (do (swap! state assoc :pin pin) (later - #(on-success - {:key-uid (get-in @state [:application-info :key-uid]) - :encryption-public-key (ethereum/sha3 pin)}))) + (if @derived-acc + (let [[id keys] (multiaccount->keys pin @derived-acc)] + (status/multiaccount-store-derived + id + (:key-uid keys) + [constants/path-wallet-root + constants/path-eip1581 + constants/path-whisper + constants/path-default-wallet] + (ethereum/sha3 pin) + #(on-success keys))) + #(on-success + {:key-uid (get-in @state [:application-info :key-uid]) + :encryption-public-key (ethereum/sha3 pin)})))) (do (log/debug "Incorrect PIN" pin) (swap! state update-in @@ -255,7 +321,7 @@ #js {:code "EUNSPECIFIED" :message "Unexpected error SW, 0x63C2"}))))) -(defn sign [{:keys [pin hash data path on-success on-failure]}] +(defn sign [{:keys [pin hash data path typed? on-success on-failure]}] (if (= pin (get @state :pin)) (later #(let [address @@ -269,18 +335,30 @@ (-> (:multiaccount/accounts @re-frame.db/app-db) first :address)) - params (types/clj->json - {:account address - :password (ethereum/sha3 pin) - :data (or data (str "0x" hash))})] - (status/sign-message - params - (fn [res] - (let [signature (-> res - types/json->clj - :result - ethereum/normalized-hex)] - (on-success signature)))))) + password (ethereum/sha3 pin)] + (if-not typed? + (let [params (types/clj->json + {:account address + :password password + :data (or data (str "0x" hash))})] + (status/sign-message + params + (fn [res] + (let [signature (-> res + types/json->clj + :result + ethereum/normalized-hex)] + (on-success signature))))) + (status/sign-typed-data + data + address + password + (fn [res] + (let [signature (-> res + types/json->clj + :result + ethereum/normalized-hex)] + (on-success signature))))))) (do (swap! state update-in [:application-info :pin-retry-counter] @@ -313,58 +391,86 @@ (defrecord SimulatedKeycard [] keycard/Keycard (keycard/check-nfc-support [this args] + (log/debug "simulated card check-nfc-support") (check-nfc-support args)) (keycard/check-nfc-enabled [this args] + (log/debug "simulated card check-nfc-enabled") (check-nfc-enabled args)) (keycard/open-nfc-settings [this] + (log/debug "simulated card open-nfc-setting") (open-nfc-settings)) (keycard/register-card-events [this args] + (log/debug "simulated card register-card-event") (register-card-events args)) (keycard/on-card-connected [this callback] + (log/debug "simulated card on-card-connected") (on-card-connected callback)) (keycard/on-card-disconnected [this callback] + (log/debug "simulated card on-card-disconnected") (on-card-disconnected callback)) (keycard/remove-event-listener [this event] + (log/debug "simulated card remove-event-listener") (remove-event-listener event)) (keycard/remove-event-listeners [this] + (log/debug "simulated card remove-event-listener") (remove-event-listeners)) (keycard/get-application-info [this args] + (log/debug "simulated card get-application-info") (get-application-info args)) (keycard/install-applet [this args] + (log/debug "simulated card install-applet") (install-applet args)) (keycard/init-card [this args] + (log/debug "simulated card init-card") (init-card args)) (keycard/install-applet-and-init-card [this args] + (log/debug "simulated card install-applet-and-init-card") (install-applet-and-init-card args)) (keycard/pair [this args] + (log/debug "simulated card pair") (pair args)) (keycard/generate-and-load-key [this args] + (log/debug "simulated card generate-and-load-key") (generate-and-load-key args)) (keycard/unblock-pin [this args] + (log/debug "simulated card unblock-pin") (unblock-pin args)) (keycard/verify-pin [this args] + (log/debug "simulated card verify-pin") (verify-pin args)) (keycard/change-pin [this args] + (log/debug "simulated card change-pin") (change-pin args)) (keycard/unpair [this args] + (log/debug "simulated card unpair") (unpair args)) (keycard/delete [this args] + (log/debug "simulated card delete") (delete args)) (keycard/remove-key [this args] + (log/debug "simulated card remove-key") (remove-key args)) (keycard/remove-key-with-unpair [this args] + (log/debug "simulated card remove-key-with-unpair") (remove-key-with-unpair args)) (keycard/export-key [this args] + (log/debug "simulated card export-key") (export-key args)) (keycard/unpair-and-delete [this args] + (log/debug "simulated card unpair-and-delete") (unpair-and-delete args)) (keycard/get-keys [this args] + (log/debug "simulated card get-keys") (get-keys args)) (keycard/sign [this args] + (log/debug "simulated card sign") (sign args)) (keycard/save-multiaccount-and-login [this args] + (log/debug "simulated card save-multiaccount-and-login") (save-multiaccount-and-login args)) (keycard/login [this args] + (log/debug "simulated card login") (login args)) (keycard/send-transaction-with-signature [this args] + (log/debug "simulated card send-transaction-with-signature") (send-transaction-with-signature args))) diff --git a/src/status_im/hardwallet/test_menu.cljs b/src/status_im/hardwallet/test_menu.cljs index 1f7fceb840..b9d2df4e67 100644 --- a/src/status_im/hardwallet/test_menu.cljs +++ b/src/status_im/hardwallet/test_menu.cljs @@ -23,6 +23,7 @@ :align-items :center}} [button "conn" :connect-card simulated-keycard/connect-card] [button "conn sell" :connect-selected-card simulated-keycard/connect-selected-card] + [button "pair" :connect-pairing-card simulated-keycard/connect-pairing-card] [button "disc" :disconnect-card simulated-keycard/disconnect-card] [button "res" :keycard-reset-state simulated-keycard/reset-state]]) diff --git a/src/status_im/signing/keycard.cljs b/src/status_im/signing/keycard.cljs index 44d846354d..313765fdba 100644 --- a/src/status_im/signing/keycard.cljs +++ b/src/status_im/signing/keycard.cljs @@ -61,7 +61,7 @@ (let [{:keys [result error]} (types/json->clj result)] {:db (update db :hardwallet assoc :hash result - :type? typed? + :typed? typed? :data data)})) (fx/defn hash-transaction diff --git a/src/status_im/ui/screens/hardwallet/setup/subs.cljs b/src/status_im/ui/screens/hardwallet/setup/subs.cljs index 655607fcf6..73bfeb9659 100644 --- a/src/status_im/ui/screens/hardwallet/setup/subs.cljs +++ b/src/status_im/ui/screens/hardwallet/setup/subs.cljs @@ -1,6 +1,7 @@ (ns status-im.ui.screens.hardwallet.setup.subs (:require [re-frame.core :as re-frame] - [clojure.string :as string])) + [clojure.string :as string] + [status-im.ethereum.core :as ethereum])) (re-frame/reg-sub :hardwallet-setup-step @@ -101,4 +102,4 @@ (re-frame/reg-sub :hardwallet-multiaccount-whisper-public-key (fn [db] - (str "0x" (get-in db [:hardwallet :multiaccount-whisper-public-key])))) + (ethereum/normalized-hex (get-in db [:hardwallet :multiaccount-whisper-public-key]))))