From f1e83158d9281fb24550cb0a5c8fcc7ced7be426 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 2 Apr 2020 15:10:18 +0300 Subject: [PATCH] Testing menu for keycard e2e tests --- .env | 1 + .env.e2e | 2 + src/status_im/hardwallet/card.cljs | 588 ++++++++++++------ src/status_im/hardwallet/keycard.cljs | 29 + src/status_im/hardwallet/real_keycard.cljs | 234 +++++++ .../hardwallet/simulated_keycard.cljs | 178 ++++++ src/status_im/hardwallet/test_menu.cljs | 27 + src/status_im/ui/screens/views.cljs | 8 +- src/status_im/utils/config.cljs | 1 + 9 files changed, 869 insertions(+), 199 deletions(-) create mode 100644 src/status_im/hardwallet/keycard.cljs create mode 100644 src/status_im/hardwallet/real_keycard.cljs create mode 100644 src/status_im/hardwallet/simulated_keycard.cljs create mode 100644 src/status_im/hardwallet/test_menu.cljs diff --git a/.env b/.env index 2d8d4e1d17..9f3e5c7976 100644 --- a/.env +++ b/.env @@ -22,3 +22,4 @@ CONTRACT_NODES=1 MOBILE_UI_FOR_DESKTOP=1 STATUS_GO_PROTOCOL=0 STATUS_GO_ENABLE_NIMBUS=0 +KEYCARD_TEST_MENU=1 diff --git a/.env.e2e b/.env.e2e index cf5fb81a44..caf30c951d 100644 --- a/.env.e2e +++ b/.env.e2e @@ -5,6 +5,7 @@ ETHEREUM_DEV_CLUSTER=1 EXTENSIONS=0 FLEET=eth.prod GROUP_CHATS_ENABLED=1 +HARDWALLET_ENABLED=1 LOG_LEVEL_STATUS_GO=info LOG_LEVEL=debug MAILSERVER_CONFIRMATIONS_ENABLED=0 @@ -21,3 +22,4 @@ MOBILE_UI_FOR_DESKTOP=1 BLANK_PREVIEW=0 TOOLTIP_EVENTS=1 COMMANDS_ENABLED=1 +KEYCARD_TEST_MENU=1 diff --git a/src/status_im/hardwallet/card.cljs b/src/status_im/hardwallet/card.cljs index f77b455e3d..e561efc879 100644 --- a/src/status_im/hardwallet/card.cljs +++ b/src/status_im/hardwallet/card.cljs @@ -1,224 +1,418 @@ (ns status-im.hardwallet.card - (:require [re-frame.core :as re-frame] - [status-im.react-native.js-dependencies :as js-dependencies] - [status-im.utils.config :as config] - [status-im.utils.platform :as platform] - [taoensso.timbre :as log])) + (:require + [status-im.hardwallet.keycard :as keycard] + [status-im.hardwallet.real-keycard :as real-keycard] + [status-im.hardwallet.simulated-keycard :as simulated-keycard] + [taoensso.timbre :as log] + [re-frame.core :as re-frame] + [status-im.utils.config :as config])) -(defonce keycard (.-default js-dependencies/status-keycard)) -(defonce event-emitter (.-DeviceEventEmitter js-dependencies/react-native)) -(defonce active-listeners (atom [])) +(defonce card (if config/keycard-test-menu-enabled? + (simulated-keycard/SimulatedKeycard.) + (real-keycard/RealKeycard.))) + +(defn check-nfc-support [] + (log/info "[keycard] check-nfc-support") + (keycard/check-nfc-support + card + {:on-success + (fn [response] + (log/info "[keycard response] check-nfc-support" response) + (re-frame/dispatch + [:hardwallet.callback/check-nfc-support-success response]))})) + +(defn check-nfc-enabled [] + (log/info "[keycard] check-nfc-enabled") + (keycard/check-nfc-enabled + card + {:on-success + (fn [response] + (log/info "[keycard response] check-nfc-enabled" response) + (re-frame/dispatch + [:hardwallet.callback/check-nfc-enabled-success response]))})) + +(defn open-nfc-settings [] + (log/info "[keycard] open-nfc-settings") + (keycard/open-nfc-settings card)) + +(defn remove-event-listener [event] + (log/info "[keycard] remove-event-listener") + (keycard/remove-event-listener card event)) + +(defn on-card-disconnected [callback] + (log/info "[keycard] on-card-disconnected") + (keycard/on-card-disconnected card callback)) + +(defn on-card-connected [callback] + (log/info "[keycard] on-card-connected") + (keycard/on-card-connected card callback)) + +(defn remove-event-listeners [] + (log/info "[keycard] remove-event-listeners") + (keycard/remove-event-listeners card)) + +(defn register-card-events [] + (log/info "[keycard] register-card-events") + (keycard/register-card-events + card + {:on-card-connected + #(re-frame/dispatch [:hardwallet.callback/on-card-connected]) + + :on-card-disconnected + #(re-frame/dispatch [:hardwallet.callback/on-card-disconnected]) + + :on-nfc-enabled + #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success true]) + + :on-nfc-disabled + #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success false])})) (defn- error-object->map [object] {:code (.-code object) :error (.-message object)}) -(defn check-nfc-support [] - (log/debug "[keycard] check-nfc-support") - (when (and config/hardwallet-enabled? - platform/android?) - (.. keycard - nfcIsSupported - (then #(re-frame/dispatch [:hardwallet.callback/check-nfc-support-success %]))))) - -(defn check-nfc-enabled [] - (log/debug "[keycard] check-nfc-enabled") - (when (and config/hardwallet-enabled? - platform/android?) - (.. keycard - nfcIsEnabled - (then #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success %]))))) - -(defn open-nfc-settings [] - (log/debug "[keycard] open-nfc-settings") - (when platform/android? - (.openNfcSettings keycard))) - -(defn remove-event-listeners [] - (doseq [event ["keyCardOnConnected" "keyCardOnDisconnected"]] - (.removeAllListeners event-emitter event))) - -(defn remove-event-listener [event] - (.remove event)) - -(defn on-card-connected [callback] - (when (and config/hardwallet-enabled? - platform/android?) - (.addListener event-emitter "keyCardOnConnected" callback))) - -(defn on-card-disconnected [callback] - (when (and config/hardwallet-enabled? - platform/android?) - (.addListener event-emitter "keyCardOnDisconnected" callback))) - -(defn on-nfc-enabled [callback] - (when (and config/hardwallet-enabled? - platform/android?) - (.addListener event-emitter "keyCardOnNFCEnabled" callback))) - -(defn on-nfc-disabled [callback] - (when (and config/hardwallet-enabled? - platform/android?) - (.addListener event-emitter "keyCardOnNFCDisabled" callback))) - -(defn register-card-events [] - (doseq [listener @active-listeners] - (remove-event-listener listener)) - (reset! active-listeners - [(on-card-connected #(re-frame/dispatch [:hardwallet.callback/on-card-connected])) - (on-card-disconnected #(re-frame/dispatch [:hardwallet.callback/on-card-disconnected])) - (on-nfc-enabled #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success true])) - (on-nfc-disabled #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success false]))])) - -(defn get-application-info [{:keys [pairing on-success]}] - (log/debug "[keycard] get-application-info") - (.. keycard - (getApplicationInfo (str pairing)) - (then #(re-frame/dispatch [:hardwallet.callback/on-get-application-info-success % on-success])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-get-application-info-error (error-object->map %)])))) +(defn get-application-info [{:keys [on-success] :as args}] + (log/info "[keycard] get-application-info") + (keycard/get-application-info + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] get-application-info" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-get-application-info-success + response on-success])) + :on-failure + (fn [response] + (log/info "[keycard response fail] get-application-info" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-get-application-info-error + (error-object->map response)]))}))) (defn install-applet [] - (log/debug "[keycard] install-applet") - (when config/hardwallet-enabled? - (.. keycard - installApplet - (then #(re-frame/dispatch [:hardwallet.callback/on-install-applet-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-install-applet-error (error-object->map %)]))))) + (log/info "[keycard] install-applet") + (keycard/install-applet + card + {:on-success + (fn [response] + (log/info "[keycard response succ] install-applet" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-install-applet-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] install-applet" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-install-applet-error + (error-object->map response)]))})) (defn init-card [pin] - (log/debug "[keycard] init-card") - (when config/hardwallet-enabled? - (.. keycard - (init pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-init-card-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-init-card-error (error-object->map %)]))))) + (log/info "[keycard] init-card") + (keycard/init-card + card + {:pin pin + :on-success + (fn [response] + (log/info "[keycard response succ] init-card" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-init-card-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] init-card" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-init-card-error + (error-object->map response)]))})) (defn install-applet-and-init-card [pin] - (log/debug "[keycard] install-applet-and-init-card") - (when config/hardwallet-enabled? - (.. keycard - (installAppletAndInitCard pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-install-applet-and-init-card-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-install-applet-and-init-card-error (error-object->map %)]))))) + (log/info "[keycard] install-applet-and-init-card") + (keycard/install-applet-and-init-card + card + {:pin pin + :on-success + (fn [response] + (log/info "[keycard response succ] install-applet-and-init-card" + (js->clj response :keywordize-keys true)) + #(re-frame/dispatch + [:hardwallet.callback/on-install-applet-and-init-card-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] install-applet-and-init-card" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-install-applet-and-init-card-error + (error-object->map response)]))})) -(defn pair - [{:keys [password]}] - (log/debug "[keycard] pair") - (when password - (.. keycard - (pair password) - (then #(re-frame/dispatch [:hardwallet.callback/on-pair-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-pair-error (error-object->map %)]))))) +(defn pair [args] + (log/info "[keycard] pair" args) + (keycard/pair + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] pair" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-pair-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] pair" (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-pair-error (error-object->map response)]))}))) -(defn generate-mnemonic - [{:keys [pairing words]}] - (log/debug "[keycard] generate-mnemonic") - (when pairing - (.. keycard - (generateMnemonic pairing words) - (then #(re-frame/dispatch [:hardwallet.callback/on-generate-mnemonic-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-generate-mnemonic-error (error-object->map %)]))))) +(defn generate-mnemonic [args] + (log/info "[keycard] generate-mnemonic" args) + (keycard/generate-mnemonic + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] generate-mnemonic" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-generate-mnemonic-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] generate-mnemonic" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-generate-mnemonic-error + (error-object->map response)]))}))) -(defn generate-and-load-key - [{:keys [mnemonic pairing pin]}] - (log/debug "[keycard] generate-and-load-key") - (when pairing - (.. keycard - (generateAndLoadKey mnemonic pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-generate-and-load-key-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-generate-and-load-key-error (error-object->map %)]))))) +(defn generate-and-load-key [args] + (log/info "[keycard] generate-and-load-key" args) + (keycard/generate-and-load-key + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] generate-and-load-key" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-generate-and-load-key-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] generate-and-load-key" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-generate-and-load-key-error + (error-object->map response)]))}))) -(defn unblock-pin - [{:keys [puk new-pin pairing]}] - (log/debug "[keycard] unblock-pin") - (when (and pairing new-pin puk) - (.. keycard - (unblockPin pairing puk new-pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-unblock-pin-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-unblock-pin-error (error-object->map %)]))))) +(defn unblock-pin [args] + (log/info "[keycard] unblock-pin" args) + (keycard/unblock-pin + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] unblock-pin" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-unblock-pin-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] unblock-pin" + (error-object->map response)) + (re-frame/dispatch [:hardwallet.callback/on-unblock-pin-error + (error-object->map response)]))}))) -(defn verify-pin - [{:keys [pin pairing]}] - (log/debug "[keycard] verify-pin") - (when (and pairing (not-empty pin)) - (.. keycard - (verifyPin pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-verify-pin-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-verify-pin-error (error-object->map %)]))))) +(defn verify-pin [args] + (log/info "[keycard] verify-pin" args) + (keycard/verify-pin + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] verify-pin" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-verify-pin-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] verify-pin" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-verify-pin-error + (error-object->map response)]))}))) -(defn change-pin - [{:keys [current-pin new-pin pairing]}] - (log/debug "[keycard] change-pin") - (when (and pairing current-pin new-pin) - (.. keycard - (changePin pairing current-pin new-pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-change-pin-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-change-pin-error (error-object->map %)]))))) +(defn change-pin [args] + (log/info "[keycard] change-pin" args) + (keycard/change-pin + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] change-pin" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-change-pin-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] change-pin" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-change-pin-error + (error-object->map response)]))}))) -(defn unpair - [{:keys [pin pairing]}] - (log/debug "[keycard] unpair") - (when (and pairing pin) - (.. keycard - (unpair pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-unpair-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-unpair-error (error-object->map %)]))))) +(defn unpair [args] + (log/info "[keycard] unpair" args) + (keycard/unpair + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] unpair" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-unpair-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] unpair" (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-unpair-error + (error-object->map response)]))}))) -(defn delete - [] - (log/debug "[keycard] delete") - (.. keycard - (delete) - (then #(re-frame/dispatch [:hardwallet.callback/on-delete-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-delete-error (error-object->map %)])))) +(defn delete [] + (log/info "[keycard] delete") + (keycard/delete + card + {:on-success + (fn [response] + (log/info "[keycard response succ] delete" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-delete-success response])) + :on-failure + (fn [response] + (log/debug "[keycard response fail] delete" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-delete-error + (error-object->map response)]))})) -(defn remove-key - [{:keys [pin pairing]}] - (log/debug "[keycard] remove-key") - (.. keycard - (removeKey pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-remove-key-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-remove-key-error (error-object->map %)])))) +(defn remove-key [args] + (log/info "[keycard] remove-key" args) + (keycard/remove-key + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] remove-key" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-remove-key-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] remove-key" response) + (re-frame/dispatch [:hardwallet.callback/on-remove-key-error + (error-object->map response)]))}))) -(defn remove-key-with-unpair - [{:keys [pin pairing]}] - (log/debug "[keycard] remove-key-with-unpair") - (.. keycard - (removeKeyWithUnpair pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-remove-key-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-remove-key-error (error-object->map %)])))) +(defn remove-key-with-unpair [args] + (log/info "[keycard] remove-key-with-unpair" args) + (keycard/remove-key-with-unpair + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] remove-key-with-unpair" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-remove-key-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] remove-key-with-unpair" + (error-object->map response)) + (re-frame/dispatch [:hardwallet.callback/on-remove-key-error + (error-object->map response)]))}))) -(defn export-key - [{:keys [pin pairing path]}] - (log/debug "[keycard] export-key pairing:" pairing "pin:" pin "path:" path) - (.. keycard - (exportKeyWithPath pairing pin path) - (then #(re-frame/dispatch [:hardwallet.callback/on-export-key-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-export-key-error (error-object->map %)])))) +(defn export-key [args] + (log/info "[keycard] export-key" args) + (keycard/export-key + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] export-key" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-export-key-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] export-key" + (error-object->map response)) + (re-frame/dispatch [:hardwallet.callback/on-export-key-error + (error-object->map response)]))}))) -(defn unpair-and-delete - [{:keys [pin pairing]}] - (log/debug "[keycard] unpair-and-delete") - (when (and pairing pin) - (.. keycard - (unpairAndDelete pairing pin) - (then #(re-frame/dispatch [:hardwallet.callback/on-delete-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-delete-error (error-object->map %)]))))) +(defn unpair-and-delete [args] + (log/info "[keycard] unpair-and-delete" args) + (keycard/unpair-and-delete + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] unpair-and-delete" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-delete-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] unpair-and-delete" + (error-object->map response)) + (re-frame/dispatch [:hardwallet.callback/on-delete-error + (error-object->map response)]))}))) -(defn get-keys - [{:keys [pairing pin on-success]}] - (log/debug "[keycard] get-keys") - (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 get-keys [{:keys [on-success] :as args}] + (log/info "[keycard] get-keys" args) + (keycard/get-keys + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] get-keys" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [(or on-success :hardwallet.callback/on-get-keys-success) + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] get-keys" + (error-object->map response)) + (re-frame/dispatch [:hardwallet.callback/on-get-keys-error + (error-object->map response)]))}))) -(defn sign - [{:keys [pairing pin hash]}] - (log/debug "[keycard] sign") - (when (and pairing pin hash) - (.. keycard - (sign pairing pin hash) - (then #(re-frame/dispatch [:hardwallet.callback/on-sign-success %])) - (catch #(re-frame/dispatch [:hardwallet.callback/on-sign-error (error-object->map %)]))))) +(defn sign [args] + (log/info "[keycard] sign" args) + (keycard/sign + card + (merge + args + {:on-success + (fn [response] + (log/info "[keycard response succ] sign" (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-sign-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] sign" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-sign-error + (error-object->map response)]))}))) diff --git a/src/status_im/hardwallet/keycard.cljs b/src/status_im/hardwallet/keycard.cljs new file mode 100644 index 0000000000..d54eccddbb --- /dev/null +++ b/src/status_im/hardwallet/keycard.cljs @@ -0,0 +1,29 @@ +(ns status-im.hardwallet.keycard) + +(defprotocol Keycard + (check-nfc-support [this args]) + (check-nfc-enabled [this args]) + (open-nfc-settings [this]) + (register-card-events [this args]) + (on-card-disconnected [this callback]) + (on-card-connected [this callback]) + (remove-event-listener [this event]) + (remove-event-listeners [this]) + (get-application-info [this args]) + (install-applet [this args]) + (init-card [this args]) + (install-applet-and-init-card [this args]) + (pair [this args]) + (generate-mnemonic [this args]) + (generate-and-load-key [this args]) + (unblock-pin [this args]) + (verify-pin [this args]) + (change-pin [this args]) + (unpair [this args]) + (delete [this args]) + (remove-key [this args]) + (remove-key-with-unpair [this args]) + (export-key [this args]) + (unpair-and-delete [this args]) + (get-keys [this args]) + (sign [this args])) diff --git a/src/status_im/hardwallet/real_keycard.cljs b/src/status_im/hardwallet/real_keycard.cljs new file mode 100644 index 0000000000..2ccd367cbb --- /dev/null +++ b/src/status_im/hardwallet/real_keycard.cljs @@ -0,0 +1,234 @@ +(ns status-im.hardwallet.real-keycard + (:require [status-im.react-native.js-dependencies :as js-dependencies] + [status-im.hardwallet.keycard :as keycard])) + +(defonce status-keycard (.-default js-dependencies/status-keycard)) +(defonce event-emitter (.-DeviceEventEmitter js-dependencies/react-native)) +(defonce active-listeners (atom [])) + +(defn check-nfc-support [{:keys [on-success]}] + (.. status-keycard + nfcIsSupported + (then on-success))) + +(defn check-nfc-enabled [{:keys [on-success]}] + (.. status-keycard + nfcIsEnabled + (then on-success))) + +(defn open-nfc-settings [] + (.openNfcSettings status-keycard)) + +(defn remove-event-listeners [] + (doseq [event ["keyCardOnConnected" "keyCardOnDisconnected"]] + (.removeAllListeners event-emitter event))) + +(defn remove-event-listener [event] + (.remove event)) + +(defn on-card-connected [callback] + (.addListener event-emitter "keyCardOnConnected" callback)) + +(defn on-card-disconnected [callback] + (.addListener event-emitter "keyCardOnDisconnected" callback)) + +(defn on-nfc-enabled [callback] + (.addListener event-emitter "keyCardOnNFCEnabled" callback)) + +(defn on-nfc-disabled [callback] + (.addListener event-emitter "keyCardOnNFCDisabled" callback)) + +(defn register-card-events [args] + (doseq [listener @active-listeners] + (remove-event-listener listener)) + (reset! active-listeners + [(on-card-connected (:on-card-connected args)) + (on-card-disconnected (:on-card-disconnected args)) + (on-nfc-enabled (:on-nfc-enabled args)) + (on-nfc-disabled (:on-nfc-disabled args))])) + +(defn get-application-info [{:keys [pairing on-success on-failure]}] + (.. status-keycard + (getApplicationInfo (str pairing)) + (then on-success) + (catch on-failure))) + +(defn install-applet [{:keys [on-success on-failure]}] + (.. status-keycard + installApplet + (then on-success) + (catch on-failure))) + +(defn init-card [{:keys [pin on-success on-failure]}] + (.. status-keycard + (init pin) + (then on-success) + (catch on-failure))) + +(defn install-applet-and-init-card [{:keys [pin on-success on-failure]}] + (.. status-keycard + (installAppletAndInitCard pin) + (then on-success) + (catch on-failure))) + +(defn pair + [{:keys [password on-success on-failure]}] + (when password + (.. status-keycard + (pair password) + (then on-success) + (catch on-failure)))) + +(defn generate-mnemonic + [{:keys [pairing words on-success on-failure]}] + (when pairing + (.. status-keycard + (generateMnemonic pairing words) + (then on-success) + (catch on-failure)))) + +(defn generate-and-load-key + [{:keys [mnemonic pairing pin on-success on-failure]}] + (when pairing + (.. status-keycard + (generateAndLoadKey mnemonic pairing pin) + (then on-success) + (catch on-failure)))) + +(defn unblock-pin + [{:keys [puk new-pin pairing on-success on-failure]}] + (when (and pairing new-pin puk) + (.. status-keycard + (unblockPin pairing puk new-pin) + (then on-success) + (catch on-failure)))) + +(defn verify-pin + [{:keys [pin pairing on-success on-failure]}] + (when (and pairing (not-empty pin)) + (.. status-keycard + (verifyPin pairing pin) + (then on-success) + (catch on-failure)))) + +(defn change-pin + [{:keys [current-pin new-pin pairing on-success on-failure]}] + (when (and pairing current-pin new-pin) + (.. status-keycard + (changePin pairing current-pin new-pin) + (then on-success) + (catch on-failure)))) + +(defn unpair + [{:keys [pin pairing on-success on-failure]}] + (when (and pairing pin) + (.. status-keycard + (unpair pairing pin) + (then on-success) + (catch on-failure)))) + +(defn delete [{:keys [on-success on-failure]}] + (.. status-keycard + (delete) + (then on-success) + (catch on-failure))) + +(defn remove-key + [{:keys [pin pairing on-success on-failure]}] + (.. status-keycard + (removeKey pairing pin) + (then on-success) + (catch on-failure))) + +(defn remove-key-with-unpair + [{:keys [pin pairing on-success on-failure]}] + (.. status-keycard + (removeKeyWithUnpair pairing pin) + (then on-success) + (catch on-failure))) + +(defn export-key + [{:keys [pin pairing path on-success on-failure]}] + (.. status-keycard + (exportKeyWithPath pairing pin path) + (then on-success) + (catch on-failure))) + +(defn unpair-and-delete + [{:keys [pin pairing on-success on-failure]}] + (when (and pairing pin) + (.. status-keycard + (unpairAndDelete pairing pin) + (then on-success) + (catch on-failure)))) + +(defn get-keys + [{:keys [pairing pin on-success on-failure]}] + (when (and pairing (not-empty pin)) + (.. status-keycard + (getKeys pairing pin) + (then on-success) + (catch on-failure)))) + +(defn sign + [{:keys [pairing pin hash on-success on-failure]}] + (when (and pairing pin hash) + (.. status-keycard + (sign pairing pin hash) + (then on-success) + (catch on-failure)))) + +(defrecord RealKeycard [] + keycard/Keycard + (keycard/check-nfc-support [this args] + (check-nfc-support args)) + (keycard/check-nfc-enabled [this args] + (check-nfc-enabled args)) + (keycard/open-nfc-settings [this] + (open-nfc-settings)) + (keycard/register-card-events [this args] + (register-card-events args)) + (keycard/on-card-connected [this callback] + (on-card-connected callback)) + (keycard/on-card-disconnected [this callback] + (on-card-disconnected callback)) + (keycard/remove-event-listener [this event] + (remove-event-listener event)) + (keycard/remove-event-listeners [this] + (remove-event-listeners)) + (keycard/get-application-info [this args] + (get-application-info args)) + (keycard/install-applet [this args] + (install-applet args)) + (keycard/init-card [this args] + (init-card args)) + (keycard/install-applet-and-init-card [this args] + (install-applet-and-init-card args)) + (keycard/pair [this args] + (pair args)) + (keycard/generate-mnemonic [this args] + (generate-mnemonic args)) + (keycard/generate-and-load-key [this args] + (generate-and-load-key args)) + (keycard/unblock-pin [this args] + (unblock-pin args)) + (keycard/verify-pin [this args] + (verify-pin args)) + (keycard/change-pin [this args] + (change-pin args)) + (keycard/unpair [this args] + (unpair args)) + (keycard/delete [this args] + (delete args)) + (keycard/remove-key [this args] + (remove-key args)) + (keycard/remove-key-with-unpair [this args] + (remove-key-with-unpair args)) + (keycard/export-key [this args] + (export-key args)) + (keycard/unpair-and-delete [this args] + (unpair-and-delete args)) + (keycard/get-keys [this args] + (get-keys args)) + (keycard/sign [this args] + (sign args))) diff --git a/src/status_im/hardwallet/simulated_keycard.cljs b/src/status_im/hardwallet/simulated_keycard.cljs new file mode 100644 index 0000000000..02428c60d7 --- /dev/null +++ b/src/status_im/hardwallet/simulated_keycard.cljs @@ -0,0 +1,178 @@ +(ns status-im.hardwallet.simulated-keycard + (:require [status-im.hardwallet.keycard :as keycard] + [status-im.utils.utils :as utils])) + +(def initial-state + {:card-connected? false + :application-info {:initialized? false}}) + +(defonce state (atom initial-state)) + +(defn connect-card [] + (swap! state assoc :card-connected? true) + (doseq [callback (vals (get @state :on-card-connected))] + (callback))) + +(defn disconnect-card [] + (swap! state assoc :card-connected? false) + (doseq [callback (vals (get @state :on-card-disconnected))] + (callback))) + +(defn reset-state [] + (reset! state initial-state)) + +(defn- later [f] + (utils/set-timeout f 500)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn check-nfc-support [{:keys [on-success]}] + (later #(on-success true))) + +(defn check-nfc-enabled [{:keys [on-success]}] + (later #(on-success true))) + +(defn open-nfc-settings []) + +(defn on-card-connected [callback] + (let [id (random-uuid)] + (swap! state update :on-card-connected assoc id callback) + id)) + +(defn on-card-disconnected [callback] + (let [id (random-uuid)] + (swap! state update :on-card-disconnected assoc id callback) + id)) + +(defn register-card-events [args] + (on-card-connected (:on-card-connected args)) + (on-card-disconnected (:on-card-disconnected args))) + +(defn remove-event-listener [id] + (swap! state update :on-card-connected dissoc id) + (swap! state update :on-card-disconnected dissoc id)) + +(defn remove-event-listeners [] + (swap! state dissoc :on-card-connected) + (swap! state dissoc :on-card-disconnected)) + +(defn get-application-info [{:keys [on-success]}] + (later #(on-success (get @state :application-info)))) + +(defn install-applet [args]) + +(def kk1-password "6d9ZHjn94kFP4bPm") + +(defn init-card [{:keys [pin on-success]}] + (swap! state assoc :application-info + {:free-pairing-slots 5 + :app-version "2.2" + :secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e", :key-uid "", :instance-uid "9c3f27ee5dfc39c2b14f4d6d3379cd68" + :paired? false + :has-master-key? false + :initialized? true}) + (swap! state assoc :pin pin) + (later + #(on-success {:password kk1-password + :puk "320612366918" + :pin pin}))) + +(defn install-applet-and-init-card [args]) + +(def kk1-pair "ADEol+GCD67EO7zU6ko0DNK7XrNs9w2+h9GxcibNY4yf") + +(defn pair [{:keys [password on-success]}] + (when (= password kk1-password) + (later #(on-success kk1-pair)))) + +(defn generate-mnemonic [args]) + +(defn generate-and-load-key [{:keys [pin pairing on-success]}] + (when (and (= pin (get @state :pin)) + (= pairing kk1-pair)) + (later + #(on-success + {:key-uid "08f1e42f076b956715dac6b93ad1282e435be877a90c9353f6c6dfe455474047" + :encryption-public-key "04a15b33d5c76ff72c3b3863fe2cb2b45c25f87c6accc96fa95457845e3f69ba5fc2d835351d17b5031e1723513824612003facb98f508af2866382ed996125b4d" + :address "f75457177cd2b7bdc407a6c4881eb490f66ca3c2" + :whisper-public-key "04d25f563a8a2897a7025a1f022eee78ba7c0e182aae04ab640bc9e118698734257647e18cb6c95f825e6d03d8e3550178b13a30dceba722be7c8fcd0adecc0fa9" + :instance-uid "1b360b10a9a68b7d494e8f059059f118" + :wallet-root-public-key "0463187f5c917eef481e04af704c14e57a9e8596516f0ec10a4556561ad49b5aa249976ec545d37d04f4d4c7d1c0d9a2141dc61e458b09631d25fa7858c6323ea3" + :wallet-root-address "e034a084d2282e265f83e3fdfa48b42c3d53312a" + :whisper-address "87f1c9bbe1c907143413cf018caad355dde16b3c" + :public-key "04035d4efe4e96f8fa0e49a94433c972e510f0c8698348b4e1acd3b4d3083c61283b932ec54dd9512566931b26627a5d3122a916577459b7926fce6a278055f899" + :whisper-private-key "34bc7d0c258c4f2ac1dac4fd6c55c9478bac1f4a9d8b9f1152c8551ab7187b43" + :wallet-address "c8435ef92bbb76bc1861833713e202e18ebd4601" + :wallet-public-key "044887a5a2599d722aa1af8cda800a17415d3a071c4706e111ad05465c3bf10fcb6f92c8d74df994160e0ba4aeff71f7a6d256cf36ce8cff3d313b8a0709404886"})))) + +(defn unblock-pin [args]) + +(defn verify-pin [{:keys [pin pairing on-success]}] + (when (and (= pairing kk1-pair) + (= pin (get @state :pin))) + (later #(on-success 3)))) + +(defn change-pin [args]) +(defn unpair [args]) +(defn delete [args]) +(defn remove-key [args]) +(defn remove-key-with-unpair [args]) +(defn export-key [args]) +(defn unpair-and-delete [args]) +(defn get-keys [args]) +(defn sign [args]) + +(defrecord SimulatedKeycard [] + keycard/Keycard + (keycard/check-nfc-support [this args] + (check-nfc-support args)) + (keycard/check-nfc-enabled [this args] + (check-nfc-enabled args)) + (keycard/open-nfc-settings [this] + (open-nfc-settings)) + (keycard/register-card-events [this args] + (register-card-events args)) + (keycard/on-card-connected [this callback] + (on-card-connected callback)) + (keycard/on-card-disconnected [this callback] + (on-card-disconnected callback)) + (keycard/remove-event-listener [this event] + (remove-event-listener event)) + (keycard/remove-event-listeners [this] + (remove-event-listeners)) + (keycard/get-application-info [this args] + (get-application-info args)) + (keycard/install-applet [this args] + (install-applet args)) + (keycard/init-card [this args] + (init-card args)) + (keycard/install-applet-and-init-card [this args] + (install-applet-and-init-card args)) + (keycard/pair [this args] + (pair args)) + (keycard/generate-mnemonic [this args] + (generate-mnemonic args)) + (keycard/generate-and-load-key [this args] + (generate-and-load-key args)) + (keycard/unblock-pin [this args] + (unblock-pin args)) + (keycard/verify-pin [this args] + (verify-pin args)) + (keycard/change-pin [this args] + (change-pin args)) + (keycard/unpair [this args] + (unpair args)) + (keycard/delete [this args] + (delete args)) + (keycard/remove-key [this args] + (remove-key args)) + (keycard/remove-key-with-unpair [this args] + (remove-key-with-unpair args)) + (keycard/export-key [this args] + (export-key args)) + (keycard/unpair-and-delete [this args] + (unpair-and-delete args)) + (keycard/get-keys [this args] + (get-keys args)) + (keycard/sign [this args] + (sign args))) diff --git a/src/status_im/hardwallet/test_menu.cljs b/src/status_im/hardwallet/test_menu.cljs new file mode 100644 index 0000000000..e3390ce439 --- /dev/null +++ b/src/status_im/hardwallet/test_menu.cljs @@ -0,0 +1,27 @@ +(ns status-im.hardwallet.test-menu + (:require [status-im.ui.components.react :as react] + [status-im.hardwallet.simulated-keycard :as simulated-keycard])) + +(defn button [label accessibility-label handler] + [react/view + {:style {:width 50 + :height 40 + :justify-content :center + :align-items :center}} + [react/text + {:on-press handler + :accessibility-label accessibility-label} + label]]) + +(defn test-menu [] + [react/view + {:style {:position :absolute + :top 100 + :right 0 + :width 50 + :justify-content :center + :align-items :center}} + [button "conn" :connect-card simulated-keycard/connect-card] + [button "disc" :disconnect-card simulated-keycard/disconnect-card] + [button "res" :keycard-reset-state simulated-keycard/reset-state]]) + diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 176cacfb89..96c0787e97 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -24,7 +24,9 @@ status-im.ui.screens.wallet.collectibles.cryptokitties.views status-im.ui.screens.wallet.collectibles.superrare.views status-im.ui.screens.wallet.collectibles.kudos.views - [status-im.ui.components.colors :as colors])) + [status-im.ui.components.colors :as colors] + [status-im.hardwallet.test-menu :as hardwallet.test-menu] + [status-im.utils.config :as config])) (defview bottom-sheet [] (letsubs [{:keys [show? view]} [:bottom-sheet]] @@ -124,4 +126,6 @@ [wallet/select-account] [signing/signing] [bottom-sheet] - [popover/popover]]])}))) + [popover/popover] + (when config/keycard-test-menu-enabled? + [hardwallet.test-menu/test-menu])]])}))) diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index dc10cd3b0d..cc3346248a 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -39,6 +39,7 @@ (def nimbus-enabled? (enabled? (get-config :STATUS_GO_ENABLE_NIMBUS "0"))) (def waku-enabled? (enabled? (get-config :WAKU_ENABLED "0"))) (def commands-enabled? (enabled? (get-config :COMMANDS_ENABLED "0"))) +(def keycard-test-menu-enabled? (enabled? (get-config :KEYCARD_TEST_MENU "0"))) ;; CONFIG VALUES (def log-level