From ae982edc284432658363c170163ce4e62fa74ee5 Mon Sep 17 00:00:00 2001 From: Mohsen Date: Wed, 29 May 2024 00:45:45 +0300 Subject: [PATCH] [#20035] fix: apply suggestion and add tests --- src/native_module/core.cljs | 35 +-- .../wallet/missing_keypairs/view.cljs | 4 +- .../contexts/settings/wallet/data_store.cljs | 47 ++++ .../contexts/settings/wallet/events.cljs | 210 +++++++++--------- .../contexts/settings/wallet/events_test.cljs | 80 +++++-- .../keypairs_and_accounts/scan_qr/view.cljs | 37 +-- .../wallet/keypairs_and_accounts/view.cljs | 6 +- 7 files changed, 249 insertions(+), 170 deletions(-) create mode 100644 src/status_im/contexts/settings/wallet/data_store.cljs diff --git a/src/native_module/core.cljs b/src/native_module/core.cljs index 7785d22400f..ea9497723df 100644 --- a/src/native_module/core.cljs +++ b/src/native_module/core.cljs @@ -604,20 +604,27 @@ (defn get-connection-string-for-exporting-keypairs-keystores "Generates connection string form status-go for the purpose of exporting keypairs and keystores on sender side" - [config-json callback] - (log/info "[native-module] Fetching Export Keypairs Connection String" - {:fn :get-connection-string-for-exporting-keypairs-keystores - :config-json config-json}) - (.getConnectionStringForExportingKeypairsKeystores ^js (network) config-json callback)) + ([config-json] + (native-utils/promisify-native-module-call get-connection-string-for-exporting-keypairs-keystores + config-json)) + ([config-json callback] + (log/info "[native-module] Fetching Export Keypairs Connection String" + {:fn :get-connection-string-for-exporting-keypairs-keystores + :config-json config-json}) + (.getConnectionStringForExportingKeypairsKeystores ^js (network) config-json callback))) (defn input-connection-string-for-importing-keypairs-keystores "Provides connection string to status-go for the purpose of importing keypairs and keystores on the receiver side" - [connection-string config-json callback] - (log/info "[native-module] Sending Import Keypairs Connection String" - {:fn :input-connection-string-for-importing-keypairs-keystores - :config-json config-json - :connection-string connection-string}) - (.inputConnectionStringForImportingKeypairsKeystores ^js (network) - connection-string - config-json - callback)) + ([connection-string config-json] + (native-utils/promisify-native-module-call input-connection-string-for-importing-keypairs-keystores + connection-string + config-json)) + ([connection-string config-json callback] + (log/info "[native-module] Sending Import Keypairs Connection String" + {:fn :input-connection-string-for-importing-keypairs-keystores + :config-json config-json + :connection-string connection-string}) + (.inputConnectionStringForImportingKeypairsKeystores ^js (network) + connection-string + config-json + callback))) diff --git a/src/quo/components/wallet/missing_keypairs/view.cljs b/src/quo/components/wallet/missing_keypairs/view.cljs index 63f75047868..0e465fdd344 100644 --- a/src/quo/components/wallet/missing_keypairs/view.cljs +++ b/src/quo/components/wallet/missing_keypairs/view.cljs @@ -11,7 +11,7 @@ [utils.i18n :as i18n])) (defn title-view - [{:keys [keypairs blur? on-import-click]}] + [{:keys [keypairs blur? on-import-press]}] (let [theme (quo.theme/use-theme)] [rn/view {:accessibility-label :title @@ -33,7 +33,7 @@ {:type :outline :background :blur :size 24 - :on-press on-import-click} + :on-press on-import-press} (i18n/label :t/import)]] [text/text {:size :paragraph-2 diff --git a/src/status_im/contexts/settings/wallet/data_store.cljs b/src/status_im/contexts/settings/wallet/data_store.cljs new file mode 100644 index 00000000000..f24a3cdc975 --- /dev/null +++ b/src/status_im/contexts/settings/wallet/data_store.cljs @@ -0,0 +1,47 @@ +(ns status-im.contexts.settings.wallet.data-store) + +(defn extract-keypair-name + [db key-uids-set] + (when (= (count key-uids-set) 1) + (let [key-uid (first key-uids-set) + keypairs (get-in db [:wallet :keypairs])] + (->> (filter #(= (:key-uid %) key-uid) keypairs) + first + :name)))) + +(defn update-keypair + [keypairs key-uid update-fn] + (mapcat (fn [keypair] + (if (= (keypair :key-uid) key-uid) + (if-let [updated (update-fn keypair)] + [updated] + []) + [keypair])) + keypairs)) + +(defn make-accounts-fully-operable + [accounts key-uids-set] + (reduce-kv + (fn [acc k account] + (if (and (contains? key-uids-set (:key-uid account)) + (= (keyword (:operable account)) :no)) + (assoc acc k (assoc account :operable :fully)) + (assoc acc k account))) + {} + accounts)) + +(defn- make-keypairs-accounts-fully-operable + [accounts] + (map (fn [account] + (assoc account :operable :fully)) + accounts)) + +(defn make-keypairs-fully-operable + [keypairs key-uids-set] + (map (fn [keypair] + (if (contains? key-uids-set (:key-uid keypair)) + (update keypair + :accounts + make-keypairs-accounts-fully-operable) + keypair)) + keypairs)) diff --git a/src/status_im/contexts/settings/wallet/events.cljs b/src/status_im/contexts/settings/wallet/events.cljs index 8a7222d3bdc..46d1736653d 100644 --- a/src/status_im/contexts/settings/wallet/events.cljs +++ b/src/status_im/contexts/settings/wallet/events.cljs @@ -1,6 +1,8 @@ (ns status-im.contexts.settings.wallet.events (:require [native-module.core :as native-module] + [promesa.core :as promesa] + [status-im.contexts.settings.wallet.data-store :as data-store] [status-im.contexts.syncing.events :as syncing-events] [status-im.contexts.syncing.utils :as sync-utils] [taoensso.timbre :as log] @@ -9,22 +11,12 @@ [utils.security.core :as security] [utils.transforms :as transforms])) -(defn- update-keypair - [keypairs key-uid update-fn] - (mapcat (fn [keypair] - (if (= (keypair :key-uid) key-uid) - (if-let [updated (update-fn keypair)] - [updated] - []) - [keypair])) - keypairs)) - (rf/reg-event-fx :wallet/rename-keypair-success (fn [{:keys [db]} [key-uid name]] {:db (update-in db [:wallet :keypairs] - #(update-keypair % key-uid (fn [keypair] (assoc keypair :name name)))) + #(data-store/update-keypair % key-uid (fn [keypair] (assoc keypair :name name)))) :fx [[:dispatch [:navigate-back]] [:dispatch [:toasts/upsert @@ -42,31 +34,44 @@ (rf/reg-event-fx :wallet/rename-keypair rename-keypair) +(rf/reg-fx :effects.connection-string/export-keypair + (fn [{:keys [key-uid sha3-pwd keypair-key-uid on-success on-fail]}] + (let [config-map (transforms/clj->json {:senderConfig {:loggedInKeyUid key-uid + :keystorePath "" + :keypairsToExport [keypair-key-uid] + :password (security/safe-unmask-data + sha3-pwd)} + :serverConfig {:timeout 0}})] + (-> (native-module/get-connection-string-for-exporting-keypairs-keystores + config-map) + (promesa/then (fn [response] + (if (sync-utils/valid-connection-string? response) + (on-success response) + (on-fail "generic-error: failed to get connection string")))) + (promesa/catch on-fail))))) + (defn get-key-pair-export-connection [{:keys [db]} [{:keys [sha3-pwd keypair-key-uid callback]}]] - (let [key-uid (get-in db [:profile/profile :key-uid]) - config-map (transforms/clj->json {:senderConfig {:loggedInKeyUid key-uid - :keystorePath "" - :keypairsToExport [keypair-key-uid] - :password (security/safe-unmask-data - sha3-pwd)} - :serverConfig {:timeout 0}}) - handle-connection (fn [response] - (when (sync-utils/valid-connection-string? response) - (callback response) - (rf/dispatch [:hide-bottom-sheet])))] - (native-module/get-connection-string-for-exporting-keypairs-keystores - config-map - handle-connection))) + (let [key-uid (get-in db [:profile/profile :key-uid])] + {:fx [[:effects.connection-string/export-keypair + {:key-uid key-uid + :sha3-pwd sha3-pwd + :keypair-key-uid keypair-key-uid + :on-success (fn [connect-string] + (callback connect-string) + (rf/dispatch [:hide-bottom-sheet])) + :on-fail (fn [error] + (rf/dispatch [:toasts/upsert + {:type :negative + :text error}]))}]]})) (rf/reg-event-fx :wallet/get-key-pair-export-connection get-key-pair-export-connection) -(rf/reg-event-fx - :wallet/remove-keypair-success +(rf/reg-event-fx :wallet/remove-keypair-success (fn [{:keys [db]} [key-uid]] {:db (update-in db [:wallet :keypairs] - #(update-keypair % key-uid (fn [_] nil))) + #(data-store/update-keypair % key-uid (fn [_] nil))) :fx [[:dispatch [:hide-bottom-sheet]] [:dispatch [:toasts/upsert @@ -84,85 +89,80 @@ (rf/reg-event-fx :wallet/remove-keypair remove-keypair) -(defn extract-keypair-name - [db key-uids-set] - (when (= (count key-uids-set) 1) - (let [key-uid (first key-uids-set) - keypairs (get-in db [:wallet :keypairs])] - (->> (filter #(= (:key-uid %) key-uid) keypairs) - first - :name)))) - -(defn update-accounts - [accounts key-uids-set] - (into {} - (map (fn [[k account]] - (if (and (contains? key-uids-set (:key-uid account)) - (= (:operable account) :no)) - [k (assoc account :operable :fully)] - [k account])) - accounts))) - -(defn update-keypairs - [keypairs key-uids-set] - (map (fn [keypair] - (if (contains? key-uids-set (:key-uid keypair)) - (update keypair - :accounts - (fn [accounts] - (map (fn [account] - (if (and (contains? key-uids-set (:key-uid account)) - (= (:operable account) ":no")) - (assoc account :operable ":fully") - account)) - accounts))) - keypair)) - keypairs)) - -(rf/reg-event-fx :wallet/make-key-pairs-fully-operable - (fn [{:keys [db]} [key-uids-to-update]] - (let [key-uids-set (set key-uids-to-update) - keypair-name (extract-keypair-name db key-uids-set)] - {:db (-> db - (update-in [:wallet :accounts] update-accounts key-uids-set) - (update-in [:wallet :keypairs] update-keypairs key-uids-set)) - :fx [[:dispatch - [:toasts/upsert - {:type :positive - :theme :dark - :text (if (= (count key-uids-to-update) 1) - (i18n/label :t/key-pair-imported-successfully {:name keypair-name}) - (i18n/label :t/key-pairs-successfully-imported - {:count (count key-uids-to-update)}))}]]]}))) - -(defn- input-connection-string-for-importing-keypairs-keystores-callback - [res keypairs-key-uids] - (log/info "[local-pairing] input-connection-string-for-importing-keypairs-keystores callback" - {:response res - :event :settings/input-connection-string-for-importing-keypairs-keystores-callback}) - (let [error (when (syncing-events/extract-error res) - (str "generic-error: " res))] - (when-not (some? error) - (rf/dispatch [:wallet/make-key-pairs-fully-operable keypairs-key-uids])) - (when (some? error) - (rf/dispatch [:toasts/upsert - {:type :negative - :text error}])))) +(defn make-keypairs-accounts-fully-operable + [{:keys [db]} [key-uids-to-update]] + (let [key-uids-set (set key-uids-to-update) + keypair-name (data-store/extract-keypair-name db key-uids-set)] + {:db (-> db + (update-in [:wallet :accounts] #(data-store/make-accounts-fully-operable % key-uids-set)) + (update-in [:wallet :keypairs] #(data-store/make-keypairs-fully-operable % key-uids-set))) + :fx [[:dispatch + [:toasts/upsert + {:type :positive + :theme :dark + :text (if (= (count key-uids-to-update) 1) + (i18n/label :t/key-pair-imported-successfully {:name keypair-name}) + (i18n/label :t/key-pairs-successfully-imported + {:count (count key-uids-to-update)}))}]]]})) + +(rf/reg-event-fx :wallet/make-keypairs-accounts-fully-operable make-keypairs-accounts-fully-operable) + +(rf/reg-fx :effects.connection-string/import-keypair + (fn [{:keys [key-uid sha3-pwd keypairs-key-uids connection-string on-success on-fail]}] + (let [config-map (.stringify js/JSON + (clj->js + {:receiverConfig + {:loggedInKeyUid key-uid + :keystorePath "" + :password (security/safe-unmask-data + sha3-pwd) + :keypairsToImport keypairs-key-uids}}))] + (-> (native-module/input-connection-string-for-importing-keypairs-keystores + connection-string + config-map) + (promesa/then (fn [res] + (let [error (when (syncing-events/extract-error res) + (str "generic-error: " res))] + (if-not (some? error) + (on-success) + (on-fail error))))) + (promesa/catch #(log/error "error import-keypair/connection-string " %)))))) (defn connection-string-for-key-pair-import [{:keys [db]} [{:keys [sha3-pwd keypairs-key-uids connection-string]}]] - (let [key-uid (get-in db [:profile/profile :key-uid]) - config-map (.stringify js/JSON - (clj->js - {:receiverConfig - {:loggedInKeyUid key-uid - :keystorePath "" - :password (security/safe-unmask-data - sha3-pwd) - :keypairsToImport keypairs-key-uids}}))] - (native-module/input-connection-string-for-importing-keypairs-keystores - connection-string - config-map - #(input-connection-string-for-importing-keypairs-keystores-callback % keypairs-key-uids)))) + (let [key-uid (get-in db [:profile/profile :key-uid])] + {:fx [[:effects.connection-string/import-keypair + {:key-uid key-uid + :sha3-pwd sha3-pwd + :keypairs-key-uids keypairs-key-uids + :connection-string connection-string + :on-success #(rf/dispatch [:wallet/make-keypairs-accounts-fully-operable + keypairs-key-uids]) + :on-fail #(rf/dispatch [:toasts/upsert + {:type :negative + :text %}])}]]})) (rf/reg-event-fx :wallet/connection-string-for-key-pair-import connection-string-for-key-pair-import) + +(defn success-keypair-qr-scan + [_ [connection-string keypairs-key-uids]] + {:fx [(if (sync-utils/valid-connection-string? connection-string) + [:dispatch + [:standard-auth/authorize-with-password + {:blur? true + :theme :dark + :auth-button-label (i18n/label :t/confirm) + :on-auth-success (fn [password] + (rf/dispatch [:hide-bottom-sheet]) + (rf/dispatch + [:wallet/connection-string-for-key-pair-import + {:connection-string connection-string + :keypairs-key-uids keypairs-key-uids + :sha3-pwd password}]))}]] + [:dispatch + [:toasts/upsert + {:type :negative + :theme :dark + :text (i18n/label :t/invalid-qr)}]])]}) + +(rf/reg-event-fx :wallet/success-keypair-qr-scan success-keypair-qr-scan) diff --git a/src/status_im/contexts/settings/wallet/events_test.cljs b/src/status_im/contexts/settings/wallet/events_test.cljs index c37b7452bcd..e69a49533a7 100644 --- a/src/status_im/contexts/settings/wallet/events_test.cljs +++ b/src/status_im/contexts/settings/wallet/events_test.cljs @@ -1,20 +1,74 @@ (ns status-im.contexts.settings.wallet.events-test (:require - [cljs.test :refer-macros [deftest is]] + [cljs.test :refer-macros [deftest is testing]] matcher-combinators.test [status-im.contexts.settings.wallet.events :as sut])) (def key-uid "0xfef454bb492ee4677594f8e05921c84f336fa811deb99b8d922477cc87a38b98") +(defn mock-db + [keypairs accounts] + {:wallet {:keypairs keypairs + :accounts accounts} + :profile {:profile {:key-uid "test-key-uid"}}}) -(deftest rename-keypair-test - (let [new-keypair-name "key pair new" - cofx {:db {}} - expected {:fx [[:json-rpc/call - [{:method "accounts_updateKeypairName" - :params [key-uid new-keypair-name] - :on-success [:wallet/rename-keypair-success key-uid new-keypair-name] - :on-error fn?}]]]}] - (is (match? expected - (sut/rename-keypair cofx - [{:key-uid key-uid - :keypair-name new-keypair-name}]))))) +(deftest test-rename-keypair + (let [db (mock-db [{:key-uid "key-1" :name "Old Name"}] {}) + new-name "New Name"] + (testing "rename-keypair" + (let [effects (sut/rename-keypair {:db db} [{:key-uid key-uid :keypair-name new-name}]) + result-db (:db effects) + updated-keypair (some #(when (= (:key-uid %) key-uid) %) (:wallet/keypairs result-db))] + (is (match? (:name updated-keypair) new-name)))))) + +(deftest test-get-key-pair-export-connection + (let [db (mock-db [] {}) + sha3-pwd "test-password" + keypair-key-uid "test-keypair-uid" + callback (fn [connect-string] (println "callback" connect-string))] + (testing "get-key-pair-export-connection" + (let [effects (sut/get-key-pair-export-connection + {:db db} + [{:sha3-pwd sha3-pwd :keypair-key-uid keypair-key-uid :callback callback}]) + fx (:fx effects)] + (is (some? fx)))))) + +(deftest test-remove-keypair + (let [db (mock-db [{:key-uid "key-1" :name "Key 1"}] {})] + (testing "remove-keypair" + (let [effects (sut/remove-keypair {:db db} [{:key-uid key-uid}]) + fx (:fx effects)] + (is (some? fx)))))) + +(deftest test-make-keypairs-accounts-fully-operable + (let [db (mock-db [{:key-uid "key-1" :accounts [{:key-uid "key-1" :operable "no"}]}] + {"0x1" {:key-uid "key-1" :operable "no"}}) + key-uids-to-update ["key-1"]] + (testing "make-keypairs-accounts-fully-operable" + (let [effects (sut/make-keypairs-accounts-fully-operable {:db db} [key-uids-to-update]) + result-db (:db effects) + updated-keypair (some #(when (= (:key-uid %) "key-1") %) (:wallet/keypairs result-db)) + updated-account (get-in result-db [:wallet :accounts "0x1"])] + (is (match? (-> updated-keypair :accounts first :operable) :fully)) + (is (match? (:operable updated-account) :fully)))))) + +(deftest test-connection-string-for-key-pair-import + (let [db (mock-db [] {}) + sha3-pwd "test-password" + keypairs-key-uids ["test-keypair-uid"] + connection-string "test-connection-string"] + (testing "connection-string-for-key-pair-import" + (let [effects (sut/connection-string-for-key-pair-import + {:db db} + [{:sha3-pwd sha3-pwd + :keypairs-key-uids keypairs-key-uids + :connection-string connection-string}]) + fx (:fx effects)] + (is (some? fx)))))) + +(deftest test-success-keypair-qr-scan + (let [connection-string "valid-connection-string" + keypairs-key-uids ["keypair-uid"]] + (testing "success-keypair-qr-scan" + (let [effects (sut/success-keypair-qr-scan nil [connection-string keypairs-key-uids]) + fx (:fx effects)] + (is (some? fx)))))) diff --git a/src/status_im/contexts/settings/wallet/keypairs_and_accounts/scan_qr/view.cljs b/src/status_im/contexts/settings/wallet/keypairs_and_accounts/scan_qr/view.cljs index 187f66036d1..3038ae968af 100644 --- a/src/status_im/contexts/settings/wallet/keypairs_and_accounts/scan_qr/view.cljs +++ b/src/status_im/contexts/settings/wallet/keypairs_and_accounts/scan_qr/view.cljs @@ -3,45 +3,16 @@ [react-native.core :as rn] [status-im.common.scan-qr-code.view :as scan-qr-code] [status-im.contexts.communities.events] - [status-im.contexts.syncing.utils :as sync-utils] - [utils.debounce :as debounce] [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn show-invalid-qr-toast - [] - (debounce/debounce-and-dispatch - [:toasts/upsert - {:type :negative - :theme :dark - :text (i18n/label :t/invalid-qr)}] - 300)) - -(defn- on-valid-connection-received - [connection-string keypairs-key-uids] - (rf/dispatch - [:standard-auth/authorize-with-password - {:blur? true - :theme :dark - :auth-button-label (i18n/label :t/confirm) - :on-auth-success (fn [password] - (rf/dispatch [:hide-bottom-sheet]) - (rf/dispatch - [:wallet/connection-string-for-key-pair-import - {:connection-string connection-string - :keypairs-key-uids keypairs-key-uids - :sha3-pwd password}]))}])) - (defn view [] - (let [keypairs (rf/sub [:get-screen-params]) - keypairs-key-uids (rn/use-memo #(map :key-uid keypairs) [keypairs]) + (let [keypairs-key-uids (rf/sub [:get-screen-params]) on-success-scan (rn/use-callback (fn [scanned-text] - (if (sync-utils/valid-connection-string? scanned-text) - (on-valid-connection-received scanned-text - keypairs-key-uids) - (show-invalid-qr-toast))) - [keypairs-key-uids])] + (rf/dispatch [:wallet/success-keypair-qr-scan scanned-text + keypairs-key-uids]) + [keypairs-key-uids]))] [scan-qr-code/view {:title (i18n/label :t/scan-key-pairs-qr-code) :subtitle (i18n/label :t/find-it-in-setting) diff --git a/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs b/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs index 5a8d6c95ff8..2b997880603 100644 --- a/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs +++ b/src/status_im/contexts/settings/wallet/keypairs_and_accounts/view.cljs @@ -94,9 +94,9 @@ customization-color (rf/sub [:profile/customization-color]) {missing-keypairs :missing operable-keypairs :operable} (rf/sub [:wallet/settings-keypairs-accounts]) - on-import-click (rn/use-callback #(rf/dispatch [:open-modal + on-import-press (rn/use-callback #(rf/dispatch [:open-modal :screen/settings.scan-key-pair-qr - missing-keypairs]) + (map :key-uid missing-keypairs)]) [missing-keypairs])] [quo/overlay {:type :shell @@ -116,7 +116,7 @@ [quo/missing-keypairs {:blur? true :keypairs missing-keypairs - :on-import-click on-import-click + :on-import-press on-import-press :container-style style/missing-keypairs-container-style :on-options-press on-missing-keypair-options-press}]) [rn/flat-list