[#7217] check card state before installation

Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2019-02-08 16:30:44 +03:00
parent 7a6a508696
commit bae935d3e4
No known key found for this signature in database
GPG Key ID: 43D1DAF5AD39C927
15 changed files with 419 additions and 264 deletions

View File

@ -55,7 +55,7 @@
"react-native-safe-area-view": "0.9.0",
"react-native-securerandom": "git+https://github.com/status-im/react-native-securerandom.git#0.1.1-2",
"react-native-splash-screen": "3.1.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.3.4",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.3.7",
"react-native-svg": "6.5.2",
"react-native-tcp": "git+https://github.com/status-im/react-native-tcp.git#v3.3.0-1-status",
"react-native-udp": "git+https://github.com/status-im/react-native-udp.git#2.3.1-1",

View File

@ -6010,9 +6010,9 @@ react-native-splash-screen@3.1.1:
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.1.1.tgz#1a4e46c9fdce53ff52af2a2cb4181788c4e30b30"
integrity sha512-PU2YocOSGbLjL9Vgcq/cwMNuHHKNjjuPpa1IPMuWo+6EB/fSZ5VOmxSa7+eucQe3631s3NhGuk3eHKahU03a4Q==
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#v2.3.4":
version "2.3.4"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#04b0fb6fcbe588bd7fa076e1b0379e661bf1bddc"
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#v2.3.7":
version "2.3.7"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#9e6df66bfd9288584031cff5455445230059720b"
react-native-svg@6.5.2:
version "6.5.2"

View File

@ -1,7 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="path-1-inside-1" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20 6H4C3.44772 6 3 6.44772 3 7V17C3 17.5523 3.44772 18 4 18H20C20.5523 18 21 17.5523 21 17V7C21 6.44772 20.5523 6 20 6ZM4 4C2.34315 4 1 5.34315 1 7V17C1 18.6569 2.34315 20 4 20H20C21.6569 20 23 18.6569 23 17V7C23 5.34315 21.6569 4 20 4H4Z"/>
</mask>
<path d="M4 8H20V4H4V8ZM5 7C5 7.55228 4.55228 8 4 8V4C2.34315 4 1 5.34315 1 7H5ZM5 17V7H1V17H5ZM4 16C4.55228 16 5 16.4477 5 17H1C1 18.6569 2.34315 20 4 20V16ZM20 16H4V20H20V16ZM19 17C19 16.4477 19.4477 16 20 16V20C21.6569 20 23 18.6569 23 17H19ZM19 7V17H23V7H19ZM20 8C19.4477 8 19 7.55229 19 7H23C23 5.34314 21.6569 4 20 4V8ZM3 7C3 6.44772 3.44772 6 4 6V2C1.23858 2 -1 4.23858 -1 7H3ZM3 17V7H-1V17H3ZM4 18C3.44772 18 3 17.5523 3 17H-1C-1 19.7614 1.23858 22 4 22V18ZM20 18H4V22H20V18ZM21 17C21 17.5523 20.5523 18 20 18V22C22.7614 22 25 19.7614 25 17H21ZM21 7V17H25V7H21ZM20 6C20.5523 6 21 6.44772 21 7H25C25 4.23858 22.7614 2 20 2V6ZM4 6H20V2H4V6Z" fill="black" mask="url(#path-1-inside-1)"/>
<rect x="5" y="10" width="4" height="4" rx="1" fill="black"/>
</svg>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 6H20C20.5523 6 21 6.44772 21 7V17C21 17.5523 20.5523 18 20 18H4C3.44769 18 3 17.5523 3 17V7C3 6.44772 3.44769 6 4 6ZM1 7C1 5.34314 2.34314 4 4 4H20C21.6569 4 23 5.34314 23 7V17C23 18.6569 21.6569 20 20 20H4C2.34314 20 1 18.6569 1 17V7ZM6 10C5.44769 10 5 10.4477 5 11V13C5 13.5523 5.44769 14 6 14H8C8.55231 14 9 13.5523 9 13V11C9 10.4477 8.55231 10 8 10H6Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 526 B

View File

@ -893,22 +893,16 @@
;; hardwallet module
(handlers/register-handler-fx
:hardwallet.ui/get-application-info
(fn [{:keys [db]} _]
{:hardwallet/get-application-info (get-in db [:hardwallet :secrets :pairing])}))
(handlers/register-handler-fx
:hardwallet.callback/on-retrieve-pairing-success
(fn [{:keys [db]} [_ pairing-data]]
{:db (update-in db [:hardwallet :secrets] merge (select-keys pairing-data
[:pairing :paired-on]))}))
(handlers/register-handler-fx
:hardwallet.callback/on-register-card-events
(fn [cofx [_ listeners]]
(hardwallet/on-register-card-events cofx listeners)))
(handlers/register-handler-fx
:hardwallet/get-application-info
(fn [_ _]
{:hardwallet/get-application-info nil}))
(handlers/register-handler-fx
:hardwallet.callback/on-get-application-info-success
(fn [cofx [_ info on-success]]
@ -939,6 +933,16 @@
(fn [cofx [_ data]]
(hardwallet/on-card-disconnected cofx data)))
(handlers/register-handler-fx
:hardwallet.callback/on-init-card-success
(fn [cofx [_ secrets]]
(hardwallet/on-init-card-success cofx secrets)))
(handlers/register-handler-fx
:hardwallet.callback/on-init-card-error
(fn [cofx [_ error]]
(hardwallet/on-init-card-error cofx error)))
(handlers/register-handler-fx
:hardwallet.callback/on-install-applet-and-init-card-success
(fn [cofx [_ secrets]]
@ -1047,6 +1051,11 @@
(fn [cofx _]
(hardwallet/login-with-keycard cofx false)))
(handlers/register-handler-fx
:hardwallet/check-card-state
(fn [cofx _]
(hardwallet/check-card-state cofx)))
(handlers/register-handler-fx
:hardwallet.callback/on-get-keys-error
(fn [cofx [_ error]]
@ -1067,32 +1076,15 @@
(fn [_ _]
{:hardwallet/open-nfc-settings nil}))
(handlers/register-handler-fx
:hardwallet.ui/hold-card-button-pressed
(fn [{:keys [db] :as cofx} _]
(fx/merge cofx
{:db (assoc-in db [:hardwallet :setup-step] :begin)}
(navigation/navigate-to-cofx :hardwallet-setup nil))))
(handlers/register-handler-fx
:hardwallet.ui/begin-setup-button-pressed
(fn [_ _]
{:ui/show-confirmation {:title ""
:content (i18n/label :t/begin-keycard-setup-confirmation-text)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/no)
:on-accept #(re-frame/dispatch [:hardwallet.ui/begin-setup-confirm-button-pressed])
:on-cancel #()}}))
(fn [cofx _]
(hardwallet/begin-setup-button-pressed cofx)))
(handlers/register-handler-fx
:hardwallet.ui/begin-setup-confirm-button-pressed
:hardwallet/start-installation
(fn [cofx _]
(hardwallet/load-preparing-screen cofx)))
(handlers/register-handler-fx
:hardwallet/install-applet-and-init-card
(fn [cofx _]
(hardwallet/install-applet-and-init-card cofx)))
(hardwallet/start-installation cofx)))
(handlers/register-handler-fx
:hardwallet.ui/pair-card-button-pressed
@ -1102,11 +1094,12 @@
(handlers/register-handler-fx
:hardwallet.ui/pair-code-input-changed
(fn [{:keys [db]} [_ pair-code]]
{:db (assoc-in db [:hardwallet :pair-code] pair-code)}))
{:db (assoc-in db [:hardwallet :secrets :password] pair-code)}))
(handlers/register-handler-fx
:hardwallet.ui/pair-code-next-button-pressed
(fn [{:keys [db]} _]))
(fn [cofx]
(hardwallet/pair cofx)))
(handlers/register-handler-fx
:hardwallet.ui/recovery-phrase-next-button-pressed

View File

@ -56,10 +56,24 @@
(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 install-applet-and-init-card []
(defn install-applet []
(when config/hardwallet-enabled?
(.. keycard
installAppletAndInitCard
installApplet
(then #(re-frame/dispatch [:hardwallet.callback/on-install-applet-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-install-applet-error (error-object->map %)])))))
(defn init-card [pin]
(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 %)])))))
(defn install-applet-and-init-card [pin]
(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 %)])))))

View File

@ -16,20 +16,34 @@
(def default-pin "000000")
(defn get-pairing [db]
(or
(get-in db [:hardwallet :secrets :pairing])
(get-in db [:account/account :pairing])))
(defn- find-account-by-keycard-instance-uid
[db keycard-instance-uid]
(->> (:accounts/accounts db)
vals
(filter #(= keycard-instance-uid (:keycard-instance-uid %)))
first))
(defn get-pairing
([db]
(get-pairing db nil))
([db instance-uid]
(or
(get-in db [:account/account :keycard-pairing])
(get-in db [:hardwallet :secrets :pairing])
(when instance-uid
(:keycard-pairing
(find-account-by-keycard-instance-uid db instance-uid))))))
(fx/defn remove-pairing-from-account
[{:keys [db]}]
(let [account (-> db
(get :account/account)
(assoc :keycard-pairing nil)
(assoc :keycard-paired-on nil))]
;TODO remove remove-pairing when keycard login will be ready
{:hardwallet/remove-pairing nil
:data-store/base-tx [(accounts-store/save-account-tx account)]}))
[{:keys [db]} {:keys [remove-instance-uid?]}]
(let [account (cond-> (:account/account db)
true (assoc :keycard-pairing nil
:keycard-paired-on nil)
remove-instance-uid? (assoc :keycard-instance-uid nil))]
{:db (-> db
(assoc :account/account account)
(assoc-in [:accounts/accounts (:address account)] account))
:data-store/base-tx [(accounts-store/save-account-tx account)]}))
(defn hardwallet-supported? [{:keys [db]}]
(and config/hardwallet-enabled?
@ -44,6 +58,74 @@
:content (i18n/label :t/keycard-unauthorized-operation)}}
(navigation/navigate-to-cofx :keycard-settings nil)))
(fx/defn show-no-keycard-applet-alert [_]
{:utils/show-confirmation {:title (i18n/label :t/no-keycard-applet-on-card)
:content (i18n/label :t/keycard-applet-will-be-installed)
:cancel-button-text ""
:confirm-button-text :t/next}})
(fx/defn show-keycard-has-account-alert
[{:keys [db] :as cofx}]
(fx/merge cofx
{:utils/show-confirmation {:title nil
:content (i18n/label :t/keycard-has-account-on-it)
:cancel-button-text ""
:confirm-button-text :t/okay}}
(if (empty? (:accounts/accounts db))
(navigation/navigate-to-cofx :intro nil)
(navigation/navigate-to-cofx :accounts nil))))
(defn- card-state->setup-step [state]
(case state
:not-paired :pair
:no-pairing-slots :no-slots
:begin))
(defn- get-card-state
[{:keys [has-master-key?
applet-installed?
initialized?
free-pairing-slots
paired?]}]
(cond
(and (not paired?)
(zero? free-pairing-slots))
:no-pairing-slots
(and (not paired?)
has-master-key?
(pos? free-pairing-slots))
:not-paired
(not applet-installed?)
:blank
(not initialized?)
:pre-init
(not has-master-key?)
:init
has-master-key?
:account))
(fx/defn set-setup-step
[{:keys [db]} card-state]
{:db (assoc-in db [:hardwallet :setup-step] (card-state->setup-step card-state))})
(fx/defn check-card-state
[{:keys [db] :as cofx}]
(let [app-info (get-in db [:hardwallet :application-info])
card-state (get-card-state app-info)]
(fx/merge cofx
{:db (assoc-in db [:hardwallet :card-state] card-state)}
(when (= card-state :blank)
(show-no-keycard-applet-alert))
(if (= card-state :account)
(show-keycard-has-account-alert)
(set-setup-step card-state)))))
(fx/defn navigate-to-keycard-settings
[{:keys [db] :as cofx}]
(fx/merge cofx
@ -104,15 +186,19 @@
[{:keys [db]}]
{:db (assoc-in db [:hardwallet :on-card-read] nil)})
(fx/defn dispatch-event
[_ event]
{:dispatch [event]})
(fx/defn on-get-application-info-success
[{:keys [db]} info on-success]
[{:keys [db] :as cofx} info on-success]
(let [info' (js->clj info :keywordize-keys true)
{:keys [pin-retry-counter puk-retry-counter]} info'
connect-screen? (= (:view-id db) :hardwallet-connect)
enter-step (if (zero? pin-retry-counter)
:puk
(get-in db [:hardwallet :pin :enter-step]))]
(fx/merge {}
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] enter-step)
(assoc-in [:hardwallet :application-info] info')
@ -123,22 +209,26 @@
(if (zero? puk-retry-counter)
(navigation/navigate-to-cofx :keycard-settings nil)
(when on-success
#(assoc % :dispatch [on-success]))))))
(dispatch-event on-success))))))
(fx/defn on-get-application-info-error
[{:keys [db] :as cofx} error]
(log/debug "[hardwallet] application info error " error)
(let [on-card-read (get-in db [:hardwallet :on-card-read])
connect-screen? (= (:view-id db) :hardwallet-connect)
login? (= on-card-read :hardwallet/login-with-keycard)]
(if login?
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-read] nil)
:utils/show-popup {:title (i18n/label :t/wrong-card)
{:utils/show-popup {:title (i18n/label :t/wrong-card)
:content (i18n/label :t/wrong-card-text)}}
(clear-on-card-read)
(navigation/navigate-to-cofx :accounts nil))
{:db (-> db
(assoc-in [:hardwallet :application-info-error] error)
(assoc-in [:hardwallet :application-info :applet-installed?] false))})))
(fx/merge cofx
{:db (assoc-in db [:hardwallet :application-info-error] error)}
(when-not connect-screen?
(clear-on-card-read))
(when on-card-read
(dispatch-event on-card-read))))))
(fx/defn set-nfc-support
[{:keys [db]} supported?]
@ -155,7 +245,7 @@
:db (-> db
(assoc-in [:hardwallet :setup-step] :begin)
(assoc-in [:hardwallet :on-card-connected] nil)
(assoc-in [:hardwallet :on-card-read] nil)
(assoc-in [:hardwallet :on-card-read] :hardwallet/check-card-state)
(assoc-in [:hardwallet :pin :on-verified] nil))}
(navigation/navigate-to-cofx :hardwallet-connect nil)))
@ -246,7 +336,7 @@
:on-verified nil}))
:utils/show-popup {:title ""
:content (i18n/label :t/card-reseted)}}
(remove-pairing-from-account)
(remove-pairing-from-account {:remove-instance-uid? true})
(navigation/navigate-to-cofx :keycard-settings nil)))
(fx/defn on-delete-error
@ -294,25 +384,20 @@
(fx/defn proceed-to-reset-card
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
puk-retry-counter (get-in db [:hardwallet :application-info :puk-retry-counter])
pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
pairing (get-pairing db)
enter-step (if (zero? pin-retry-counter) :puk :current)]
(if (or (zero? puk-retry-counter)
(empty? pairing))
(delete-card cofx)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :on-card-connected] :hardwallet/navigate-to-enter-pin-screen)
(assoc-in [:hardwallet :pin] {:enter-step enter-step
:current []
:puk []
:status nil
:error-label nil
:on-verified :hardwallet/unpair-and-delete}))}
(if card-connected?
(navigate-to-enter-pin-screen)
(navigation/navigate-to-cofx :hardwallet-connect nil))))))
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :on-card-connected] :hardwallet/navigate-to-enter-pin-screen)
(assoc-in [:hardwallet :pin] {:enter-step enter-step
:current []
:puk []
:status nil
:error-label nil
:on-verified :hardwallet/unpair-and-delete}))}
(if card-connected?
(navigate-to-enter-pin-screen)
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn error-button-pressed [{:keys [db] :as cofx}]
(let [return-to-step (get-in db [:hardwallet :return-to-step] :begin)]
@ -336,16 +421,24 @@
(defn- proceed-to-pin-confirmation [fx]
(assoc-in fx [:db :hardwallet :pin :enter-step] :confirmation))
(fx/defn load-preparing-screen
[{:keys [db]}]
{:db (assoc-in db [:hardwallet :setup-step] :preparing)
:dispatch [:hardwallet/start-installation]})
(fx/defn pin-match
[{:keys [db] :as fx}]
(let [pairing (get-pairing db)
new-pin (vector->string (get-in db [:hardwallet :pin :original]))
current-pin (vector->string (get-in db [:hardwallet :pin :current]))]
(fx/merge fx
{:db (assoc-in db [:hardwallet :pin :status] :verifying)
:hardwallet/change-pin {:new-pin new-pin
:current-pin current-pin
:pairing pairing}})))
current-pin (vector->string (get-in db [:hardwallet :pin :current]))
setup-step (get-in db [:hardwallet :setup-step])]
(if (= setup-step :pin)
(load-preparing-screen fx)
(fx/merge fx
{:db (assoc-in db [:hardwallet :pin :status] :verifying)
:hardwallet/change-pin {:new-pin new-pin
:current-pin current-pin
:pairing pairing}}))))
(fx/defn dispatch-on-verified-event
[{:keys [db]} event]
@ -385,7 +478,7 @@
{:db (-> db
(update-in [:hardwallet :pin] merge {:status nil
:error-label nil}))}
(when (not= on-verified :hardwallet/unpair)
(when-not (contains? #{:hardwallet/unpair :hardwallet/unpair-and-delete} on-verified)
(get-application-info pairing))
(when on-verified
(dispatch-on-verified-event on-verified)))))
@ -428,15 +521,15 @@
(fx/defn on-unpair-success
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :secrets] nil)
(assoc-in [:hardwallet :on-card-connected] nil)
(assoc-in [:hardwallet :pin] {:status nil
:error-label nil
:on-verified nil}))
:utils/show-popup {:title ""
:content (i18n/label :t/card-unpaired)}}
(remove-pairing-from-account)
{:db (-> db
(assoc-in [:hardwallet :secrets] nil)
(assoc-in [:hardwallet :on-card-connected] nil)
(assoc-in [:hardwallet :pin] {:status nil
:error-label nil
:on-verified nil}))
:utils/show-popup {:title ""
:content (i18n/label :t/card-unpaired)}}
(remove-pairing-from-account nil)
(navigation/navigate-to-cofx :keycard-settings nil)))
(fx/defn on-unpair-error
@ -501,7 +594,8 @@
(fx/defn get-keys-from-keycard
[{:keys [db]}]
(let [{:keys [pairing]} (get-in db [:hardwallet :secrets])
(let [account-address (get-in db [:accounts/login :address])
pairing (get-in db [:accounts/accounts account-address :keycard-pairing])
pin (string/join (get-in db [:hardwallet :pin :login]))]
(when (and pairing
(not (empty? pin)))
@ -576,23 +670,17 @@
(let [{:keys [pairing]} (get-in cofx [:db :hardwallet :secrets])]
{:hardwallet/generate-mnemonic {:pairing pairing}}))
(fx/defn dispatch-on-card-connected-event
[_ event]
{:dispatch [event]})
(defn login-with-keycard
[{:keys [db] :as cofx} auto-login?]
(let [pairing (get-pairing db)
account-login-address (get-in db [:accounts/login :address])
(let [account-login-address (get-in db [:accounts/login :address])
account-was-manually-selected? account-login-address
account-instance-uid (get-in db [:accounts/accounts account-login-address :keycard-instance-uid])
keycard-instance-uid (get-in db [:hardwallet :application-info :instance-uid])
account (find-account-by-keycard-instance-uid db keycard-instance-uid)
account-mismatch? (if account-was-manually-selected?
(not= account-instance-uid keycard-instance-uid)
(->> (:accounts/accounts db)
vals
(filter #(= keycard-instance-uid (:keycard-instance-uid %)))
empty?))]
(nil? account))
pairing (:keycard-pairing account)]
(cond
(empty? keycard-instance-uid)
@ -613,7 +701,9 @@
:content (i18n/label :t/no-pairing-on-device)}}
auto-login?
(navigation/navigate-to-cofx cofx :enter-pin nil)
(fx/merge cofx
{:db (assoc db :accounts/login (select-keys account [:address :name :photo-path]))}
(navigation/navigate-to-cofx :enter-pin nil))
:else
(get-keys-from-keycard cofx))))
@ -622,27 +712,31 @@
[{:keys [db] :as cofx} data]
(log/debug "[hardwallet] card connected " data)
(let [return-to-step (get-in db [:hardwallet :return-to-step])
setup-running? (get-in db [:hardwallet :setup-step])
setup-step (get-in db [:hardwallet :setup-step])
setup-running? (boolean setup-step)
pin-enter-step (get-in db [:hardwallet :pin :enter-step])
login? (= :login pin-enter-step)
accounts-screen? (= :accounts (:view-id db))
auto-login? accounts-screen?
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
should-read-instance-uid? (nil? instance-uid)
on-card-connected (get-in db [:hardwallet :on-card-connected])
on-card-read (if auto-login?
:hardwallet/auto-login
(get-in db [:hardwallet :on-card-read]))
pairing (get-pairing db)]
on-card-read (cond
auto-login? :hardwallet/auto-login
should-read-instance-uid? :hardwallet/get-application-info
:else (get-in db [:hardwallet :on-card-read]))
pairing (get-pairing db instance-uid)]
(fx/merge cofx
{:db (cond-> db
return-to-step (assoc-in [:hardwallet :setup-step] return-to-step)
true (assoc-in [:hardwallet :card-connected?] true)
true (assoc-in [:hardwallet :card-read-in-progress?] (boolean on-card-read))
true (assoc-in [:hardwallet :return-to-step] nil))
:hardwallet/get-application-info {:pairing pairing
:hardwallet/get-application-info {:pairing pairing
:on-success on-card-read}}
(when (and on-card-connected
(not login?))
(dispatch-on-card-connected-event on-card-connected))
(dispatch-event on-card-connected))
(when setup-running?
(navigation/navigate-to-cofx :hardwallet-setup nil)))))
@ -659,14 +753,33 @@
on-card-connected)
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn load-preparing-screen
(fx/defn begin-setup-button-pressed
[{:keys [db]}]
{:db (assoc-in db [:hardwallet :setup-step] :preparing)
:dispatch [:hardwallet/install-applet-and-init-card]})
{:db (-> db
(assoc-in [:hardwallet :setup-step] :pin)
(assoc-in [:hardwallet :pin :enter-step] :original)
(assoc-in [:hardwallet :pin :original] [])
(assoc-in [:hardwallet :pin :confirmation] []))})
(fx/defn install-applet-and-init-card
(fx/defn start-installation
[{:keys [db]}]
{:hardwallet/install-applet-and-init-card nil})
(let [card-state (get-in db [:hardwallet :card-state])
pin (vector->string (get-in db [:hardwallet :pin :original]))]
(case card-state
:blank
{:hardwallet/install-applet-and-init-card pin}
:pre-init
{:hardwallet/init-card pin}
:init
{:hardwallet/install-applet-and-init-card pin}
(do
(log/debug (str "Cannot start keycard installation from state: " card-state))
{:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/something-went-wrong)}}))))
(fx/defn on-install-applet-and-init-card-success
[{:keys [db]} secrets]
@ -675,6 +788,8 @@
(assoc-in [:hardwallet :setup-step] :secret-keys)
(assoc-in [:hardwallet :secrets] secrets'))}))
(def on-init-card-success on-install-applet-and-init-card-success)
(defn- tag-lost-exception? [code]
(= code "android.nfc.TagLostException"))
@ -692,23 +807,49 @@
(assoc-in [:hardwallet :setup-error] error))}
(process-error code)))
(def on-init-card-error on-install-applet-and-init-card-error)
(fx/defn set-account-pairing
[{:keys [db]} {:keys [address] :as account} pairing paired-on]
(let [account' (assoc account :keycard-pairing pairing
:keycard-paired-on paired-on)]
{:db (-> db
(assoc db :accounts/account account')
(assoc-in [:accounts/accounts address] account'))
:data-store/base-tx [(accounts-store/save-account-tx account')]}))
(fx/defn on-pairing-success
[{:keys [db]} pairing]
;TODO remove persistence to async storage when keycard login will be ready
{:hardwallet/persist-pairing pairing
:db (-> db
(assoc-in [:hardwallet :setup-step] :card-ready)
(assoc-in [:hardwallet :secrets :pairing] pairing)
(assoc-in [:hardwallet :secrets :paired-on] (utils.datetime/timestamp)))})
[{:keys [db] :as cofx} pairing]
(let [setup-step (get-in db [:hardwallet :setup-step])
instance-uid (get-in db [:hardwallet :application-info :instance-uid])
account (find-account-by-keycard-instance-uid db instance-uid)
paired-on (utils.datetime/timestamp)
next-step (if (= setup-step :enter-pair-code)
:begin
:card-ready)]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :application-info :paired?] true)
(assoc-in [:hardwallet :setup-step] next-step)
(assoc-in [:hardwallet :secrets :pairing] pairing)
(assoc-in [:hardwallet :secrets :paired-on] paired-on))}
(when account
(set-account-pairing account pairing paired-on))
(when (= next-step :begin)
(check-card-state)))))
(fx/defn on-pairing-error
[{:keys [db] :as cofx} {:keys [error code]}]
(log/debug "[hardwallet] pairing error: " error)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :return-to-step] :secret-keys)
(assoc-in [:hardwallet :setup-error] error))}
(process-error code)))
(let [setup-step (get-in db [:hardwallet :setup-step])
next-step (if (= setup-step :enter-pair-code)
:enter-pair-code
:secret-keys)]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :return-to-step] next-step)
(assoc-in [:hardwallet :setup-error] error))}
(process-error code))))
(fx/defn on-generate-mnemonic-success
[{:keys [db]} mnemonic]
@ -766,7 +907,8 @@
(fx/defn generate-and-load-key
[{:keys [db] :as cofx}]
(let [{:keys [mnemonic pairing pin]} (get-in db [:hardwallet :secrets])]
(let [{:keys [mnemonic pairing]} (get-in db [:hardwallet :secrets])
pin (vector->string (get-in db [:hardwallet :pin :original]))]
(fx/merge cofx
{:hardwallet/generate-and-load-key {:mnemonic mnemonic
:pairing pairing

View File

@ -25,6 +25,10 @@
:hardwallet/install-applet-and-init-card
card/install-applet-and-init-card)
(re-frame/reg-fx
:hardwallet/init-card
card/init-card)
(re-frame/reg-fx
:hardwallet/register-card-events
card/register-card-events)
@ -73,37 +77,6 @@
:hardwallet/get-keys
card/get-keys)
;TODO remove when keycard login will be ready
(re-frame/reg-fx
:hardwallet/persist-pairing
(fn [pairing]
(.. js-dependencies/react-native
-AsyncStorage
(setItem "status-keycard-pairing"
(js/JSON.stringify
#js {"pairing" pairing
"paired-on" (utils.datetime/timestamp)})))))
;TODO remove when keycard login will be ready
(re-frame/reg-fx
:hardwallet/retrieve-pairing
(fn []
(.. js-dependencies/react-native
-AsyncStorage
(getItem "status-keycard-pairing")
(then #(re-frame/dispatch [:hardwallet.callback/on-retrieve-pairing-success
(-> %
(js/JSON.parse)
(js->clj :keywordize-keys true))])))))
;TODO remove when keycard login will be ready
(re-frame/reg-fx
:hardwallet/remove-pairing
(fn []
(.. js-dependencies/react-native
-AsyncStorage
(removeItem "status-keycard-pairing"))))
(re-frame/reg-fx
:hardwallet/login-with-keycard
statusgo/login-with-keycard)

View File

@ -91,22 +91,20 @@
push-notifications/stored network/type]
:node/keys [status]
:or {network (get app-db :network)}} :db}]
;TODO remove retrieve-pairing when keycard login will be ready
{:hardwallet/retrieve-pairing nil
:db (assoc app-db
:contacts/contacts {}
:initial-props initial-props
:desktop/desktop (merge desktop (:desktop/desktop app-db))
:network-status network-status
:peers-count (or peers-count 0)
:peers-summary (or peers-summary [])
:node/status status
:network network
:network/type type
:hardwallet hardwallet
:device-UUID device-UUID
:view-id view-id
:push-notifications/stored stored)})
{:db (assoc app-db
:contacts/contacts {}
:initial-props initial-props
:desktop/desktop (merge desktop (:desktop/desktop app-db))
:network-status network-status
:peers-count (or peers-count 0)
:peers-summary (or peers-summary [])
:node/status status
:network network
:network/type type
:hardwallet hardwallet
:device-UUID device-UUID
:view-id view-id
:push-notifications/stored stored)})
(fx/defn initialize-app
[cofx encryption-key]

View File

@ -36,28 +36,31 @@
"Close window"]]]]]))
(def step-name
{:preparing {:label :t/initialization
{:pin {:label :t/pin-code
:number 1
:next-step :preparing}
:preparing {:label :t/initialization
:number 2
:next-step :secret-keys}
:secret-keys {:label :t/puk-and-pair-codes
:number 2
:number 3
:next-step :pairing}
:pairing {:label :t/pairing
:number 3
:number 4
:next-step :recovery-phrase}
:card-ready {:label :t/pairing
:number 3
:number 5
:next-step :recovery-phrase}
:generating-mnemonic {:label :t/recovery-phrase
:number 4}
:number 5}
:recovery-phrase-confirm-word1 {:label :t/recovery-phrase
:number 4}
:number 5}
:recovery-phrase-confirm-word2 {:label :t/recovery-phrase
:number 4}
:number 5}
:loading-keys {:label :t/recovery-phrase
:number 4}
:number 5}
:recovery-phrase {:label :t/recovery-phrase
:number 4}})
:number 5}})
(defn- setup-steps [step]
(let [current-step (step-name step)
@ -96,21 +99,17 @@
(animation/start)))
:display-name "maintain-card"
:reagent-render (fn [step] [react/view styles/maintain-card-container
[react/touchable-highlight
{:on-press #(do
(re-frame/dispatch [:hardwallet.ui/get-application-info])
(reset! modal-visible? true))}
[react/view styles/hardwallet-icon-container
[vector-icons/icon :main-icons/keycard {:color colors/blue}]
[vector-icons/icon :icons/indicator-small {:color colors/blue
:container-style (styles/hardwallet-icon-indicator-small-container
(interpolate-fn [0 0.5 1 0.5 0]))}]
[vector-icons/icon :icons/indicator-middle {:color colors/blue
:container-style (styles/hardwallet-icon-indicator-middle-container
(interpolate-fn [1 0.4 0 0.4 0.8]))}]
[vector-icons/icon :icons/indicator-big {:color colors/blue
:container-style (styles/hardwallet-icon-indicator-big-container
(interpolate-fn [0.5 0.8 0.5 0.8 0.4]))}]]]
[react/view styles/hardwallet-icon-container
[vector-icons/icon :main-icons/keycard {:color colors/blue}]
[vector-icons/icon :icons/indicator-small {:color colors/blue
:container-style (styles/hardwallet-icon-indicator-small-container
(interpolate-fn [0 0.5 1 0.5 0]))}]
[vector-icons/icon :icons/indicator-middle {:color colors/blue
:container-style (styles/hardwallet-icon-indicator-middle-container
(interpolate-fn [1 0.4 0 0.4 0.8]))}]
[vector-icons/icon :icons/indicator-big {:color colors/blue
:container-style (styles/hardwallet-icon-indicator-big-container
(interpolate-fn [0.5 0.8 0.5 0.8 0.4]))}]]
[setup-steps step]
[application-info modal-visible?]])})))

View File

@ -104,6 +104,20 @@
(def pin-retries 3)
(def puk-retries 5)
(defview create-pin []
(letsubs [pin [:hardwallet/pin]
step [:hardwallet/pin-enter-step]
status [:hardwallet/pin-status]
error-label [:hardwallet/pin-error-label]]
[pin-view {:pin pin
:title-label (case step
:confirmation :t/repeat-pin
:t/create-a-pin)
:description-label :t/create-pin-description
:step step
:status status
:error-label error-label}]))
(defview enter-pin []
(letsubs [pin [:hardwallet/pin]
step [:hardwallet/pin-enter-step]
@ -128,7 +142,7 @@
:title-label (case step
:current :t/current-pin
:login :t/current-pin
:original :t/create-pin
:original :t/create-a-pin
:confirmation :t/repeat-pin
:t/current-pin)
:description-label (case step

View File

@ -130,9 +130,10 @@
[action-row {:icon :main-icons/close
:label :t/unpair-card
:on-press #(re-frame/dispatch [:keycard-settings.ui/unpair-card-pressed])}]])])]
[react/view {:margin-bottom 20
:margin-left 16}
[action-row {:icon :main-icons/logout
:color-theme :red
:label :t/reset-card
:on-press #(re-frame/dispatch [:keycard-settings.ui/reset-card-pressed])}]]]]))
(when pairing
[react/view {:margin-bottom 20
:margin-left 16}
[action-row {:icon :main-icons/logout
:color-theme :red
:label :t/reset-card
:on-press #(re-frame/dispatch [:keycard-settings.ui/reset-card-pressed])}]])]]))

View File

@ -115,7 +115,8 @@
:color colors/black})
(def bottom-container
{:height 60
{:height 52
:width "100%"
:justify-content :center
:align-items :center
:border-top-width 1
@ -128,8 +129,7 @@
:flex-direction :row
:width 160
:height 44
:border-radius 10
:margin-bottom 14})
:border-radius 10})
(def begin-button-container
{:background-color colors/gray-background
@ -143,8 +143,7 @@
(def bottom-button-text
{:font-size 15
:color colors/blue
:line-height 20})
:color colors/blue})
(def next-button-container
{:flex-direction :row
@ -313,9 +312,11 @@
:color colors/black})
(def enter-pair-code-explanation-text
{:font-size 15
:padding-top 5
:color colors/gray})
{:font-size 15
:padding-top 5
:text-align :center
:padding-horizontal 60
:color colors/gray})
(def card-is-empty-text
{:color colors/black

View File

@ -6,10 +6,15 @@
(fn [db]
(get-in db [:hardwallet :setup-step])))
(re-frame/reg-sub
:hardwallet-card-state
(fn [db]
(get-in db [:hardwallet :card-state])))
(re-frame/reg-sub
:hardwallet-pair-code
(fn [db]
(get-in db [:hardwallet :pair-code])))
(get-in db [:hardwallet :secrets :password])))
(re-frame/reg-sub
:hardwallet-recovery-phrase-word

View File

@ -187,7 +187,7 @@
:forward? true}]]]]))
(defn- card-with-button-view
[{:keys [text-label button-label button-container-style on-press]}]
[{:keys [text-label button-label button-container-style on-press show-icon?]}]
"Generic view with centered card image and button at the bottom.
Used by 'Prepare', 'Pair', 'No slots', 'Card is linked' screens"
[react/view styles/card-with-button-view-container
@ -195,13 +195,17 @@
[react/image {:source (:hardwallet-card resources/ui)
:style styles/hardwallet-card-image}]
[react/view styles/center-text-container
[react/text {:style styles/center-text}
[react/text {:style (assoc styles/center-text :padding-horizontal 60)}
(i18n/label text-label)]]]
[react/touchable-highlight
{:on-press on-press}
[react/view (merge styles/bottom-button-container button-container-style)
[react/text {:style styles/bottom-button-text}
(i18n/label button-label)]]]])
[react/view styles/bottom-container
[react/touchable-highlight
{:on-press on-press}
[react/view (merge styles/bottom-button-container button-container-style)
[react/text {:style styles/bottom-button-text}
(i18n/label button-label)]
(when show-icon?
[vector-icons/icon :icons/link {:color colors/blue
:container-style {:margin-left 5}}])]]]])
(defn begin []
[react/view styles/card-blank-container
@ -219,10 +223,11 @@
[react/text {:style styles/remaining-steps-text}
(i18n/label :t/remaining-steps)]
[react/view {:margin-bottom 25}
(for [[number text] [["1" (i18n/label :t/initialization-of-the-card)]
["2" (i18n/label :t/puk-and-pairing-codes-displayed)]
["3" (i18n/label :t/device-pairing)]
["4" (i18n/label :t/recovery-phrase)]]]
(for [[number text] [["1" (i18n/label :t/create-pin)]
["2" (i18n/label :t/initialization-of-the-card)]
["3" (i18n/label :t/puk-and-pairing-codes-displayed)]
["4" (i18n/label :t/device-pairing)]
["5" (i18n/label :t/recovery-phrase)]]]
^{:key number} [react/view styles/remaining-step-row
[react/view styles/remaining-step-row-text
[react/text {:style {:color colors/black}}
@ -238,21 +243,23 @@
(i18n/label :t/begin-set-up)]]]]]])
(defn pair []
[card-with-button-view {:text-label :t/pair-card-question
:button-label :t/pair-card
:on-press-event #(re-frame/dispatch [:hardwallet.ui/pair-card-button-pressed])}])
[card-with-button-view {:text-label :t/pair-card-question
:button-label :t/pair-card
:on-press #(re-frame/dispatch [:hardwallet.ui/pair-card-button-pressed])}])
(defn no-slots []
[card-with-button-view {:text-label :t/no-pairing-slots-available
:button-label :t/help
:button-label :t/help-capitalized
:show-icon? true
:button-container-style {:background-color colors/white}
:on-press-event (.openURL react/linking "https://hardwallet.status.im")}])
:on-press #(.openURL react/linking "https://hardwallet.status.im")}])
(defn card-already-linked []
[card-with-button-view {:text-label :t/card-already-linked
:button-label :t/help
:button-label :t/help-capitalized
:show-icon? true
:button-container-style {:background-color colors/white}
:on-press-event (.openURL react/linking "https://hardwallet.status.im")}])
:on-press #(.openURL react/linking "https://hardwallet.status.im")}])
(defview error []
(letsubs [error [:hardwallet-setup-error]]
@ -263,15 +270,20 @@
[react/view styles/center-text-container
[react/text {:style styles/center-text}
(i18n/label :t/something-went-wrong)]
[react/text {:style styles/center-text}
(str (:code error) "\n" (:error error))]]]
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:hardwallet.ui/error-button-pressed])}
[react/view styles/bottom-button-container
[react/text {:style styles/bottom-button-text
:font :medium
:uppercase? false}
(i18n/label :t/try-again)]]]]))
[react/view {:padding-horizontal 20
:margin-top 20}
[react/text {:style styles/center-text}
(if (map? error)
(str (:code error) "\n" (:error error))
(str error))]]]]
[react/view styles/bottom-container
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:hardwallet.ui/error-button-pressed])}
[react/view styles/bottom-button-container
[react/text {:style styles/bottom-button-text
:font :medium
:uppercase? false}
(i18n/label :t/try-again)]]]]]))
(defn- loading-view [{:keys [title-label text-label estimated-time-seconds step-number]}]
"Generic view with waiting time estimate and loading indicator.
@ -293,7 +305,8 @@
(defview preparing []
(letsubs [progress-bar (atom nil)
listener (atom nil)]
listener (atom nil)
card-state [:hardwallet-card-state]]
{:component-will-mount (fn []
(when @listener
(.removeListener @listener)))
@ -315,10 +328,13 @@
[react/text {:style styles/estimated-time-text}
(i18n/label :t/taking-long-hold-phone-connected)]]
[react/view styles/progress-bar-container
[react/progress-bar {:styleAttr "Horizontal"
:indeterminate false
:progress 0
:ref #(reset! progress-bar %)}]]]))
(if (contains? #{:blank :init} card-state)
[react/progress-bar {:styleAttr "Horizontal"
:indeterminate false
:progress 0
:ref #(reset! progress-bar %)}]
[react/activity-indicator {:animating true
:size :large}])]]))
(defn- generating-mnemonic []
[react/view styles/loading-view-container
@ -378,7 +394,7 @@
:no-slots [no-slots]
:card-already-linked [card-already-linked]
:pairing [pairing]
:pin [pin.views/enter-pin]
:pin [pin.views/create-pin]
:recovery-phrase [recovery-phrase]
:recovery-phrase-confirm-word1 [recovery-phrase-confirm-word step]
:recovery-phrase-confirm-word2 [recovery-phrase-confirm-word step]

View File

@ -797,6 +797,8 @@
"card-is-blank": "This card is blank",
"card-setup-prepare-text": "The whole process will take a few minutes.",
"card-is-paired": "Card is paired",
"no-keycard-applet-on-card": "No Keycard applet on card",
"keycard-applet-will-be-installed": "Keycard applet will automatically be installed",
"begin-set-up": "Begin setup",
"maintain-card-to-phone-contact": "Maintain card-to-phone contact during process.",
"preparing-card": "Preparing card",
@ -842,7 +844,8 @@
"change-pin": "Change PIN",
"enter-pin": "Enter PIN",
"enter-pin-description": "Enter your PIN code to login\n to your account",
"create-pin": "Create a PIN",
"create-pin": "Create PIN",
"create-a-pin": "Create a PIN",
"create-pin-description": "You'll need your card + this PIN to log in and to confirm transactions",
"repeat-pin": "Repeat new PIN",
"puk-mismatch": "PUK code does not match",
@ -858,11 +861,12 @@
"card-unpaired": "Card has been unpaired from current device",
"card-reseted": "Card has been reseted",
"unpair-card-confirmation": "This operation will unpair card from current device. Requires PIN authorization. Do you want to proceed?",
"pair-card": "pair card",
"pair-card-question": "Do you want to pair card to this device?",
"pair-card": "Pair to this device",
"pair-card-question": "Card is ready to pair",
"enter-pair-code": "Enter pair code",
"enter-pair-code-description": "Needed to link your card to this device",
"no-pairing-slots-available": "No pairing slots are available.\n You could unpair the device\n that already paired with the card",
"enter-pair-code-description": "SECURITY NOTE: Use only the code you wrote down during card setup.",
"no-pairing-slots-available": "This card is already paired to 5 devices and cannot pair to this one. Please use one of the paired devices, log in with this card and free up pairing slots on the card",
"keycard-has-account-on-it": "This card has already an account on it. If you wish to change it, login first and reset your card.",
"card-already-linked": "Card is already linked to another account",
"keycard-unauthorized-operation": "You're unauthorized to perform this operation.",
"no-account-on-card": "No account on this card",
@ -871,7 +875,6 @@
"wrong-card-text": "You have tapped a card that does not correspond to the account you selected. Please try again.",
"account-not-listed": "Account not listed",
"account-not-listed-text": "The account on this card is not listed on your phone. Would you like to login with this new account?",
"wrong-card-text": "You have tapped a card that does not correspond to the account you selected. Please try again.",
"no-pairing-on-device": "Card is not paired to this device",
"help": "help",
"help-capitalized": "Help",