diff --git a/src/status_im2/common/biometric/events.cljs b/src/status_im2/common/biometric/events.cljs index edb9ac1f2a8..7508e197a07 100644 --- a/src/status_im2/common/biometric/events.cljs +++ b/src/status_im2/common/biometric/events.cljs @@ -2,9 +2,11 @@ (:require [native-module.core :as native-module] [re-frame.core :as re-frame] + [react-native.async-storage :as async-storage] [react-native.platform :as platform] [react-native.touch-id :as touch-id] [status-im2.common.keychain.events :as keychain] + [taoensso.timbre :as log] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -41,6 +43,7 @@ {:db (assoc db :biometric/supported-type supported-type)}) (rf/defn show-message + {:events [:biometric/show-message]} [_ code] (let [handle-error? (and code (not (contains? #{"USER_CANCELED" "USER_FALLBACK"} code))) @@ -52,6 +55,48 @@ {:title (i18n/label :t/biometric-auth-login-error-title) :content content}}))) +(defn- supress-biometry-error-key + [key-uid] + (keyword (str "biometric/supress-not-enrolled-error-" key-uid))) + +;; NOTE: if the account had biometrics registered, but it's not enrolled at the moment, +;; we should show the error message only once and supress further "NOT_ENROLLED" errors +;; until biometry is enrolled again. Note that we can only know that when :biometric/authenticate +;; is dispatched and fails with "NOT_ENROLLED", since :biometric/get-supported-biometric-type +;; only tells us what kind of biometric is available on the device, but it doesn't know of its +;; enrollment status. +(re-frame/reg-fx + :biometric/supress-not-enrolled-error + (fn [[key-uid dispatch-event]] + (let [storage-key (supress-biometry-error-key key-uid)] + (-> (async-storage/get-item storage-key identity) + (.then (fn [item] + (when (not item) + (rf/dispatch dispatch-event) + (async-storage/set-item! storage-key true)))) + (.catch (fn [err] + (log/error "Couldn't supress biometry NOT_ENROLLED error" + {:key-uid key-uid + :event :biometric/supress-not-enrolled-error + :error err}))))))) + +;; NOTE: when biometrics is re-enrolled, we erase the flag in async-storage to assure +;; the "NOT_ENROLLED" error message will be shown again if biometrics is un-enrolled +;; in the future. +(re-frame/reg-fx + :biometric/reset-not-enrolled-error + (fn [key-uid] + (let [storage-key (supress-biometry-error-key key-uid)] + (-> (async-storage/get-item storage-key identity) + (.then (fn [supress?] + (when supress? + (async-storage/set-item! storage-key nil)))) + (.catch (fn [err] + (log/error "Couldn't reset supressing biometry NOT_ENROLLED error" + {:key-uid key-uid + :event :biometric/reset-not-enrolled-error + :error err}))))))) + (re-frame/reg-fx :biometric/authenticate (fn [options] diff --git a/src/status_im2/contexts/profile/login/events.cljs b/src/status_im2/contexts/profile/login/events.cljs index b51619ee5f9..9c9cc3a626d 100644 --- a/src/status_im2/contexts/profile/login/events.cljs +++ b/src/status_im2/contexts/profile/login/events.cljs @@ -173,14 +173,6 @@ :on-fail #(rf/dispatch [:profile.login/biometric-auth-fail %])}]))}}))) -(rf/defn biometric-auth-success - {:events [:profile.login/biometric-success]} - [{:keys [db] :as cofx}] - (let [key-uid (get-in db [:profile/login :key-uid])] - (keychain/get-user-password cofx - key-uid - #(rf/dispatch [:profile.login/get-user-password-success %])))) - ;; result of :keychain/get-auth-method above (rf/defn get-user-password-success {:events [:profile.login/get-user-password-success]} @@ -192,12 +184,27 @@ (navigation/init-root :progress) (biometrics-login)))) -(rf/defn biometric-auth-fail - {:events [:profile.login/biometric-auth-fail]} - [{:keys [db] :as cofx} code] - (rf/merge cofx - (navigation/init-root :profiles) - (biometric/show-message code))) +(rf/reg-event-fx + :profile.login/biometric-success + (fn [{:keys [db]}] + (let [key-uid (get-in db [:profile/login :key-uid])] + {:db db + :fx [[:biometric/reset-not-enrolled-error 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 + (fn [{:keys [db]} [code]] + (let [key-uid (get-in db [:profile/login :key-uid])] + {:db db + :fx [[:dispatch [:init-root :profiles]] + (if (= code "NOT_ENROLLED") + [:biometric/supress-not-enrolled-error + [key-uid + [:biometric/show-message code]]] + [:dispatch [:biometric/show-message code]])]}))) + (rf/defn verify-database-password {:events [:profile.login/verify-database-password]}