diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fb30b4cad3..7568fe3fb1 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -270,7 +270,7 @@ PODS: - React - react-native-status (1.0.0): - React - - react-native-status-keycard (2.5.33): + - react-native-status-keycard (2.5.34): - Keycard - React - react-native-webview (10.9.2): @@ -628,7 +628,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: Keycard: - :commit: 36e260cfafc2755a47f1e5f542858ceb0c6c37df + :commit: 75c956d64a7d9fdf63e1aac9c2f36237e792c3eb :git: https://github.com/status-im/Keycard.swift.git secp256k1: :commit: 46a1fa30d9b8babeae85ff519050f42394ab5fcc @@ -679,7 +679,7 @@ SPEC CHECKSUMS: react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4 react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-status: 45dbf1302ce3c258b459dfab137cd1c2c68c295d - react-native-status-keycard: dac854029a37eabf04a8ede091ddeee71ab049b9 + react-native-status-keycard: efdf1a51fe36a8ca4741234c0c428ef25b73d162 react-native-webview: 4e96d493f9f90ba4f03b28933f30b2964df07e39 React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b diff --git a/src/status_im/keycard/card.cljs b/src/status_im/keycard/card.cljs index 7841da788d..7174adfd99 100644 --- a/src/status_im/keycard/card.cljs +++ b/src/status_im/keycard/card.cljs @@ -256,6 +256,24 @@ [:keycard.callback/on-change-pin-error (error-object->map response)]))}))) +(defn change-pairing [args] + (log/debug "[keycard] change-pairing") + (keycard/change-pairing + card + (merge + args + {:on-success + (fn [response] + (log/debug "[keycard response succ] change-pairing") + (re-frame/dispatch + [:keycard.callback/on-change-pairing-success response])) + :on-failure + (fn [response] + (log/debug "[keycard response fail] change-pairing") + (re-frame/dispatch + [:keycard.callback/on-change-pin-error + (error-object->map response)]))}))) + (defn unpair [args] (log/debug "[keycard] unpair") (keycard/unpair diff --git a/src/status_im/keycard/change_pin.cljs b/src/status_im/keycard/change_pin.cljs index 40eb9e388c..012b9dd96f 100644 --- a/src/status_im/keycard/change_pin.cljs +++ b/src/status_im/keycard/change_pin.cljs @@ -5,6 +5,7 @@ [status-im.utils.fx :as fx] [taoensso.timbre :as log] [status-im.keycard.common :as common] + [status-im.utils.security :as security] [status-im.keycard.login :as keycard.login])) (fx/defn change-credentials-pressed @@ -26,8 +27,9 @@ :status nil :error-label nil :on-verified (case changing - :pin :keycard/proceed-to-change-pin - :puk :keycard/proceed-to-change-puk)})} + :pin :keycard/proceed-to-change-pin + :puk :keycard/proceed-to-change-puk + :pairing :keycard/proceed-to-change-pairing)})} (common/navigate-to-enter-pin-screen))))) (fx/defn proceed-to-change-pin @@ -48,6 +50,11 @@ (assoc-in [:keycard :pin :status] nil))} (navigation/navigate-to-cofx :enter-pin-settings nil))) +(fx/defn proceed-to-change-pairing + {:events [:keycard/proceed-to-change-pairing]} + [{:keys [db] :as cofx}] + (navigation/navigate-to-cofx cofx :change-pairing-code nil)) + (fx/defn discard-pin-change {:events [::on-cancel]} [{:keys [db] :as cofx}] @@ -103,6 +110,32 @@ :keycard/change-puk {:puk puk :pin pin}})))})) +(fx/defn change-pairing + {:events [:keycard/change-pairing]} + [{:keys [db] :as cofx}] + (common/show-connection-sheet + cofx + {:sheet-options {:on-cancel [::on-cancel]} + :on-card-connected :keycard/change-pairing + :handler + (fn [{:keys [db] :as cofx}] + (let [pairing (get-in db [:keycard :pin :pairing-code]) + pin (common/vector->string + (get-in db [:keycard :pin :current]))] + (fx/merge + cofx + {:db (assoc-in db [:keycard :pin :status] :verifying) + :keycard/change-pairing {:pairing pairing + :pin pin}})))})) + +(fx/defn change-pairing-code + {:events [:keycard/change-pairing-code]} + [{:keys [db] :as cofx} pairing] + (fx/merge + cofx + {:db (assoc-in db [:keycard :pin :pairing-code] (security/unmask pairing))} + (change-pairing))) + (fx/defn on-change-pin-success {:events [:keycard.callback/on-change-pin-success]} [{:keys [db] :as cofx}] @@ -135,6 +168,18 @@ (common/hide-connection-sheet) (navigation/navigate-to-cofx :keycard-settings nil))) +(fx/defn on-change-pairing-success + {:events [:keycard.callback/on-change-pairing-success]} + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (assoc-in db [:keycard :pin] {:status nil + :pairing-code nil + :error-label nil}) + :utils/show-popup {:title "" + :content (i18n/label :t/pairing-changed)}} + (common/hide-connection-sheet) + (navigation/navigate-to-cofx :keycard-settings nil))) + (fx/defn on-change-pin-error {:events [:keycard.callback/on-change-pin-error]} [{:keys [db] :as cofx} error] diff --git a/src/status_im/keycard/fx.cljs b/src/status_im/keycard/fx.cljs index d12bf6ad67..14b72051ed 100644 --- a/src/status_im/keycard/fx.cljs +++ b/src/status_im/keycard/fx.cljs @@ -111,6 +111,10 @@ :keycard/change-puk card/change-puk) +(re-frame/reg-fx + :keycard/change-pairing + card/change-pairing) + (re-frame/reg-fx :keycard/unpair card/unpair) diff --git a/src/status_im/keycard/keycard.cljs b/src/status_im/keycard/keycard.cljs index 13d48eaaaf..39a49879bf 100644 --- a/src/status_im/keycard/keycard.cljs +++ b/src/status_im/keycard/keycard.cljs @@ -24,6 +24,7 @@ (verify-pin [this args]) (change-pin [this args]) (change-puk [this args]) + (change-pairing [this args]) (unpair [this args]) (delete [this args]) (remove-key [this args]) diff --git a/src/status_im/keycard/real_keycard.cljs b/src/status_im/keycard/real_keycard.cljs index a84e79e1a3..51566eb5ce 100644 --- a/src/status_im/keycard/real_keycard.cljs +++ b/src/status_im/keycard/real_keycard.cljs @@ -178,6 +178,14 @@ (then on-success) (catch on-failure)))) +(defn change-pairing + [{:keys [pin pairing on-success on-failure]}] + (when (and pin pairing) + (.. status-keycard + (changePairingPassword pin pairing) + (then on-success) + (catch on-failure)))) + (defn unpair [{:keys [pin on-success on-failure]}] (when (and pin) @@ -325,6 +333,8 @@ (change-pin args)) (keycard/change-puk [this args] (change-puk args)) + (keycard/change-pairing [this args] + (change-pairing args)) (keycard/unpair [this args] (unpair args)) (keycard/delete [this args] diff --git a/src/status_im/keycard/simulated_keycard.cljs b/src/status_im/keycard/simulated_keycard.cljs index afdb845ce7..6c9e389c41 100644 --- a/src/status_im/keycard/simulated_keycard.cljs +++ b/src/status_im/keycard/simulated_keycard.cljs @@ -261,6 +261,8 @@ (log/warn "change-pin not implemented" args)) (defn change-puk [args] (log/warn "change-puk not implemented" args)) +(defn change-pairing [args] + (log/warn "change-pairing not implemented" args)) (defn unpair [args] (log/warn "unpair not implemented" args)) (defn delete [args] @@ -484,6 +486,9 @@ (keycard/change-puk [this args] (log/debug "simulated card change-puk") (change-puk args)) + (keycard/change-pairing [this args] + (log/debug "simulated card change-pairing") + (change-pairing args)) (keycard/unpair [this args] (log/debug "simulated card unpair") (unpair args)) diff --git a/src/status_im/ui/screens/keycard/pairing/views.cljs b/src/status_im/ui/screens/keycard/pairing/views.cljs new file mode 100644 index 0000000000..3838484cff --- /dev/null +++ b/src/status_im/ui/screens/keycard/pairing/views.cljs @@ -0,0 +1,98 @@ +(ns status-im.ui.screens.keycard.pairing.views + (:require [re-frame.core :as re-frame] + [reagent.core :as reagent] + [status-im.ui.components.topbar :as topbar] + [status-im.ui.components.toolbar :as toolbar] + [status-im.i18n.i18n :as i18n] + [status-im.utils.security :as security] + [quo.react-native :as rn] + [quo.core :as quo])) + +(defn validate-pairing-code [pairing-code] + (>= (count pairing-code) 1)) + +(defn confirm-pairing-code [pairing-code confirm] + (= pairing-code confirm)) + +(defn change-pairing-code [] + (let [pairing-code (reagent/atom nil) + confirm (reagent/atom nil) + show-error (reagent/atom nil) + confirm-ref (atom nil)] + (fn [] + (let [valid-pairing-code (validate-pairing-code @pairing-code) + valid-form (confirm-pairing-code @pairing-code @confirm) + on-submit (fn [] + (if (and valid-pairing-code valid-form) + (do (reset! show-error false) + (re-frame/dispatch [:keycard/change-pairing-code @pairing-code])) + (reset! show-error true)))] + [rn/keyboard-avoiding-view {:flex 1} + [topbar/topbar + {:border-bottom false + :navigation + {:icon :main-icons/back + :accessibility-label :back-button + :on-press #(re-frame/dispatch [:navigate-to :keycard-settings])}}] + [rn/view {:style {:flex 1 + :justify-content :space-between + :padding-vertical 16 + :padding-horizontal 16}} + + [rn/view + [quo/text {:weight :bold + :align :center + :size :x-large} + (i18n/label :t/change-pairing-title)]] + [rn/view + [rn/view {:style {:padding 16}} + [quo/text-input {:secure-text-entry true + :auto-capitalize :none + :auto-focus true + :show-cancel false + :accessibility-label :password-input + :placeholder (i18n/label :t/pairing-code-placeholder) + :on-change-text #(reset! pairing-code (security/mask-data %)) + :return-key-type :next + :on-submit-editing #(when valid-pairing-code + (some-> ^js @confirm-ref .focus))}]] + [rn/view {:style {:padding 16 + :opacity (if-not valid-pairing-code 0.33 1)}} + [quo/text-input {:secure-text-entry true + :get-ref #(reset! confirm-ref %) + :auto-capitalize :none + :show-cancel false + :accessibility-label :password-input + :editable valid-pairing-code + :placeholder (i18n/label :t/confirm-pairing-code-placeholder) + :return-key-type :go + :error (when @show-error (i18n/label :t/pairing-code_error1)) + :blur-on-submit true + :on-focus #(reset! show-error false) + :on-submit-editing on-submit + :on-change-text #(do + (reset! confirm (security/mask-data %)) + (cond + (> (count @pairing-code) (count @confirm)) + (reset! show-error false) + + (not (confirm-pairing-code @pairing-code @confirm)) + (reset! show-error true) + + :else (reset! show-error false)))}]]] + [rn/view + [quo/text {:color :secondary + :align :center + :size :small} + (i18n/label :t/change-pairing-description)]]] + [toolbar/toolbar + {:show-border? true + :right [quo/button + {:on-press on-submit + :accessibility-label :onboarding-next-button + :disabled (or (nil? @confirm) + (not valid-pairing-code) + (not valid-form)) + :type :secondary + :after :main-icons/next} + (i18n/label :t/change-pairing)]}]])))) diff --git a/src/status_im/ui/screens/keycard/settings/views.cljs b/src/status_im/ui/screens/keycard/settings/views.cljs index 371eb9da55..2c202874d2 100644 --- a/src/status_im/ui/screens/keycard/settings/views.cljs +++ b/src/status_im/ui/screens/keycard/settings/views.cljs @@ -98,6 +98,11 @@ :title (i18n/label :t/change-puk) :accessibility-label "change-puk" :on-press #(re-frame/dispatch [:keycard-settings.ui/change-credentials-pressed :puk])}] + [quo/list-item {:icon :main-icons/password + :size :small + :title (i18n/label :t/change-pairing) + :accessibility-label "change-pairing" + :on-press #(re-frame/dispatch [:keycard-settings.ui/change-credentials-pressed :pairing])}] [quo/list-item {:icon :main-icons/keycard :size :small :title (i18n/label :t/keycard-backup) diff --git a/src/status_im/ui/screens/routing/profile_stack.cljs b/src/status_im/ui/screens/routing/profile_stack.cljs index 0ff74e03bb..899e983533 100644 --- a/src/status_im/ui/screens/routing/profile_stack.cljs +++ b/src/status_im/ui/screens/routing/profile_stack.cljs @@ -33,6 +33,7 @@ [status-im.ui.screens.fleet-settings.views :as fleet-settings] [status-im.ui.screens.profile.seed.views :as profile.seed] [status-im.ui.screens.keycard.pin.views :as keycard.pin] + [status-im.ui.screens.keycard.pairing.views :as keycard.pairing] [status-im.ui.screens.keycard.settings.views :as keycard.settings] [status-im.ui.components.tabbar.styles :as tabbar.styles] [status-im.ui.screens.routing.core :as navigation] @@ -134,4 +135,6 @@ {:name :keycard-pin :component keycard.settings/reset-pin} {:name :enter-pin-settings - :component keycard.pin/enter-pin}]]) + :component keycard.pin/enter-pin} + {:name :change-pairing-code + :component keycard.pairing/change-pairing-code}]]) diff --git a/translations/en.json b/translations/en.json index e6a828bd43..c9a7f8eac6 100644 --- a/translations/en.json +++ b/translations/en.json @@ -121,6 +121,9 @@ "change-password": "Change Password", "change-pin": "Change 6-digit passcode", "change-puk": "Change 12-digit PUK", + "change-pairing": "Change pairing code", + "change-pairing-title": "Create a new pairing code", + "change-pairing-description": "Changing the pairing code does not affect the current pairings. However, any new pairing will require the new code.", "changed-amount-warning": "Amount was changed from {{old}} to {{new}}", "changed-asset-warning": "Asset was changed from {{old}} to {{new}}", "chaos-mode": "Chaos mode", @@ -950,6 +953,9 @@ "paired-devices": "Paired devices", "pairing": "Pairing", "pairing-card": "Pairing card", + "pairing-code-placeholder":"Pairing code...", + "pairing-code_error1": "Pairing codes don't match.", + "confirm-pairing-code-placeholder": "Confirm your pairing code...", "pairing-go-to-installation": "Go to pairing settings", "pairing-maximum-number-reached-content": "Please disable one of your devices before enabling a new one.", "pairing-maximum-number-reached-title": "Max number of devices reached", @@ -973,6 +979,7 @@ "photos-access-error": "To grant the required photos permission, please go to your system settings and make sure that Status > Photos is selected.", "pin-changed": "6-digit passcode has been changed", "puk-changed": "12-digit PUK has been changed", + "pairing-changed": "Pairing code has been changed", "pin-code": "6-digit passcode", "pin-mismatch": "Wrong passcode", "pin-retries-left": "{{number}} attemps left",