This commit is contained in:
parent
9862abb7eb
commit
f0079961f4
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
|
@ -3,8 +3,7 @@
|
|||
["react-native" :as rn]
|
||||
["react-native-status-keycard" :default status-keycard]
|
||||
[react-native.platform :as platform]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]))
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defonce event-emitter
|
||||
(if platform/ios?
|
||||
|
@ -94,22 +93,14 @@
|
|||
[{:keys [on-success on-failure]}]
|
||||
(.. status-keycard
|
||||
(getApplicationInfo)
|
||||
(then (fn [response]
|
||||
(let [info (-> response
|
||||
(js->clj :keywordize-keys true)
|
||||
(update :key-uid address/normalized-hex))]
|
||||
(on-success info))))
|
||||
(then on-success)
|
||||
(catch on-failure)))
|
||||
|
||||
(defn factory-reset
|
||||
[{:keys [on-success on-failure]}]
|
||||
(.. status-keycard
|
||||
(factoryReset)
|
||||
(then (fn [response]
|
||||
(let [info (-> response
|
||||
(js->clj :keywordize-keys true)
|
||||
(update :key-uid address/normalized-hex))]
|
||||
(on-success info))))
|
||||
(then on-success)
|
||||
(catch on-failure)))
|
||||
|
||||
(defn install-applet
|
||||
|
@ -155,6 +146,13 @@
|
|||
(then on-success)
|
||||
(catch on-failure)))
|
||||
|
||||
(defn save-mnemonic
|
||||
[{:keys [mnemonic pin on-success on-failure]}]
|
||||
(.. status-keycard
|
||||
(saveMnemonic mnemonic pin)
|
||||
(then on-success)
|
||||
(catch on-failure)))
|
||||
|
||||
(defn unblock-pin
|
||||
[{:keys [puk new-pin on-success on-failure]}]
|
||||
(when (and new-pin puk)
|
||||
|
|
|
@ -508,17 +508,16 @@
|
|||
new-password-hashed
|
||||
callback))))
|
||||
|
||||
(defn convert-to-keycard-account
|
||||
[{:keys [key-uid] :as multiaccount-data} settings current-password# new-password callback]
|
||||
(log/debug "[native-module] convert-to-keycard-account")
|
||||
(defn convert-to-keycard-profile
|
||||
[{:keys [key-uid] :as profile} settings password new-password callback]
|
||||
(.convertToKeycardAccount ^js (encryption)
|
||||
key-uid
|
||||
(types/clj->json multiaccount-data)
|
||||
(types/clj->json profile)
|
||||
(types/clj->json settings)
|
||||
""
|
||||
current-password#
|
||||
(:keycard-instance-uid settings)
|
||||
password
|
||||
new-password
|
||||
callback))
|
||||
#(when callback (callback (types/json->clj %)))))
|
||||
|
||||
(defn backup-disabled-data-dir
|
||||
[]
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"
|
||||
[{:keys [holder-name locked?]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
label (if (boolean holder-name)
|
||||
label (if holder-name
|
||||
(i18n/label :t/user-keycard {:name holder-name})
|
||||
(i18n/label :t/empty-keycard))]
|
||||
[rn/view {:style (style/card-container locked? theme)}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
(defn container
|
||||
[container-style]
|
||||
(merge container-style
|
||||
{:flex-direction :row
|
||||
:align-items :flex-start}))
|
||||
{:padding-vertical 7
|
||||
:padding-horizontal 20
|
||||
:flex-direction :row
|
||||
:align-items :flex-start}))
|
||||
|
||||
(def index
|
||||
{:margin-left 5})
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
:or {type :bullet}}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view {:style (style/container container-style)}
|
||||
[rn/view {:style style/index}
|
||||
[rn/view
|
||||
(case type
|
||||
:step
|
||||
[step/view
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
(def header
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:height 32})
|
||||
:justify-content :space-between})
|
||||
|
||||
(def header-title
|
||||
{:flex 1
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
[rn/view {:style (merge style/container container-style)}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:number-of-lines 1
|
||||
:weight :semi-bold
|
||||
:style style/text
|
||||
:accessibility-label accessibility-label}
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
:margin-bottom 8})
|
||||
|
||||
(def item-text
|
||||
{:margin-top 10
|
||||
:margin-left -4})
|
||||
{:margin-left -24})
|
||||
|
||||
(def info-text
|
||||
{:margin-top -5})
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
:qr-code (js/require "../resources/images/ui2/qr-code.png")
|
||||
:keycard-logo (js/require "../resources/images/ui2/keycard-logo.png")
|
||||
:keycard-watermark (js/require "../resources/images/ui2/keycard-watermark.png")
|
||||
:keycard-buy (js/require "../resources/images/ui2/keycard-buy.png")
|
||||
:keycard-migration (js/require "../resources/images/ui2/keycard-migration.png")
|
||||
:keycard-migration-failed (js/require "../resources/images/ui2/keycard-migration-failed.png")
|
||||
:keycard-migration-succeeded (js/require "../resources/images/ui2/keycard-migration-succeeded.png")
|
||||
:not-keycard (js/require "../resources/images/ui2/not-keycard.png")
|
||||
:discover (js/require "../resources/images/ui2/discover.png")
|
||||
:invite-friends (js/require "../resources/images/ui2/invite-friends.png")
|
||||
:transaction-progress (js/require "../resources/images/ui2/transaction-progress.png")
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
(ns status-im.common.standard-authentication.enter-password.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.standard-authentication.core :as standard-authentication]
|
||||
[status-im.common.standard-authentication.enter-password.style :as style]
|
||||
[status-im.common.standard-authentication.password-input.view :as password-input]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
@ -31,11 +32,12 @@
|
|||
:full-name (profile.utils/displayed-name profile)
|
||||
:customization-color customization-color
|
||||
:size 24}]]
|
||||
[password-input/view
|
||||
[standard-authentication/password-input
|
||||
{:on-press-biometrics on-press-biometrics
|
||||
:blur? true
|
||||
:processing processing
|
||||
:error error
|
||||
:error {:error? (not (string/blank? error))
|
||||
:error-message error}
|
||||
:default-password password
|
||||
:sign-in-enabled? sign-in-enabled?}]
|
||||
[quo/button
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.common.standard-authentication.password-input.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
|
@ -12,14 +11,6 @@
|
|||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- get-error-message
|
||||
[error]
|
||||
(if (and (some? error)
|
||||
(or (= error "file is not a database")
|
||||
(string/starts-with? (string/lower-case error) "failed")))
|
||||
(i18n/label :t/oops-wrong-password)
|
||||
error))
|
||||
|
||||
(defn- error-info
|
||||
[error-message processing shell?]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
|
@ -49,21 +40,21 @@
|
|||
(i18n/label :t/forgot-password)]]]))
|
||||
|
||||
(defn view
|
||||
[{:keys [shell? on-press-biometrics blur?]}]
|
||||
(let [{:keys [error processing]} (rf/sub [:profile/login])
|
||||
error-message (rn/use-memo #(get-error-message error) [error])
|
||||
error? (boolean (seq error-message))
|
||||
default-value (rn/use-ref-atom "") ;;bug on Android
|
||||
;;https://github.com/status-im/status-mobile/issues/19004
|
||||
theme (quo.theme/use-theme)
|
||||
on-change-password (rn/use-callback
|
||||
(fn [entered-password]
|
||||
(reset! default-value entered-password)
|
||||
(debounce/debounce-and-dispatch [:profile/on-password-input-changed
|
||||
{:password (security/mask-data
|
||||
entered-password)
|
||||
:error ""}]
|
||||
100)))]
|
||||
[{:keys [shell? on-press-biometrics blur? processing error]}]
|
||||
(let [{:keys [error?
|
||||
error-message]} error
|
||||
default-value (rn/use-ref-atom "") ;;bug on Android
|
||||
;;https://github.com/status-im/status-mobile/issues/19004
|
||||
theme (quo.theme/use-theme)
|
||||
on-change-password (rn/use-callback
|
||||
(fn [entered-password]
|
||||
(reset! default-value entered-password)
|
||||
(debounce/debounce-and-dispatch
|
||||
[:profile/on-password-input-changed
|
||||
{:password (security/mask-data
|
||||
entered-password)
|
||||
:error ""}]
|
||||
100)))]
|
||||
[:<>
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[quo/input
|
||||
|
|
|
@ -580,13 +580,14 @@
|
|||
(def ^:const sheet-screen-handle-height 20)
|
||||
|
||||
(def ^:const status-hostname "status.app")
|
||||
(def ^:const get-keycard-url "https://get.keycard.tech/")
|
||||
|
||||
(def ^:const community-joined-notification-type "communityJoined")
|
||||
|
||||
(def ^:const default-telemetry-server-url "https://telemetry.status.im")
|
||||
|
||||
(def ^:const contact-item-height 56)
|
||||
|
||||
(def ^:const page-nav-height 56)
|
||||
(def ^:const currency-item-height 64)
|
||||
|
||||
(def ^:const slippages [0.1 0.5 1])
|
||||
|
|
|
@ -4,20 +4,18 @@
|
|||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
{:keys [on-success]} (rf/sub [:get-screen-params])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/authorise-with-password)
|
||||
:description :context-tag
|
||||
|
@ -31,5 +29,5 @@
|
|||
:container-style {}
|
||||
:customization-color customization-color
|
||||
:track-text (i18n/label :t/slide-to-authorise)
|
||||
:on-auth-success #(println "TBD" (security/safe-unmask-data %))
|
||||
:on-auth-success #(when on-success (on-success %))
|
||||
:auth-button-label (i18n/label :t/confirm)}]]]))
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/check-keycard)
|
||||
:description :text
|
||||
|
@ -23,14 +21,9 @@
|
|||
{:resize-mode :contain
|
||||
:source (resources/get-image :check-your-keycard)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[rn/view {:style {:padding-horizontal 10}}
|
||||
[quo/markdown-list
|
||||
{:container-style {:padding-vertical 10}
|
||||
:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list
|
||||
{:container-style {:padding-bottom 25}
|
||||
:description (i18n/label :t/keep-card-steady)}]]
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:keycard/connect])
|
||||
:container-style {:margin-horizontal 20}}
|
||||
(i18n/label :t/ready-to-scan)]])
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/migration.check-empty-card])}}]])
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
[native-module.core :as native-module]
|
||||
[react-native.async-storage :as async-storage]
|
||||
[react-native.platform :as platform]
|
||||
status-im.contexts.keycard.nfc.effects
|
||||
[status-im.contexts.keycard.utils :as keycard.utils]
|
||||
[status-im.contexts.profile.config :as profile.config]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as transforms]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defonce ^:private active-listeners (atom []))
|
||||
|
||||
|
@ -32,106 +32,45 @@
|
|||
(rf/reg-fx :effects.keycard/register-card-events register-card-events)
|
||||
(rf/reg-fx :effects.keycard/unregister-card-events unregister-card-events)
|
||||
|
||||
(defn check-nfc-enabled
|
||||
[]
|
||||
(log/debug "[keycard] check-nfc-enabled")
|
||||
(keycard/check-nfc-enabled
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response] check-nfc-enabled")
|
||||
(rf/dispatch [:keycard/on-check-nfc-enabled-success response]))}))
|
||||
(rf/reg-fx :effects.keycard/check-nfc-enabled check-nfc-enabled)
|
||||
(rf/reg-fx :effects.keycard/get-application-info
|
||||
(fn [args]
|
||||
(keycard/get-application-info (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/get-keys
|
||||
(fn [args]
|
||||
(keycard/get-keys (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign
|
||||
(fn [args]
|
||||
(keycard/sign (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :keycard/init-card
|
||||
(fn [args]
|
||||
(keycard/init-card (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/generate-and-load-key
|
||||
(fn [args]
|
||||
(keycard/generate-and-load-key (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/login-with-keycard
|
||||
(fn [{:keys [key-uid password whisper-private-key]}]
|
||||
(native-module/login-account
|
||||
(assoc (profile.config/login)
|
||||
:keyUid key-uid
|
||||
:password password
|
||||
:keycardWhisperPrivateKey whisper-private-key))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/set-pairing-to-keycard
|
||||
(fn [pairings]
|
||||
(keycard/set-pairings pairings)))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.keycard.ios/start-nfc
|
||||
(fn [args]
|
||||
(log/debug "fx start-nfc")
|
||||
(keycard/start-nfc args)))
|
||||
:keycard/persist-pairings
|
||||
(fn [pairings]
|
||||
(async-storage/set-item! "status-keycard-pairings" pairings)))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.keycard.ios/stop-nfc
|
||||
(fn [args]
|
||||
(log/debug "fx stop-nfc")
|
||||
(keycard/stop-nfc args)))
|
||||
|
||||
(defn- error-object->map
|
||||
[^js object]
|
||||
{:code (.-code object)
|
||||
:error (.-message object)})
|
||||
|
||||
(defn get-application-info
|
||||
[{:keys [on-success on-failure] :as args}]
|
||||
(log/debug "[keycard] get-application-info")
|
||||
(keycard/get-application-info
|
||||
(assoc
|
||||
args
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] get-application-info")
|
||||
(when on-success
|
||||
(on-success response)))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/error "[keycard response fail] get-application-info")
|
||||
(when on-failure
|
||||
(on-failure (error-object->map response)))))))
|
||||
(rf/reg-fx :effects.keycard/get-application-info get-application-info)
|
||||
|
||||
(defn get-keys
|
||||
[{:keys [on-success on-failure] :as args}]
|
||||
(log/debug "[keycard] get-keys")
|
||||
(keycard/get-keys
|
||||
(assoc
|
||||
args
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] get-keys")
|
||||
(when on-success
|
||||
(on-success (transforms/js->clj response))))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/warn "[keycard response fail] get-keys"
|
||||
(error-object->map response))
|
||||
(when on-failure
|
||||
(on-failure (error-object->map response)))))))
|
||||
(rf/reg-fx :effects.keycard/get-keys get-keys)
|
||||
|
||||
(defn login
|
||||
[{:keys [key-uid password whisper-private-key]}]
|
||||
(native-module/login-account
|
||||
(assoc (profile.config/login)
|
||||
:keyUid key-uid
|
||||
:password password
|
||||
:keycardWhisperPrivateKey whisper-private-key)))
|
||||
(rf/reg-fx :effects.keycard/login-with-keycard login)
|
||||
|
||||
(defn retrieve-pairings
|
||||
[]
|
||||
(async-storage/get-item
|
||||
"status-keycard-pairings"
|
||||
#(rf/dispatch [:keycard/on-retrieve-pairings-success %])))
|
||||
(rf/reg-fx :effects.keycard/retrieve-pairings retrieve-pairings)
|
||||
|
||||
(defn set-pairing-to-keycard
|
||||
[pairings]
|
||||
(keycard/set-pairings pairings))
|
||||
(rf/reg-fx :effects.keycard/set-pairing-to-keycard set-pairing-to-keycard)
|
||||
|
||||
(defn sign
|
||||
[{:keys [on-success on-failure] :as args}]
|
||||
(log/debug "[keycard] sign")
|
||||
(keycard/sign
|
||||
(assoc
|
||||
args
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] sign")
|
||||
(when on-success
|
||||
(on-success (transforms/js->clj response))))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/warn "[keycard response fail] sign"
|
||||
(error-object->map response))
|
||||
(when on-failure
|
||||
(on-failure (error-object->map response)))))))
|
||||
(rf/reg-fx :effects.keycard/sign sign)
|
||||
(rf/reg-fx :effects.keycard/retrieve-pairings
|
||||
(fn []
|
||||
(async-storage/get-item
|
||||
"status-keycard-pairings"
|
||||
#(rf/dispatch [:keycard/on-retrieve-pairings-success %]))))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.keycard.sheets.migrate.view :as sheets.migrate]
|
||||
[status-im.contexts.keycard.migrate.sheets.view :as sheets.migrate]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -11,10 +11,8 @@
|
|||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-empty)
|
||||
:description :text
|
||||
|
@ -26,10 +24,15 @@
|
|||
:subtitle (i18n/label :t/use-keycard-login-sign)
|
||||
:button-label (i18n/label :t/import-profile-key-pair)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :generate-keys)
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:theme :dark
|
||||
:content (fn [] [sheets.migrate/view])}])}]]
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press (fn []
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:theme :dark
|
||||
:content (fn []
|
||||
[sheets.migrate/view
|
||||
{:on-continue #(rf/dispatch
|
||||
[:keycard/migration.get-phrase])}])}]))}]]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 32 :margin-horizontal 28}}
|
||||
|
|
|
@ -1,42 +1,37 @@
|
|||
(ns status-im.contexts.keycard.error.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def titles
|
||||
{:keycard/error.keycard-wrong {:title "Keycard is not empty"
|
||||
:description "You can’t use it to store new keys right now"}
|
||||
:keycard/error.keycard-unpaired {:title "Keycard is full"
|
||||
:description "All pairing slots are occupied"}
|
||||
:keycard/error.keycard-frozen {:title "Keycard is locked"
|
||||
:description "You can’t use it right now"}
|
||||
:keycard/error.keycard-locked {:title "Keycard is locked"
|
||||
:description "You can’t use it right now"}})
|
||||
{:keycard/error.keycard-blank {:title (i18n/label :t/keycard-empty)
|
||||
:description (i18n/label :t/no-key-pair-keycard)}
|
||||
:keycard/error.keycard-wrong-profile {:title (i18n/label :t/keycard-not-empty)
|
||||
:description (i18n/label :t/cant-store-new-keys)}
|
||||
:keycard/error.keycard-unpaired {:title (i18n/label :t/keycard-full)
|
||||
:description (i18n/label :t/pairing-slots-occupied)}
|
||||
:keycard/error.keycard-frozen {:title (i18n/label :t/keycard-locked)
|
||||
:description (i18n/label :t/cant-use-right-now)}
|
||||
:keycard/error.keycard-locked {:title (i18n/label :t/keycard-locked)
|
||||
:description (i18n/label :t/cant-use-right-now)}})
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [top bottom]} (safe-area/get-insets)
|
||||
error (rf/sub [:keycard/application-info-error])
|
||||
(let [error (rf/sub [:keycard/application-info-error])
|
||||
{:keys [title description]} (get titles error)]
|
||||
[quo/overlay
|
||||
{:type :shell
|
||||
:container-style {:padding-top top
|
||||
:padding-bottom bottom}}
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title title
|
||||
:description :text
|
||||
:description-text description}]
|
||||
[rn/view {:height 226}]
|
||||
[rn/view {:padding-horizontal 20}
|
||||
[quo/info-message
|
||||
{:container-style {:padding-top 15}
|
||||
:icon :i/info
|
||||
:size :default}
|
||||
"To unlock or factory reset the Keycard, please use the Status desktop app. If you'd like this features on mobile, feel free to upvote them and discuss in the Status community."]]]))
|
||||
[rn/view {:style {:margin-horizontal 20}}
|
||||
[quo/keycard {:holder-name ""}]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 20}}
|
||||
(i18n/label :t/unlock-reset-instructions)]]]))
|
||||
|
|
|
@ -1,116 +1,117 @@
|
|||
(ns status-im.contexts.keycard.events
|
||||
(:require [re-frame.core :as rf]
|
||||
status-im.contexts.keycard.login.events
|
||||
status-im.contexts.keycard.nfc-sheet.events
|
||||
status-im.contexts.keycard.migrate.events
|
||||
status-im.contexts.keycard.migrate.re-encrypting.events
|
||||
status-im.contexts.keycard.nfc.events
|
||||
status-im.contexts.keycard.nfc.sheets.events
|
||||
status-im.contexts.keycard.pin.events
|
||||
status-im.contexts.keycard.sign.events
|
||||
[status-im.contexts.keycard.utils :as keycard.utils]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-check-nfc-enabled-success
|
||||
(fn [{:keys [db]} [nfc-enabled?]]
|
||||
{:db (assoc-in db [:keycard :nfc-enabled?] nfc-enabled?)}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/on-nfc-user-cancelled
|
||||
(fn [{:keys [db]}]
|
||||
(log/debug "[keycard] nfc user cancelled")
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :status] nil)
|
||||
(assoc-in [:keycard :on-nfc-cancelled-event-vector] nil))
|
||||
:fx [(when-let [on-nfc-cancelled-event-vector (get-in db [:keycard :on-nfc-cancelled-event-vector])]
|
||||
[:dispatch on-nfc-cancelled-event-vector])]}))
|
||||
utils.datetime))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-card-connected
|
||||
(fn [{:keys [db]} _]
|
||||
(log/debug "[keycard] card globally connected")
|
||||
{:db (assoc-in db [:keycard :card-connected?] true)
|
||||
:fx [(when-let [event (get-in db [:keycard :on-card-connected-event-vector])]
|
||||
[:dispatch event])]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-card-disconnected
|
||||
(fn [{:keys [db]} _]
|
||||
(log/debug "[keycard] card disconnected")
|
||||
{:db (assoc-in db [:keycard :card-connected?] false)
|
||||
:fx [(when-let [event (get-in db [:keycard :on-card-disconnected-event-vector])]
|
||||
[:dispatch event])]}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/start-nfc
|
||||
(fn [_]
|
||||
{:effects.keycard.ios/start-nfc nil}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/on-nfc-timeout
|
||||
(fn [{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc timeout")
|
||||
{:db (assoc-in db [:keycard :card-connected?] false)
|
||||
:fx [[:dispatch-later [{:ms 500 :dispatch [:keycard.ios/start-nfc]}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-retrieve-pairings-success
|
||||
(fn [{:keys [db]} [pairings]]
|
||||
{:db (assoc-in db [:keycard :pairings] pairings)
|
||||
:fx [[:effects.keycard/set-pairing-to-keycard pairings]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/on-start-nfc-success
|
||||
(fn [{:keys [db]} [{:keys [on-cancel-event-vector]}]]
|
||||
(log/debug "[keycard] nfc started success")
|
||||
{:db (assoc-in db [:keycard :on-nfc-cancelled-event-vector] on-cancel-event-vector)}))
|
||||
(rf/reg-event-fx :keycard/update-pairings
|
||||
(fn [{:keys [db]} [instance-uid pairing]]
|
||||
(let [pairings (get-in db [:keycard :pairings])
|
||||
new-pairings (assoc pairings
|
||||
instance-uid
|
||||
{:pairing pairing
|
||||
:paired-on (utils.datetime/timestamp)})]
|
||||
{:db (assoc-in db [:keycard :pairings] new-pairings)
|
||||
:keycard/persist-pairings new-pairings})))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-action-with-pin-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
(log/debug "[keycard] on-action-with-pin-error: " error)
|
||||
(let [tag-was-lost? (keycard.utils/tag-lost? (:error error))
|
||||
pin-retries-count (keycard.utils/pin-retries (:error error))]
|
||||
(if tag-was-lost?
|
||||
(if (or tag-was-lost? (nil? pin-retries-count))
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(if (nil? pin-retries-count)
|
||||
{:effects.utils/show-popup {:title "wrong-keycard"}}
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||
(assoc-in [:keycard :pin :status] :error))
|
||||
:fx [[:dispatch [:keycard/disconnect]]
|
||||
(when (zero? pin-retries-count)
|
||||
[:effects.utils/show-popup {:title "frozen-keycard"}])]})))))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-get-application-info-success
|
||||
(fn [{:keys [db]} [application-info {:keys [key-uid on-success-fx]}]]
|
||||
(if-let [error (keycard.utils/validate-application-info key-uid application-info)]
|
||||
(case error
|
||||
:keycard/error.not-keycard
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.not-keycard]]]}
|
||||
:keycard/error.keycard-blank
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.empty]]]}
|
||||
{:db (assoc-in db [:keycard :application-info-error] error)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||
(assoc-in [:keycard :pin :status] :error))
|
||||
:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.error]]]})
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info] application-info)
|
||||
(assoc-in [:keycard :pin :status] :verifying))
|
||||
:fx on-success-fx})))
|
||||
(when (zero? pin-retries-count)
|
||||
[:dispatch
|
||||
[:keycard/on-application-info-error
|
||||
:keycard/error.keycard-locked]])]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard/get-application-info
|
||||
(fn [_ [{:keys [on-success on-failure]}]]
|
||||
{:effects.keycard/get-application-info {:on-success on-success :on-failure on-failure}}))
|
||||
(rf/reg-event-fx :keycard/get-keys
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/get-keys data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/cancel-connection
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-connected-event-vector] nil)
|
||||
(assoc-in [:keycard :on-nfc-cancelled-event-vector] nil))}))
|
||||
{:db (update db :keycard dissoc :on-card-connected-event-vector :on-nfc-cancelled-event-vector)}))
|
||||
|
||||
(rf/reg-event-fx :keycard/disconnect
|
||||
(fn [_ _]
|
||||
{:fx [[:dispatch [:keycard/cancel-connection]]
|
||||
[:dispatch [:keycard/hide-connection-sheet]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-application-info-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
{:db (assoc-in db [:keycard :application-info-error] error)
|
||||
:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch
|
||||
[:open-modal
|
||||
(if (= :keycard/error.not-keycard error)
|
||||
:screen/keycard.not-keycard
|
||||
:screen/keycard.error)]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/update-application-info
|
||||
(fn [{:keys [db]} [app-info]]
|
||||
{:db (update db
|
||||
:keycard
|
||||
#(-> %
|
||||
(assoc :application-info app-info)
|
||||
(dissoc :application-info-error)))}))
|
||||
|
||||
(rf/reg-event-fx :keycard/get-application-info
|
||||
(fn [_ [{:keys [key-uid on-success on-error]}]]
|
||||
{:effects.keycard/get-application-info
|
||||
{:on-success (fn [{:keys [instance-uid new-pairing] :as app-info}]
|
||||
(rf/dispatch [:keycard/update-application-info app-info])
|
||||
(when (and instance-uid new-pairing)
|
||||
(rf/dispatch [:keycard/update-pairings instance-uid new-pairing]))
|
||||
(if-let [error (keycard.utils/validate-application-info key-uid app-info)]
|
||||
(if on-error
|
||||
(on-error error)
|
||||
(rf/dispatch [:keycard/on-application-info-error error]))
|
||||
(when on-success (on-success app-info))))
|
||||
:on-error (fn []
|
||||
(if on-error
|
||||
(on-error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error
|
||||
:keycard/error.not-keycard])))}}))
|
||||
|
||||
(rf/reg-event-fx :keycard/connect
|
||||
(fn [{:keys [db]} [args]]
|
||||
(let [connected? (get-in db [:keycard :card-connected?])
|
||||
event-vector [:keycard/get-application-info
|
||||
{:on-success #(rf/dispatch [:keycard/on-get-application-info-success % args])}]]
|
||||
(fn [{:keys [db]} [{:keys [key-uid on-success on-error on-connect-event-vector]}]]
|
||||
(let [event-vector
|
||||
(or on-connect-event-vector
|
||||
[:keycard/get-application-info
|
||||
{:key-uid key-uid
|
||||
:on-success on-success
|
||||
:on-error on-error}])]
|
||||
{:db (assoc-in db [:keycard :on-card-connected-event-vector] event-vector)
|
||||
:fx [[:dispatch
|
||||
[:keycard/show-connection-sheet
|
||||
{:on-cancel-event-vector [:keycard/cancel-connection]}]]
|
||||
(when connected?
|
||||
(when (get-in db [:keycard :card-connected?])
|
||||
[:dispatch event-vector])]})))
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
(fn [{:keys [db]} [data]]
|
||||
(let [{:keys [key-uid encryption-public-key
|
||||
whisper-private-key]} data
|
||||
key-uid (str "0x" key-uid)
|
||||
profile (get-in db [:profile/profiles-overview key-uid])]
|
||||
{:db
|
||||
(-> db
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
(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]))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.check-empty-card
|
||||
(fn [{:keys [db]}]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{: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 %])}]))
|
||||
:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.empty]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
|
||||
|
||||
(defn get-application-info-and-continue
|
||||
[key-uid]
|
||||
(rf/dispatch [:keycard/get-application-info
|
||||
{:key-uid key-uid
|
||||
:on-success #(rf/dispatch [:keycard/migration.continue])
|
||||
:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch [:keycard/migration.continue])
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.continue
|
||||
(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]))]
|
||||
(cond
|
||||
|
||||
(not initialized?)
|
||||
{:fx [[:keycard/init-card
|
||||
{:pin pin
|
||||
:on-success #(get-application-info-and-continue key-uid)
|
||||
:on-failure on-failure}]]}
|
||||
|
||||
(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}]]}
|
||||
|
||||
:else
|
||||
{:fx [[:effects.keycard/get-keys
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch [:keycard/migration.convert-to-keycard-profile %])
|
||||
:on-failure on-failure}]]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.start
|
||||
(fn [{:keys [db]}]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid (get-in db [:profile/profile :key-uid])
|
||||
:on-success #(rf/dispatch [:keycard/migration.continue])
|
||||
:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch [:keycard/migration.continue])
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.get-phrase
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :migration] nil)
|
||||
:fx [[:dispatch [:navigate-back]]
|
||||
(if (string/blank? (get-in db [:profile/profile :mnemonic]))
|
||||
[:dispatch
|
||||
[:open-modal :screen/use-recovery-phrase
|
||||
{:on-success #(rf/dispatch [:keycard/migration.phrase-entered %])}]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/backup-recovery-phrase
|
||||
{:on-success #(rf/dispatch [:keycard/migration.phrase-backed-up %])}]])]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.phrase-entered
|
||||
(fn [{:keys [db]} [{:keys [phrase]}]]
|
||||
{:db (assoc-in db [:keycard :migration :masked-phrase] (security/mask-data phrase))
|
||||
:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.authorise
|
||||
{:on-success #(rf/dispatch [:keycard/migration.authorisation-success %])}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.phrase-backed-up
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db
|
||||
[:keycard :migration :masked-phrase]
|
||||
(security/mask-data (get-in db [:profile/profile :mnemonic])))
|
||||
:fx [[:dispatch [:profile.settings/profile-update :mnemonic nil]]
|
||||
[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.authorise
|
||||
{:on-success #(rf/dispatch [:keycard/migration.authorisation-success %])}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.authorisation-success
|
||||
(fn [{:keys [db]} [masked-password]]
|
||||
(let [{:keys [initialized?]} (get-in db [:keycard :application-info])]
|
||||
{: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.pin.create
|
||||
{:on-complete (fn [new-pin]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/migration.pin-created new-pin]))}]])]})))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.pin-created
|
||||
(fn [{:keys [db]} [pin]]
|
||||
{:db (assoc-in db [:keycard :migration :pin] pin)
|
||||
:fx [[:dispatch [:open-modal :screen/keycard.migrate]]]}))
|
|
@ -0,0 +1,32 @@
|
|||
(ns status-im.contexts.keycard.migrate.fail.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/failed-to-migrate-key-pair)
|
||||
:description :context-tag
|
||||
:context-tag {:full-name profile-name
|
||||
:profile-picture profile-picture
|
||||
:customization-color customization-color}
|
||||
:container-style {:margin-top constants/page-nav-height}}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration-failed)}]]
|
||||
[quo/divider-label (i18n/label :t/what-you-can-do)]
|
||||
[quo/markdown-list {:description (i18n/label :t/log-out-remove-profile)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/recover-status-profile)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/log-out-remove)
|
||||
:button-one-props {:on-press #(rf/dispatch [:logout])}}]]))
|
|
@ -0,0 +1,31 @@
|
|||
(ns status-im.contexts.keycard.migrate.re-encrypting.events
|
||||
(:require [clojure.string :as string]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.convert-to-keycard-profile
|
||||
(fn [{:keys [db]} [{:keys [key-uid instance-uid encryption-public-key]}]]
|
||||
(let [{:keys [masked-password]} (get-in db [:keycard :migration])
|
||||
{:keys [pairing paired-on]} (get-in db [:keycard :pairings instance-uid])
|
||||
{:keys [kdfIterations]} (:profile/profile db)]
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:navigate-back]]
|
||||
[:dispatch [:open-modal :screen/keycard.re-encrypting]]
|
||||
[:effects.profile/convert-to-keycard-profile
|
||||
{:profile
|
||||
{:key-uid key-uid
|
||||
:keycard-pairing pairing
|
||||
:kdfIterations kdfIterations}
|
||||
:settings
|
||||
{:keycard-instance-uid instance-uid
|
||||
:keycard-paired-on paired-on
|
||||
:keycard-pairing pairing}
|
||||
:password
|
||||
(security/safe-unmask-data masked-password)
|
||||
:new-password
|
||||
encryption-public-key
|
||||
:callback
|
||||
(fn [{:keys [error]}]
|
||||
(if (string/blank? error)
|
||||
(rf/dispatch [:navigate-to :screen/keycard.migrate.success])
|
||||
(rf/dispatch [:navigate-to :screen/keycard.migrate.fail])))}]]})))
|
|
@ -0,0 +1,27 @@
|
|||
(ns status-im.contexts.keycard.migrate.re-encrypting.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/re-encrypting-data)
|
||||
:description :context-tag
|
||||
:context-tag {:full-name profile-name
|
||||
:profile-picture profile-picture
|
||||
:customization-color customization-color}
|
||||
:container-style {:margin-top constants/page-nav-height}}]
|
||||
[quo/text {:style {:padding-horizontal 20}}
|
||||
(i18n/label :t/do-not-quit)]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration)}]]]))
|
|
@ -1,15 +1,14 @@
|
|||
(ns status-im.contexts.keycard.sheets.migrate.view
|
||||
(ns status-im.contexts.keycard.migrate.sheets.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
recovery-phrase-backed-up? (rf/sub [:profile/recovery-phrase-backed-up?])]
|
||||
[{:keys [on-continue]}]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:type :context-tag
|
||||
|
@ -28,11 +27,7 @@
|
|||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:on-press #(if recovery-phrase-backed-up?
|
||||
(rf/dispatch [:open-modal :screen/use-recovery-phrase
|
||||
{:on-success (fn [])}])
|
||||
(rf/dispatch [:open-modal :screen/backup-recovery-phrase
|
||||
{:on-success (fn [])}]))}
|
||||
:button-one-props {:on-press on-continue}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:type :grey
|
||||
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
|
|
@ -0,0 +1,31 @@
|
|||
(ns status-im.contexts.keycard.migrate.success.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/key-pair-migrated-successfully)
|
||||
:description :context-tag
|
||||
:context-tag {:full-name profile-name
|
||||
:profile-picture profile-picture
|
||||
:customization-color customization-color}
|
||||
:container-style {:margin-top constants/page-nav-height}}]
|
||||
[quo/text {:style {:padding-horizontal 20}}
|
||||
(i18n/label :t/use-keycard-for-status)]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration-succeeded)}]]
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:logout])
|
||||
:container-style {:margin-horizontal 20}}
|
||||
(i18n/label :t/logout)]]))
|
|
@ -0,0 +1,34 @@
|
|||
(ns status-im.contexts.keycard.migrate.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/ready-to-migrate-key-pair)
|
||||
:description :context-tag
|
||||
:context-tag {:full-name profile-name
|
||||
:profile-picture profile-picture
|
||||
:customization-color customization-color}}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[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])}}]]))
|
|
@ -0,0 +1,11 @@
|
|||
(ns status-im.contexts.keycard.nfc.effects
|
||||
(:require [keycard.keycard :as keycard]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-fx :effects.keycard/check-nfc-enabled
|
||||
(fn []
|
||||
(keycard/check-nfc-enabled
|
||||
{:on-success #(rf/dispatch [:keycard/on-check-nfc-enabled-success %])})))
|
||||
|
||||
(rf/reg-fx :effects.keycard.ios/start-nfc keycard/start-nfc)
|
||||
(rf/reg-fx :effects.keycard.ios/stop-nfc keycard/stop-nfc)
|
|
@ -0,0 +1,27 @@
|
|||
(ns status-im.contexts.keycard.nfc.events
|
||||
(:require [utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/start-nfc
|
||||
(fn [_]
|
||||
{:fx [[:effects.keycard.ios/start-nfc]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/on-start-nfc-success
|
||||
(fn [{:keys [db]} [{:keys [on-cancel-event-vector]}]]
|
||||
{:db (assoc-in db [:keycard :on-nfc-cancelled-event-vector] on-cancel-event-vector)}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/on-nfc-timeout
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (assoc-in db [:keycard :card-connected?] false)
|
||||
:fx [[:dispatch-later [{:ms 500 :dispatch [:keycard.ios/start-nfc]}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-check-nfc-enabled-success
|
||||
(fn [{:keys [db]} [nfc-enabled?]]
|
||||
{:db (assoc-in db [:keycard :nfc-enabled?] nfc-enabled?)}))
|
||||
|
||||
(rf/reg-event-fx :keycard.ios/on-nfc-user-cancelled
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :status] nil)
|
||||
(assoc-in [:keycard :on-nfc-cancelled-event-vector] nil))
|
||||
:fx [(when-let [on-nfc-cancelled-event-vector (get-in db [:keycard :on-nfc-cancelled-event-vector])]
|
||||
[:dispatch on-nfc-cancelled-event-vector])]}))
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.keycard.nfc-sheet.events
|
||||
(ns status-im.contexts.keycard.nfc.sheets.events
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.platform :as platform]
|
||||
[taoensso.timbre :as log]))
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.keycard.nfc-sheet.view
|
||||
(ns status-im.contexts.keycard.nfc.sheets.view
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
quo.theme
|
||||
[react-native.core :as rn]
|
|
@ -1,28 +1,24 @@
|
|||
(ns status-im.contexts.keycard.not-keycard.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[status-im.common.resources :as resources]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [top bottom]} (safe-area/get-insets)]
|
||||
[quo/overlay
|
||||
{:type :shell
|
||||
:container-style {:padding-top top
|
||||
:padding-bottom bottom}}
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/oops-not-keycard)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/make-sure-keycard)}]
|
||||
[rn/view {:flex 1}]
|
||||
[rn/view {:padding-horizontal 20}
|
||||
[quo/button {:on-press #(rf/dispatch [:keycard/connect])}
|
||||
(i18n/label :t/try-again)]]]))
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/oops-not-keycard)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/make-sure-keycard)}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :not-keycard)}]]
|
||||
[rn/view {:padding-horizontal 20}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
(:require [clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]))
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[{:keys [on-complete]}]
|
||||
(let [[pin set-pin] (rn/use-state "")
|
||||
[]
|
||||
(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)
|
||||
|
@ -38,10 +41,15 @@
|
|||
(set-stage :repeat)))))))
|
||||
[pin stage first-pin])]
|
||||
[rn/view {:style {:padding-bottom 12 :flex 1}}
|
||||
[quo/drawer-top
|
||||
{:title (if (= :create stage)
|
||||
(i18n/label :t/create-keycard-pin)
|
||||
(i18n/label :t/repeat-keycard-pin))}]
|
||||
[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))
|
||||
:description :text
|
||||
:description-text "You’ll need this PIN to login and sign transactions"}]
|
||||
[rn/view {:style {:flex 1 :justify-content :center :align-items :center :padding-vertical 34}}
|
||||
[quo/pin-input
|
||||
{:blur? false
|
||||
|
|
|
@ -23,3 +23,7 @@
|
|||
(assoc-in [:keycard :pin :status] nil))
|
||||
:fx [(when (and on-complete (= (dec max-numbers) (count pin)))
|
||||
[:effects.keycard.pin/dispatch-on-complete [on-complete new-pin]])]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard.pin/clear
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :pin] nil)}))
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn auth
|
||||
[{:keys [on-complete]}]
|
||||
(let [{:keys [text status]} (rf/sub [:keycard/pin])
|
||||
pin-retry-counter (rf/sub [:keycard/pin-retry-counter])
|
||||
error? (= status :error)]
|
||||
[{:keys [on-complete error]}]
|
||||
(let [{:keys [error? error-message]} error
|
||||
{:keys [text status]} (rf/sub [:keycard/pin])
|
||||
pin-retry-counter (rf/sub [:keycard/pin-retry-counter])
|
||||
error? (or error? (= status :error))]
|
||||
(rn/use-unmount #(rf/dispatch [:keycard.pin/clear]))
|
||||
[rn/view {:padding-bottom 12 :flex 1}
|
||||
[rn/view {:flex 1 :justify-content :center :align-items :center :padding 34}
|
||||
[quo/pin-input
|
||||
|
@ -18,7 +20,9 @@
|
|||
:number-of-filled-pins (count text)
|
||||
:error? error?
|
||||
:info (when error?
|
||||
(i18n/label :t/pin-retries-left {:number pin-retry-counter}))}]]
|
||||
(if error-message
|
||||
error-message
|
||||
(i18n/label :t/pin-retries-left {:number pin-retry-counter})))}]]
|
||||
[quo/numbered-keyboard
|
||||
{:delete-key? true
|
||||
:on-delete #(rf/dispatch [:keycard.pin/delete-pressed])
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
:s (subs signature 64 128)
|
||||
:v (str (js/parseInt (subs signature 128 130) 16))}})
|
||||
|
||||
(rf/reg-event-fx :keycard/sign
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/sign data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/sign-hash
|
||||
(fn [{:keys [db]} [pin-text tx-hash]]
|
||||
(let [current-address (get-in db [:wallet :current-viewing-account-address])
|
||||
|
@ -15,16 +19,16 @@
|
|||
key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success-fx [[:effects.keycard/sign
|
||||
{:pin pin-text
|
||||
:path path
|
||||
:hash (utils.address/naked-address tx-hash)
|
||||
:on-success
|
||||
#(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch
|
||||
[:wallet/proceed-with-transactions-signatures
|
||||
(get-signature-map tx-hash %)]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error
|
||||
%])}]]}]]]})))
|
||||
{:key-uid key-uid
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:keycard/sign
|
||||
{:pin pin-text
|
||||
:path path
|
||||
:hash (utils.address/naked-address tx-hash)
|
||||
:on-success (fn [signature]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:wallet/proceed-with-transactions-signatures
|
||||
(get-signature-map tx-hash signature)]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]})))
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
(ns status-im.contexts.keycard.utils
|
||||
(:require [taoensso.timbre :as log]))
|
||||
(:require [clojure.string :as string]
|
||||
[utils.address :as address]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(def pin-mismatch-error #"Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)")
|
||||
|
||||
|
@ -16,33 +18,55 @@
|
|||
(re-matches #".*NFCError:100.*" error)))
|
||||
|
||||
(defn validate-application-info
|
||||
[profile-key-uid {:keys [key-uid paired? pin-retry-counter puk-retry-counter] :as application-info}]
|
||||
(let [profile-mismatch? (or (nil? profile-key-uid) (not= profile-key-uid key-uid))]
|
||||
(log/debug "[keycard]" "login-with-keycard"
|
||||
"empty application info" (empty? application-info)
|
||||
"no key-uid" (empty? key-uid)
|
||||
"profile-mismatch?" profile-mismatch?
|
||||
"no pairing" paired?)
|
||||
(cond
|
||||
(empty? application-info)
|
||||
:keycard/error.not-keycard
|
||||
[profile-key-uid
|
||||
{:keys [key-uid has-master-key? paired? pin-retry-counter puk-retry-counter] :as application-info}]
|
||||
|
||||
(empty? (:key-uid application-info))
|
||||
:keycard/error.keycard-blank
|
||||
(cond
|
||||
(empty? application-info)
|
||||
:keycard/error.not-keycard
|
||||
|
||||
profile-mismatch?
|
||||
:keycard/error.keycard-wrong
|
||||
(not has-master-key?)
|
||||
:keycard/error.keycard-blank
|
||||
|
||||
(not paired?)
|
||||
:keycard/error.keycard-unpaired
|
||||
(not= profile-key-uid key-uid)
|
||||
:keycard/error.keycard-wrong-profile
|
||||
|
||||
(and (zero? pin-retry-counter)
|
||||
(or (nil? puk-retry-counter)
|
||||
(pos? puk-retry-counter)))
|
||||
:keycard/error.keycard-frozen
|
||||
(not paired?)
|
||||
:keycard/error.keycard-unpaired
|
||||
|
||||
(zero? puk-retry-counter)
|
||||
:keycard/error.keycard-locked
|
||||
(and (zero? pin-retry-counter)
|
||||
(or (nil? puk-retry-counter)
|
||||
(pos? puk-retry-counter)))
|
||||
:keycard/error.keycard-frozen
|
||||
|
||||
:else
|
||||
nil)))
|
||||
(zero? puk-retry-counter)
|
||||
:keycard/error.keycard-locked
|
||||
|
||||
:else
|
||||
nil))
|
||||
|
||||
(defn- error-object->map
|
||||
[^js object]
|
||||
{:code (.-code object)
|
||||
:error (.-message object)})
|
||||
|
||||
(defn normalize-key-uid
|
||||
[{:keys [key-uid] :as data}]
|
||||
(if (string/blank? key-uid)
|
||||
data
|
||||
(update data :key-uid address/normalized-hex)))
|
||||
|
||||
(defn get-on-success
|
||||
[{:keys [on-success]}]
|
||||
#(when on-success (on-success (normalize-key-uid (transforms/js->clj %)))))
|
||||
|
||||
(defn get-on-failure
|
||||
[{:keys [on-failure]}]
|
||||
#(when on-failure (on-failure (error-object->map %))))
|
||||
|
||||
(defn wrap-handlers
|
||||
[args]
|
||||
(assoc
|
||||
args
|
||||
:on-success (get-on-success args)
|
||||
:on-failure (get-on-failure args)))
|
||||
|
|
|
@ -13,3 +13,7 @@
|
|||
(rf/reg-fx :effects.profile/enable-local-notifications
|
||||
(fn []
|
||||
(native-module/start-local-notifications)))
|
||||
|
||||
(rf/reg-fx :effects.profile/convert-to-keycard-profile
|
||||
(fn [{:keys [profile settings password new-password callback]}]
|
||||
(native-module/convert-to-keycard-profile profile settings password new-password callback)))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.contexts.profile.profiles.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
|
@ -182,7 +183,7 @@
|
|||
:render-fn profile-card}]]))
|
||||
|
||||
(defn password-input
|
||||
[]
|
||||
[processing error]
|
||||
(let [auth-method (rf/sub [:auth-method])
|
||||
on-press-biometrics (fn []
|
||||
(rf/dispatch [:biometric/authenticate
|
||||
|
@ -193,18 +194,31 @@
|
|||
%])}]))]
|
||||
|
||||
[standard-authentication/password-input
|
||||
{:shell? true
|
||||
{:processing processing
|
||||
:error error
|
||||
:shell? true
|
||||
:blur? true
|
||||
:on-press-biometrics (when (= auth-method constants/auth-method-biometric) on-press-biometrics)}]))
|
||||
|
||||
(defn- get-error-message
|
||||
[error]
|
||||
(if (and (some? error)
|
||||
(or (= error "file is not a database")
|
||||
(string/starts-with? (string/lower-case error) "failed")))
|
||||
(i18n/label :t/oops-wrong-password)
|
||||
error))
|
||||
|
||||
(defn login-section
|
||||
[{:keys [show-profiles]}]
|
||||
(let [processing (rf/sub [:profile/login-processing])
|
||||
{:keys [key-uid name keycard-pairing
|
||||
(let [{:keys [key-uid name keycard-pairing
|
||||
customization-color]} (rf/sub [:profile/login-profile])
|
||||
sign-in-enabled? (rf/sub [:sign-in-enabled?])
|
||||
profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
|
||||
login-multiaccount (rn/use-callback #(rf/dispatch [:profile.login/login]))]
|
||||
{:keys [error processing]} (rf/sub [:profile/login])
|
||||
error-message (rn/use-memo #(get-error-message error) [error])
|
||||
error {:error? (boolean (seq error-message))
|
||||
:error-message error-message}
|
||||
login-profile (rn/use-callback #(rf/dispatch [:profile.login/login]))]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style style/login-container
|
||||
:keyboard-vertical-offset (- (safe-area/get-bottom))}
|
||||
|
@ -239,17 +253,20 @@
|
|||
:card-style style/login-profile-card}]
|
||||
(if keycard-pairing
|
||||
[keycard.pin/auth
|
||||
{:on-complete
|
||||
(fn [pin-text]
|
||||
{:error error
|
||||
:on-complete
|
||||
(fn [pin]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success-fx [[:effects.keycard/get-keys
|
||||
{:pin pin-text
|
||||
:on-success #(rf/dispatch [:keycard.login/on-get-keys-success %])
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error
|
||||
%])}]]}]))}]
|
||||
[password-input])]
|
||||
{:key-uid key-uid
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:keycard/get-keys
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch [:keycard.login/on-get-keys-success %])
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]))}]
|
||||
[password-input processing error])]
|
||||
(when-not keycard-pairing
|
||||
[quo/button
|
||||
{:size 40
|
||||
|
@ -258,7 +275,7 @@
|
|||
:accessibility-label :login-button
|
||||
:icon-left :i/unlocked
|
||||
:disabled? (or (not sign-in-enabled?) processing)
|
||||
:on-press login-multiaccount
|
||||
:on-press login-profile
|
||||
:container-style {:margin-bottom (+ (safe-area/get-bottom) 12)}}
|
||||
(i18n/label :t/log-in)])]))
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -27,11 +28,11 @@
|
|||
:subtitle (i18n/label :t/secure-wallet-card)
|
||||
:button-label (i18n/label :t/buy-keycard)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :generate-keys)
|
||||
:on-press #()}]
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
|
||||
[rn/view {:style {:margin-top 24}}
|
||||
[quo/text
|
||||
{:style {:margin-bottom 12
|
||||
{:style {:margin-bottom 1
|
||||
:color colors/white-opa-70}
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
|
|
|
@ -41,10 +41,9 @@
|
|||
(for [label points]
|
||||
^{:key label}
|
||||
[quo/markdown-list
|
||||
{:description (i18n/label label)
|
||||
:blur? true
|
||||
:type (when lock? :lock)
|
||||
:container-style {:padding-top 8}}])]})
|
||||
{:description (i18n/label label)
|
||||
:blur? true
|
||||
:type (when lock? :lock)}])]})
|
||||
|
||||
(defn- on-privacy-policy-press
|
||||
[]
|
||||
|
|
|
@ -69,12 +69,6 @@
|
|||
transitions/new-to-status-modal-animations
|
||||
transitions/push-animations-for-transparent-background)}))
|
||||
|
||||
(def keycard-modal-screen-options
|
||||
(assoc transparent-modal-screen-options
|
||||
:layout nil
|
||||
:theme :dark
|
||||
:insets {:top? true :bottom? true}))
|
||||
|
||||
(def sheet-options
|
||||
{:layout {:componentBackgroundColor :transparent
|
||||
:orientation ["portrait"]
|
||||
|
|
|
@ -32,7 +32,12 @@
|
|||
[status-im.contexts.keycard.check.view :as keycard.check]
|
||||
[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.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.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]
|
||||
|
@ -310,8 +315,9 @@
|
|||
:component settings/view}
|
||||
|
||||
{:name :screen/settings.keycard
|
||||
:metrics {:track? :true}
|
||||
:options options/keycard-modal-screen-options
|
||||
:metrics {:track? :true
|
||||
:alias-id :settings.keycard}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component settings.keycard/view}
|
||||
|
||||
{:name :edit-profile
|
||||
|
@ -877,29 +883,73 @@
|
|||
|
||||
(def keycard-screens
|
||||
[{:name :screen/keycard.check
|
||||
:metrics {:track? true}
|
||||
:options options/keycard-modal-screen-options
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.check}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.check/view}
|
||||
|
||||
{:name :screen/keycard.empty
|
||||
:metrics {:track? true}
|
||||
:options options/keycard-modal-screen-options
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.empty}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.empty/view}
|
||||
|
||||
{:name :screen/keycard.error
|
||||
:metrics {:track? true}
|
||||
:options options/keycard-modal-screen-options
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.error}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.error/view}
|
||||
|
||||
{:name :screen/keycard.not-keycard
|
||||
:metrics {:track? true}
|
||||
:options options/keycard-modal-screen-options
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.not-keycard}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.not-keycard/view}
|
||||
|
||||
{:name :screen/keycard.authorise
|
||||
:metrics {:track? true}
|
||||
:options options/keycard-modal-screen-options
|
||||
:component keycard.authorise/view}])
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.authorise}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.authorise/view}
|
||||
|
||||
{:name :screen/keycard.migrate
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.migrate}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.migrate/view}
|
||||
|
||||
{:name :screen/keycard.re-encrypting
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.re-encrypting}
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component keycard.re-encrypting/view}
|
||||
|
||||
{:name :screen/keycard.migrate.success
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.migrate.success}
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component keycard.migrate.success/view}
|
||||
|
||||
{:name :screen/keycard.migrate.fail
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.migrate.fail}
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component keycard.migrate.fail/view}
|
||||
|
||||
{:name :screen/keycard.pin.create
|
||||
:metrics {:track? :true
|
||||
:alias-id :keycard.pin.create}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component pin.create/view}])
|
||||
|
||||
(defn screens
|
||||
[]
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[status-im.common.bottom-sheet-screen.view :as bottom-sheet-screen]
|
||||
[status-im.common.bottom-sheet.view :as bottom-sheet]
|
||||
[status-im.common.toasts.view :as toasts]
|
||||
[status-im.contexts.keycard.nfc-sheet.view :as keycard.sheet]
|
||||
[status-im.contexts.keycard.nfc.sheets.view :as keycard.sheet]
|
||||
[status-im.navigation.screens :as screens]
|
||||
[status-im.setup.hot-reload :as reloader]
|
||||
[utils.re-frame :as rf]))
|
||||
|
|
|
@ -293,6 +293,8 @@
|
|||
"cant-fetch-info": "Can't fetch info",
|
||||
"cant-open-public-chat": "Can't open public chat",
|
||||
"cant-report-bug": "Can't report a bug",
|
||||
"cant-store-new-keys": "You can’t use it to store new keys right now",
|
||||
"cant-use-right-now": "You can’t use it right now",
|
||||
"card-is-blank": "This card is blank",
|
||||
"card-reseted": "Card has been reseted",
|
||||
"card-unpaired": "Card has been unpaired from current device",
|
||||
|
@ -782,6 +784,8 @@
|
|||
"display-collectibles": "Display collectibles",
|
||||
"do-not-cheat": "Don't try to cheat",
|
||||
"do-not-cheat-description": "These 12 words give access to all of your funds so it is important that you write them in the correct order, take it seriously.",
|
||||
"do-not-quit": "Do not quit the application or turn off your device. Doing so will lead to data corruption, loss of your Status profile and the inability to use Status.",
|
||||
|
||||
"do-not-share": "Do not share",
|
||||
"done": "Done",
|
||||
"dont-ask": "Don't ask me again",
|
||||
|
@ -1010,6 +1014,7 @@
|
|||
"failed": "Failed",
|
||||
"failed-on": "Failed on",
|
||||
"failed-to-fetch-community": "Failed to fetch community",
|
||||
"failed-to-migrate-key-pair": "Failed to migrate key pair",
|
||||
"faq": "Frequently asked questions",
|
||||
"fast": "Fast",
|
||||
"favorite-communities": "Your favourite communities",
|
||||
|
@ -1317,6 +1322,7 @@
|
|||
"key-name-error-too-short": "Key pair name must be at least {{count}} characters",
|
||||
"key-on-device": "Private key is saved on this device",
|
||||
"key-pair-imported-successfully": "{{name}} key pair imported successfully",
|
||||
"key-pair-migrated-successfully": "Profile key pair successfully migrated",
|
||||
"key-pair-name-updated": "Key pair name updated",
|
||||
"key-pair-removed": "Key pair and derived accounts has been removed",
|
||||
"key-pairs-successfully-imported": "{{count}} key pairs successfully imported",
|
||||
|
@ -1344,6 +1350,7 @@
|
|||
"keycard-factory-reset-text": "Performing this will delete any mnemonic phrase stored on the card. Make sure you have a backup of the mnemonic phrase you've been using with this Keycard.",
|
||||
"keycard-factory-reset-title": "Are you sure you want to perform a factory reset?",
|
||||
"keycard-free-pairing-slots": "Keycard has {{n}} free pairing slots",
|
||||
"keycard-full": "Keycard is full",
|
||||
"keycard-has-multiaccount-on-it": "This card is full. Each card can hold one main key pair",
|
||||
"keycard-init-description": "Put the card to the back of your phone to continue",
|
||||
"keycard-init-title": "Looking for cards...",
|
||||
|
@ -1354,6 +1361,8 @@
|
|||
"keycard-is-frozen-factory-reset": "Reset with mnemonic",
|
||||
"keycard-is-frozen-reset": "Reset with PUK",
|
||||
"keycard-is-frozen-title": "Keycard is frozen",
|
||||
"keycard-locked": "Keycard is locked",
|
||||
"keycard-not-empty": "Keycard is not empty",
|
||||
"keycard-onboarding-finishing-header": "Finishing up",
|
||||
"keycard-onboarding-intro-header": "Store your keys on Keycard",
|
||||
"keycard-onboarding-intro-text": "Get ready, this might take a few minutes, but it's important to secure your account",
|
||||
|
@ -1450,6 +1459,8 @@
|
|||
"log-in": "Log in",
|
||||
"log-level": "Log level",
|
||||
"log-level-settings": "Log level settings",
|
||||
"log-out-remove": "Log out & Remove profile",
|
||||
"log-out-remove-profile": "Log out and remove profile from this device",
|
||||
"logged-in": "Logged in",
|
||||
"logging": "Logging",
|
||||
"logging-enabled": "Logging enabled?",
|
||||
|
@ -1718,6 +1729,7 @@
|
|||
"no-fees": "No fees",
|
||||
"no-group-chats": "No group chats",
|
||||
"no-group-chats-description": "Much fun. Have friends. Wow!",
|
||||
"no-key-pair-keycard": "There is no key pair on this Keycard",
|
||||
"no-keycard-applet-on-card": "No Keycard applet on card",
|
||||
"no-messages": "No messages",
|
||||
"no-messages-description": "Here’s a cat in a box instead",
|
||||
|
@ -1876,6 +1888,7 @@
|
|||
"pairing-new-installation-detected-title": "New device detected",
|
||||
"pairing-no-info": "No info",
|
||||
"pairing-please-set-a-name": "Please set a name for your device.",
|
||||
"pairing-slots-occupied": "All pairing slots are occupied",
|
||||
"paraswap-error": "Paraswap error: {{paraswap-error}}",
|
||||
"participate-in-the-metaverse": "Participate in the truly free metaverse",
|
||||
"passphrase": "Passphrase",
|
||||
|
@ -2024,9 +2037,11 @@
|
|||
"re-encrypt": "Re-encrypt",
|
||||
"re-encrypt-data": "Re-encrypt your data",
|
||||
"re-encrypt-key": "Re-encrypt your keys",
|
||||
"re-encrypting-data": "Re-encrypting data",
|
||||
"read": "Read",
|
||||
"read-more": "Read more",
|
||||
"ready-keycard": "Get your Keycard ready",
|
||||
"ready-to-migrate-key-pair": "Ready to migrate profile key pair to the Keycard",
|
||||
"ready-to-scan": "Ready to Scan",
|
||||
"rearrange-categories": "Rearrange Categories",
|
||||
"receive": "Receive",
|
||||
|
@ -2045,6 +2060,7 @@
|
|||
"recover": "Recover",
|
||||
"recover-key": "Access existing keys",
|
||||
"recover-keycard-multiaccount-not-supported": "Keys for this account already exist and can't be added again. If you've lost your password, passcode or Keycard, uninstall the app, reinstall and access your keys by entering your seed phrase",
|
||||
"recover-status-profile": "Recover your Status profile with recovery phrase",
|
||||
"recover-with-keycard": "Recover with Keycard",
|
||||
"recover-with-seed-phrase": "Recover with seed phrase",
|
||||
"recovering-key": "Accessing keys...",
|
||||
|
@ -2170,6 +2186,7 @@
|
|||
"scan-an-account-qr-code": "Scan an account QR code",
|
||||
"scan-an-address-qr-code": "Scan an address QR code",
|
||||
"scan-key-pairs-qr-code": "Scan key pairs QR code",
|
||||
"scan-keycard": "Scan Keycard",
|
||||
"scan-or-enter-a-sync-code": "Scan or enter a sync code",
|
||||
"scan-or-enter-sync-code": "Scan or enter sync code",
|
||||
"scan-or-enter-sync-code-seen-on-this-device": "Scan or enter sync code seen on this device",
|
||||
|
@ -2622,6 +2639,7 @@
|
|||
"unknown-status-go-error": "Unknown status-go error",
|
||||
"unlimited": "Unlimited",
|
||||
"unlock": "Unlock",
|
||||
"unlock-reset-instructions": "To unlock or factory reset the Keycard, please use the Status desktop app. If you'd like this feature on mobile, feel free to upvote them and discuss in the Status community.",
|
||||
"unmute": "Unmute",
|
||||
"unmute-channel": "Unmute channel",
|
||||
"unmute-chat": "Unmute chat",
|
||||
|
@ -2660,6 +2678,7 @@
|
|||
"use-as-profile-picture": "Use as profile picture",
|
||||
"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-login-sign": "Use this Keycard to login and sign transactions",
|
||||
"use-keycard-subtitle": "Keys will be stored on your Keycard",
|
||||
"use-photo": "Use Photo",
|
||||
|
@ -2809,6 +2828,7 @@
|
|||
"what-to-do": "What you would like to do?",
|
||||
"what-we-will-receive": "What we will receive:",
|
||||
"what-we-wont-receive": "What we won't receive:",
|
||||
"what-you-can-do": "What you can do:",
|
||||
"whats-on-your-mind": "What’s on your mind…",
|
||||
"which-connection-to-use": "Which connection to use for syncing?",
|
||||
"who-are-you-looking-for": "Who are you looking for ?",
|
||||
|
|
Loading…
Reference in New Issue