Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the PIN of the Keycard #22008

Merged
merged 1 commit into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions src/status_im/contexts/keycard/change_pin/events.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
(ns status-im.contexts.keycard.change-pin.events
(:require [status-im.contexts.keycard.utils :as utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))

(rf/reg-event-fx :keycard/change-pin.enter-current-pin
(fn [{:keys [db]}]
{:db (update db :keycard dissoc :change-pin)
:fx [[:dispatch [:navigate-back]]
[:dispatch
[:open-modal :screen/keycard.pin.enter
{:title (i18n/label :t/enter-current-keycard-pin)
:on-complete (fn [current-pin]
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/change-pin.save-current-pin current-pin])
(rf/dispatch [:keycard/change-pin.enter-new-pin]))}]]]}))

(rf/reg-event-fx :keycard/change-pin.save-current-pin
(fn [{:keys [db]} [pin]]
{:db (assoc-in db [:keycard :change-pin :current-pin] (security/mask-data pin))}))

(rf/reg-event-fx :keycard/change-pin.enter-new-pin
(fn [_]
{:fx [[:dispatch
[:open-modal :screen/keycard.pin.create
{:title (i18n/label :t/create-new-keycard-pin)
:repeat-stage-title (i18n/label :t/repeat-new-keycard-pin)
:on-complete (fn [new-pin]
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/change-pin.save-new-pin new-pin])
(rf/dispatch [:open-modal :screen/keycard.ready-to-change-pin]))}]]]}))

(rf/reg-event-fx :keycard/change-pin.save-new-pin
(fn [{:keys [db]} [pin]]
{:db (assoc-in db [:keycard :change-pin :new-pin] (security/mask-data pin))}))

(defn- change-pin-and-continue
[current-pin new-pin]
(rf/dispatch [:keycard/change-pin
{:on-success (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.pin-change-success]))
:on-failure (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:open-modal :screen/keycard.pin-change-failed]))
:current-pin current-pin
:new-pin new-pin}]))

(defn- verify-pin-and-continue
[current-pin new-pin]
(rf/dispatch
[:keycard/verify-pin
{:pin current-pin
:on-success #(change-pin-and-continue current-pin new-pin)
:on-failure (fn [error]
(when-not (utils/tag-lost? (:error error))
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:keycard/on-action-with-pin-error error])
(rf/dispatch [:keycard/change-pin.enter-current-pin])))}]))

(rf/reg-event-fx :keycard/change-pin.verify-current-pin-and-continue
(fn [{:keys [db]}]
(let [{:keys [current-pin new-pin]} (get-in db [:keycard :change-pin])
unmasked-current-pin (security/safe-unmask-data current-pin)
unmasked-new-pin (security/safe-unmask-data new-pin)]
{:fx [[:dispatch
[:keycard/connect
{:key-uid (get-in db [:profile/profile :key-uid])
:on-success #(verify-pin-and-continue unmasked-current-pin unmasked-new-pin)}]]]})))
82 changes: 82 additions & 0 deletions src/status_im/contexts/keycard/change_pin/view.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
(ns status-im.contexts.keycard.change-pin.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.contexts.keycard.common.view :as common.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))

(defn change-pin-confirmation-sheet
[]
[quo/documentation-drawers
{:title (i18n/label :t/change-pin-keycard)
:shell? true}
[rn/view
[quo/text {:size :paragraph-2}
(i18n/label :t/change-pin-keycard-message)]
[quo/bottom-actions
{:actions :two-actions
:container-style {:margin-horizontal -20}
:blur? true
:button-one-label (i18n/label :t/continue)
:button-one-props {:on-press #(rf/dispatch [:keycard/change-pin.enter-current-pin])}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:on-press events-helper/hide-bottom-sheet
:type :grey}}]]])

(defn ready-to-change-pin
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/ready-to-change-pin)}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is being duplicated too much. As of this PR, I see it duplicated 12 times across keycard namespaces. We can simply create a style namespace at contexts/keycard/ for example and reuse. Or even simpler have a common component using this style map and reuse it across keycard views.

Not a blocker for this PR, but I think we can do better in a subsequent PR.

[rn/image
{:resize-mode :contain}]]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/scan-keycard)
:button-one-props {:on-press #(rf/dispatch
[:keycard/change-pin.verify-current-pin-and-continue])}}]])

(defn pin-change-success
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard-pin-changed)
:description :text
:description-text (i18n/label :t/keycard-pin-changed-description)}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
[rn/image
{:resize-mode :contain}]]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/done)
:button-one-props {:on-press events-helper/navigate-back}}]])

(defn pin-change-failed
[]
[:<>
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (i18n/label :t/keycard-pin-change-failed)
:description :text
:description-text (i18n/label :t/keycard-pin-change-failed-description)}]
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
[rn/image
{:resize-mode :contain}]]
[common.view/tips]
[quo/bottom-actions
{:actions :one-action
:button-one-label (i18n/label :t/try-again)
:button-one-props {:on-press (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:open-modal :screen/keycard.ready-to-change-pin]))}}]])
4 changes: 4 additions & 0 deletions src/status_im/contexts/keycard/effects.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
(fn [args]
(keycard/verify-pin (keycard.utils/wrap-handlers args))))

(rf/reg-fx :effects.keycard/change-pin
(fn [args]
(keycard/change-pin (keycard.utils/wrap-handlers args))))

(rf/reg-fx :effects.keycard/sign
(fn [args]
(-> (keycard/sign args)
Expand Down
4 changes: 4 additions & 0 deletions src/status_im/contexts/keycard/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@
(fn [_ [data]]
{:effects.keycard/verify-pin data}))

(rf/reg-event-fx :keycard/change-pin
(fn [_ [data]]
{:effects.keycard/change-pin data}))

(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
{:fx [[:dispatch
Expand Down
15 changes: 14 additions & 1 deletion src/status_im/contexts/keycard/manage/profile_keys/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.contexts.keycard.backup.view :as backup.view]
[status-im.contexts.keycard.change-pin.view :as change-pin.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))

Expand All @@ -29,10 +30,22 @@
[quo/keycard {:holder-name ""}]]
[quo/section-label
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
[quo/settings-item
{:title (i18n/label :t/change-pin-keycard)
:image :icon
:blur? true
:image-props :i/keycard
:action :arrow
:description :text
:description-props {:text (i18n/label :t/change-pin-keycard-description)}
:on-press (fn []
(rf/dispatch [:show-bottom-sheet
{:content change-pin.view/change-pin-confirmation-sheet}]))}]
[quo/settings-item
{:title (i18n/label :t/backup-keycard)
:image :icon
:image-props :i/profile
:blur? true
:image-props :i/keycard
:action :arrow
:description :text
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
Expand Down
68 changes: 35 additions & 33 deletions src/status_im/contexts/keycard/pin/create/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,47 @@

(defn view
[]
(let [{:keys [on-complete]} (rf/sub [:get-screen-params])
[pin set-pin] (rn/use-state "")
[first-pin set-first-pin] (rn/use-state "")
[error? set-error] (rn/use-state false)
[stage set-stage] (rn/use-state :create)
pin-empty? (string/blank? pin)
on-delete (rn/use-callback
(fn []
(set-error false)
(if (= (count pin) 1)
(do
(set-pin "")
(set-stage :create))
(when (and pin (pos? (count pin)))
(set-pin (.slice pin 0 -1)))))
[pin])
on-press (rn/use-callback
(fn [new-symbol]
(let [new-pin (str pin new-symbol)]
(when (<= (count new-pin) constants/pincode-length)
(set-pin new-pin)
(when (= constants/pincode-length (count new-pin))
(if (= :repeat stage)
(if (= first-pin new-pin)
(on-complete new-pin)
(set-error true))
(do
(set-pin "")
(set-first-pin new-pin)
(set-stage :repeat)))))))
[pin stage first-pin])]
(let [{:keys [on-complete title repeat-stage-title]} (rf/sub [:get-screen-params])
[pin set-pin] (rn/use-state "")
[first-pin set-first-pin] (rn/use-state "")
[error? set-error] (rn/use-state false)
[stage set-stage] (rn/use-state :create)
pin-empty? (string/blank? pin)
on-delete (rn/use-callback
(fn []
(set-error false)
(if (= (count pin) 1)
(do
(set-pin "")
(set-stage :create))
(when (and pin (pos? (count pin)))
(set-pin (.slice pin 0 -1)))))
[pin])
on-press (rn/use-callback
(fn [new-symbol]
(let [new-pin (str pin new-symbol)]
(when (<= (count new-pin)
constants/pincode-length)
(set-pin new-pin)
(when (= constants/pincode-length
(count new-pin))
(if (= :repeat stage)
(if (= first-pin new-pin)
(on-complete new-pin)
(set-error true))
(do
(set-pin "")
(set-first-pin new-pin)
(set-stage :repeat)))))))
[pin stage first-pin])]
[rn/view {:style {:padding-bottom 12 :flex 1}}
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top
{:title (if (= :create stage)
(i18n/label :t/create-keycard-pin)
(i18n/label :t/repeat-keycard-pin))
(or title (i18n/label :t/create-keycard-pin))
(or repeat-stage-title (i18n/label :t/repeat-keycard-pin)))
:description :text
:description-text (i18n/label :t/pin-needed-login-sign)}]
[rn/view {:style {:flex 1 :justify-content :center :align-items :center :padding-vertical 34}}
Expand Down
4 changes: 2 additions & 2 deletions src/status_im/contexts/keycard/pin/enter/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

(defn view
[]
(let [{:keys [on-complete]} (rf/sub [:get-screen-params])]
(let [{:keys [on-complete title]} (rf/sub [:get-screen-params])]
[rn/view {:style {:padding-bottom 12 :flex 1}}
[quo/page-nav
{:icon-name :i/close
:on-press events-helper/navigate-back}]
[quo/page-top {:title (i18n/label :t/enter-keycard-pin)}]
[quo/page-top {:title (or title (i18n/label :t/enter-keycard-pin))}]
[keycard.pin/auth {:on-complete on-complete}]]))
1 change: 1 addition & 0 deletions src/status_im/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
status-im.contexts.communities.overview.events
status-im.contexts.communities.sharing.events
status-im.contexts.contact.blocking.events
status-im.contexts.keycard.change-pin.events
status-im.contexts.keycard.effects
status-im.contexts.keycard.events
status-im.contexts.keycard.feature-unavailable.events
Expand Down
6 changes: 3 additions & 3 deletions src/status_im/navigation/effects.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@
theme)})
options
(when sheet?
options/sheet-options))}}]}})))
(state/navigation-state-push {:id component
:type :modal})))
options/sheet-options))}}]}})
(state/navigation-state-push {:id component
:type :modal})))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did something change here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes,

Removed navigation state management code, except for one small instance, which I believe will help avoid potential bugs in the future (only push the modal to the state when opening it).


(rf/reg-fx :open-modal-fx open-modal)

Expand Down
19 changes: 19 additions & 0 deletions src/status_im/navigation/screens.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
[status-im.contexts.communities.overview.view :as communities.overview]
[status-im.contexts.keycard.authorise.view :as keycard.authorise]
[status-im.contexts.keycard.backup.view :as keycard.backup]
[status-im.contexts.keycard.change-pin.view :as keycard.change-pin]
[status-im.contexts.keycard.check.view :as keycard.check]
[status-im.contexts.keycard.create.view :as keycard.create]
[status-im.contexts.keycard.different-card.view :as keycard.different-card]
Expand Down Expand Up @@ -1032,6 +1033,24 @@
:modalPresentationStyle :fullScreen}
:component keycard.create/ready-to-add}

{:name :screen/keycard.ready-to-change-pin
:metrics {:track? true}
:options {:insets {:top? true :bottom? true}
:modalPresentationStyle :fullScreen}
:component keycard.change-pin/ready-to-change-pin}

{:name :screen/keycard.pin-change-success
:metrics {:track? true}
:options {:insets {:top? true :bottom? true}
:modalPresentationStyle :fullScreen}
:component keycard.change-pin/pin-change-success}

{:name :screen/keycard.pin-change-failed
:metrics {:track? true}
:options {:insets {:top? true :bottom? true}
:modalPresentationStyle :fullScreen}
:component keycard.change-pin/pin-change-failed}

{:name :screen/keycard.factory-reset.success
:metrics {:track? true}
:options {:theme :dark
Expand Down
Loading