[#10002] Follow up after #10008

- ensure that `:key-uid` is always added to `app-db` with proper case
- tests which cover multiacc duplication case
This commit is contained in:
Roman Volosovskyi 2020-02-13 15:21:54 +02:00
parent e5f7a94ee2
commit 9a713148c7
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
10 changed files with 124 additions and 29 deletions

View File

@ -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}

View File

@ -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]}

View File

@ -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?))

View File

@ -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

View File

@ -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)}))

View File

@ -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]))

View File

@ -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?]))

View File

@ -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))

View File

@ -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

View File

@ -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)))))