diff --git a/src/status_im/hardwallet/core.cljs b/src/status_im/hardwallet/core.cljs index 10e0fc58a8..7b8e0597e8 100644 --- a/src/status_im/hardwallet/core.cljs +++ b/src/status_im/hardwallet/core.cljs @@ -1846,20 +1846,20 @@ (assoc :intro-wizard nil))} (multiaccounts.create/on-multiaccount-created {:derived {constants/path-wallet-root-keyword - {:publicKey wallet-root-public-key + {:public-key wallet-root-public-key :address (eip55/address->checksum wallet-root-address)} constants/path-whisper-keyword - {:publicKey whisper-public-key + {:public-key whisper-public-key :address (eip55/address->checksum whisper-address) :name name :photo-path photo-path} constants/path-default-wallet-keyword - {:publicKey wallet-public-key + {:public-key wallet-public-key :address (eip55/address->checksum wallet-address)}} :address address :public-key public-key :keycard-instance-uid instance-uid - :keyUid (ethereum/normalized-hex key-uid) + :key-uid (ethereum/normalized-hex key-uid) :keycard-pairing pairing :keycard-paired-on paired-on :chat-key whisper-private-key} diff --git a/src/status_im/multiaccounts/create/core.cljs b/src/status_im/multiaccounts/create/core.cljs index b84a936cbc..499f841416 100644 --- a/src/status_im/multiaccounts/create/core.cljs +++ b/src/status_im/multiaccounts/create/core.cljs @@ -51,13 +51,30 @@ (let [{:keys [selected-id multiaccounts]} (:intro-wizard db)] (some #(when (= selected-id (:id %)) %) multiaccounts))) +(defn normalize-derived-data-keys [derived-data] + (->> derived-data + (map (fn [[path {:keys [publicKey] :as data}]] + [path (cond-> (-> data + (dissoc :publicKey) + (assoc :public-key publicKey)))])) + (into {}))) + +(defn normalize-multiaccount-data-keys + [{:keys [publicKey keyUid derived] :as data}] + (cond-> (-> data + (dissoc :keyUid :publicKey) + (assoc :key-uid keyUid + :public-key publicKey)) + derived + (update :derived normalize-derived-data-keys))) + (fx/defn create-multiaccount [{:keys [db]}] (let [{:keys [selected-id key-code]} (:intro-wizard db) hashed-password (ethereum/sha3 (security/safe-unmask-data key-code)) callback (fn [result] - (let [derived-data (types/json->clj result) - public-key (get-in derived-data [constants/path-whisper-keyword :publicKey])] + (let [derived-data (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] @@ -191,17 +208,17 @@ (defn prepare-accounts-data [multiaccount] - [(let [{:keys [publicKey address]} + [(let [{:keys [public-key address]} (get-in multiaccount [:derived constants/path-default-wallet-keyword])] - {:public-key publicKey + {:public-key public-key :address (eip55/address->checksum address) :color colors/blue :wallet true :path constants/path-default-wallet :name "Status account"}) - (let [{:keys [publicKey address name photo-path]} + (let [{:keys [public-key address name photo-path]} (get-in multiaccount [:derived constants/path-whisper-keyword])] - {:public-key publicKey + {:public-key public-key :address (eip55/address->checksum address) :name name :photo-path photo-path @@ -227,7 +244,7 @@ (fx/defn on-multiaccount-created [{:keys [signing-phrase random-guid-generator db] :as cofx} - {:keys [address chat-key keycard-instance-uid keyUid + {:keys [address chat-key keycard-instance-uid key-uid keycard-pairing keycard-paired-on mnemonic public-key] :as multiaccount} password @@ -236,7 +253,7 @@ multiaccount-data {:name name :address address :photo-path photo-path - :key-uid keyUid + :key-uid key-uid :keycard-pairing keycard-pairing} keycard-multiaccount? (boolean keycard-pairing) eip1581-address (get-in multiaccount [:derived @@ -247,7 +264,7 @@ {;; address of the master key :address address ;; sha256 of master public key - :key-uid keyUid + :key-uid key-uid ;; The address from which we derive any wallet :wallet-root-address (get-in multiaccount [:derived @@ -274,7 +291,7 @@ :keycard-pairing keycard-pairing :keycard-paired-on keycard-paired-on)) db (assoc db - :multiaccounts/login {:key-uid keyUid + :multiaccounts/login {:key-uid key-uid :name name :photo-path photo-path :password password @@ -311,7 +328,9 @@ 5 12 [constants/path-whisper constants/path-default-wallet] - #(re-frame/dispatch [:intro-wizard/on-keys-generated (types/json->clj %)])))) + #(re-frame/dispatch [:intro-wizard/on-keys-generated + (mapv normalize-multiaccount-data-keys + (types/json->clj %))])))) (fx/defn on-keys-generated {:events [:intro-wizard/on-keys-generated]} diff --git a/src/status_im/multiaccounts/db.cljs b/src/status_im/multiaccounts/db.cljs index 70df61ae9a..c89a25bb6d 100644 --- a/src/status_im/multiaccounts/db.cljs +++ b/src/status_im/multiaccounts/db.cljs @@ -30,7 +30,7 @@ (spec/def :multiaccount/accounts (spec/coll-of :multiaccount/account :kind vector?)) (spec/def :multiaccount/address :global/address) -(spec/def :multiaccount/key-uid string?) +(spec/def :multiaccount/key-uid :global/key-uid) (spec/def :multiaccount/name :global/not-empty-string) (spec/def :multiaccount/public-key :global/public-key) (spec/def :multiaccount/signed-up? (spec/nilable boolean?)) @@ -76,6 +76,20 @@ :multiaccount/keycard-paired-on :multiaccount/root-address :multiaccount/accounts])) +;; generated multiaccounts +(spec/def :generated-multiaccounts/id string?) +(spec/def :generated-multiaccounts/derived-key + (spec/keys :req-un [:multiaccount/address + :multiaccount/public-key])) +(spec/def :generated-multiaccounts/derived + (spec/map-of keyword? :generated-multiaccounts/derived-key)) +(spec/def :multiaccounts/generated-multiaccount + (spec/keys :req-un [:multiaccount/address + :multiaccount/mnemonic + :multiaccount/public-key + :multiaccount/key-uid + :generated-multiaccounts/id] + :opt-un [:generated-multiaccounts/derived])) ;;used during recovering multiaccount (spec/def :multiaccounts/recover (spec/nilable map?)) diff --git a/src/status_im/multiaccounts/recover/core.cljs b/src/status_im/multiaccounts/recover/core.cljs index faef6d069a..51ef050f3d 100644 --- a/src/status_im/multiaccounts/recover/core.cljs +++ b/src/status_im/multiaccounts/recover/core.cljs @@ -19,8 +19,9 @@ [taoensso.timbre :as log])) (defn existing-account? - [root-key multiaccounts] - (contains? multiaccounts (:keyUid root-key))) + [multiaccounts key-uid] + {:pre [(not (nil? key-uid))]} + (contains? multiaccounts key-uid)) (re-frame/reg-fx ::validate-mnemonic @@ -100,7 +101,9 @@ passphrase password (fn [result] - (let [{:keys [id] :as root-data} (types/json->clj 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 @@ -108,13 +111,16 @@ constants/path-whisper constants/path-default-wallet] (fn [result] - (let [derived-data (types/json->clj result) - public-key (get-in derived-data [constants/path-whisper-keyword :publicKey])] + (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-whisper (derived-data constants/path-whisper-keyword) - derived-data-extended (assoc-in derived-data [constants/path-whisper-keyword] (merge derived-whisper {:name name :photo-path photo-path}))] + (let [derived-data-extended + (update derived-data + constants/path-whisper-keyword + merge {:name name :photo-path photo-path})] (re-frame/dispatch [::import-multiaccount-success root-data derived-data-extended])))))))))))) @@ -130,7 +136,7 @@ (fx/defn on-import-multiaccount-success {:events [::import-multiaccount-success]} - [{:keys [db] :as cofx} root-data derived-data] + [{:keys [db] :as cofx} {:keys [key-uid] :as root-data} derived-data] (let [multiaccounts (:multiaccounts/multiaccounts db)] (fx/merge cofx @@ -139,8 +145,8 @@ :derived derived-data :step :recovery-success :forward-action :multiaccounts.recover/re-encrypt-pressed)} - (when (existing-account? root-data multiaccounts) - (show-existing-multiaccount-alert (:keyUid root-data))) + (when (existing-account? multiaccounts key-uid) + (show-existing-multiaccount-alert key-uid)) (navigation/navigate-to-cofx :recover-multiaccount-success nil)))) (fx/defn enter-phrase-pressed diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 322dd852e2..7aae83a325 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -265,7 +265,7 @@ :intro-wizard/recovery-success :<- [:intro-wizard] (fn [wizard-state] - {:pubkey (get-in wizard-state [:derived constants/path-whisper-keyword :publicKey]) + {:pubkey (get-in wizard-state [:derived constants/path-whisper-keyword :public-key]) :name (get-in wizard-state [:derived constants/path-whisper-keyword :name]) :photo-path (get-in wizard-state [:derived constants/path-whisper-keyword :photo-path]) :processing? (:processing? wizard-state)})) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index b6f3dcf25a..abc6781ecf 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -15,6 +15,7 @@ status-im.browser.db status-im.ui.screens.add-new.new-public-chat.db status-im.ui.components.bottom-sheet.core + status-im.ui.screens.intro.db [status-im.wallet.db :as wallet.db])) ;; initial state of app-db @@ -314,4 +315,5 @@ ::collectibles :registry/registry ::two-pane-ui-enabled? - ::add-account])) + ::add-account + :intro-wizard/intro-wizard])) diff --git a/src/status_im/ui/screens/intro/db.cljs b/src/status_im/ui/screens/intro/db.cljs new file mode 100644 index 0000000000..667c0f2437 --- /dev/null +++ b/src/status_im/ui/screens/intro/db.cljs @@ -0,0 +1,36 @@ +(ns status-im.ui.screens.intro.db + (:require [cljs.spec.alpha :as spec] + status-im.multiaccounts.db)) + +(spec/def :intro-wizrad/encrypt-with-password? boolean?) +(spec/def :intro-wizard/multiaccounts + (spec/coll-of :multiaccounts/generated-multiaccount)) +(spec/def :intro-wizard/selected-storage-type? keyword?) +(spec/def :intro-wizard/selected-id :generated-multiaccounts/id) +(spec/def :intro-wizard/back-action keyword?) +(spec/def :intro-wizard/weak-password? boolean?) +(spec/def :intro-wizard/forward-action keyword?) +(spec/def :intro-wizard/first-time-setup? boolean?) +(spec/def :intro-wizard/step (spec/nilable keyword?)) +(spec/def :intro-wizard/root-key :multiaccounts/generated-multiaccount) +(spec/def :intro-wizard/passphrase string?) +(spec/def :intro-wizard/recovering? boolean?) +(spec/def :intro-wizard/passphrase-word-count int?) +(spec/def :intro-wizard/derived :generated-multiaccounts/derived) +(spec/def :intro-wizard/next-button-disabled? boolean?) + +(spec/def :intro-wizard/intro-wizard + (spec/keys :req-un [:intro-wizrad/encrypt-with-password? + :intro-wizard/back-action + :intro-wizard/weak-password? + :intro-wizard/forward-action + :intro-wizard/first-time-setup? + :intro-wizard/step] + :opt-un [:intro-wizard/selected-id + :intro-wizard/selected-storage-type? + :intro-wizard/multiaccounts + :intro-wizard/root-key + :intro-wizard/passphrase + :intro-wizard/passphrase-word-count + :intro-wizard/derived + :intro-wizard/next-button-disabled?])) diff --git a/src/status_im/ui/screens/intro/views.cljs b/src/status_im/ui/screens/intro/views.cljs index 3b8ea66fce..3d3a7803b3 100644 --- a/src/status_im/ui/screens/intro/views.cljs +++ b/src/status_im/ui/screens/intro/views.cljs @@ -131,7 +131,7 @@ {:content-container-style {:justify-content :flex-start}} (for [[acc accessibility-n] (map vector multiaccounts (range (count multiaccounts)))] (let [selected? (= (:id acc) selected-id) - public-key (get-in acc [:derived constants/path-whisper-keyword :publicKey])] + public-key (get-in acc [:derived constants/path-whisper-keyword :public-key])] ^{:key public-key} [react/touchable-highlight {:accessibility-label (keyword (str "select-account-button-" accessibility-n)) diff --git a/src/status_im/utils/db.cljs b/src/status_im/utils/db.cljs index 4584dca092..4f2136b8b6 100644 --- a/src/status_im/utils/db.cljs +++ b/src/status_im/utils/db.cljs @@ -5,8 +5,12 @@ (defn valid-public-key? [s] (boolean (re-matches #"0x04[0-9a-f]{128}" s))) +(defn valid-key-uid? [s] + (boolean (re-matches #"0x[0-9a-f]{64}" s))) + (spec/def :global/not-empty-string (spec/and string? not-empty)) (spec/def :global/public-key (spec/and :global/not-empty-string valid-public-key?)) +(spec/def :global/key-uid (spec/and :global/not-empty-string valid-key-uid?)) (spec/def :global/address ethereum/address?) (spec/def :status/tag (spec/and :global/not-empty-string diff --git a/test/cljs/status_im/test/multiaccounts/recover/core.cljs b/test/cljs/status_im/test/multiaccounts/recover/core.cljs index d239287e6c..91c2880c9b 100644 --- a/test/cljs/status_im/test/multiaccounts/recover/core.cljs +++ b/test/cljs/status_im/test/multiaccounts/recover/core.cljs @@ -52,3 +52,17 @@ (is (= (i18n/label :recovery-typo-dialog-title) (-> new-cofx :ui/show-confirmation :title))) (is (= (i18n/label :recovery-typo-dialog-description) (-> new-cofx :ui/show-confirmation :content))) (is (= (i18n/label :recovery-confirm-phrase) (-> new-cofx :ui/show-confirmation :confirm-button-text))))) + +(deftest on-import-multiaccount-success + (testing "importing a new multiaccount" + (let [res (models/on-import-multiaccount-success + {:db {:multiaccounts/multiaccounts {:acc1 {}}}} + {:key-uid :acc2} + nil)] + (is (nil? (:utils/show-confirmation res))))) + (testing "importing an existing multiaccount" + (let [res (models/on-import-multiaccount-success + {:db {:multiaccounts/multiaccounts {:acc1 {}}}} + {:key-uid :acc1} + nil)] + (is (contains? res :utils/show-confirmation)))))