[#7887] handle tag lost errors

Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2019-05-01 20:09:00 +03:00
parent 1f24f1c4f6
commit 5762967a44
No known key found for this signature in database
GPG Key ID: 43D1DAF5AD39C927
8 changed files with 221 additions and 132 deletions

View File

@ -1315,6 +1315,16 @@
(fn [cofx _]
(hardwallet/pair cofx)))
(handlers/register-handler-fx
:hardwallet/verify-pin
(fn [cofx _]
(hardwallet/verify-pin cofx)))
(handlers/register-handler-fx
:hardwallet/change-pin
(fn [cofx _]
(hardwallet/change-pin cofx)))
(handlers/register-handler-fx
:hardwallet.ui/success-button-pressed
(fn [cofx _]
@ -1326,9 +1336,14 @@
(hardwallet/update-pin cofx number step)))
(handlers/register-handler-fx
:hardwallet.ui/navigate-back-button-clicked
:hardwallet.ui/enter-pin-navigate-back-button-clicked
(fn [cofx _]
(hardwallet/navigate-back-button-clicked cofx)))
(hardwallet/enter-pin-navigate-back-button-clicked cofx)))
(handlers/register-handler-fx
:hardwallet.ui/hardwallet-connect-navigate-back-button-clicked
(fn [cofx _]
(hardwallet/hardwallet-connect-navigate-back-button-clicked cofx)))
(handlers/register-handler-fx
:hardwallet/process-pin-input

View File

@ -41,7 +41,13 @@
(:keycard-pairing
(find-account-by-keycard-instance-uid db instance-uid))))))
(fx/defn navigate-back-button-clicked
(fx/defn hardwallet-connect-navigate-back-button-clicked
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
(navigation/navigate-back)))
(fx/defn enter-pin-navigate-back-button-clicked
[{:keys [db] :as cofx}]
(let [screen-before (set (take 4 (:navigation-stack db)))
navigate-to-browser? (contains? screen-before :browser-stack)]
@ -210,10 +216,8 @@
(defn enter-pin-screen-did-load
[{:keys [db]}]
{:db (-> db
(assoc-in [:hardwallet :pin :sign] [])
(assoc-in [:hardwallet :pin :login] [])
(assoc-in [:hardwallet :pin :current] []))})
(let [enter-step (get-in db [:hardwallet :pin :enter-step])]
{:db (assoc-in db [:hardwallet :pin enter-step] [])}))
(defn hardwallet-connect-screen-did-load
[{:keys [db]}]
@ -377,29 +381,27 @@
(fx/defn change-pin-pressed
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
(let [pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
enter-step (if (zero? pin-retry-counter) :puk :current)]
(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 []
:original []
:confirmation []
:status nil
:error-label nil
:on-verified :hardwallet/proceed-to-change-pin}))}
(if card-connected?
(navigate-to-enter-pin-screen)
(navigation/navigate-to-cofx :hardwallet-connect-settings nil)))))
{:db
(assoc-in db [:hardwallet :pin] {:enter-step enter-step
:current []
:puk []
:original []
:confirmation []
:status nil
:error-label nil
:on-verified :hardwallet/proceed-to-change-pin})}
(navigate-to-enter-pin-screen))))
(fx/defn proceed-to-change-pin
[{:keys [db]}]
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] :original)
(assoc-in [:hardwallet :pin :status] nil))})
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :pin :enter-step] :original)
(assoc-in [:hardwallet :pin :status] nil))}
(navigation/navigate-to-cofx :enter-pin-settings nil)))
(fx/defn unpair-card-pressed
[_]
@ -412,21 +414,16 @@
(fx/defn unpair-card-confirmed
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
(let [pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
enter-step (if (zero? pin-retry-counter) :puk :current)]
(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}))}
(if card-connected?
(navigate-to-enter-pin-screen)
(navigation/navigate-to-cofx :hardwallet-connect-settings nil)))))
{:db (assoc-in db [:hardwallet :pin] {:enter-step enter-step
:current []
:puk []
:status nil
:error-label nil
:on-verified :hardwallet/unpair})}
(navigate-to-enter-pin-screen))))
(defn- vector->string [v]
"Converts numbers stored in vector into string,
@ -527,13 +524,8 @@
(navigation/navigate-to-cofx :keycard-settings nil)))
(fx/defn reset-card-pressed
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])]
(if card-connected?
(navigation/navigate-to-cofx cofx :reset-card nil)
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/navigate-to-reset-card-screen)}
(navigation/navigate-to-cofx :hardwallet-connect-settings nil)))))
[cofx]
(navigation/navigate-to-cofx cofx :reset-card nil))
(fx/defn delete-card
[{:keys [db] :as cofx}]
@ -556,8 +548,7 @@
(fx/defn proceed-to-reset-card
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
(let [pin-retry-counter (get-in db [:hardwallet :application-info :pin-retry-counter])
enter-step (if (zero? pin-retry-counter) :puk :current)]
(fx/merge cofx
{:db (-> db
@ -568,9 +559,7 @@
:status nil
:error-label nil
:on-verified :hardwallet/remove-key-with-unpair}))}
(if card-connected?
(navigate-to-enter-pin-screen)
(navigation/navigate-to-cofx :hardwallet-connect-settings nil)))))
(navigate-to-enter-pin-screen))))
(fx/defn error-button-pressed
[{:keys [db] :as cofx}]
@ -621,19 +610,24 @@
(dispatch-event :hardwallet/start-installation)
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn pin-match
[{:keys [db] :as fx}]
(fx/defn change-pin
[{:keys [db] :as cofx}]
(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]))
setup-step (get-in db [:hardwallet :setup-step])]
setup-step (get-in db [:hardwallet :setup-step])
card-connected? (get-in db [:hardwallet :card-connected?])]
(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}}))))
(load-preparing-screen cofx)
(if card-connected?
(fx/merge cofx
{:db (assoc-in db [:hardwallet :pin :status] :verifying)
:hardwallet/change-pin {:new-pin new-pin
:current-pin current-pin
:pairing pairing}})
(fx/merge cofx
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/change-pin)}
(navigation/navigate-to-cofx :hardwallet-connect nil))))))
(fx/defn dispatch-on-verified-event
[{:keys [db]} event]
@ -671,12 +665,20 @@
{:hardwallet/get-application-info {:pairing pairing'
:on-success on-card-read}}))
(defn- tag-lost-exception? [code error]
(or
(= code "android.nfc.TagLostException")
(= error "Tag was lost.")))
(def pin-mismatch-error #"Unexpected error SW, 0x63C\d+")
(fx/defn on-verify-pin-success
[{:keys [db] :as cofx}]
(let [on-verified (get-in db [:hardwallet :pin :on-verified])
pairing (get-pairing db)]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :on-card-connected] nil)
(update-in [:hardwallet :pin] merge {:status nil
:error-label nil}))}
(when-not (contains? #{:hardwallet/unpair
@ -687,17 +689,35 @@
(dispatch-on-verified-event on-verified)))))
(defn on-verify-pin-error
[{:keys [db]} error]
(let [pairing (get-pairing db)]
[{:keys [db] :as cofx} error]
(let [tag-was-lost? (= "Tag was lost." (:error error))
setup? (boolean (get-in db [:hardwallet :setup-step]))]
(log/debug "[hardwallet] verify pin error" error)
{:hardwallet/get-application-info {:pairing pairing}
:db (update-in db [:hardwallet :pin] merge {:status :error
:error-label :t/pin-mismatch
:enter-step :current
:puk []
:current []
:original []
:confirmation []})}))
(fx/merge cofx
(if tag-was-lost?
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :on-card-connected] :hardwallet/verify-pin)
(assoc-in [:hardwallet :pin :status] nil))
:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/cannot-read-card)}}
(navigation/navigate-to-cofx (if setup?
:hardwallet-connect
:hardwallet-connect-settings) nil))
(if (re-matches pin-mismatch-error (:error error))
(fx/merge cofx
{:db (update-in db [:hardwallet :pin] merge {:status :error
:enter-step :current
:puk []
:current []
:original []
:confirmation []
:sign []
:error-label :t/pin-mismatch})}
(when-not setup?
(navigation/navigate-to-cofx :enter-pin-settings nil))
(get-application-info (get-pairing db) nil))
(show-wrong-keycard-alert cofx true))))))
(fx/defn on-change-pin-success
[{:keys [db] :as cofx}]
@ -712,14 +732,31 @@
(accounts.logout/logout))))
(fx/defn on-change-pin-error
[{:keys [db]} error]
[{:keys [db] :as cofx} error]
(log/debug "[hardwallet] change pin error" error)
{:db (update-in db [:hardwallet :pin] merge {:status :error
:error-label :t/pin-mismatch
:enter-step :original
:puk []
:confirmation []
:original []})})
(let [tag-was-lost? (= "Tag was lost." (:error error))]
(fx/merge cofx
(if tag-was-lost?
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :on-card-connected] :hardwallet/change-pin)
(assoc-in [:hardwallet :pin :status] nil))
:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/cannot-read-card)}}
(navigation/navigate-to-cofx :hardwallet-connect nil))
(if (re-matches pin-mismatch-error (:error error))
(fx/merge cofx
{:db (update-in db [:hardwallet :pin] merge {:status :error
:enter-step :current
:puk []
:current []
:original []
:confirmation []
:sign []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin-settings nil)
(get-application-info (get-pairing db) nil))
(show-wrong-keycard-alert cofx true))))))
(fx/defn on-unpair-success
[{:keys [db] :as cofx}]
@ -751,7 +788,7 @@
(defn- verify-pin
[{:keys [db] :as cofx}]
(let [pin (vector->string (get-in cofx [:db :hardwallet :pin :current]))
(let [pin (vector->string (get-in db [:hardwallet :pin :current]))
pairing (get-pairing db)
card-connected? (get-in db [:hardwallet :card-connected?])]
(if card-connected?
@ -816,6 +853,15 @@
(assoc-in [:hardwallet :on-card-read] :hardwallet/login-with-keycard))}
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn navigate-to-connect-screen
[{:keys [db] :as cofx} screen-name]
(let [modal? (get-in db [:navigation/screen-params :wallet-send-modal-stack :modal?])]
(navigation/navigate-to-cofx cofx
(if modal?
:hardwallet-connect-modal
screen-name)
nil)))
(fx/defn sign
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:hardwallet :card-connected?])
@ -837,7 +883,7 @@
{:db (assoc-in db [:hardwallet :on-card-connected] :hardwallet/sign)}
(when-not keycard-match?
(show-wrong-keycard-alert card-connected?))
(navigation/navigate-to-cofx :hardwallet-connect-sign nil)))))
(navigate-to-connect-screen :hardwallet-connect-sign)))))
(fx/defn prepare-to-sign
[{:keys [db] :as cofx}]
@ -894,7 +940,7 @@
(and (= enter-step :confirmation)
(= (get-in db [:hardwallet :pin :original])
(get-in db [:hardwallet :pin :confirmation])))
(pin-match)
(change-pin)
(and (= enter-step :confirmation)
(= pin-code-length numbers-entered)
@ -950,7 +996,9 @@
{:db (-> db
(assoc-in [:hardwallet :card-connected?] true)
(assoc-in [:hardwallet :card-read-in-progress?] (boolean on-card-read)))}
(when (not= on-card-connected :hardwallet/sign)
(when-not (contains? #{:hardwallet/sign
:hardwallet/verify-pin
:hardwallet/change-pin} on-card-connected)
(get-application-info pairing on-card-read))
(when (and on-card-connected
(not login?))
@ -1006,11 +1054,8 @@
(def on-init-card-success on-install-applet-and-init-card-success)
(defn- tag-lost-exception? [code]
(= code "android.nfc.TagLostException"))
(fx/defn process-error [{:keys [db] :as cofx} code]
(if (tag-lost-exception? code)
(fx/defn process-error [{:keys [db] :as cofx} code error]
(if (tag-lost-exception? code error)
(navigation/navigate-to-cofx cofx :hardwallet-connect nil)
{:db (assoc-in db [:hardwallet :setup-step] :error)}))
@ -1019,7 +1064,7 @@
(log/debug "[hardwallet] install applet and init card error: " error)
(fx/merge cofx
{:db (assoc-in db [:hardwallet :setup-error] error)}
(process-error code)))
(process-error code error)))
(def on-init-card-error on-install-applet-and-init-card-error)
@ -1062,7 +1107,7 @@
(assoc-in [:hardwallet :setup-error] (i18n/label :t/invalid-pairing-password))
(assoc-in [:hardwallet :on-card-connected] nil))}
(when (not= setup-step :enter-pair-code)
(process-error code)))))
(process-error code error)))))
(fx/defn on-generate-mnemonic-success
[{:keys [db]} mnemonic]
@ -1076,7 +1121,7 @@
(log/debug "[hardwallet] generate mnemonic error: " error)
(fx/merge cofx
{:db (assoc-in db [:hardwallet :setup-error] error)}
(process-error code)))
(process-error code error)))
(fx/defn recovery-phrase-start-confirmation [{:keys [db]}]
(let [mnemonic (get-in db [:hardwallet :secrets :mnemonic])
@ -1210,7 +1255,7 @@
(log/debug "[hardwallet] generate and load key error: " error)
(fx/merge cofx
{:db (assoc-in db [:hardwallet :setup-error] error)}
(process-error code)))
(process-error code error)))
(fx/defn on-get-keys-success
[{:keys [db] :as cofx} data]
@ -1244,14 +1289,19 @@
(let [tag-was-lost? (= "Tag was lost." (:error error))
instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
(if tag-was-lost?
{:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/tag-was-lost)}}
(fx/merge cofx
{:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}
:db (update-in db [:hardwallet :pin] merge {:status :error
:login []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin-login nil)))))
{:db (assoc-in db [:hardwallet :pin :status] nil)
:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/cannot-read-card)}}
(navigation/navigate-to-cofx :hardwallet-connect nil))
(if (re-matches pin-mismatch-error (:error error))
(fx/merge cofx
{:hardwallet/get-application-info {:pairing (get-pairing db instance-uid)}
:db (update-in db [:hardwallet :pin] merge {:status :error
:login []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin-login nil))
(show-wrong-keycard-alert cofx true)))))
(fx/defn send-transaction-with-signature
[_ data]
@ -1289,16 +1339,27 @@
:on-completed #(re-frame/dispatch [:wallet.callback/transaction-completed (types/json->clj %)])})
(sign-message-completed signature)))))
(def pin-mismatch-error #"Unexpected error SW, 0x63C\d+")
(fx/defn on-sign-error
[{:keys [db] :as cofx} error]
(log/debug "[hardwallet] sign error: " error)
(if (re-matches pin-mismatch-error (:error error))
(let [tag-was-lost? (= "Tag was lost." (:error error))
modal? (get-in db [:navigation/screen-params :wallet-send-modal-stack :modal?])]
(fx/merge cofx
{:db (update-in db [:hardwallet :pin] merge {:status :error
:sign []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx :enter-pin-sign nil)
(get-application-info (get-pairing db) nil))
(show-wrong-keycard-alert cofx true)))
(if tag-was-lost?
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :on-card-connected] :hardwallet/prepare-to-sign)
(assoc-in [:hardwallet :pin :status] nil))
:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/cannot-read-card)}}
(navigate-to-connect-screen :hardwallet-connect-sign)))
(if (re-matches pin-mismatch-error (:error error))
(fx/merge cofx
{:db (update-in db [:hardwallet :pin] merge {:status :error
:sign []
:error-label :t/pin-mismatch})}
(navigation/navigate-to-cofx (if modal?
:enter-pin-modal
:enter-pin-sign) nil)
(get-application-info (get-pairing db) nil))
(show-wrong-keycard-alert cofx true)))))

View File

@ -9,7 +9,8 @@
[status-im.ui.components.styles :as components.styles]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors]))
[status-im.ui.components.colors :as colors]
[status-im.ui.components.toolbar.actions :as toolbar.actions]))
(defview nfc-enabled []
(letsubs [card-read-in-progress? [:hardwallet/card-read-in-progress?]]
@ -48,7 +49,9 @@
:flex-direction :column
:justify-content :space-between}
[toolbar/toolbar {}
toolbar/default-nav-back
[toolbar/nav-button (assoc toolbar.actions/default-back
:handler
#(re-frame/dispatch [:hardwallet.ui/hardwallet-connect-navigate-back-button-clicked]))]
nil]
[react/view styles/hardwallet-connect
(if nfc-enabled?

View File

@ -132,7 +132,7 @@
nil
[toolbar/nav-button (assoc toolbar.actions/default-back
:handler
#(re-frame/dispatch [:hardwallet.ui/navigate-back-button-clicked]))]
#(re-frame/dispatch [:hardwallet.ui/enter-pin-navigate-back-button-clicked]))]
nil]
(if (zero? pin-retry-counter)
[pin-view {:pin pin

View File

@ -8,10 +8,7 @@
[status-im.react-native.resources :as resources]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.colors :as colors]
[status-im.ui.screens.hardwallet.components :as components]
[status-im.ui.screens.hardwallet.pin.views :as pin.views]
[status-im.ui.components.common.common :as components.common]
[reagent.core :as reagent]))
[status-im.ui.components.common.common :as components.common]))
(defn- action-row [{:keys [icon label on-press color-theme]}]
[react/touchable-highlight
@ -45,7 +42,8 @@
:size :large}]]))
(defn- reset-card-next-button [disabled?]
[react/view {:margin-right 18}
[react/view {:margin-right 18
:margin-bottom 15}
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:keycard-settings.ui/reset-card-next-button-pressed])
:disabled? disabled?
@ -75,7 +73,7 @@
:justify-content :space-between
:align-items :center
:width "100%"
:height 52
:height 68
:border-top-width 1
:border-color colors/gray-light}
[react/view {:flex 1}]
@ -127,7 +125,7 @@
:label :t/unpair-card
:on-press #(re-frame/dispatch [:keycard-settings.ui/unpair-card-pressed])}]])])]
(when pairing
[react/view {:margin-bottom 20
[react/view {:margin-bottom 35
:margin-left 16}
[action-row {:icon :main-icons/logout
:color-theme :red

View File

@ -413,17 +413,24 @@
(send-keycard-transaction cofx)
{:db (assoc-in db [:wallet :send-transaction :show-password-input?] true)}))))
(fx/defn keycard-hash-message
[_ data typed?]
(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 %)])}}))
(handlers/register-handler-fx
:wallet.ui/sign-message-button-clicked
(fn [{:keys [db]} [_ typed? screen-params password-error-cb]]
(fn [{:keys [db] :as cofx} [_ typed? screen-params password-error-cb]]
(let [{:keys [data from password]} screen-params
keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))]
keycard-account? (boolean (get-in db [:account/account :keycard-instance-uid]))
modal? (= (:view-id db) :wallet-sign-message-modal)]
(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 %)])}})
(fx/merge cofx
{:db (assoc-in db [:navigation/screen-params :wallet-send-modal-stack :modal?] modal?)}
(keycard-hash-message data typed?))
(if typed?
{::sign-typed-data {:data data
:password password

View File

@ -20,16 +20,20 @@
:confirmation []
:enter-step :original}}}}))))
(testing "confirmation entered"
(is (= {:db {:hardwallet {:pin {:original [1 2 3 4 5 6]
:confirmation [1 2 3 4 5 6]
:enter-step :confirmation
:status :verifying}}}
(is (= {:db {:hardwallet {:pin {:original [1 2 3 4 5 6]
:confirmation [1 2 3 4 5 6]
:current [1 1 1 1 1 1]
:enter-step :confirmation
:status :verifying}
:card-connected? true}}
:hardwallet/change-pin {:new-pin "123456"
:current-pin ""
:current-pin "111111"
:pairing nil}}
(hardwallet/process-pin-input {:db {:hardwallet {:pin {:original [1 2 3 4 5 6]
:confirmation [1 2 3 4 5 6]
:enter-step :confirmation}}}}))))
(hardwallet/process-pin-input {:db {:hardwallet {:pin {:original [1 2 3 4 5 6]
:confirmation [1 2 3 4 5 6]
:current [1 1 1 1 1 1]
:enter-step :confirmation}
:card-connected? true}}}))))
(testing "confirmation doesn't match"
(is (= {:db {:hardwallet {:pin {:original []

View File

@ -878,6 +878,7 @@
"cannot-use-default-pin": "PIN 000000 is not allowed.\nPlease use another number",
"pin-changed": "PIN has been changed",
"pin-retries-left": "You have {{number}} retries left",
"cannot-read-card": "Can't read card.\nPlease hold it to the back of your phone",
"keycard-blocked": "Keycard has been blocked.\nYou need to reset card to continue using it.",
"reset-card": "Reset card",
"reset-card-description": "This operation will reset card to initial state. It will erase all card data including private keys. Operation is not reversible.",
@ -892,7 +893,7 @@
"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.",
"keycard-unauthorized-operation": "You're unauthorized to perform this operation.\n Please tap valid card and try again.",
"no-account-on-card": "No account on this card",
"no-account-on-card-text": "The card you are presenting does not hold any account. Please try again with the right card",
"wrong-card": "Wrong card",