[#20434] Allow users from v1 to login with keycard (#20558)

This commit is contained in:
flexsurfer 2024-07-12 12:02:17 +02:00 committed by GitHub
parent 721aa51d8d
commit d2e975f6d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 964 additions and 669 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -1,38 +1,277 @@
(ns keycard.keycard)
(ns keycard.keycard
(:require
["react-native" :as rn]
["react-native-status-keycard" :default status-keycard]
[react-native.platform :as platform]
[taoensso.timbre :as log]
[utils.address :as address]))
(defprotocol Keycard
(start-nfc [this args])
(stop-nfc [this args])
(set-nfc-message [this args])
(check-nfc-support [this args])
(check-nfc-enabled [this args])
(open-nfc-settings [this])
(register-card-events [this args])
(set-pairings [this args])
(on-card-disconnected [this callback])
(on-card-connected [this callback])
(remove-event-listener [this event])
(remove-event-listeners [this])
(get-application-info [this args])
(factory-reset [this args])
(install-applet [this args])
(install-cash-applet [this args])
(init-card [this args])
(install-applet-and-init-card [this args])
(pair [this args])
(generate-and-load-key [this args])
(unblock-pin [this args])
(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])
(remove-key-with-unpair [this args])
(export-key [this args])
(unpair-and-delete [this args])
(import-keys [this args])
(get-keys [this args])
(sign [this args])
(sign-typed-data [this args]))
(defonce event-emitter
(if platform/ios?
(new (.-NativeEventEmitter rn) status-keycard)
(.-DeviceEventEmitter rn)))
(defn start-nfc
[{:keys [on-success on-failure prompt-message]}]
(log/debug "start-nfc")
(.. status-keycard
(startNFC (str prompt-message))
(then on-success)
(catch on-failure)))
(defn stop-nfc
[{:keys [on-success on-failure error-message]}]
(log/debug "stop-nfc")
(.. status-keycard
(stopNFC (str error-message))
(then on-success)
(catch on-failure)))
(defn set-nfc-message
[{:keys [on-success on-failure status-message]}]
(log/debug "set-nfc-message")
(.. status-keycard
(setNFCMessage (str status-message))
(then on-success)
(catch on-failure)))
(defn check-nfc-support
[{:keys [on-success]}]
(.. status-keycard
nfcIsSupported
(then on-success)))
(defn check-nfc-enabled
[{:keys [on-success]}]
(.. status-keycard
nfcIsEnabled
(then on-success)))
(defn open-nfc-settings
[]
(.openNfcSettings status-keycard))
(defn remove-event-listeners
[]
(doseq [event ["keyCardOnConnected" "keyCardOnDisconnected" "keyCardOnNFCUserCancelled"
"keyCardOnNFCTimeout"]]
(.removeAllListeners ^js event-emitter event)))
(defn remove-event-listener
[^js event]
(when event
(.remove event)))
(defn on-card-connected
[callback]
(.addListener ^js event-emitter "keyCardOnConnected" callback))
(defn on-card-disconnected
[callback]
(.addListener ^js event-emitter "keyCardOnDisconnected" callback))
(defn on-nfc-user-cancelled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCUserCancelled" callback))
(defn on-nfc-timeout
[callback]
(.addListener ^js event-emitter "keyCardOnNFCTimeout" callback))
(defn on-nfc-enabled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCEnabled" callback))
(defn on-nfc-disabled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCDisabled" callback))
(defn set-pairings
[pairings]
(.. status-keycard (setPairings (clj->js (or pairings {})))))
(defn get-application-info
[{: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))))
(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))))
(catch on-failure)))
(defn install-applet
[{:keys [on-success on-failure]}]
(.. status-keycard
installApplet
(then on-success)
(catch on-failure)))
(defn install-cash-applet
[{:keys [on-success on-failure]}]
(.. status-keycard
installCashApplet
(then on-success)
(catch on-failure)))
(defn init-card
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(init pin)
(then on-success)
(catch on-failure)))
(defn install-applet-and-init-card
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(installAppletAndInitCard pin)
(then on-success)
(catch on-failure)))
(defn pair
[{:keys [password on-success on-failure]}]
(when password
(.. status-keycard
(pair password)
(then on-success)
(catch on-failure))))
(defn generate-and-load-key
[{:keys [mnemonic pin on-success on-failure]}]
(.. status-keycard
(generateAndLoadKey mnemonic pin)
(then on-success)
(catch on-failure)))
(defn unblock-pin
[{:keys [puk new-pin on-success on-failure]}]
(when (and new-pin puk)
(.. status-keycard
(unblockPin puk new-pin)
(then on-success)
(catch on-failure))))
(defn verify-pin
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(verifyPin pin)
(then on-success)
(catch on-failure))))
(defn change-pin
[{:keys [current-pin new-pin on-success on-failure]}]
(when (and current-pin new-pin)
(.. status-keycard
(changePin current-pin new-pin)
(then on-success)
(catch on-failure))))
(defn change-puk
[{:keys [pin puk on-success on-failure]}]
(when (and pin puk)
(.. status-keycard
(changePUK pin puk)
(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 pin
(.. status-keycard
(unpair pin)
(then on-success)
(catch on-failure))))
(defn delete
[{:keys [on-success on-failure]}]
(.. status-keycard
(delete)
(then on-success)
(catch on-failure)))
(defn remove-key
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(removeKey pin)
(then on-success)
(catch on-failure)))
(defn remove-key-with-unpair
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(removeKeyWithUnpair pin)
(then on-success)
(catch on-failure)))
(defn export-key
[{:keys [pin path on-success on-failure]}]
(.. status-keycard
(exportKeyWithPath pin path)
(then on-success)
(catch on-failure)))
(defn unpair-and-delete
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(unpairAndDelete pin)
(then on-success)
(catch on-failure))))
(defn import-keys
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(importKeys pin)
(then on-success)
(catch on-failure))))
(defn get-keys
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(getKeys pin)
(then on-success)
(catch on-failure))))
(defn sign
[{pin :pin path :path card-hash :hash on-success :on-success on-failure :on-failure}]
(when (and pin card-hash)
(if path
(.. status-keycard
(signWithPath pin path card-hash)
(then on-success)
(catch on-failure))
(.. status-keycard
(sign pin card-hash)
(then on-success)
(catch on-failure)))))
(defn sign-typed-data
[{card-hash :hash on-success :on-success on-failure :on-failure}]
(when card-hash
(.. status-keycard
(signPinless card-hash)
(then on-success)
(catch on-failure))))

View File

@ -1,365 +0,0 @@
(ns keycard.real-keycard
(:require
["react-native" :as rn]
["react-native-status-keycard" :default status-keycard]
[keycard.keycard :as keycard]
[react-native.platform :as platform]
[taoensso.timbre :as log]
[utils.address :as address]))
(defonce event-emitter
(if platform/ios?
(new (.-NativeEventEmitter rn) status-keycard)
(.-DeviceEventEmitter rn)))
(defonce active-listeners (atom []))
(defn start-nfc
[{:keys [on-success on-failure prompt-message]}]
(log/debug "start-nfc")
(.. status-keycard
(startNFC (str prompt-message))
(then on-success)
(catch on-failure)))
(defn stop-nfc
[{:keys [on-success on-failure error-message]}]
(log/debug "stop-nfc")
(.. status-keycard
(stopNFC (str error-message))
(then on-success)
(catch on-failure)))
(defn set-nfc-message
[{:keys [on-success on-failure status-message]}]
(log/debug "set-nfc-message")
(.. status-keycard
(setNFCMessage (str status-message))
(then on-success)
(catch on-failure)))
(defn check-nfc-support
[{:keys [on-success]}]
(.. status-keycard
nfcIsSupported
(then on-success)))
(defn check-nfc-enabled
[{:keys [on-success]}]
(.. status-keycard
nfcIsEnabled
(then on-success)))
(defn open-nfc-settings
[]
(.openNfcSettings status-keycard))
(defn remove-event-listeners
[]
(doseq [event ["keyCardOnConnected" "keyCardOnDisconnected" "keyCardOnNFCUserCancelled"
"keyCardOnNFCTimeout"]]
(.removeAllListeners ^js event-emitter event)))
(defn remove-event-listener
[^js event]
(.remove event))
(defn on-card-connected
[callback]
(.addListener ^js event-emitter "keyCardOnConnected" callback))
(defn on-card-disconnected
[callback]
(.addListener ^js event-emitter "keyCardOnDisconnected" callback))
(defn on-nfc-user-cancelled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCUserCancelled" callback))
(defn on-nfc-timeout
[callback]
(.addListener ^js event-emitter "keyCardOnNFCTimeout" callback))
(defn on-nfc-enabled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCEnabled" callback))
(defn on-nfc-disabled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCDisabled" callback))
(defn set-pairings
[{:keys [pairings]}]
(.. status-keycard (setPairings (clj->js (or pairings {})))))
(defn register-card-events
[args]
(doseq [listener @active-listeners]
(remove-event-listener listener))
(reset! active-listeners
[(on-card-connected (:on-card-connected args))
(on-card-disconnected (:on-card-disconnected args))
(on-nfc-user-cancelled (:on-nfc-user-cancelled args))
(on-nfc-timeout (:on-nfc-timeout args))
(on-nfc-enabled (:on-nfc-enabled args))
(on-nfc-disabled (:on-nfc-disabled args))]))
(defn get-application-info
[{: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))))
(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))))
(catch on-failure)))
(defn install-applet
[{:keys [on-success on-failure]}]
(.. status-keycard
installApplet
(then on-success)
(catch on-failure)))
(defn install-cash-applet
[{:keys [on-success on-failure]}]
(.. status-keycard
installCashApplet
(then on-success)
(catch on-failure)))
(defn init-card
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(init pin)
(then on-success)
(catch on-failure)))
(defn install-applet-and-init-card
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(installAppletAndInitCard pin)
(then on-success)
(catch on-failure)))
(defn pair
[{:keys [password on-success on-failure]}]
(when password
(.. status-keycard
(pair password)
(then on-success)
(catch on-failure))))
(defn generate-and-load-key
[{:keys [mnemonic pin on-success on-failure]}]
(.. status-keycard
(generateAndLoadKey mnemonic pin)
(then on-success)
(catch on-failure)))
(defn unblock-pin
[{:keys [puk new-pin on-success on-failure]}]
(when (and new-pin puk)
(.. status-keycard
(unblockPin puk new-pin)
(then on-success)
(catch on-failure))))
(defn verify-pin
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(verifyPin pin)
(then on-success)
(catch on-failure))))
(defn change-pin
[{:keys [current-pin new-pin on-success on-failure]}]
(when (and current-pin new-pin)
(.. status-keycard
(changePin current-pin new-pin)
(then on-success)
(catch on-failure))))
(defn change-puk
[{:keys [pin puk on-success on-failure]}]
(when (and pin puk)
(.. status-keycard
(changePUK pin puk)
(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 pin
(.. status-keycard
(unpair pin)
(then on-success)
(catch on-failure))))
(defn delete
[{:keys [on-success on-failure]}]
(.. status-keycard
(delete)
(then on-success)
(catch on-failure)))
(defn remove-key
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(removeKey pin)
(then on-success)
(catch on-failure)))
(defn remove-key-with-unpair
[{:keys [pin on-success on-failure]}]
(.. status-keycard
(removeKeyWithUnpair pin)
(then on-success)
(catch on-failure)))
(defn export-key
[{:keys [pin path on-success on-failure]}]
(.. status-keycard
(exportKeyWithPath pin path)
(then on-success)
(catch on-failure)))
(defn unpair-and-delete
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(unpairAndDelete pin)
(then on-success)
(catch on-failure))))
(defn import-keys
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(importKeys pin)
(then on-success)
(catch on-failure))))
(defn get-keys
[{:keys [pin on-success on-failure]}]
(when (not-empty pin)
(.. status-keycard
(getKeys pin)
(then on-success)
(catch on-failure))))
(defn sign
[{pin :pin path :path card-hash :hash on-success :on-success on-failure :on-failure}]
(when (and pin card-hash)
(if path
(.. status-keycard
(signWithPath pin path card-hash)
(then on-success)
(catch on-failure))
(.. status-keycard
(sign pin card-hash)
(then on-success)
(catch on-failure)))))
(defn sign-typed-data
[{card-hash :hash on-success :on-success on-failure :on-failure}]
(when card-hash
(.. status-keycard
(signPinless card-hash)
(then on-success)
(catch on-failure))))
(defrecord RealKeycard []
keycard/Keycard
(keycard/start-nfc [_this args]
(start-nfc args))
(keycard/stop-nfc [_this args]
(stop-nfc args))
(keycard/set-nfc-message [_this args]
(set-nfc-message args))
(keycard/check-nfc-support [_this args]
(check-nfc-support args))
(keycard/check-nfc-enabled [_this args]
(check-nfc-enabled args))
(keycard/open-nfc-settings [_this]
(open-nfc-settings))
(keycard/register-card-events [_this args]
(register-card-events args))
(keycard/on-card-connected [_this callback]
(on-card-connected callback))
(keycard/on-card-disconnected [_this callback]
(on-card-disconnected callback))
(keycard/remove-event-listener [_this event]
(remove-event-listener event))
(keycard/remove-event-listeners [_this]
(remove-event-listeners))
(keycard/set-pairings [_this args]
(set-pairings args))
(keycard/get-application-info [_this args]
(get-application-info args))
(keycard/factory-reset [_this args]
(factory-reset args))
(keycard/install-applet [_this args]
(install-applet args))
(keycard/install-cash-applet [_this args]
(install-cash-applet args))
(keycard/init-card [_this args]
(init-card args))
(keycard/install-applet-and-init-card [_this args]
(install-applet-and-init-card args))
(keycard/pair [_this args]
(pair args))
(keycard/generate-and-load-key [_this args]
(generate-and-load-key args))
(keycard/unblock-pin [_this args]
(unblock-pin args))
(keycard/verify-pin [_this args]
(verify-pin args))
(keycard/change-pin [_this args]
(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]
(delete args))
(keycard/remove-key [_this args]
(remove-key args))
(keycard/remove-key-with-unpair [_this args]
(remove-key-with-unpair args))
(keycard/export-key [_this args]
(export-key args))
(keycard/unpair-and-delete [_this args]
(unpair-and-delete args))
(keycard/import-keys [_this args]
(import-keys args))
(keycard/get-keys [_this args]
(get-keys args))
(keycard/sign [_this args]
(sign args))
(keycard/sign-typed-data [_this args]
(sign-typed-data args)))

View File

@ -1,58 +0,0 @@
(ns legacy.status-im.utils.keychain.core
(:require
[oops.core :as oops]
[re-frame.core :as re-frame]
[react-native.keychain :as keychain]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn- whisper-key-name
[address]
(str address "-whisper"))
(re-frame/reg-fx
:keychain/get-keycard-keys
(fn [[key-uid callback]]
(keychain/get-credentials
key-uid
(fn [encryption-key-data]
(if encryption-key-data
(keychain/get-credentials
(whisper-key-name key-uid)
(fn [whisper-key-data]
(if whisper-key-data
(callback [(oops/oget encryption-key-data "password")
(oops/oget whisper-key-data "password")])
(callback nil))))
(callback nil))))))
(re-frame/reg-fx
:keychain/save-keycard-keys
(fn [[key-uid encryption-public-key whisper-private-key]]
(keychain/save-credentials
key-uid
key-uid
encryption-public-key
#(when-not %
(log/error
(str "Error while saving encryption-public-key"))))
(keychain/save-credentials
(whisper-key-name key-uid)
key-uid
whisper-private-key
#(when-not %
(log/error
(str "Error while saving whisper-private-key"))))))
(rf/defn get-keycard-keys
[_ key-uid]
{:keychain/get-keycard-keys
[key-uid
#(re-frame/dispatch
[:multiaccounts.login.callback/get-keycard-keys-success key-uid %])]})
(rf/defn save-keycard-keys
[_ key-uid encryption-public-key whisper-private-key]
{:keychain/save-keycard-keys [key-uid
encryption-public-key
whisper-private-key]})

View File

@ -110,8 +110,11 @@
(def status-keycard
#js
{:default #js
{:nfcIsSupported (fn [] #js {:then identity})
:nfcIsEnabled (fn [] #js {:then identity})}})
{:nfcIsSupported (fn [] #js {:then identity})
:nfcIsEnabled (fn [] #js {:then identity})
:getApplicationInfo (fn [] #js {:then identity})
:getKeys (fn [] #js {:then identity})
:setPairings (fn [] #js {:then identity})}})
(def snoopy #js {:default #js {}})
(def snoopy-filter #js {:default #js {}})

View File

@ -87,31 +87,6 @@
config
#(callback (types/json->clj %))))
(defn save-multiaccount-and-login-with-keycard
"NOTE: chat-key is a whisper private key sent from keycard"
[key-uid multiaccount-data password settings config accounts-data chat-key]
(log/debug "[native-module] save-account-and-login-with-keycard")
(init-keystore
key-uid
#(.saveAccountAndLoginWithKeycard
^js (account-manager)
multiaccount-data
password
settings
config
accounts-data
chat-key)))
(defn login-with-config
"NOTE: beware, the password has to be sha3 hashed"
[key-uid account-data hashed-password config]
(log/debug "[native-module] loginWithConfig")
(clear-web-data)
(let [config (if config (types/clj->json config) "")]
(init-keystore
key-uid
#(.loginWithConfig ^js (account-manager) account-data hashed-password config))))
(defn login-account
"NOTE: beware, the password has to be sha3 hashed"
[{:keys [keyUid] :as request}]
@ -153,19 +128,6 @@
(clear-web-data)
(.logout ^js (account-manager)))
(defn multiaccount-load-account
"NOTE: beware, the password has to be sha3 hashed
this function is used after storing an account when you still want to
derive accounts from it, because saving an account flushes the loaded keys
from memory"
[address hashed-password callback]
(log/debug "[native-module] multiaccount-load-account")
(.multiAccountLoadAccount ^js (account-manager)
(types/clj->json {:address address
:password hashed-password})
callback))
(defn multiaccount-derive-addresses
"NOTE: this should be named derive-accounts
this only derive addresses, they still need to be stored
@ -179,38 +141,6 @@
:paths paths})
callback)))
(defn multiaccount-store-account
"NOTE: beware, the password has to be sha3 hashed
this stores the account and flush keys in memory so
in order to also store derived accounts like initial wallet
and chat accounts, you need to load the account again with
`multiaccount-load-account` before using `multiaccount-store-derived`
and the id of the account stored will have changed"
[account-id key-uid hashed-password callback]
(log/debug "[native-module] multiaccount-store-account")
(when (status)
(init-keystore
key-uid
#(.multiAccountStoreAccount ^js (account-manager)
(types/clj->json {:accountID account-id
:password hashed-password})
callback))))
(defn multiaccount-store-derived
"NOTE: beware, the password has to be sha3 hashed"
[account-id key-uid paths hashed-password callback]
(log/debug "[native-module] multiaccount-store-derived"
"account-id"
account-id)
(init-keystore
key-uid
#(.multiAccountStoreDerived ^js (account-manager)
(types/clj->json {:accountID account-id
:paths paths
:password hashed-password})
callback)))
(defn multiaccount-generate-and-derive-addresses
"used to generate multiple multiaccounts for onboarding
NOTE: nothing is saved so you will need to use
@ -234,37 +164,12 @@
:Bip39Passphrase password})
callback))
(defn multiaccount-import-private-key
[private-key callback]
(log/debug "[native-module] multiaccount-import-private-key")
(.multiAccountImportPrivateKey ^js (account-manager)
(types/clj->json {:privateKey private-key})
callback))
(defn verify
"NOTE: beware, the password has to be sha3 hashed"
[address hashed-password callback]
(log/debug "[native-module] verify")
(.verify ^js (account-manager) address hashed-password callback))
(defn verify-database-password
"NOTE: beware, the password has to be sha3 hashed"
[key-uid hashed-password callback]
(log/debug "[native-module] verify-database-password")
(.verifyDatabasePassword ^js (account-manager) key-uid hashed-password callback))
(defn login-with-keycard
[{:keys [key-uid multiaccount-data password chat-key node-config]}]
(log/debug "[native-module] login-with-keycard")
(clear-web-data)
(init-keystore
key-uid
#(.loginWithKeycard ^js (account-manager)
multiaccount-data
password
chat-key
(types/clj->json node-config))))
(defn set-soft-input-mode
[mode]
(log/debug "[native-module] set-soft-input-mode")

View File

@ -0,0 +1,43 @@
(ns quo.components.pin-input.pin.view
(:require [quo.foundations.colors :as colors]
quo.theme
[react-native.core :as rn]))
(defn view
[{:keys [theme state blur?]}]
(let [app-theme (quo.theme/use-theme)
theme (or theme app-theme)]
[rn/view {:style {:width 36 :height 36 :align-items :center :justify-content :center}}
(case state
:active
[rn/view
{:style {:width 16
:height 16
:border-radius 8
:background-color (if blur?
colors/white-opa-20
(colors/theme-colors colors/neutral-40 colors/neutral-50 theme))}}]
:filled
[rn/view
{:style {:width 16
:height 16
:border-radius 8
:background-color (if blur?
colors/white
(colors/theme-colors colors/neutral-100 colors/white theme))}}]
:error
[rn/view
{:style {:width 16
:height 16
:border-radius 8
:background-color (if blur?
colors/danger-60
(colors/theme-colors colors/danger-50 colors/danger-60 theme))}}]
[rn/view
{:style
{:width 12
:height 12
:border-radius 6
:background-color (if blur?
colors/white-opa-20
(colors/theme-colors colors/neutral-40 colors/neutral-50 theme))}}])]))

View File

@ -0,0 +1,27 @@
(ns quo.components.pin-input.view
(:require [quo.components.markdown.text :as text]
[quo.components.pin-input.pin.view :as pin]
[quo.foundations.colors :as colors]
quo.theme
[react-native.core :as rn]))
(defn view
[{:keys [number-of-pins number-of-filled-pins error? info]
:or {number-of-pins 6 number-of-filled-pins 0}}]
(let [theme (quo.theme/use-theme)]
[rn/view {:style {:align-items :center}}
[rn/view {:style {:flex-direction :row}}
(for [i (range 1 (inc number-of-pins))]
^{:key i}
[pin/view
{:state (cond
error? :error
(<= i number-of-filled-pins) :filled
(= i (inc number-of-filled-pins)) :active)}])]
(when info
[text/text
{:style {:color (if error?
(colors/theme-colors colors/danger-50 colors/danger-60 theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}
:size :paragraph-2}
info])]))

View File

@ -120,6 +120,7 @@
quo.components.overlay.view
quo.components.password.password-tips.view
quo.components.password.tips.view
quo.components.pin-input.view
quo.components.profile.collectible-list-item.view
quo.components.profile.collectible.view
quo.components.profile.expanded-collectible.view
@ -320,6 +321,9 @@
(def keyboard-key quo.components.numbered-keyboard.keyboard-key.view/view)
(def numbered-keyboard quo.components.numbered-keyboard.numbered-keyboard.view/view)
;;;; PIN input
(def pin-input quo.components.pin-input.view/view)
;;;; Links
(def internal-link-card quo.components.links.internal-link-card.view/view)
(def link-preview quo.components.links.link-preview.view/view)

View File

@ -63,8 +63,10 @@
(defn view
[{:keys [hide? insets]}
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
gradient-cover? customization-color hide-handle? blur-radius]
:or {border-radius 12}}]
gradient-cover? customization-color hide-handle? blur-radius
hide-on-background-press?]
:or {border-radius 12
hide-on-background-press? true}}]
(let [theme (quo.theme/use-theme)
{window-height :height} (rn/get-window)
[sheet-height set-sheet-height] (rn/use-state 0)
@ -119,7 +121,7 @@
:on-layout handle-layout-height}
;; backdrop
[rn/pressable
{:on-press #(rf/dispatch [:hide-bottom-sheet])
{:on-press #(when hide-on-background-press? (rf/dispatch [:hide-bottom-sheet]))
:style {:flex 1}}
[reanimated/view
{:style (reanimated/apply-animations-to-style

View File

@ -144,6 +144,10 @@
(fn [_ [opts]]
{:keychain/save-password-and-auth-method opts}))
(defn- whisper-key-name
[address]
(str address "-whisper"))
;; NOTE: migrating the plaintext password in the keychain
;; with the hashed one. Added due to the sync onboarding
;; flow, where the password arrives already hashed.
@ -151,17 +155,38 @@
:keychain/password-hash-migration
(fn [{:keys [key-uid callback]
:or {callback identity}}]
(-> (get-password-migration! key-uid identity)
(.then (fn [migrated?]
(if migrated?
(callback)
(-> (get-user-password! key-uid identity)
(.then security/hash-masked-password)
(.then #(save-user-password! key-uid %))
(.then #(save-password-migration! key-uid))
(.then callback)))))
(.catch (fn [err]
(log/error "Failed to migrate the keychain password"
{:error err
:key-uid key-uid
:event :keychain/password-hash-migration}))))))
(keychain/get-credentials
(whisper-key-name key-uid)
(fn [whisper-key-data]
(if whisper-key-data
(callback) ;; we don't need to migrate keycard password
(-> (get-password-migration! key-uid identity)
(.then (fn [migrated?]
(if migrated?
(callback)
(-> (get-user-password! key-uid identity)
(.then security/hash-masked-password)
(.then #(save-user-password! key-uid %))
(.then #(save-password-migration! key-uid))
(.then callback)))))
(.catch (fn [err]
(log/error "Failed to migrate the keychain password"
{:error err
:key-uid key-uid
:event :keychain/password-hash-migration})))))))))
(re-frame/reg-fx
:keychain/get-keycard-keys
(fn [[key-uid callback]]
(keychain/get-credentials
key-uid
(fn [encryption-key-data]
(if encryption-key-data
(keychain/get-credentials
(whisper-key-name key-uid)
(fn [whisper-key-data]
(if whisper-key-data
(callback [(oops/oget encryption-key-data "password")
(oops/oget whisper-key-data "password")])
(callback nil))))
(callback nil))))))

View File

@ -25,7 +25,9 @@
:invite-friends (js/require "../resources/images/ui2/invite-friends.png")
:transaction-progress (js/require "../resources/images/ui2/transaction-progress.png")
:welcome-illustration (js/require "../resources/images/ui2/welcome_illustration.png")
:notifications (js/require "../resources/images/ui2/notifications.png")})
:notifications (js/require "../resources/images/ui2/notifications.png")
:nfc-prompt (js/require "../resources/images/ui2/nfc-prompt.png")
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")})
(def ui-themed
{:angry-man

View File

@ -10,11 +10,14 @@
(defn authorize
[{:keys [db]} [args]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
(let [key-uid (get-in db [:profile/profile :key-uid])
keycard? (get-in db [:profile/profile :keycard-pairing])]
{:fx [[:effects.biometric/check-if-available
{:key-uid key-uid
:on-success #(rf/dispatch [:standard-auth/authorize-with-biometric args])
:on-fail #(rf/dispatch [:standard-auth/authorize-with-password args])}]]}))
:on-fail (if keycard?
#(rf/dispatch [:standard-auth/authorize-with-keycard args])
#(rf/dispatch [:standard-auth/authorize-with-password args]))}]]}))
(schema/=> authorize events-schema/?authorize)
(rf/reg-event-fx :standard-auth/authorize authorize)
@ -45,8 +48,11 @@
(defn on-biometric-success
[{:keys [db]} [on-auth-success]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:keychain/get-user-password [key-uid on-auth-success]]
(let [key-uid (get-in db [:profile/profile :key-uid])
keycard? (get-in db [:profile/profile :keycard-pairing])]
{:fx [(if keycard?
[:keychain/get-keycard-keys [key-uid on-auth-success]]
[:keychain/get-user-password [key-uid on-auth-success]])
[:dispatch [:standard-auth/set-success true]]
[:dispatch [:standard-auth/reset-login-password]]]}))

View File

@ -126,6 +126,7 @@
(def ^:const profile-pictures-visibility-none 3)
(def ^:const min-password-length 6)
(def ^:const pincode-length 6)
(def ^:const new-password-min-length 10)
(def ^:const max-group-chat-participants 20)
(def ^:const max-group-chat-name-length 24)

View File

@ -0,0 +1,111 @@
(ns status-im.contexts.keycard.effects
(:require [keycard.keycard :as keycard]
[native-module.core :as native-module]
[react-native.async-storage :as async-storage]
[react-native.platform :as platform]
[status-im.contexts.profile.config :as profile.config]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(defonce ^:private active-listeners (atom []))
(defn register-card-events
[]
(doseq [listener @active-listeners]
(keycard/remove-event-listener listener))
(reset! active-listeners
[(keycard/on-card-connected #(rf/dispatch [:keycard/on-card-connected]))
(keycard/on-card-disconnected #(rf/dispatch [:keycard/on-card-disconnected]))
(when platform/ios?
(keycard/on-nfc-user-cancelled #(rf/dispatch [:keycard.ios/on-nfc-user-cancelled])))
(when platform/ios?
(keycard/on-nfc-timeout #(rf/dispatch [:keycard.ios/on-nfc-timeout])))
(keycard/on-nfc-enabled #(rf/dispatch [:keycard/on-check-nfc-enabled-success true]))
(keycard/on-nfc-disabled #(rf/dispatch [:keycard/on-check-nfc-enabled-success false]))]))
(rf/reg-fx :effects.keycard/register-card-events register-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.ios/start-nfc
(fn [args]
(log/debug "fx start-nfc")
(keycard/start-nfc args)))
(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)

View File

@ -0,0 +1,57 @@
(ns status-im.contexts.keycard.events
(:require [re-frame.core :as rf]
status-im.contexts.keycard.login.events
status-im.contexts.keycard.pin.events
status-im.contexts.keycard.sheet.events
[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 (assoc-in db [:keycard :pin :status] nil)
:fx [(when-let [on-nfc-cancelled-event-vector (get-in db [:keycard :on-nfc-cancelled-event-vector])]
[:dispatch on-nfc-cancelled-event-vector])]}))
(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/get-application-info
(fn [_ [{:keys [on-success on-failure]}]]
(log/debug "[keycard] get-application-info")
{:effects.keycard/get-application-info {:on-success on-success
:on-failure on-failure}}))
(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)}))

View File

@ -0,0 +1,87 @@
(ns status-im.contexts.keycard.login.events
(:require [status-im.contexts.keycard.utils :as keycard.utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/reg-event-fx :keycard.login/on-get-keys-error
(fn [{:keys [db]} [error]]
(log/debug "[keycard] get keys 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?
{: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)
(update-in [:keycard :pin] assoc :status :error))
:fx [[:dispatch [:keycard/hide-connection-sheet]]
(when (zero? pin-retries-count)
[:effects.utils/show-popup {:title "frozen-keycard"}])]})))))
(rf/reg-event-fx :keycard.login/on-get-keys-success
(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
(dissoc :keycard)
(update :profile/login assoc
:password encryption-public-key
:key-uid key-uid
:name (:name profile)))
:fx [[:dispatch [:keycard/hide-connection-sheet]]
[:effects.keycard/login-with-keycard
{:password encryption-public-key
:whisper-private-key whisper-private-key
:key-uid key-uid}]]})))
(rf/reg-event-fx :keycard.login/on-get-keys-from-keychain-success
(fn [{:keys [db]} [key-uid [encryption-public-key whisper-private-key]]]
(when (and encryption-public-key whisper-private-key)
(let [profile (get-in db [:profile/profiles-overview key-uid])]
{:db
(-> db
(dissoc :keycard)
(update :profile/login assoc
:password encryption-public-key
:key-uid key-uid
:name (:name profile)))
:fx [[:dispatch [:keycard/hide-connection-sheet]]
[:effects.keycard/login-with-keycard
{:password encryption-public-key
:whisper-private-key whisper-private-key
:key-uid key-uid}]]}))))
(rf/reg-event-fx :keycard.login/on-get-application-info-success
(fn [{:keys [db]} [application-info]]
(let [profile (get-in db [:profile/profiles-overview (get-in db [:profile/login :key-uid])])
pin (get-in db [:keycard :pin :text])
error (keycard.utils/validate-application-info profile application-info)]
(if error
{:effects.utils/show-popup {:title (str error)}}
{:db (-> db
(assoc-in [:keycard :application-info] application-info)
(assoc-in [:keycard :pin :status] :verifying))
:effects.keycard/get-keys {:pin pin
:on-success #(rf/dispatch [:keycard.login/on-get-keys-success %])
:on-failure #(rf/dispatch [:keycard.login/on-get-keys-error %])}}))))
(rf/reg-event-fx :keycard.login/cancel-reading-card
(fn [{:keys [db]}]
{:db (assoc-in db [:keycard :on-card-connected-event-vector] nil)}))
(rf/reg-event-fx :keycard/read-card-and-login
(fn [{:keys [db]}]
(let [connected? (get-in db [:keycard :card-connected?])
event-vector [:keycard/get-application-info
{:on-success #(rf/dispatch [:keycard.login/on-get-application-info-success %])}]]
(log/debug "[keycard] proceed-to-login")
{:db (assoc-in db [:keycard :on-card-connected-event-vector] event-vector)
:fx [[:dispatch
[:keycard/show-connection-sheet
{:on-cancel-event-vector [:keycard.login/cancel-reading-card]}]]
(when connected?
[:dispatch event-vector])]})))

View File

@ -0,0 +1,21 @@
(ns status-im.contexts.keycard.pin.events
(:require [utils.re-frame :as rf]))
(rf/reg-event-fx :keycard.pin/delete-pressed
(fn [{:keys [db]}]
(let [pin (get-in db [:keycard :pin :text])]
(when (and pin (pos? (count pin)))
{:db (-> db
(assoc-in [:keycard :pin :text] (.slice pin 0 -1))
(assoc-in [:keycard :pin :status] nil))}))))
(rf/reg-event-fx :keycard.pin/number-pressed
(fn [{:keys [db]} [number max-numbers on-complete-event]]
(let [pin (get-in db [:keycard :pin :text])
new-pin (str pin number)]
(when (<= (count new-pin) max-numbers)
{:db (-> db
(assoc-in [:keycard :pin :text] new-pin)
(assoc-in [:keycard :pin :status] nil))
:fx [(when (= (dec max-numbers) (count pin))
[:dispatch [on-complete-event]])]}))))

View File

@ -0,0 +1,26 @@
(ns status-im.contexts.keycard.pin.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn auth
[callback-event-key]
(let [{:keys [text status]} (rf/sub [:keycard/pin])
pin-retry-counter (rf/sub [:keycard/pin-retry-counter])
error? (= status :error)]
[rn/view {:padding-bottom 12 :flex 1}
[rn/view {:flex 1 :justify-content :center :align-items :center :padding 34}
[quo/pin-input
{:blur? false
:number-of-pins constants/pincode-length
:number-of-filled-pins (count text)
:error? error?
:info (when error?
(i18n/label :t/pin-retries-left {:number pin-retry-counter}))}]]
[quo/numbered-keyboard
{:delete-key? true
:on-delete #(rf/dispatch [:keycard.pin/delete-pressed])
:on-press #(rf/dispatch [:keycard.pin/number-pressed % constants/pincode-length
callback-event-key])}]]))

View File

@ -0,0 +1,30 @@
(ns status-im.contexts.keycard.sheet.events
(:require [re-frame.core :as rf]
[react-native.platform :as platform]
[taoensso.timbre :as log]))
(rf/reg-event-fx :keycard/show-connection-sheet-component
(fn [{:keys [db]} [{:keys [on-cancel-event-vector]}]]
{:db (assoc-in db [:keycard :connection-sheet-opts] {:on-close #(rf/dispatch on-cancel-event-vector)})
:fx [[:dismiss-keyboard true]
[:show-nfc-sheet nil]]}))
(rf/reg-event-fx :keycard/show-connection-sheet
(fn [_ [args]]
(if platform/android?
{:dispatch [:keycard/show-connection-sheet-component args]}
{:effects.keycard.ios/start-nfc
{:on-success
(fn []
(log/debug "nfc started successfully. next: show-connection-sheet")
(rf/dispatch [:keycard.ios/on-start-nfc-success args]))
:on-failure
(fn []
(log/debug "nfc failed star starting. not calling show-connection-sheet"))}})))
(rf/reg-event-fx :keycard/hide-connection-sheet
(fn [{:keys [db]}]
(if platform/android?
{:db (assoc-in db [:keycard :connection-sheet-opts] nil)
:fx [[:hide-nfc-sheet nil]]}
{:effects.keycard.ios/stop-nfc nil})))

View File

@ -0,0 +1,36 @@
(ns status-im.contexts.keycard.sheet.view
(:require [quo.foundations.colors :as colors]
quo.theme
[react-native.core :as rn]
[status-im.common.resources :as resources]
[utils.re-frame :as rf]))
(defn connect-keycard
[]
(let [connected? (rf/sub [:keycard/connected?])
{:keys [on-close]} (rf/sub [:keycard/connection-sheet-opts])
theme (quo.theme/use-theme)]
[rn/view {:flex 1}
[rn/view {:flex 1}]
[rn/view
{:style {:align-items :center
:padding-horizontal 36
:padding-vertical 30
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}}
[rn/text {:style {:font-size 26 :color "#9F9FA5" :margin-bottom 36}}
"Ready to Scan"]
[rn/image
{:source (resources/get-image :nfc-prompt)}]
[rn/text {:style {:font-size 16 :color :white :margin-vertical 36}}
(if connected?
"Connected. Dont move your card."
"Hold your phone near a Status Keycard")]
[rn/pressable
{:on-press (fn []
(when on-close (on-close))
(rf/dispatch [:keycard/hide-connection-sheet]))
:style {:flex-direction :row}}
[rn/view
{:style {:background-color "#8E8E93" :flex 1 :align-items :center :padding 18 :border-radius 10}}
[rn/text {:style {:color :white :font-size 16}}
"Cancel"]]]]]))

View File

@ -0,0 +1,45 @@
(ns status-im.contexts.keycard.utils
(:require [taoensso.timbre :as log]))
(def pin-mismatch-error #"Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)")
(defn pin-retries
[error]
(when-let [matched-error (re-matches pin-mismatch-error error)]
(js/parseInt (second (filter some? matched-error)))))
(defn tag-lost?
[error]
(or
(= error "Tag was lost.")
(= error "NFCError:100")
(re-matches #".*NFCError:100.*" error)))
(defn validate-application-info
[profile {:keys [key-uid paired? pin-retry-counter puk-retry-counter] :as application-info}]
(let [profile-mismatch? (or (nil? profile) (not= (:key-uid profile) 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)
:not-keycard
(empty? (:key-uid application-info))
:keycard-blank
profile-mismatch?
:keycard-wrong
(not paired?)
:keycard-unpaired
(and (zero? pin-retry-counter)
(or (nil? puk-retry-counter)
(pos? puk-retry-counter)))
nil
:else
nil)))

View File

@ -144,6 +144,7 @@
small-option-card]
[status-im.contexts.preview.quo.password.password-tips :as password-tips]
[status-im.contexts.preview.quo.password.tips :as tips]
[status-im.contexts.preview.quo.pin-input.pin-input :as pin-input]
[status-im.contexts.preview.quo.profile.collectible :as collectible]
[status-im.contexts.preview.quo.profile.collectible-list-item :as collectible-list-item]
[status-im.contexts.preview.quo.profile.expanded-collectible :as expanded-collectible]
@ -369,6 +370,8 @@
:component keyboard-key/view}
{:name :numbered-keyboard
:component numbered-keyboard/view}]
:pin-input [{:name :pin-input
:component pin-input/view}]
:links [{:name :internal-link-card
:options {:insets {:top true}}
:component internal-link-card/view}

View File

@ -0,0 +1,27 @@
(ns status-im.contexts.preview.quo.pin-input.pin-input
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :blur? :type :boolean}
{:type :number
:key :number-of-pins}
{:type :number
:key :number-of-filled-pins}
{:type :boolean
:key :error?}
{:type :text
:key :info}])
(defn view
[]
(let [[state set-state] (rn/use-state {:blur? false
:number-of-pins 6
:number-of-filled-pins 0})]
[preview/preview-container
{:state state
:set-state set-state
:descriptor descriptor}
[rn/view {:style {:padding-vertical 40 :align-items :center :justify-content :center}}
[quo/pin-input state]]]))

View File

@ -186,9 +186,13 @@
(rf/reg-event-fx
:profile.login/biometric-success
(fn [{:keys [db]}]
(let [key-uid (get-in db [:profile/login :key-uid])]
{:keychain/get-user-password [key-uid
#(rf/dispatch [:profile.login/get-user-password-success %])]})))
(let [key-uid (get-in db [:profile/login :key-uid])
keycard? (get-in db [:profile/profiles-overview key-uid :keycard-pairing])]
(if keycard?
{:keychain/get-keycard-keys
[key-uid #(rf/dispatch [:keycard.login/on-get-keys-from-keychain-success key-uid %])]}
{:keychain/get-user-password
[key-uid #(rf/dispatch [:profile.login/get-user-password-success %])]}))))
(rf/reg-event-fx
:profile.login/biometric-auth-fail

View File

@ -10,6 +10,7 @@
[status-im.common.standard-authentication.core :as standard-authentication]
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.keycard.pin.view :as keycard.pin]
[status-im.contexts.onboarding.common.background.view :as background]
[status-im.contexts.profile.profiles.style :as style]
[taoensso.timbre :as log]
@ -140,7 +141,7 @@
[:profile/profile-selected key-uid])
(rf/dispatch
[:profile.login/login-with-biometric-if-available key-uid])
(when-not keycard-pairing (set-hide-profiles)))}]))
(set-hide-profiles))}]))
(defn- profiles-section
[{:keys [hide-profiles]}]
@ -189,8 +190,8 @@
[:profile.login/biometric-success])
:on-fail #(rf/dispatch
[:profile.login/biometric-auth-fail
%])}]))
]
%])}]))]
[standard-authentication/password-input
{:shell? true
:blur? true
@ -199,7 +200,7 @@
(defn login-section
[{:keys [show-profiles]}]
(let [processing (rf/sub [:profile/login-processing])
{:keys [key-uid name
{: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])
@ -228,7 +229,7 @@
:disabled? processing
:accessibility-label :show-profiles}
:i/multi-profile]]
[rn/scroll-view
[(if keycard-pairing rn/view rn/scroll-view)
{:keyboard-should-persist-taps :always
:style {:flex 1}}
[quo/profile-card
@ -236,17 +237,20 @@
:customization-color (or customization-color :primary)
:profile-picture profile-picture
:card-style style/login-profile-card}]
[password-input]]
[quo/button
{:size 40
:type :primary
:customization-color (or customization-color :primary)
:accessibility-label :login-button
:icon-left :i/unlocked
:disabled? (or (not sign-in-enabled?) processing)
:on-press login-multiaccount
:container-style {:margin-bottom (+ (safe-area/get-bottom) 12)}}
(i18n/label :t/log-in)]]))
(if keycard-pairing
[keycard.pin/auth :keycard/read-card-and-login]
[password-input])]
(when-not keycard-pairing
[quo/button
{:size 40
:type :primary
:customization-color (or customization-color :primary)
:accessibility-label :login-button
:icon-left :i/unlocked
:disabled? (or (not sign-in-enabled?) processing)
:on-press login-multiaccount
:container-style {:margin-bottom (+ (safe-area/get-bottom) 12)}}
(i18n/label :t/log-in)])]))
(defn view
[]

View File

@ -41,10 +41,5 @@
:visibility-status-updates {}
:stickers/packs-pending #{}
:settings/change-password {}
:keycard {:nfc-enabled? false
:pin {:original []
:confirmation []
:current []
:puk []
:enter-step :original}}
:keycard {}
:theme :light})

View File

@ -25,6 +25,8 @@
status-im.contexts.communities.overview.events
status-im.contexts.communities.sharing.events
status-im.contexts.contact.blocking.events
status-im.contexts.keycard.effects
status-im.contexts.keycard.events
status-im.contexts.onboarding.common.overlay.events
status-im.contexts.onboarding.events
status-im.contexts.profile.events
@ -57,6 +59,9 @@
:theme/init-theme nil
:network/listen-to-network-info nil
:effects.biometric/get-supported-type nil
:effects.keycard/register-card-events nil
:effects.keycard/check-nfc-enabled nil
:effects.keycard/retrieve-pairings nil
;;app starting flow continues in get-profiles-overview
:profile/get-profiles-overview #(rf/dispatch [:profile/get-profiles-overview-success %])
:effects.font/get-font-file-for-initials-avatar

View File

@ -81,14 +81,22 @@
(fn [] views/bottom-sheet))
;;;; Alert Banner
(navigation/register-component
"alert-banner"
(fn [] (gesture/gesture-handler-root-hoc views/alert-banner #js {:flex 0}))
(fn [] views/alert-banner))
;;;; LEGACY (should be removed in status 2.0)
;;;; NFC sheet
(navigation/register-component
"popover"
(fn [] (gesture/gesture-handler-root-hoc views/popover-comp))
(fn [] views/popover-comp)))
"nfc-sheet"
(fn [] (gesture/gesture-handler-root-hoc views/nfc-sheet-comp))
(fn [] views/nfc-sheet-comp)))
;;;; LEGACY (should be removed in status 2.0)
(navigation/register-component
"popover"
(fn [] (gesture/gesture-handler-root-hoc views/popover-comp))
(fn [] views/popover-comp))

View File

@ -230,6 +230,7 @@
(fn [] (navigation/dissmiss-overlay "bottom-sheet")))
;;;; Alert Banner
(rf/reg-fx :show-alert-banner
(fn [[view-id theme]]
(show-overlay "alert-banner"
@ -245,67 +246,17 @@
(reset! state/alert-banner-shown? false)
(reload-status-nav-color-fx [view-id theme])))
;;;; Merge options
;;;; NFC sheet
(rf/reg-fx :merge-options
(fn [{:keys [id options]}]
(navigation/merge-options id options)))
(rf/reg-fx :show-nfc-sheet
(fn [] (show-overlay "nfc-sheet")))
(rf/reg-fx :hide-nfc-sheet
(fn [] (navigation/dissmiss-overlay "nfc-sheet")))
;;;; Legacy (should be removed in status 2.0)
(defn- get-screen-component
[component]
(let [{:keys [options]} (get views/screens component)]
{:component {:id component
:name component
:options (merge (options/statusbar-and-navbar-options (:theme options) nil nil)
options)}}))
(rf/reg-fx :set-stack-root-fx
(fn [[stack component]]
;; We don't have bottom tabs as separate stacks anymore,. So the old way of pushing screens in
;; specific tabs will not work. Disabled set-stack-root for :shell-stack as it is not working
;; and currently only being used for browser and some rare keycard flows after login
(when-not (= @state/root-id :shell-stack)
(log/debug :set-stack-root-fx stack component)
(navigation/set-stack-root
(name stack)
(if (vector? component)
(mapv get-screen-component component)
(get-screen-component component))))))
(rf/reg-fx :show-popover
(fn [] (show-overlay "popover")))
(rf/reg-fx :hide-popover
(fn [] (navigation/dissmiss-overlay "popover")))
(rf/reg-fx :show-visibility-status-popover
(fn [] (show-overlay "visibility-status-popover")))
(rf/reg-fx :hide-visibility-status-popover
(fn [] (navigation/dissmiss-overlay "visibility-status-popover")))
(rf/reg-fx :show-wallet-connect-sheet
(fn [] (show-overlay "wallet-connect-sheet")))
(rf/reg-fx :hide-wallet-connect-sheet
(fn [] (navigation/dissmiss-overlay "wallet-connect-sheet")))
(rf/reg-fx :show-wallet-connect-success-sheet
(fn [] (show-overlay "wallet-connect-success-sheet")))
(rf/reg-fx :hide-wallet-connect-success-sheet
(fn [] (navigation/dissmiss-overlay "wallet-connect-success-sheet")))
(rf/reg-fx :show-wallet-connect-app-management-sheet
(fn [] (show-overlay "wallet-connect-app-management-sheet")))
(rf/reg-fx :hide-wallet-connect-app-management-sheet
(fn [] (navigation/dissmiss-overlay "wallet-connect-app-management-sheet")))
(rf/reg-fx :show-signing-sheet
(fn [] (show-overlay "signing-sheet")))
(rf/reg-fx :hide-signing-sheet
(fn [] (navigation/dissmiss-overlay "signing-sheet")))

View File

@ -74,11 +74,6 @@
[{:keys [db]} root-id]
{:set-root [root-id (:theme db)]})
(rf/defn set-stack-root
{:events [:set-stack-root]}
[_ stack root]
{:set-stack-root-fx [stack root]})
(rf/defn change-tab
{:events [:navigate-change-tab]}
[{:keys [db]} stack-id]

View File

@ -11,6 +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.sheet.view :as keycard.sheet]
[status-im.navigation.screens :as screens]
[status-im.setup.hot-reload :as reloader]
[utils.re-frame :as rf]))
@ -121,6 +122,17 @@
[alert-banner/view]])
functional-compiler))
(def nfc-sheet-comp
(reagent/reactify-component
(fn []
(let [app-theme (rf/sub [:theme])]
^{:key (str "nfc-sheet-" @reloader/cnt)}
[quo.theme/provider app-theme
[rn/keyboard-avoiding-view
{:style {:position :relative :flex 1}}
[keycard.sheet/connect-keycard]]]))
functional-compiler))
;; LEGACY (should be removed in status 2.0)
(def popover-comp

View File

@ -0,0 +1,38 @@
(ns status-im.subs.keycard
(:require [utils.re-frame :as rf]))
(rf/reg-sub
:keycard/keycard-profile?
(fn [db]
(not (nil? (get-in db [:profile/profile :keycard-pairing])))))
(rf/reg-sub
:keycard/nfc-enabled?
:<- [:keycard]
(fn [keycard]
(:nfc-enabled? keycard)))
(rf/reg-sub
:keycard/connected?
:<- [:keycard]
(fn [keycard]
(:card-connected? keycard)))
(rf/reg-sub
:keycard/pin
:<- [:keycard]
(fn [keycard]
(:pin keycard)))
(rf/reg-sub
:keycard/pin-retry-counter
:<- [:keycard]
(fn [keycard]
(get-in keycard [:application-info :pin-retry-counter])))
(rf/reg-sub
:keycard/connection-sheet-opts
:<- [:keycard]
(fn [keycard]
(:connection-sheet-opts keycard)))

View File

@ -9,6 +9,7 @@
status-im.subs.community.account-selection
status-im.subs.contact
status-im.subs.general
status-im.subs.keycard
status-im.subs.messages
status-im.subs.onboarding
status-im.subs.pairing
@ -186,3 +187,6 @@
;; centralized-metrics
(reg-root-key-sub :centralized-metrics/enabled? :centralized-metrics/enabled?)
(reg-root-key-sub :centralized-metrics/user-confirmed? :centralized-metrics/user-confirmed?)
;;keycard
(reg-root-key-sub :keycard :keycard)

View File

@ -81,6 +81,8 @@
(def sub (comp deref re-frame/subscribe))
(def reg-sub re-frame/reg-sub)
(def dispatch re-frame/dispatch)
(def reg-fx re-frame/reg-fx)