From 03ec410862f3eb7562a5f34ee06bb662e1e16d50 Mon Sep 17 00:00:00 2001 From: flexsurfer Date: Tue, 5 Nov 2024 14:48:45 +0100 Subject: [PATCH] [#21446] Keycard - Current profile key pair migrate (#21558) [#21470] Keycard - Keycard initialized but has no keys --- .../contexts/keycard/migrate/events.cljs | 32 +++++-------- .../keycard/migrate/profile_keys/view.cljs | 34 ++++++++++++++ .../contexts/keycard/migrate/view.cljs | 15 ++++-- .../contexts/keycard/pin/create/view.cljs | 2 +- .../contexts/keycard/pin/enter/view.cljs | 18 ++++++++ src/status_im/navigation/screens.cljs | 46 ++++++++++--------- src/status_im/subs/keycard.cljs | 6 +++ translations/en.json | 6 +++ 8 files changed, 113 insertions(+), 46 deletions(-) create mode 100644 src/status_im/contexts/keycard/migrate/profile_keys/view.cljs create mode 100644 src/status_im/contexts/keycard/pin/enter/view.cljs diff --git a/src/status_im/contexts/keycard/migrate/events.cljs b/src/status_im/contexts/keycard/migrate/events.cljs index 29583cead3..cea2c1a41b 100644 --- a/src/status_im/contexts/keycard/migrate/events.cljs +++ b/src/status_im/contexts/keycard/migrate/events.cljs @@ -1,6 +1,5 @@ (ns status-im.contexts.keycard.migrate.events (:require [clojure.string :as string] - [status-im.contexts.keycard.pin.view :as keycard.pin] [utils.re-frame :as rf] [utils.security.core :as security])) @@ -11,12 +10,8 @@ {:key-uid (get-in db [:profile/profile :key-uid]) :on-success (fn [] - ;;TODO keys already on the keycard, new flow needs to be implemented - ;; https://github.com/status-im/status-mobile/issues/21446 (rf/dispatch [:keycard/disconnect]) - (rf/dispatch [:open-modal :screen/keycard.authorise - {:on-success - #(rf/dispatch [:keycard/migration.authorisation-success %])}])) + (rf/dispatch [:open-modal :screen/keycard.profile-keys])) :on-error (fn [error] (if (= error :keycard/error.keycard-blank) @@ -40,31 +35,27 @@ (fn [{:keys [db]}] (let [key-uid (get-in db [:profile/profile :key-uid]) {:keys [initialized? has-master-key?]} (get-in db [:keycard :application-info]) - {:keys [masked-phrase pin]} (get-in db [:keycard :migration]) - on-failure (fn [] - (rf/dispatch [:keycard/disconnect]) - (rf/dispatch [:navigate-to - :screen/keycard.migrate.fail]))] + {:keys [masked-phrase pin]} (get-in db [:keycard :migration])] + (cond (not initialized?) {:fx [[:keycard/init-card {:pin pin - :on-success #(get-application-info-and-continue key-uid) - :on-failure on-failure}]]} + :on-success #(get-application-info-and-continue key-uid)}]]} (not has-master-key?) {:fx [[:effects.keycard/generate-and-load-key {:mnemonic (security/safe-unmask-data masked-phrase) :pin pin :on-success #(get-application-info-and-continue key-uid) - :on-failure on-failure}]]} + :on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]} :else {:fx [[:effects.keycard/get-keys {:pin pin :on-success #(rf/dispatch [:keycard/migration.convert-to-keycard-profile %]) - :on-failure on-failure}]]})))) + :on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]})))) (rf/reg-event-fx :keycard/migration.start (fn [{:keys [db]}] @@ -115,11 +106,7 @@ {:db (assoc-in db [:keycard :migration :masked-password] masked-password) :fx [[:dispatch [:navigate-back]] (if initialized? - [:dispatch - [:show-bottom-sheet - {:content (fn [] - [keycard.pin/auth - {:on-complete #(rf/dispatch [:keycard/migration.pin-created %])}])}]] + [:dispatch [:open-modal :screen/keycard.migrate]] [:dispatch [:open-modal :screen/keycard.pin.create {:on-complete (fn [new-pin] @@ -130,3 +117,8 @@ (fn [{:keys [db]} [pin]] {:db (assoc-in db [:keycard :migration :pin] pin) :fx [[:dispatch [:open-modal :screen/keycard.migrate]]]})) + +(rf/reg-event-fx :keycard/migration.pin-entered + (fn [{:keys [db]} [pin]] + {:db (assoc-in db [:keycard :migration :pin] pin) + :fx [[:dispatch [:keycard/migration.start]]]})) diff --git a/src/status_im/contexts/keycard/migrate/profile_keys/view.cljs b/src/status_im/contexts/keycard/migrate/profile_keys/view.cljs new file mode 100644 index 0000000000..c0488057aa --- /dev/null +++ b/src/status_im/contexts/keycard/migrate/profile_keys/view.cljs @@ -0,0 +1,34 @@ +(ns status-im.contexts.keycard.migrate.profile-keys.view + (:require [quo.core :as quo] + [react-native.core :as rn] + [status-im.common.events-helper :as events-helper] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn view + [] + [:<> + [quo/page-nav + {:icon-name :i/close + :on-press events-helper/navigate-back}] + [quo/page-top + {:title (i18n/label :t/keycard-contains-key-pair) + :description :text + :description-text (i18n/label :t/finalise-migration-instructions)}] + [rn/view {:style {:margin-horizontal 20}} + [rn/view {:style {:padding-top 8 :padding-bottom 20}} + [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/finalise-migration) + :image :icon + :image-props :i/profile + :action :arrow + :description :text + :description-props {:text (i18n/label :t/use-keycard-instead-password)} + :on-press (fn [] + (rf/dispatch [:navigate-back]) + (rf/dispatch [:open-modal :screen/keycard.authorise + {:on-success + #(rf/dispatch [:keycard/migration.authorisation-success + %])}]))}]]]) diff --git a/src/status_im/contexts/keycard/migrate/view.cljs b/src/status_im/contexts/keycard/migrate/view.cljs index 8ed7058572..aef01f0ff6 100644 --- a/src/status_im/contexts/keycard/migrate/view.cljs +++ b/src/status_im/contexts/keycard/migrate/view.cljs @@ -10,7 +10,8 @@ [] (let [profile-name (rf/sub [:profile/name]) profile-picture (rf/sub [:profile/image]) - customization-color (rf/sub [:profile/customization-color])] + customization-color (rf/sub [:profile/customization-color]) + initialized? (rf/sub [:keycard/initialized?])] [:<> [quo/page-nav {:icon-name :i/close @@ -30,5 +31,13 @@ [quo/markdown-list {:description (i18n/label :t/keep-card-steady)}] [quo/bottom-actions {:actions :one-action - :button-one-label (i18n/label :t/scan-keycard) - :button-one-props {:on-press #(rf/dispatch [:keycard/migration.start])}}]])) + :button-one-label (if initialized? (i18n/label :t/enter-keycard-pin) (i18n/label :t/scan-keycard)) + :button-one-props {:on-press + (fn [] + (if initialized? + (do + (rf/dispatch [:navigate-back]) + (rf/dispatch [:open-modal :screen/keycard.pin.enter + {:on-complete #(rf/dispatch + [:keycard/migration.pin-entered %])}])) + (rf/dispatch [:keycard/migration.start])))}}]])) diff --git a/src/status_im/contexts/keycard/pin/create/view.cljs b/src/status_im/contexts/keycard/pin/create/view.cljs index e54a81ec24..fbb9fd7827 100644 --- a/src/status_im/contexts/keycard/pin/create/view.cljs +++ b/src/status_im/contexts/keycard/pin/create/view.cljs @@ -49,7 +49,7 @@ (i18n/label :t/create-keycard-pin) (i18n/label :t/repeat-keycard-pin)) :description :text - :description-text "You’ll need this PIN to login and sign transactions"}] + :description-text (i18n/label :t/pin-needed-login-sign)}] [rn/view {:style {:flex 1 :justify-content :center :align-items :center :padding-vertical 34}} [quo/pin-input {:blur? false diff --git a/src/status_im/contexts/keycard/pin/enter/view.cljs b/src/status_im/contexts/keycard/pin/enter/view.cljs new file mode 100644 index 0000000000..edbeb183bb --- /dev/null +++ b/src/status_im/contexts/keycard/pin/enter/view.cljs @@ -0,0 +1,18 @@ +(ns status-im.contexts.keycard.pin.enter.view + (:require [quo.core :as quo] + [react-native.core :as rn] + [status-im.common.events-helper :as events-helper] + [status-im.contexts.keycard.pin.view :as keycard.pin] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn view + [] + (let [{:keys [on-complete]} (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)}] + [rn/view {:style {:flex 1}}] + [keycard.pin/auth {:on-complete on-complete}]])) diff --git a/src/status_im/navigation/screens.cljs b/src/status_im/navigation/screens.cljs index ede4b2e818..7a19c7950c 100644 --- a/src/status_im/navigation/screens.cljs +++ b/src/status_im/navigation/screens.cljs @@ -33,11 +33,13 @@ [status-im.contexts.keycard.empty.view :as keycard.empty] [status-im.contexts.keycard.error.view :as keycard.error] [status-im.contexts.keycard.migrate.fail.view :as keycard.migrate.fail] + [status-im.contexts.keycard.migrate.profile-keys.view :as keycard.migrate.profile-keys] [status-im.contexts.keycard.migrate.re-encrypting.view :as keycard.re-encrypting] [status-im.contexts.keycard.migrate.success.view :as keycard.migrate.success] [status-im.contexts.keycard.migrate.view :as keycard.migrate] [status-im.contexts.keycard.not-keycard.view :as keycard.not-keycard] - [status-im.contexts.keycard.pin.create.view :as pin.create] + [status-im.contexts.keycard.pin.create.view :as keycard.pin.create] + [status-im.contexts.keycard.pin.enter.view :as keycard.pin.enter] [status-im.contexts.onboarding.create-or-sync-profile.view :as create-or-sync-profile] [status-im.contexts.onboarding.create-password.view :as create-password] [status-im.contexts.onboarding.create-profile.view :as create-profile] @@ -883,44 +885,37 @@ (def keycard-screens [{:name :screen/keycard.check - :metrics {:track? :true - :alias-id :keycard.check} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} :component keycard.check/view} {:name :screen/keycard.empty - :metrics {:track? :true - :alias-id :keycard.empty} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} :component keycard.empty/view} {:name :screen/keycard.error - :metrics {:track? :true - :alias-id :keycard.error} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} :component keycard.error/view} {:name :screen/keycard.not-keycard - :metrics {:track? :true - :alias-id :keycard.not-keycard} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} :component keycard.not-keycard/view} {:name :screen/keycard.authorise - :metrics {:track? :true - :alias-id :keycard.authorise} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} :component keycard.authorise/view} {:name :screen/keycard.migrate - :metrics {:track? :true - :alias-id :keycard.migrate} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} :component keycard.migrate/view} {:name :screen/keycard.re-encrypting - :metrics {:track? :true - :alias-id :keycard.re-encrypting} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true} :popGesture false :hardwareBackButton {:dismissModalOnPress false @@ -928,8 +923,7 @@ :component keycard.re-encrypting/view} {:name :screen/keycard.migrate.success - :metrics {:track? :true - :alias-id :keycard.migrate.success} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true} :popGesture false :hardwareBackButton {:dismissModalOnPress false @@ -937,8 +931,7 @@ :component keycard.migrate.success/view} {:name :screen/keycard.migrate.fail - :metrics {:track? :true - :alias-id :keycard.migrate.fail} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true} :popGesture false :hardwareBackButton {:dismissModalOnPress false @@ -946,10 +939,19 @@ :component keycard.migrate.fail/view} {:name :screen/keycard.pin.create - :metrics {:track? :true - :alias-id :keycard.pin.create} + :metrics {:track? :true} :options {:insets {:top? true :bottom? true}} - :component pin.create/view}]) + :component keycard.pin.create/view} + + {:name :screen/keycard.pin.enter + :metrics {:track? :true} + :options {:insets {:top? true :bottom? true}} + :component keycard.pin.enter/view} + + {:name :screen/keycard.profile-keys + :metrics {:track? :true} + :options {:insets {:top? true :bottom? true}} + :component keycard.migrate.profile-keys/view}]) (defn screens [] diff --git a/src/status_im/subs/keycard.cljs b/src/status_im/subs/keycard.cljs index 245d3a5434..2fd2e29670 100644 --- a/src/status_im/subs/keycard.cljs +++ b/src/status_im/subs/keycard.cljs @@ -41,3 +41,9 @@ :<- [:keycard] (fn [keycard] (:application-info-error keycard))) + +(rf/reg-sub + :keycard/initialized? + :<- [:keycard] + (fn [keycard] + (get-in keycard [:application-info :initialized?]))) diff --git a/translations/en.json b/translations/en.json index 96647a2cb5..f9e70ed8fa 100644 --- a/translations/en.json +++ b/translations/en.json @@ -965,6 +965,7 @@ "enter-chat-key": "Enter chat key or scan a QR", "enter-contact-code": "ENS (vitalik94) or chat key (0x04…)", "enter-eth": "Enter any ETH address or ENS name.", + "enter-keycard-pin": "Enter Keycard PIN", "enter-pair-code": "Enter your pairing code", "enter-pair-code-description": "Pairing code can be set from an already paired Status client", "enter-password": "Enter password", @@ -1033,6 +1034,8 @@ "fetch-timeline": "↓ Fetch", "fetching-community": "Fetching community...", "fetching-the-price-took-longer-than-expected": "Fetching the price took longer than expected.\nPlease, try again later.", + "finalise-migration": "Finalise migration", + "finalise-migration-instructions": "Finalise migration to use this Keycard for logging in and signing transactions on this device", "finalized-on": "Finalized on", "find": "Find", "find-it-in-setting": "Find it in Settings on your other synced device", @@ -1339,6 +1342,7 @@ "keycard-cancel-setup-title": "Dangerous operation", "keycard-connected-description": "Try keeping the card still", "keycard-connected-title": "Connected", + "keycard-contains-key-pair": "Keycard contains your profile key pair", "keycard-desc": "Own a Keycard? Store your keys on it; you’ll need it for transactions", "keycard-dont-ask-card": "Don't ask for card to sign in", "keycard-empty": "Keycard is empty", @@ -1945,6 +1949,7 @@ "pin-code": "6-digit passcode", "pin-limit-reached": "Pin limit reached. Unpin a previous message first.", "pin-mismatch": "Wrong passcode", + "pin-needed-login-sign": "You’ll need this PIN to login and sign transactions", "pin-not-match": "PIN do not match", "pin-one-attempt": " one attempt ", "pin-one-attempt-blocked-after": "before your Keycard gets blocked", @@ -2678,6 +2683,7 @@ "use-biometrics": "Use biometrics to fill in your password", "use-keycard": "Use Keycard", "use-keycard-for-status": "From now on, use this Keycard to login to Status and transact with derived accounts on all synced devices. To start using it, logout and log back in with this Keycard.", + "use-keycard-instead-password": "To use Keycard instead of password", "use-keycard-login-sign": "Use this Keycard to login and sign transactions", "use-keycard-subtitle": "Keys will be stored on your Keycard", "use-photo": "Use Photo",