Revert "Revert "[#7133] sign tx with keycard""

This reverts commit 4ccb1ea52d.

Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2019-04-03 11:46:53 +03:00
parent f8674c0ee1
commit 4decedf5f6
No known key found for this signature in database
GPG Key ID: 43D1DAF5AD39C927
20 changed files with 437 additions and 121 deletions

View File

@ -54,7 +54,7 @@
"react-native-safe-area-view": "0.9.0", "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-securerandom": "git+https://github.com/status-im/react-native-securerandom.git#0.1.1-2",
"react-native-splash-screen": "3.1.1", "react-native-splash-screen": "3.1.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.3.10", "react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.4.0",
"react-native-svg": "^9.2.4", "react-native-svg": "^9.2.4",
"react-native-svg-transformer": "^0.12.1", "react-native-svg-transformer": "^0.12.1",
"react-native-tcp": "git+https://github.com/status-im/react-native-tcp.git#v3.3.0-1-status", "react-native-tcp": "git+https://github.com/status-im/react-native-tcp.git#v3.3.0-1-status",

View File

@ -5355,9 +5355,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" 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== integrity sha512-PU2YocOSGbLjL9Vgcq/cwMNuHHKNjjuPpa1IPMuWo+6EB/fSZ5VOmxSa7+eucQe3631s3NhGuk3eHKahU03a4Q==
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#v2.3.10": "react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#v2.4.0":
version "2.3.10" version "2.4.0"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#a6da0a7889fdbc8cdf61771cf1b989c5cfb14b08" resolved "git+https://github.com/status-im/react-native-status-keycard.git#b9a66144b3942e40ffb30cb27fa01202b0d11061"
react-native-svg-transformer@^0.12.1: react-native-svg-transformer@^0.12.1:
version "0.12.1" version "0.12.1"

View File

@ -700,6 +700,45 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(r); StatusThreadPoolExecutor.getInstance().execute(r);
} }
@ReactMethod
public void hashMessage(final String message, final Callback callback) {
Log.d(TAG, "hashMessage");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashMessage(message);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void hashTypedData(final String data, final Callback callback) {
Log.d(TAG, "hashTypedData");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashTypedData(data);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod @ReactMethod
public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) { public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) {
Log.d(TAG, "sendTransactionWithSignature"); Log.d(TAG, "sendTransactionWithSignature");

View File

@ -956,7 +956,7 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet/get-application-info :hardwallet/get-application-info
(fn [cofx _] (fn [cofx _]
(hardwallet/get-application-info cofx nil))) (hardwallet/get-application-info cofx nil nil)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.callback/on-get-application-info-success :hardwallet.callback/on-get-application-info-success
@ -1096,6 +1096,11 @@
(fn [cofx [_ data]] (fn [cofx [_ data]]
(hardwallet/on-get-keys-success cofx data))) (hardwallet/on-get-keys-success cofx data)))
(handlers/register-handler-fx
:hardwallet.callback/on-sign-success
(fn [cofx [_ data]]
(hardwallet/on-sign-success cofx data)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet/auto-login :hardwallet/auto-login
(fn [cofx _] (fn [cofx _]
@ -1116,6 +1121,11 @@
(fn [cofx [_ error]] (fn [cofx [_ error]]
(hardwallet/on-get-keys-error cofx error))) (hardwallet/on-get-keys-error cofx error)))
(handlers/register-handler-fx
:hardwallet.callback/on-sign-error
(fn [cofx [_ error]]
(hardwallet/on-sign-error cofx error)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/status-hardwallet-option-pressed :hardwallet.ui/status-hardwallet-option-pressed
(fn [cofx _] (fn [cofx _]
@ -1250,6 +1260,11 @@
(fn [cofx [_ number step]] (fn [cofx [_ number step]]
(hardwallet/update-pin cofx number step))) (hardwallet/update-pin cofx number step)))
(handlers/register-handler-fx
:hardwallet.ui/navigate-back-button-clicked
(fn [cofx _]
(hardwallet/navigate-back-button-clicked cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet/process-pin-input :hardwallet/process-pin-input
(fn [cofx _] (fn [cofx _]
@ -1343,6 +1358,11 @@
(fn [cofx _] (fn [cofx _]
(hardwallet/navigate-to-reset-card-screen cofx))) (hardwallet/navigate-to-reset-card-screen cofx)))
(handlers/register-handler-fx
:hardwallet/sign
(fn [cofx _]
(hardwallet/sign cofx)))
;; browser module ;; browser module
(handlers/register-handler-fx (handlers/register-handler-fx

View File

@ -154,3 +154,11 @@
(getKeys pairing pin) (getKeys pairing pin)
(then #(re-frame/dispatch [:hardwallet.callback/on-get-keys-success %])) (then #(re-frame/dispatch [:hardwallet.callback/on-get-keys-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-get-keys-error (error-object->map %)])))) (catch #(re-frame/dispatch [:hardwallet.callback/on-get-keys-error (error-object->map %)]))))
(defn sign
[{:keys [pairing pin hash]}]
(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 %)])))))

View File

@ -7,13 +7,16 @@
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.utils.types :as types]
[status-im.accounts.create.core :as accounts.create] [status-im.accounts.create.core :as accounts.create]
[status-im.node.core :as node] [status-im.node.core :as node]
[status-im.utils.datetime :as utils.datetime] [status-im.utils.datetime :as utils.datetime]
[status-im.data-store.accounts :as accounts-store] [status-im.data-store.accounts :as accounts-store]
[status-im.utils.ethereum.core :as ethereum]
[clojure.string :as string] [clojure.string :as string]
[status-im.accounts.login.core :as accounts.login] [status-im.accounts.login.core :as accounts.login]
[status-im.accounts.recover.core :as accounts.recover])) [status-im.accounts.recover.core :as accounts.recover]
[status-im.models.wallet :as models.wallet]))
(def default-pin "000000") (def default-pin "000000")
@ -27,7 +30,7 @@
(defn get-pairing (defn get-pairing
([db] ([db]
(get-pairing db nil)) (get-pairing db (get-in db [:hardwallet :application-info :instance-uid])))
([db instance-uid] ([db instance-uid]
(or (or
(get-in db [:account/account :keycard-pairing]) (get-in db [:account/account :keycard-pairing])
@ -36,6 +39,21 @@
(:keycard-pairing (:keycard-pairing
(find-account-by-keycard-instance-uid db instance-uid)))))) (find-account-by-keycard-instance-uid db instance-uid))))))
(fx/defn navigate-back-button-clicked
[{:keys [db] :as cofx}]
(let [screen-before (second (get db :navigation-stack))
navigate-to-browser? (contains? #{:wallet-sign-message-modal
:wallet-send-transaction-modal
:wallet-send-modal-stack} screen-before)]
(if navigate-to-browser?
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
(models.wallet/discard-transaction)
(navigation/navigate-to-cofx :browser nil))
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
(navigation/navigate-back)))))
(fx/defn remove-pairing-from-account (fx/defn remove-pairing-from-account
[{:keys [db]} {:keys [remove-instance-uid?]}] [{:keys [db]} {:keys [remove-instance-uid?]}]
(let [account (cond-> (:account/account db) (let [account (cond-> (:account/account db)
@ -188,6 +206,7 @@
(defn enter-pin-screen-did-load (defn enter-pin-screen-did-load
[{:keys [db]}] [{:keys [db]}]
{:db (-> db {:db (-> db
(assoc-in [:hardwallet :pin :sign] [])
(assoc-in [:hardwallet :pin :login] []) (assoc-in [:hardwallet :pin :login] [])
(assoc-in [:hardwallet :pin :current] []))}) (assoc-in [:hardwallet :pin :current] []))})
@ -274,7 +293,8 @@
(let [info' (js->clj info :keywordize-keys true) (let [info' (js->clj info :keywordize-keys true)
{:keys [pin-retry-counter puk-retry-counter instance-uid]} info' {:keys [pin-retry-counter puk-retry-counter instance-uid]} info'
connect-screen? (= (:view-id db) :hardwallet-connect) connect-screen? (= (:view-id db) :hardwallet-connect)
card-state (get-in db [:hardwallet :card-state]) {:keys [card-state on-card-read]} (:hardwallet db)
on-success' (or on-success on-card-read)
accounts-screen? (= :accounts (:view-id db)) accounts-screen? (= :accounts (:view-id db))
auto-login? (and accounts-screen? auto-login? (and accounts-screen?
(not= on-success :hardwallet/auto-login)) (not= on-success :hardwallet/auto-login))
@ -295,9 +315,10 @@
instance-uid) instance-uid)
(check-card-state)) (check-card-state))
(if (zero? puk-retry-counter) (if (zero? puk-retry-counter)
(navigation/navigate-to-cofx :keycard-settings nil) {:utils/show-popup {:title (i18n/label :t/error)
(when on-success :content (i18n/label :t/keycard-blocked)}}
(dispatch-event on-success)))))) (when on-success'
(dispatch-event on-success'))))))
(fx/defn on-get-application-info-error (fx/defn on-get-application-info-error
[{:keys [db] :as cofx} error] [{:keys [db] :as cofx} error]
@ -570,12 +591,13 @@
:enter-step :puk :enter-step :puk
:puk []})})) :puk []})}))
(fx/defn get-application-info (fx/defn get-application-info
[{:keys [db]} pairing] [{:keys [db]} pairing on-card-read]
(let [instance-uid (get-in db [:hardwallet :application-info :instance-uid]) (let [instance-uid (get-in db [:hardwallet :application-info :instance-uid])
pairing' (or pairing pairing' (or pairing
(when instance-uid (when instance-uid
(get-pairing db instance-uid)))] (get-pairing db instance-uid)))]
{:hardwallet/get-application-info {:pairing pairing'}})) {:hardwallet/get-application-info {:pairing pairing'
:on-success on-card-read}}))
(fx/defn on-verify-pin-success (fx/defn on-verify-pin-success
[{:keys [db] :as cofx}] [{:keys [db] :as cofx}]
@ -586,7 +608,7 @@
(update-in [:hardwallet :pin] merge {:status nil (update-in [:hardwallet :pin] merge {:status nil
:error-label nil}))} :error-label nil}))}
(when-not (contains? #{:hardwallet/unpair :hardwallet/unpair-and-delete} on-verified) (when-not (contains? #{:hardwallet/unpair :hardwallet/unpair-and-delete} on-verified)
(get-application-info pairing)) (get-application-info pairing nil))
(when on-verified (when on-verified
(dispatch-on-verified-event on-verified))))) (dispatch-on-verified-event on-verified)))))
@ -613,7 +635,7 @@
:error-label nil})) :error-label nil}))
:utils/show-popup {:title "" :utils/show-popup {:title ""
:content (i18n/label :t/pin-changed {:pin pin})}} :content (i18n/label :t/pin-changed {:pin pin})}}
(navigation/navigate-to-cofx :keycard-settings nil)))) (navigation/navigate-back))))
(fx/defn on-change-pin-error (fx/defn on-change-pin-error
[{:keys [db]} error] [{:keys [db]} error]
@ -664,7 +686,8 @@
(defn- unblock-pin (defn- unblock-pin
[{:keys [db] :as fx}] [{:keys [db] :as fx}]
(let [puk (vector->string (get-in fx [:db :hardwallet :pin :puk])) (let [puk (vector->string (get-in fx [:db :hardwallet :pin :puk]))
pairing (get-pairing db)] instance-uid (get-in db [:hardwallet :application-info :instance-uid])
pairing (get-pairing db instance-uid)]
{:db (assoc-in db [:hardwallet :pin :status] :verifying) {:db (assoc-in db [:hardwallet :pin :status] :verifying)
:hardwallet/unblock-pin {:puk puk :hardwallet/unblock-pin {:puk puk
:new-pin default-pin :new-pin default-pin
@ -709,8 +732,26 @@
(assoc-in [:hardwallet :on-card-read] :hardwallet/login-with-keycard))} (assoc-in [:hardwallet :on-card-read] :hardwallet/login-with-keycard))}
(navigation/navigate-to-cofx :hardwallet-connect nil))))) (navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn sign
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
pairing (get-pairing db)
hash (get-in db [:hardwallet :hash])
pin (vector->string (get-in db [:hardwallet :pin :sign]))]
(if card-connected?
{:db (-> db
(assoc-in [:hardwallet :card-read-in-progress?] true)
(assoc-in [:hardwallet :pin :status] :verifying))
:hardwallet/sign {:hash (ethereum/naked-address hash)
:pairing pairing
:pin pin}}
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/sign)}
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
; PIN enter steps: ; PIN enter steps:
; login - PIN is used to login ; login - PIN is used to login
; sign - PIN for transaction sign
; current - current PIN to perform actions which require PIN auth ; current - current PIN to perform actions which require PIN auth
; original - new PIN when user changes it or creates new one ; original - new PIN when user changes it or creates new one
; confirmation - confirmation for new PIN ; confirmation - confirmation for new PIN
@ -738,6 +779,10 @@
(= pin-code-length numbers-entered)) (= pin-code-length numbers-entered))
(verify-pin) (verify-pin)
(and (= enter-step :sign)
(= pin-code-length numbers-entered))
(sign)
(and (= enter-step :puk) (and (= enter-step :puk)
(= puk-code-length numbers-entered)) (= puk-code-length numbers-entered))
(unblock-pin) (unblock-pin)
@ -800,9 +845,9 @@
(fx/merge cofx (fx/merge cofx
{:db (-> db {:db (-> db
(assoc-in [:hardwallet :card-connected?] true) (assoc-in [:hardwallet :card-connected?] true)
(assoc-in [:hardwallet :card-read-in-progress?] (boolean on-card-read))) (assoc-in [:hardwallet :card-read-in-progress?] (boolean on-card-read)))}
:hardwallet/get-application-info {:pairing pairing (when (not= on-card-connected :hardwallet/sign)
:on-success on-card-read}} (get-application-info pairing on-card-read))
(when (and on-card-connected (when (and on-card-connected
(not login?)) (not login?))
(dispatch-event on-card-connected)) (dispatch-event on-card-connected))
@ -1057,10 +1102,12 @@
encryption-public-key]} (js->clj data :keywordize-keys true) encryption-public-key]} (js->clj data :keywordize-keys true)
whisper-public-key' (str "0x" whisper-public-key) whisper-public-key' (str "0x" whisper-public-key)
{:keys [photo-path name]} (get-in db [:accounts/accounts wallet-address]) {:keys [photo-path name]} (get-in db [:accounts/accounts wallet-address])
password encryption-public-key] password encryption-public-key
instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
(fx/merge cofx (fx/merge cofx
{:db (-> db {:db (-> db
(assoc-in [:hardwallet :pin :status] nil) (assoc-in [:hardwallet :pin :status] nil)
(assoc-in [:hardwallet :pin :login] [])
(assoc-in [:hardwallet :whisper-public-key] whisper-public-key') (assoc-in [:hardwallet :whisper-public-key] whisper-public-key')
(assoc-in [:hardwallet :whisper-private-key] whisper-private-key) (assoc-in [:hardwallet :whisper-private-key] whisper-private-key)
(assoc-in [:hardwallet :wallet-address] wallet-address) (assoc-in [:hardwallet :wallet-address] wallet-address)
@ -1069,18 +1116,67 @@
:password password :password password
:address wallet-address :address wallet-address
:photo-path photo-path :photo-path photo-path
:name name))} :name name))
:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}}
(accounts.login/user-login true)))) (accounts.login/user-login true))))
(fx/defn on-get-keys-error (fx/defn on-get-keys-error
[{:keys [db] :as cofx} error] [{:keys [db] :as cofx} error]
(log/debug "[hardwallet] get keys error: " error) (log/debug "[hardwallet] get keys error: " error)
(let [tag-was-lost? (= "Tag was lost." (:error error))] (let [tag-was-lost? (= "Tag was lost." (:error error))
instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
(if tag-was-lost? (if tag-was-lost?
{:utils/show-popup {:title (i18n/label :t/error) {:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/tag-was-lost)}} :content (i18n/label :t/tag-was-lost)}}
(fx/merge cofx (fx/merge cofx
{:hardwallet/get-application-info {:pairing (get-pairing db)} {:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}
:db (update-in db [:hardwallet :pin] merge {:status :error :db (update-in db [:hardwallet :pin] merge {:status :error
:login []
:error-label :t/pin-mismatch})} :error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin nil))))) (navigation/navigate-to-cofx :enter-pin nil)))))
(fx/defn send-transaction-with-signature
[_ data]
{:send-transaction-with-signature data})
(fx/defn sign-message-completed
[{:keys [db]} signature]
(let [screen-params (get-in db [:navigation/screen-params :wallet-sign-message-modal])
signature' (-> signature
; add 27 to last byte
; https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L431
(clojure.string/replace-first #"00$", "1b")
(clojure.string/replace-first #"01$", "1c")
(ethereum/normalized-address))]
{:dispatch
[:status-im.ui.screens.wallet.send.events/sign-message-completed
screen-params
{:result signature'}]}))
(fx/defn on-sign-success
[{:keys [db] :as cofx} signature]
(log/debug "[hardwallet] sign success: " signature)
(let [transaction (get-in db [:hardwallet :transaction])]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :sign] [])
(assoc-in [:hardwallet :pin :status] nil)
(assoc-in [:hardwallet :on-card-connected] nil)
(assoc-in [:hardwallet :hash] nil)
(assoc-in [:hardwallet :transaction] nil))}
(get-application-info (get-pairing db) nil)
(if transaction
(send-transaction-with-signature {:transaction (types/clj->json transaction)
:signature signature
:on-completed #(re-frame/dispatch [:status-im.ui.screens.wallet.send.events/transaction-completed (types/json->clj %)])})
(sign-message-completed signature)))))
(fx/defn on-sign-error
[{:keys [db] :as cofx} error]
(log/debug "[hardwallet] sign error: " error)
(fx/merge cofx
{:db (update-in db [:hardwallet :pin] merge {:status :error
:sign []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin nil)
(get-application-info (get-pairing db) nil)))

View File

@ -77,6 +77,15 @@
:hardwallet/get-keys :hardwallet/get-keys
card/get-keys) card/get-keys)
(re-frame/reg-fx
:hardwallet/sign
card/sign)
(re-frame/reg-fx (re-frame/reg-fx
:hardwallet/login-with-keycard :hardwallet/login-with-keycard
statusgo/login-with-keycard) statusgo/login-with-keycard)
(re-frame/reg-fx
:send-transaction-with-signature
(fn [{:keys [transaction signature on-completed]}]
(statusgo/send-transaction-with-signature transaction signature on-completed)))

View File

@ -119,7 +119,7 @@
:error message} :error message}
:webview webview-bridge})) :webview webview-bridge}))
(defn dapp-complete-transaction [id result method message-id webview] (defn dapp-complete-transaction [id result method message-id webview keycard?]
(cond-> {:browser/send-to-bridge {:message {:type constants/web3-send-async-callback (cond-> {:browser/send-to-bridge {:message {:type constants/web3-send-async-callback
:messageId message-id :messageId message-id
:result {:jsonrpc "2.0" :result {:jsonrpc "2.0"
@ -129,7 +129,7 @@
:dispatch [:navigate-back]} :dispatch [:navigate-back]}
(constants/web3-sign-message? method) (constants/web3-sign-message? method)
(assoc :dispatch [:navigate-back]) (assoc :dispatch (if keycard? [:navigate-to :browser] [:navigate-back]))
(= method constants/web3-send-transaction) (= method constants/web3-send-transaction)
(assoc :dispatch [:navigate-to-clean :wallet-transaction-sent-modal]))) (assoc :dispatch [:navigate-to-clean :wallet-transaction-sent-modal])))

View File

@ -58,6 +58,12 @@
(defn hash-transaction [rpcParams callback] (defn hash-transaction [rpcParams callback]
(native-module/hash-transaction rpcParams callback)) (native-module/hash-transaction rpcParams callback))
(defn hash-message [message callback]
(native-module/hash-message message callback))
(defn hash-typed-data [data callback]
(native-module/hash-typed-data data callback))
(defn send-transaction-with-signature [rpcParams sig callback] (defn send-transaction-with-signature [rpcParams sig callback]
(native-module/send-transaction-with-signature rpcParams sig callback)) (native-module/send-transaction-with-signature rpcParams sig callback))

View File

@ -98,6 +98,14 @@
(when (and @node-started status) (when (and @node-started status)
(.hashTransaction status rpcParams callback))) (.hashTransaction status rpcParams callback)))
(defn hash-message [message callback]
(when (and @node-started status)
(.hashMessage status message callback)))
(defn hash-typed-data [data callback]
(when (and @node-started status)
(.hashTypedData status data callback)))
(defn sign-typed-data [data password callback] (defn sign-typed-data [data password callback]
(when (and @node-started status) (when (and @node-started status)
(.signTypedData status data password callback))) (.signTypedData status data password callback)))

View File

@ -40,7 +40,8 @@
(i18n/label :t/go-to-settings)]]]) (i18n/label :t/go-to-settings)]]])
(defview hardwallet-connect [] (defview hardwallet-connect []
(letsubs [nfc-enabled? [:hardwallet/nfc-enabled?]] (letsubs [nfc-enabled? [:hardwallet/nfc-enabled?]
setup-step [:hardwallet-setup-step]]
[react/view styles/container [react/view styles/container
[status-bar/status-bar] [status-bar/status-bar]
[react/view {:flex 1 [react/view {:flex 1
@ -53,10 +54,11 @@
(if nfc-enabled? (if nfc-enabled?
[nfc-enabled] [nfc-enabled]
[nfc-disabled])] [nfc-disabled])]
(if (= setup-step :begin)
[react/view styles/bottom-container [react/view styles/bottom-container
[react/touchable-highlight {:on-press #(.openURL react/linking "https://hardwallet.status.im")} [react/touchable-highlight {:on-press #(.openURL react/linking "https://hardwallet.status.im")}
[react/view styles/product-info-container [react/view styles/product-info-container
[react/text {:style styles/product-info-text} [react/text {:style styles/product-info-text}
(i18n/label :t/product-information)] (i18n/label :t/product-information)]
[vector-icons/icon :main-icons/link {:color colors/blue [vector-icons/icon :main-icons/link {:color colors/blue
:container-style styles/external-link-icon}]]]]]])) :container-style styles/external-link-icon}]]]])]]))

View File

@ -9,7 +9,8 @@
[status-im.ui.screens.hardwallet.components :as components] [status-im.ui.screens.hardwallet.components :as components]
[status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.actions :as actions])) [status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.actions :as toolbar.actions]))
(defn numpad-button [n step enabled?] (defn numpad-button [n step enabled?]
[react/touchable-highlight [react/touchable-highlight
@ -31,8 +32,7 @@
[numpad-row [4 5 6] step enabled?] [numpad-row [4 5 6] step enabled?]
[numpad-row [7 8 9] step enabled?] [numpad-row [7 8 9] step enabled?]
[react/view styles/numpad-row-container [react/view styles/numpad-row-container
[react/view styles/numpad-empty-button [react/view styles/numpad-empty-button]
[react/text {:style styles/numpad-empty-button-text}]]
[numpad-button 0 step enabled?] [numpad-button 0 step enabled?]
[react/touchable-highlight [react/touchable-highlight
{:on-press #(when enabled? {:on-press #(when enabled?
@ -125,7 +125,12 @@
[react/view {:flex 1 [react/view {:flex 1
:background-color colors/white} :background-color colors/white}
[status-bar/status-bar] [status-bar/status-bar]
[toolbar/toolbar nil toolbar/default-nav-back nil] [toolbar/toolbar
nil
[toolbar/nav-button (assoc toolbar.actions/default-back
:handler
#(re-frame/dispatch [:hardwallet.ui/navigate-back-button-clicked]))]
nil]
(if (zero? pin-retry-counter) (if (zero? pin-retry-counter)
[pin-view {:pin pin [pin-view {:pin pin
:retry-counter (when (< puk-retry-counter puk-retries) puk-retry-counter) :retry-counter (when (< puk-retry-counter puk-retries) puk-retry-counter)
@ -144,6 +149,7 @@
:t/current-pin) :t/current-pin)
:description-label (case step :description-label (case step
:current :t/current-pin-description :current :t/current-pin-description
:sign :t/current-pin-description
:login :t/login-pin-description :login :t/login-pin-description
:t/new-pin-description) :t/new-pin-description)
:step step :step step

View File

@ -33,3 +33,9 @@
:keycard-reset-card-disabled? :keycard-reset-card-disabled?
(fn [db] (fn [db]
(get-in db [:hardwallet :reset-card :disabled?] false))) (get-in db [:hardwallet :reset-card :disabled?] false)))
(re-frame/reg-sub
:keycard-account?
(fn [db]
(boolean
(get-in db [:account/account :keycard-instance-uid]))))

View File

@ -4,13 +4,17 @@
[{:name :wallet-send-modal-stack [{:name :wallet-send-modal-stack
:screens [:wallet-send-transaction-modal :screens [:wallet-send-transaction-modal
:wallet-transaction-sent-modal :wallet-transaction-sent-modal
:wallet-transaction-fee] :wallet-transaction-fee
:hardwallet-connect
:enter-pin]
:config {:initialRouteName :wallet-send-transaction-modal}} :config {:initialRouteName :wallet-send-transaction-modal}}
{:name :wallet-send-modal-stack-with-onboarding {:name :wallet-send-modal-stack-with-onboarding
:screens [:wallet-onboarding-setup-modal :screens [:wallet-onboarding-setup-modal
:wallet-send-transaction-modal :wallet-send-transaction-modal
:wallet-transaction-sent-modal :wallet-transaction-sent-modal
:wallet-transaction-fee] :wallet-transaction-fee
:hardwallet-connect
:enter-pin]
:config {:initialRouteName :wallet-onboarding-setup-modal}} :config {:initialRouteName :wallet-onboarding-setup-modal}}
:chat-modal :chat-modal
:show-extension-modal :show-extension-modal

View File

@ -11,6 +11,8 @@
:screens [:wallet-send-transaction :screens [:wallet-send-transaction
:recent-recipients :recent-recipients
:wallet-transaction-sent :wallet-transaction-sent
:enter-pin
:hardwallet-connect
:recipient-qr-code :recipient-qr-code
:wallet-send-assets]} :wallet-send-assets]}
{:name :request-transaction-stack {:name :request-transaction-stack

View File

@ -20,7 +20,8 @@
[status-im.utils.types :as types] [status-im.utils.types :as types]
[status-im.utils.utils :as utils] [status-im.utils.utils :as utils]
[status-im.utils.config :as config] [status-im.utils.config :as config]
[status-im.transport.utils :as transport.utils])) [status-im.transport.utils :as transport.utils]
[status-im.hardwallet.core :as hardwallet]))
;;;; FX ;;;; FX
@ -77,27 +78,6 @@
#(re-frame/dispatch [::transaction-completed (types/json->clj %)]) #(re-frame/dispatch [::transaction-completed (types/json->clj %)])
password]})))) password]}))))
;; SIGN MESSAGE
(handlers/register-handler-fx
:wallet/sign-message
(fn [_ [_ typed? screen-params password-error-cb]]
(let [{:keys [data from password]} screen-params]
(if typed?
{::sign-typed-data {:data data
:password password
:account from
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}}
{::sign-message {:params {:data data
:password (security/safe-unmask-data password)
:account from}
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}}))))
;; SEND TRANSACTION CALLBACK ;; SEND TRANSACTION CALLBACK
(handlers/register-handler-fx (handlers/register-handler-fx
::transaction-completed ::transaction-completed
@ -139,6 +119,20 @@
(if on-result (if on-result
{:dispatch (conj on-result id result method)}))))) {:dispatch (conj on-result id result method)})))))
(handlers/register-handler-fx
::hash-message-completed
(fn [{:keys [db] :as cofx} [_ {:keys [result error]}]]
(let [db' (assoc-in db [:wallet :send-transaction :in-progress?] false)]
(if error
;; ERROR
(models.wallet/handle-transaction-error (assoc cofx :db db') error)
;; RESULT
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] :sign)
(assoc-in [:hardwallet :hash] result))}
(navigation/navigate-to-cofx :enter-pin nil))))))
;; DISCARD TRANSACTION ;; DISCARD TRANSACTION
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/discard-transaction :wallet/discard-transaction
@ -148,8 +142,9 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.dapp/transaction-on-result :wallet.dapp/transaction-on-result
(fn [{db :db} [_ message-id id result method]] (fn [{db :db} [_ message-id id result method]]
(let [webview (:webview-bridge db)] (let [webview (:webview-bridge db)
(models.wallet/dapp-complete-transaction (int id) result method message-id webview)))) keycard? (boolean (get-in db [:account/account :keycard-instance-uid]))]
(models.wallet/dapp-complete-transaction (int id) result method message-id webview keycard?))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.dapp/transaction-on-error :wallet.dapp/transaction-on-error
@ -165,6 +160,7 @@
(let [{:keys [send-transaction transactions-queue]} (:wallet db) (let [{:keys [send-transaction transactions-queue]} (:wallet db)
{:keys [payload message-id] :as queued-transaction} (last transactions-queue) {:keys [payload message-id] :as queued-transaction} (last transactions-queue)
{:keys [method params id]} payload {:keys [method params id]} payload
keycard? (boolean (get-in db [:account/account :keycard-instance-uid]))
db' (update-in db [:wallet :transactions-queue] drop-last)] db' (update-in db [:wallet :transactions-queue] drop-last)]
(when (and (not (contains? #{:wallet-transaction-sent (when (and (not (contains? #{:wallet-transaction-sent
:wallet-transaction-sent-modal} :wallet-transaction-sent-modal}
@ -182,14 +178,18 @@
(let [typed? (not= constants/web3-personal-sign method) (let [typed? (not= constants/web3-personal-sign method)
[address data] (models.wallet/normalize-sign-message-params params)] [address data] (models.wallet/normalize-sign-message-params params)]
(if (and address data) (if (and address data)
(let [screen-params {:id (str (or id message-id)) (let [signing-phrase (-> (get-in db [:account/account :signing-phrase])
(clojure.string/replace-all #" " " "))
screen-params {:id (str (or id message-id))
:from address :from address
:data data :data data
:typed? typed? :typed? typed?
:decoded-data (if typed? (types/json->clj data) (transport.utils/to-utf8 data)) :decoded-data (if typed? (types/json->clj data) (transport.utils/to-utf8 data))
:on-result [:wallet.dapp/transaction-on-result message-id] :on-result [:wallet.dapp/transaction-on-result message-id]
:on-error [:wallet.dapp/transaction-on-error message-id] :on-error [:wallet.dapp/transaction-on-error message-id]
:method method}] :method method
:signing-phrase signing-phrase
:keycard? keycard?}]
(navigation/navigate-to-cofx {:db db'} :wallet-sign-message-modal screen-params)) (navigation/navigate-to-cofx {:db db'} :wallet-sign-message-modal screen-params))
{:db db'}))))))) {:db db'})))))))
@ -205,7 +205,7 @@
#(when send-command? #(when send-command?
(commands-sending/send % chat-id send-command? params)) (commands-sending/send % chat-id send-command? params))
(navigation/navigate-to-clean (navigation/navigate-to-clean
(if (= (:view-id db) :wallet-send-transaction) (if (contains? #{:wallet-send-transaction :enter-pin :hardwallet-connect} (:view-id db))
:wallet-transaction-sent :wallet-transaction-sent
:wallet-transaction-sent-modal) :wallet-transaction-sent-modal)
{}))))) {})))))
@ -314,3 +314,74 @@
{:dispatch-later [{:ms 400 :dispatch [:check-dapps-transactions-queue]}]} {:dispatch-later [{:ms 400 :dispatch [:check-dapps-transactions-queue]}]}
(navigation/navigate-back)))) (navigation/navigate-back))))
(re-frame/reg-fx
::hash-transaction
(fn [{:keys [transaction all-tokens symbol chain on-completed]}]
(status/hash-transaction (types/clj->json transaction) on-completed)))
(re-frame/reg-fx
::hash-message
(fn [{:keys [message on-completed]}]
(status/hash-message message on-completed)))
(re-frame/reg-fx
::hash-typed-data
(fn [{:keys [data on-completed]}]
(status/hash-typed-data data on-completed)))
(defn send-keycard-transaction
[{{:keys [chain] :as db} :db}]
(let [{:keys [symbol] :as transaction} (get-in db [:wallet :send-transaction])
all-tokens (:wallet/all-tokens db)
from (get-in db [:account/account :address])]
{::hash-transaction {:transaction (models.wallet/prepare-send-transaction from transaction)
:all-tokens all-tokens
:symbol symbol
:chain chain
:on-completed #(re-frame/dispatch [:wallet.callback/hash-transaction-completed %])}}))
(handlers/register-handler-fx
:wallet.callback/hash-transaction-completed
(fn [{:keys [db] :as cofx} [_ result]]
(let [{:keys [transaction hash]} (:result (types/json->clj result))]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] :sign)
(assoc-in [:hardwallet :transaction] transaction)
(assoc-in [:hardwallet :hash] hash))}
(navigation/navigate-to-clean :enter-pin nil)))))
(handlers/register-handler-fx
:wallet.ui/sign-transaction-button-clicked
(fn [{:keys [db] :as cofx} _]
(let [keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))]
(if keycard-account?
(send-keycard-transaction cofx)
{:db (assoc-in db [:wallet :send-transaction :show-password-input?] true)}))))
(handlers/register-handler-fx
:wallet.ui/sign-message-button-clicked
(fn [{:keys [db]} [_ typed? screen-params password-error-cb]]
(let [{:keys [data from password]} screen-params
keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))]
(if keycard-account?
(if typed?
{::hash-typed-data {:data data
:on-completed #(re-frame/dispatch [::hash-message-completed (types/json->clj %)])}}
{::hash-message {:message (ethereum/naked-address data)
:on-completed #(re-frame/dispatch [::hash-message-completed (types/json->clj %)])}})
(if typed?
{::sign-typed-data {:data data
:password password
:account from
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}}
{::sign-message {:params {:data data
:password (security/safe-unmask-data password)
:account from}
:on-completed #(re-frame/dispatch [::sign-message-completed
screen-params
(types/json->clj %)
password-error-cb])}})))))

View File

@ -89,3 +89,9 @@
(models.wallet/add-max-fee) (models.wallet/add-max-fee)
(check-sufficient-funds balance symbol amount) (check-sufficient-funds balance symbol amount)
(check-sufficient-gas balance symbol amount)))) (check-sufficient-gas balance symbol amount))))
(re-frame/reg-sub
:wallet.send/signing-phrase-with-padding
:<- [:account/account]
(fn [{:keys [signing-phrase]}]
(clojure.string/replace-all signing-phrase #" " " ")))

View File

@ -129,15 +129,28 @@
[react/view] [react/view]
[button/button {:style components.styles/flex [button/button {:style components.styles/flex
:disabled? (not sign-enabled?) :disabled? (not sign-enabled?)
:on-press #(re-frame/dispatch [:set-in :on-press #(re-frame/dispatch [:wallet.ui/sign-transaction-button-clicked])
[:wallet :send-transaction :show-password-input?]
true])
:text-style {:color :white} :text-style {:color :white}
:accessibility-label :sign-transaction-button} :accessibility-label :sign-transaction-button}
(i18n/label :t/transactions-sign-transaction) (i18n/label :t/transactions-sign-transaction)
[vector-icons/icon :main-icons/next {:color (if sign-enabled? colors/white colors/white-light-transparent)}]]])) [vector-icons/icon :main-icons/next {:color (if sign-enabled? colors/white colors/white-light-transparent)}]]]))
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? network all-tokens amount-input network-status]}] (defn signing-phrase-view [signing-phrase]
[react/view {:flex-direction :column
:align-items :center
:margin-top 10}
[react/view (assoc styles/signing-phrase-container :width "90%" :height 40)
[react/text {:accessibility-label :signing-phrase-text
:style {:padding-vertical 16
:text-align :center}}
signing-phrase]]
[react/text {:style {:color :white
:text-align :center
:font-size 12
:padding-vertical 14}}
(i18n/label :t/signing-phrase-warning)]])
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? keycard? signing-phrase network all-tokens amount-input network-status]}]
(let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds? (let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds?
sufficient-gas? in-progress? from-chat? symbol]} transaction sufficient-gas? in-progress? from-chat? symbol]} transaction
chain (ethereum/network->chain-keyword network) chain (ethereum/network->chain-keyword network)
@ -172,7 +185,9 @@
:amount-text amount-text :amount-text amount-text
:input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount % symbol decimals]) :input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount % symbol decimals])
:ref (partial reset! amount-input)}} token] :ref (partial reset! amount-input)}} token]
[advanced-options advanced? native-currency transaction scroll]]] [advanced-options advanced? native-currency transaction scroll]
(when keycard?
[signing-phrase-view signing-phrase])]]
(if show-password-input? (if show-password-input?
[enter-password-buttons in-progress? [enter-password-buttons in-progress?
#(re-frame/dispatch [:wallet/cancel-entering-password]) #(re-frame/dispatch [:wallet/cancel-entering-password])
@ -206,11 +221,15 @@
network [:account/network] network [:account/network]
scroll (atom nil) scroll (atom nil)
network-status [:network-status] network-status [:network-status]
all-tokens [:wallet/all-tokens]] all-tokens [:wallet/all-tokens]
signing-phrase [:wallet.send/signing-phrase-with-padding]
keycard? [:keycard-account?]]
[send-transaction-view {:modal? false [send-transaction-view {:modal? false
:transaction transaction :transaction transaction
:scroll scroll :scroll scroll
:advanced? advanced? :advanced? advanced?
:keycard? keycard?
:signing-phrase signing-phrase
:network network :network network
:all-tokens all-tokens :all-tokens all-tokens
:network-status network-status}])) :network-status network-status}]))
@ -222,12 +241,16 @@
network [:account/network] network [:account/network]
scroll (atom nil) scroll (atom nil)
network-status [:network-status] network-status [:network-status]
all-tokens [:wallet/all-tokens]] all-tokens [:wallet/all-tokens]
signing-phrase [:wallet.send/signing-phrase-with-padding]
keycard? [:keycard-account?]]
(if transaction (if transaction
[send-transaction-view {:modal? true [send-transaction-view {:modal? true
:transaction transaction :transaction transaction
:scroll scroll :scroll scroll
:advanced? advanced? :advanced? advanced?
:keycard? keycard?
:signing-phrase signing-phrase
:network network :network network
:all-tokens all-tokens :all-tokens all-tokens
:network-status network-status}] :network-status network-status}]

View File

@ -7,6 +7,7 @@
[status-im.ui.screens.wallet.components.views :as components] [status-im.ui.screens.wallet.components.views :as components]
[status-im.ui.screens.wallet.components.views :as wallet.components] [status-im.ui.screens.wallet.components.views :as wallet.components]
[status-im.ui.screens.wallet.send.styles :as styles] [status-im.ui.screens.wallet.send.styles :as styles]
[status-im.ui.screens.wallet.send.views :as wallet.send.views]
[status-im.ui.screens.wallet.main.views :as wallet.main.views] [status-im.ui.screens.wallet.main.views :as wallet.main.views]
[status-im.ui.components.toolbar.actions :as actions] [status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.toolbar.view :as toolbar]
@ -30,10 +31,11 @@
#(actions/default-handler)))] #(actions/default-handler)))]
[toolbar/content-title {:color :white} title]])) [toolbar/content-title {:color :white} title]]))
(defview enter-password-buttons [value-atom spinning? cancel-handler sign-handler sign-label] (defview enter-password-buttons [value-atom {:keys [spinning? keycard?]} cancel-handler sign-handler sign-label]
(letsubs [network-status [:network-status]] (letsubs [network-status [:network-status]]
(let [password (:password @value-atom) (let [password (:password @value-atom)
sign-enabled? (and (not (nil? password)) (not= password ""))] sign-enabled? (or keycard?
(and (not (nil? password)) (not= password "")))]
[bottom-buttons/bottom-buttons [bottom-buttons/bottom-buttons
styles/sign-buttons styles/sign-buttons
[button/button {:style components.styles/flex [button/button {:style components.styles/flex
@ -82,7 +84,7 @@
;; SIGN MESSAGE FROM DAPP ;; SIGN MESSAGE FROM DAPP
(defview sign-message-modal [] (defview sign-message-modal []
(letsubs [value-atom (reagent/atom nil) (letsubs [value-atom (reagent/atom nil)
{:keys [decoded-data in-progress? typed?] :as screen-params} [:get-screen-params :wallet-sign-message-modal] {:keys [decoded-data in-progress? typed? keycard? signing-phrase] :as screen-params} [:get-screen-params :wallet-sign-message-modal]
network-status [:network-status]] network-status [:network-status]]
[wallet.components/simple-screen {:status-bar-type :modal-wallet} [wallet.components/simple-screen {:status-bar-type :modal-wallet}
[toolbar true (i18n/label :t/sign-message)] [toolbar true (i18n/label :t/sign-message)]
@ -96,17 +98,24 @@
[components/amount-input [components/amount-input
{:disabled? true {:disabled? true
:input-options {:multiline true :input-options {:multiline true
:height 100} :height (if typed? 300 100)}
:amount-text (if typed? :amount-text (if typed?
(str "Domain\n" (:domain decoded-data) "\nMessage\n" (:message decoded-data)) (str "Domain\n" (:domain decoded-data) "\nMessage\n" (:message decoded-data))
decoded-data)} decoded-data)}
nil]]]] nil]]]
[enter-password-buttons value-atom false (when keycard?
[wallet.send.views/signing-phrase-view signing-phrase])]
[enter-password-buttons
value-atom
{:spinning? false :keycard? keycard?}
#(re-frame/dispatch [:wallet/discard-transaction-navigate-back]) #(re-frame/dispatch [:wallet/discard-transaction-navigate-back])
#(re-frame/dispatch [:wallet/sign-message typed? (merge screen-params @value-atom) #(re-frame/dispatch [:wallet.ui/sign-message-button-clicked
typed?
(merge screen-params @value-atom)
(fn [] (fn []
(swap! value-atom assoc :wrong-password? true))]) (swap! value-atom assoc :wrong-password? true))])
:t/transactions-sign] :t/transactions-sign]
[password-input-panel value-atom :t/signing-message-phrase-description false] (when-not keycard?
[password-input-panel value-atom :t/signing-message-phrase-description false])
(when in-progress? (when in-progress?
[react/view styles/processing-view])]])) [react/view styles/processing-view])]]))

View File

@ -635,6 +635,7 @@
"wallet-choose-from-contacts": "Choose from Contacts", "wallet-choose-from-contacts": "Choose from Contacts",
"send-sending-to": "to {{recipient-name}}", "send-sending-to": "to {{recipient-name}}",
"signing-phrase-description": "If you recognize these words, enter your login password to sign the transaction", "signing-phrase-description": "If you recognize these words, enter your login password to sign the transaction",
"signing-phrase-warning": "Only confirm the transaction if you recognize\n your three words",
"currency-display-name-mad": "Moroccan Dirham", "currency-display-name-mad": "Moroccan Dirham",
"here-is-your-signing-phrase": "Here is your signing phrase. You will use it to verify your transactions. *Write it down and keep it safe!*", "here-is-your-signing-phrase": "Here is your signing phrase. You will use it to verify your transactions. *Write it down and keep it safe!*",
"wants-to-access-profile": "wants to access to your profile", "wants-to-access-profile": "wants to access to your profile",