From a184b9c35ef8e23f2f243750000e51f95829ac05 Mon Sep 17 00:00:00 2001 From: Daniel Garcia-Briseno Date: Sun, 10 Apr 2022 10:43:08 -0400 Subject: [PATCH] Fix problem where signing in requires 8 charsxs Add description that emojis are supported. Update minimum password length for reset password popup add password utility Update onboarding and reset password views to share password checking code Update to support masked data Add error when password validation fails Formatting fix Fix is-sequential? function --- src/status_im/constants.cljs | 5 +- src/status_im/multiaccounts/db.cljs | 2 +- src/status_im/subs.cljs | 5 +- .../ui/screens/onboarding/password/views.cljs | 21 ++++---- src/status_im/utils/password_utils.cljs | 51 +++++++++++++++++++ translations/en.json | 3 +- 6 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 src/status_im/utils/password_utils.cljs diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 675560c85ad..f4afa28767f 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -67,7 +67,8 @@ (def ^:const profile-pictures-visibility-everyone 2) (def ^:const profile-pictures-visibility-none 3) -(def ^:const min-password-length 6) +(def ^:const min-password-length 8) ; This is the min length for new passwords +(def ^:const min-sign-in-password-length 6) ; This is the min length for signing in (def ^:const max-group-chat-participants 20) (def ^:const default-number-of-messages 20) (def ^:const default-number-of-pin-messages 3) @@ -171,4 +172,4 @@ (def ^:const visibility-status-inactive 4) (def ^:const wallet-connect-version-1 1) -(def ^:const wallet-connect-version-2 2) \ No newline at end of file +(def ^:const wallet-connect-version-2 2) diff --git a/src/status_im/multiaccounts/db.cljs b/src/status_im/multiaccounts/db.cljs index 9cdf5b5626b..81119b361a6 100644 --- a/src/status_im/multiaccounts/db.cljs +++ b/src/status_im/multiaccounts/db.cljs @@ -3,6 +3,6 @@ [status-im.constants :as const])) (defn valid-length? [password] - (>= (count password) const/min-password-length)) + (>= (count password) const/min-sign-in-password-length)) (spec/def ::password (spec/and :global/not-empty-string valid-length?)) diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 702fb4e46f9..ad389a51091 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -32,6 +32,7 @@ [status-im.utils.gfycat.core :as gfycat] [status-im.utils.money :as money] [status-im.utils.security :as security] + [status-im.utils.password-utils :as pass] [status-im.wallet.db :as wallet.db] [status-im.wallet.utils :as wallet.utils] status-im.ui.screens.keycard.subs @@ -2948,9 +2949,9 @@ (and (pos? (count current-password)) (pos? (count new-password)) (pos? (count confirm-new-password)) - (>= (count new-password) 6) + (pass/valid-password new-password) (>= (count current-password) 6) - (= new-password confirm-new-password))}))) + (pass/confirm-password new-password confirm-new-password))}))) (re-frame/reg-sub :bookmarks/active diff --git a/src/status_im/ui/screens/onboarding/password/views.cljs b/src/status_im/ui/screens/onboarding/password/views.cljs index 225b65ddda5..fa2e3afceb7 100644 --- a/src/status_im/ui/screens/onboarding/password/views.cljs +++ b/src/status_im/ui/screens/onboarding/password/views.cljs @@ -3,17 +3,11 @@ [reagent.core :as reagent] [status-im.ui.components.toolbar :as toolbar] [status-im.i18n.i18n :as i18n] - [status-im.constants :as const] [status-im.utils.security :as security] + [status-im.utils.password-utils :as pass] [quo.react-native :as rn] [quo.core :as quo])) -(defn validate-password [password] - (>= (count password) const/min-password-length)) - -(defn confirm-password [password confirm] - (= password confirm)) - (defn screen [] (let [password (reagent/atom nil) confirm (reagent/atom nil) @@ -21,8 +15,8 @@ show-error (reagent/atom nil) confirm-ref (atom nil)] (fn [] - (let [valid-password (validate-password @password) - valid-form (confirm-password @password @confirm) + (let [valid-password (pass/valid-password @password) + valid-form (pass/confirm-password @password @confirm) {:keys [recovering?]} @(re-frame/subscribe [:intro-wizard]) on-submit (fn [] (when (not @processing?) @@ -52,6 +46,11 @@ :placeholder (i18n/label :t/password-placeholder) :on-change-text #(reset! password (security/mask-data %)) :return-key-type :next + ; When the password is not valid, but it already meets the minimum length + ; Then show the error about not allowing weak passwords like aaaa and 12345 + :error (when (and (not valid-password) + (pass/meets-minimum-length? @password)) + (i18n/label :t/password_error2)) :on-submit-editing #(when valid-password (some-> ^js @confirm-ref .focus))}]] [rn/view {:style {:padding 16 @@ -74,7 +73,7 @@ (> (count @password) (count @confirm)) (reset! show-error false) - (not (confirm-password @password @confirm)) + (not (pass/confirm-password @password @confirm)) (reset! show-error true) :else (reset! show-error false)))}]]] @@ -104,4 +103,4 @@ @processing?) :type :secondary :after :main-icons/next} - (i18n/label :t/next)]}))]])))) \ No newline at end of file + (i18n/label :t/next)]}))]])))) diff --git a/src/status_im/utils/password_utils.cljs b/src/status_im/utils/password_utils.cljs new file mode 100644 index 00000000000..6b85fae8c5f --- /dev/null +++ b/src/status_im/utils/password_utils.cljs @@ -0,0 +1,51 @@ +(ns status-im.utils.password-utils + (:require [status-im.constants :as const] + [status-im.utils.security :as security])) + +(defn ord + "Convert a character to a unicode integer" + [val] + (.charCodeAt val)) + +(defn to-numbers + "Maps a string to a array of integers representing the string" + [vals] + (map ord vals)) + +(defn diff + "Compares all characters in a string to the character to their right. + If the character matches the next char, then the value becomes 1, if + the characters are different, the value becomes 0." + [vals] + (map - (next vals) vals)) + +(defn is-same? + "Returns true if both values are the same." + [a b] + (= a b)) + +(defn all-same? + "Returns true if all characters in the give string are the same." + [word] + (let [first-letter (first word)] + (every? #{first-letter} word))) + +(defn is-sequential? + "Returns true if the unicode value of all characters in the given string are sequential" + [sequence] + (all-same? (diff (to-numbers sequence)))) + +(defn meets-minimum-length? + "Returns true if the given string's length is greater than the defined minimum password length" + [password] + (>= (count password) const/min-password-length)) + +(defn valid-password + "Returns true if all password requirements are met." + [password] + (and (meets-minimum-length? password) + (not (all-same? (security/safe-unmask-data password))) + (not (is-sequential? (security/safe-unmask-data password))))) + +(defn confirm-password [password confirm] + (= password confirm)) diff --git a/translations/en.json b/translations/en.json index e606c1f3489..e961579a348 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1014,9 +1014,10 @@ "pairing-please-set-a-name": "Please set a name for your device.", "passphrase": "Passphrase", "password": "Password", - "password-description": "At least 6 characters. Your password protects your keys. You need it to unlock Status and transact.", + "password-description": "At least 8 characters. It may also include unicode characters and emojis. Your password protects your keys. You need it to unlock Status and transact.", "password-placeholder2": "Confirm your password", "password_error1": "Passwords don't match.", + "password_error2": "Password does not meet minimum requirements. At least 8 characters and not like 12345678 or aaaaaaaa", "paste": "Paste", "paste-json": "Paste JSON", "pay-to-chat": "Pay to chat",