diff --git a/signup-service/src/main/java/io/mosip/signup/helper/AuditHelper.java b/signup-service/src/main/java/io/mosip/signup/helper/AuditHelper.java index dc03d0b0..13f8e384 100644 --- a/signup-service/src/main/java/io/mosip/signup/helper/AuditHelper.java +++ b/signup-service/src/main/java/io/mosip/signup/helper/AuditHelper.java @@ -45,7 +45,7 @@ public void sendAuditTransaction(AuditEvent auditEvent, AuditEventType eventType restRequestWrapper.setRequesttime(getUTCDateTime()); String description = signUpException != null ? - ExceptionUtils.getStackTrace(signUpException) : null; + ExceptionUtils.getStackTrace(signUpException) : auditEvent.toString() + " " + eventType.toString(); if (description != null && description.length() > auditDescriptionMaxLength) { description = description.substring(0, auditDescriptionMaxLength); } diff --git a/signup-service/src/main/java/io/mosip/signup/helper/CryptoHelper.java b/signup-service/src/main/java/io/mosip/signup/helper/CryptoHelper.java index 0ab5a883..a405d442 100644 --- a/signup-service/src/main/java/io/mosip/signup/helper/CryptoHelper.java +++ b/signup-service/src/main/java/io/mosip/signup/helper/CryptoHelper.java @@ -1,39 +1,54 @@ package io.mosip.signup.helper; import io.mosip.esignet.core.util.IdentityProviderUtil; +import io.mosip.kernel.core.util.UUIDUtils; import io.mosip.signup.exception.SignUpException; import io.mosip.signup.services.CacheUtilService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import static io.mosip.kernel.core.util.UUIDUtils.NAMESPACE_OID; + @Slf4j @Component public class CryptoHelper { - private static final String AES_TRANSFORMATION = "AES/CFB/PKCS5Padding"; - public static final String CACHE_KEY = "aes"; + public static final String ALIAS_CACHE_KEY = "CURRENT_ACTIVE_ALIAS"; + + @Value("${mosip.signup.cache.symmetric-algorithm-name}") + private String symmetricAlgorithm; + + @Value("${mosip.signup.cache.symmetric-key.algorithm-name:AES}") + private String symmetricKeyAlgorithm; + + @Value("${mosip.signup.cache.symmetric-key.size:256}") + private int symmetricKeySize; @Autowired private CacheUtilService cacheUtilService; - public String symmetricEncrypt(String transactionId, String data, SecretKey secretKey) { + public String symmetricEncrypt(String data) { try { - Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION); + + String keyAlias = getActiveKeyAlias(); + SecretKey secretKey = getSecretKey(keyAlias); + + Cipher cipher = Cipher.getInstance(symmetricAlgorithm); byte[] initializationVector = IdentityProviderUtil.generateSalt(cipher.getBlockSize()); byte[] secretDataBytes = data.getBytes(StandardCharsets.UTF_8); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(initializationVector)); byte[] encryptedBytes = cipher.doFinal(secretDataBytes, 0, secretDataBytes.length); - String keyAlias = getKeyAlias(transactionId); byte[] keyAliasBytes = keyAlias.getBytes(); - cacheUtilService.setSecretKeyBasedOnAlias(keyAlias, IdentityProviderUtil.b64Encode(secretKey.getEncoded())); byte[] output = new byte[cipher.getOutputSize(secretDataBytes.length)+cipher.getBlockSize()+keyAliasBytes.length]; System.arraycopy(encryptedBytes, 0, output, 0, encryptedBytes.length); @@ -49,12 +64,12 @@ public String symmetricEncrypt(String transactionId, String data, SecretKey secr public String symmetricDecrypt(String encryptedData) { try { - Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION); + Cipher cipher = Cipher.getInstance(symmetricAlgorithm); byte[] data = IdentityProviderUtil.b64Decode(encryptedData); - byte[] keyAlias = Arrays.copyOfRange(data, data.length - 10, data.length); - byte[] iv = Arrays.copyOfRange(data, data.length-(cipher.getBlockSize()+10), data.length-10); - byte[] encryptedBytes = Arrays.copyOfRange(data, 0, data.length-(cipher.getBlockSize()+10)); + byte[] keyAlias = Arrays.copyOfRange(data, data.length-36, data.length); + byte[] iv = Arrays.copyOfRange(data, data.length-(cipher.getBlockSize()+36), data.length-36); + byte[] encryptedBytes = Arrays.copyOfRange(data, 0, data.length-(cipher.getBlockSize()+36)); String encodedSecretKey = cacheUtilService.getSecretKey(new String(keyAlias)); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(IdentityProviderUtil.b64Decode(encodedSecretKey), "AES"), @@ -67,23 +82,31 @@ public String symmetricDecrypt(String encryptedData) { } - public SecretKey getSecretKey() { - String encodedSecretKey = cacheUtilService.getSecretKey(); + public SecretKey getSecretKey(String alias) { + String encodedSecretKey = cacheUtilService.getSecretKey(alias); + return new SecretKeySpec(IdentityProviderUtil.b64Decode(encodedSecretKey), "AES"); + } + + private String getActiveKeyAlias() { + String alias = cacheUtilService.getActiveKeyAlias(); + if(alias != null) + return alias; + + log.debug("No active alias found, generating new alias and AES key."); + alias = UUIDUtils.getUUID(NAMESPACE_OID, "signup-service").toString(); + generateSecretKey(alias); + return alias; + } + + private void generateSecretKey(String alias) { try { - if(encodedSecretKey == null) { - KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); - keyGenerator.init(256); - cacheUtilService.setSecretKey(CACHE_KEY, IdentityProviderUtil.b64Encode(keyGenerator.generateKey().getEncoded())); - encodedSecretKey = cacheUtilService.getSecretKey(); - } - return new SecretKeySpec(IdentityProviderUtil.b64Decode(encodedSecretKey), "AES"); - } catch (Exception e) { - log.error("Error getting secret key", e); + KeyGenerator keyGenerator = KeyGenerator.getInstance(symmetricKeyAlgorithm); + keyGenerator.init(symmetricKeySize); + cacheUtilService.setSecretKey(alias, IdentityProviderUtil.b64Encode(keyGenerator.generateKey().getEncoded())); + cacheUtilService.setActiveKeyAlias(ALIAS_CACHE_KEY, alias); + } catch (NoSuchAlgorithmException e) { + log.error("Error generating secret key", e); throw new SignUpException("crypto_error"); } } - - private String getKeyAlias(String transactionId) { - return transactionId.substring(transactionId.length()-10); - } } diff --git a/signup-service/src/main/java/io/mosip/signup/services/CacheUtilService.java b/signup-service/src/main/java/io/mosip/signup/services/CacheUtilService.java index cd76a887..e4f1c08e 100644 --- a/signup-service/src/main/java/io/mosip/signup/services/CacheUtilService.java +++ b/signup-service/src/main/java/io/mosip/signup/services/CacheUtilService.java @@ -50,9 +50,9 @@ public String setSecretKey(String key, String secretKey) { return secretKey; } - @Cacheable(value = SignUpConstants.KEY_ALIAS, key = "#alias") - public String setSecretKeyBasedOnAlias(String alias, String secretKey) { - return secretKey; + @Cacheable(value = SignUpConstants.KEY_ALIAS, key = "#key") + public String setActiveKeyAlias(String key, String alias) { + return alias; } //---Getter--- @@ -75,11 +75,11 @@ public boolean isIdentifierBlocked(String identifier) { return value == null ? false : true; } - public String getSecretKey() { - return cacheManager.getCache(SignUpConstants.KEYSTORE).get(CryptoHelper.CACHE_KEY, String.class); + public String getSecretKey(String keyAlias) { + return cacheManager.getCache(SignUpConstants.KEYSTORE).get(keyAlias, String.class); } - public String getSecretKey(String alias) { - return cacheManager.getCache(SignUpConstants.KEY_ALIAS).get(alias, String.class); + public String getActiveKeyAlias() { + return cacheManager.getCache(SignUpConstants.KEY_ALIAS).get(CryptoHelper.ALIAS_CACHE_KEY, String.class); } } diff --git a/signup-service/src/main/java/io/mosip/signup/services/RegistrationService.java b/signup-service/src/main/java/io/mosip/signup/services/RegistrationService.java index 063377c1..4688cec7 100644 --- a/signup-service/src/main/java/io/mosip/signup/services/RegistrationService.java +++ b/signup-service/src/main/java/io/mosip/signup/services/RegistrationService.java @@ -405,9 +405,7 @@ private void checkActiveIdentityExists(String transactionId, } //set UIN in the cache to be further used for update UIN endpoint - SecretKey secretKey = cryptoHelper.getSecretKey(); - registrationTransaction.setUin(cryptoHelper.symmetricEncrypt(transactionId, - restResponseWrapper.getResponse().getIdentity().getUIN(), secretKey)); + registrationTransaction.setUin(cryptoHelper.symmetricEncrypt(restResponseWrapper.getResponse().getIdentity().getUIN())); } diff --git a/signup-service/src/main/resources/application-default.properties b/signup-service/src/main/resources/application-default.properties index dd9c19d2..8a44e091 100644 --- a/signup-service/src/main/resources/application-default.properties +++ b/signup-service/src/main/resources/application-default.properties @@ -37,6 +37,7 @@ mosip.signup.supported.challenge.otp.length=6 ## ------------------------------------- Cache configuration ----------------------------------------------------------- +mosip.signup.cache.symmetric-algorithm-name=AES/CFB/PKCS5Padding spring.cache.type=simple #spring.cache.type=redis @@ -50,13 +51,16 @@ mosip.esignet.cache.size={'challenge_generated': 200, \ 'challenge_verified': 200,\ 'status_check': 200,\ 'blocked_identifier':2000,\ - 'keystore' : 5, \ - 'key_alias' : 200 } + 'keystore' : 10, \ + 'key_alias' : 1 } + +## Note: keystore TTL should be more than the key_alias cache TTL. +## So that key rotation happens before the actual key is removed from the keystore cache. mosip.esignet.cache.expire-in-seconds={'challenge_generated': ${mosip.signup.unauthenticated.txn.timeout},\ 'challenge_verified': ${mosip.signup.verified.txn.timeout},\ 'status_check': ${mosip.signup.status-check.txn.timeout}, \ 'blocked_identifier': ${mosip.signup.generate-challenge.blocked.timeout},\ - 'keystore' : 10, \ + 'keystore' : 600, \ 'key_alias' : ${mosip.signup.verified.txn.timeout} } ## ------------------------------------- Auth adapter ------------------------------------------------------------------ @@ -141,8 +145,8 @@ mosip.signup.sms-notification-template.send-otp.khm=4Z6U4Z+S4Z6a4Z6+IHtjaGFsbGVu mosip.signup.sms-notification-template.send-otp.eng=Use {challenge} to verify your KhID account. mosip.signup.sms-notification-template.registration.khm=4Z6i4Z+S4Z6T4Z6A4Z6U4Z624Z6T4Z6F4Z674Z+H4Z6I4Z+S4Z6Y4Z+E4Z+H4Z6C4Z6O4Z6T4Z64IEtoSUQg4Z6K4Z+E4Z6Z4Z6H4Z+E4Z6C4Z6H4Z+Q4Z6Z4Z+U mosip.signup.sms-notification-template.registration.eng=You successfully registered to KhID account. -mosip.signup.sms-notification-template.forgot-passsword.khm=4Z6i4Z+S4Z6T4Z6A4Z6U4Z624Z6T4Z6V4Z+S4Z6b4Z624Z6f4Z+L4Z6U4Z+S4Z6K4Z684Z6a4Z6W4Z624Z6A4Z+S4Z6Z4Z6f4Z6Y4Z+S4Z6E4Z624Z6P4Z+LIEtoSUQg4Z6K4Z+E4Z6Z4Z6H4Z+E4Z6C4Z6H4Z+Q4Z6Z4Z+U -mosip.signup.sms-notification-template.forgot-passsword.eng=You successfully changed KhID password. +mosip.signup.sms-notification-template.forgot-password.khm=4Z6i4Z+S4Z6T4Z6A4Z6U4Z624Z6T4Z6V4Z+S4Z6b4Z624Z6f4Z+L4Z6U4Z+S4Z6K4Z684Z6a4Z6W4Z624Z6A4Z+S4Z6Z4Z6f4Z6Y4Z+S4Z6E4Z624Z6P4Z+LIEtoSUQg4Z6K4Z+E4Z6Z4Z6H4Z+E4Z6C4Z6H4Z+Q4Z6Z4Z+U +mosip.signup.sms-notification-template.forgot-password.eng=You successfully changed KhID password. #------------------------------------------ Others --------------------------------------------------------------------- logging.level.io.mosip.signup=DEBUG diff --git a/signup-service/src/main/resources/messages.properties b/signup-service/src/main/resources/messages.properties index 5e09cc01..7c253419 100644 --- a/signup-service/src/main/resources/messages.properties +++ b/signup-service/src/main/resources/messages.properties @@ -7,3 +7,4 @@ invalid_challenge_channel=Invalid Challenge channel provided. invalid_no_of_challenges=Null or empty authentication challenges not allowed. invalid_auth_factor_type=Null or empty authentication factor type not allowed. invalid_challenge=Invalid Authentication challenge provided. +crypto_error=Internal Error, Please try again. diff --git a/signup-service/src/test/resources/application-test.properties b/signup-service/src/test/resources/application-test.properties index 756dd857..4e10d344 100644 --- a/signup-service/src/test/resources/application-test.properties +++ b/signup-service/src/test/resources/application-test.properties @@ -28,9 +28,12 @@ mosip.signup.identifier.regex=^\\+855[1-9]\\d{7,8}$ mosip.signup.identifier.prefix=+855 mosip.signup.supported-languages={'khm','eng'} mosip.signup.password.pattern=^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[\\x5F\\W])(?=.{8,20})[a-zA-Z0-9\\x5F\\W]{8,20}$ -mosip.signup.fullname.pattern=^[\\u1780-\\u17FF\\u19E0-\\u19FF\\u1A00-\\u1A9F\\u0020]{1,30}$ mosip.signup.password.max-length=20 -mosip.signup.password.min-length=6 +mosip.signup.generate-challenge.blocked.timeout=300 +mosip.signup.challenge.timeout=60 +mosip.signup.audit.description.max-length=2048 +mosip.signup.password.min-length=8 +mosip.signup.fullname.pattern=^[\\u1780-\\u17FF\\u19E0-\\u19FF\\u1A00-\\u1A9F\\u0020]{1,30}$ ## Time given to generate and verify the challenge in seconds. ## Default resend delay is 60 seconds, with 3 attempts, so 60*3=180 seconds. @@ -55,7 +58,7 @@ mosip.signup.supported.challenge-types={'OTP', 'KBA'} mosip.signup.supported.challenge.otp.length=6 ## ------------------------------------- Cache configuration ----------------------------------------------------------- - +mosip.signup.cache.symmetric-algorithm-name=AES/CFB/PKCS5Padding spring.cache.type=simple #spring.cache.type=redis @@ -70,12 +73,13 @@ mosip.esignet.cache.size={'challenge_generated': 200, \ 'status_check': 200,\ 'blocked_identifier':2000,\ 'keystore' : 5, \ - 'key_alias' : 200 } + 'key_alias' : 1 } + mosip.esignet.cache.expire-in-seconds={'challenge_generated': ${mosip.signup.unauthenticated.txn.timeout},\ 'challenge_verified': ${mosip.signup.verified.txn.timeout},\ 'status_check': ${mosip.signup.status-check.txn.timeout}, \ 'blocked_identifier': ${mosip.signup.generate-challenge.blocked.timeout},\ - 'keystore' : 10, \ + 'keystore' : 600, \ 'key_alias' : ${mosip.signup.verified.txn.timeout} } ## ------------------------------------- Auth adapter ------------------------------------------------------------------ diff --git a/signup-ui/public/locales/en.json b/signup-ui/public/locales/en.json index bf4eb82b..2e285463 100644 --- a/signup-ui/public/locales/en.json +++ b/signup-ui/public/locales/en.json @@ -121,9 +121,9 @@ "not_registered": "Not Registered", "reset_pwd_failed": "Reset Password Failed", "identifier_already_registered": "Identifier already registered", - "identifier_not_found": "Identifier not found", - "invalid_kba_challenge": "Invalid Fullname challenge", - "kba_challenge_not_found": "Fullname challenge not found", + "identifier_not_found": "Invalid number or name. Please enter a registered mobile number and full name.", + "invalid_kba_challenge": "Invalid number or name. Please enter a registered mobile number and full name.", + "kba_challenge_not_found": "Invalid number or name. Please enter a registered mobile number and full name.", "identity_inactive": "Identifier inactive", "fetch_identity_failed": "Fetch Identifier Failed", "challenge_format_and_type_mismatch": "Challenge format and type mismatch", diff --git a/signup-ui/public/locales/km.json b/signup-ui/public/locales/km.json index a0a4d10b..efac5a54 100644 --- a/signup-ui/public/locales/km.json +++ b/signup-ui/public/locales/km.json @@ -121,12 +121,12 @@ "not_registered": "មិនបានចុះឈ្មោះ", "reset_pwd_failed": "ការកំណត់ពាក្យសម្ងាត់ឡើងវិញបានបរាជ័យ", "identifier_already_registered": "អត្តសញ្ញាណបានចុះឈ្មោះរួចហើយ", - "identifier_not_found": "រកមិនឃើញអត្តសញ្ញាណ", - "invalid_kba_challenge": "ឈ្មោះមិនត្រឹមត្រូវ", - "kba_challenge_not_found": "រកមិនឃើញឈ្មោះ", + "identifier_not_found": "លេខទូរស័ព្ទ ឬឈ្មោះមិនត្រឹមត្រូវ។ សូមបញ្ចូលលេខទូរស័ព្ទនិងឈ្មោះដែលបានចុះឈ្មោះ។", + "invalid_kba_challenge": "លេខទូរស័ព្ទ ឬឈ្មោះមិនត្រឹមត្រូវ។ សូមបញ្ចូលលេខទូរស័ព្ទនិងឈ្មោះដែលបានចុះឈ្មោះ។", + "kba_challenge_not_found": "លេខទូរស័ព្ទ ឬឈ្មោះមិនត្រឹមត្រូវ។ សូមបញ្ចូលលេខទូរស័ព្ទនិងឈ្មោះដែលបានចុះឈ្មោះ។", "identity_inactive": "អត្តសញ្ញាណអសកម្ម", "fetch_identity_failed": "ទាញ​យក​លេខ​សម្គាល់​បាន​បរាជ័យ", - "challenge_format_and_type_mismatch": "ទម្រង់និងប្រភេទមិនត្រូវគ្នា", + "challenge_format_and_type_mismatch": "លេខទូរស័ព្ទ ឬឈ្មោះមិនត្រឹមត្រូវ។ សូមបញ្ចូលលេខទូរស័ព្ទនិងឈ្មោះដែលបានចុះឈ្មោះ។", "knowledgebase_mismatch": "លេខទូរស័ព្ទ ឬឈ្មោះមិនត្រឹមត្រូវ។ សូមបញ្ចូលលេខទូរស័ព្ទនិងឈ្មោះដែលបានចុះឈ្មោះ។", "IDR-IDC-001": "រកមិនឃើញតម្លៃដែលបានបញ្ចូល", "IDR-IDC-002": "តម្លៃដែលបានបញ្ចូលមិនត្រឹមត្រូវ", diff --git a/signup-ui/src/components/ui/form.tsx b/signup-ui/src/components/ui/form.tsx index ffa832f9..3bbcd34f 100644 --- a/signup-ui/src/components/ui/form.tsx +++ b/signup-ui/src/components/ui/form.tsx @@ -9,6 +9,7 @@ import { FormProvider, useFormContext, } from "react-hook-form"; +import { useTranslation } from "react-i18next"; import { Label } from "~components/ui/label"; import { cn } from "~utils/cn"; @@ -146,7 +147,10 @@ const FormMessage = React.forwardRef< React.HTMLAttributes >(({ className, children, ...props }, ref) => { const { error, formMessageId } = useFormField(); - const body = error ? String(error?.message) : children; + const { t } = useTranslation(); + + // @ts-ignore + const body: React.ReactNode = error ? t(String(error.message)) : children; if (!body) { return null; diff --git a/signup-ui/src/pages/ResetPasswordPage/Otp/Otp.tsx b/signup-ui/src/pages/ResetPasswordPage/Otp/Otp.tsx index 480120d1..d3639b7f 100644 --- a/signup-ui/src/pages/ResetPasswordPage/Otp/Otp.tsx +++ b/signup-ui/src/pages/ResetPasswordPage/Otp/Otp.tsx @@ -32,6 +32,7 @@ import { ResetPasswordForm, SettingsDto, VerifyChallengeRequestDto, + ResetPasswordPossibleInvalid, } from "~typings/types"; import { resetPasswordFormDefaultValues } from "../ResetPasswordPage"; @@ -203,7 +204,7 @@ export const Otp = ({ methods, settings }: OtpProps) => { onSuccess: ({ errors }) => { if (errors.length > 0) { if ( - ["invalid_transaction", "knowledgebase_mismatch"].includes( + ["invalid_transaction", ...ResetPasswordPossibleInvalid].includes( errors[0].errorCode ) ) { diff --git a/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPage.tsx b/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPage.tsx index ff6345d1..62607c4a 100644 --- a/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPage.tsx +++ b/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPage.tsx @@ -14,7 +14,7 @@ import { validatePassword, validateUsername, } from "~pages/shared/validation"; -import { ResetPasswordForm, SettingsDto } from "~typings/types"; +import { ResetPasswordForm, ResetPasswordPossibleInvalid, SettingsDto } from "~typings/types"; import Otp from "./Otp"; import ResetPassword from "./ResetPassword"; @@ -59,9 +59,9 @@ export const ResetPasswordPage = ({ settings }: ResetPasswordPageProps) => { () => [ // Step 1 - UserInfo yup.object({ - username: validateUsername(settings, t), - fullname: validateFullName(settings, t), - captchaToken: validateCaptchaToken(t), + username: validateUsername(settings), + fullname: validateFullName(settings), + captchaToken: validateCaptchaToken(), }), // Step 2 - Otp yup.object({ @@ -69,11 +69,10 @@ export const ResetPasswordPage = ({ settings }: ResetPasswordPageProps) => { }), // Step 3 - ResetPassword yup.object({ - newPassword: validatePassword(settings, t), + newPassword: validatePassword(settings), confirmNewPassword: validateConfirmPassword( "newPassword", settings, - t, false ), }), @@ -108,7 +107,7 @@ export const ResetPasswordPage = ({ settings }: ResetPasswordPageProps) => { if ( step === ResetPasswordStep.ResetPasswordConfirmation || (criticalError && - ["invalid_transaction", "knowledgebase_mismatch"].includes( + ["invalid_transaction", ...ResetPasswordPossibleInvalid].includes( criticalError.errorCode )) ) @@ -149,7 +148,7 @@ export const ResetPasswordPage = ({ settings }: ResetPasswordPageProps) => { return ( <> {criticalError && - ["invalid_transaction", "knowledgebase_mismatch"].includes( + ["invalid_transaction", ...ResetPasswordPossibleInvalid].includes( criticalError.errorCode ) && }
diff --git a/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPopover.tsx b/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPopover.tsx index bbdb3436..c6f32bc5 100644 --- a/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPopover.tsx +++ b/signup-ui/src/pages/ResetPasswordPage/ResetPasswordPopover.tsx @@ -1,6 +1,6 @@ import { useCallback } from "react"; import { useTranslation } from "react-i18next"; -import { useLocation } from "react-router-dom"; +import { useNavigate, useLocation } from "react-router-dom"; import { ReactComponent as FailedIconSvg } from "~assets/svg/failed-icon.svg"; import { RESET_PASSWORD } from "~constants/routes"; @@ -20,9 +20,11 @@ import { criticalErrorSelector, useResetPasswordStore, } from "./useResetPasswordStore"; +import { ResetPasswordPossibleInvalid } from "~typings/types"; export const ResetPasswordPopover = () => { const { t } = useTranslation(); + const navigate = useNavigate(); const { data: settings } = useSettings(); const { criticalError } = useResetPasswordStore( @@ -37,11 +39,16 @@ export const ResetPasswordPopover = () => { const handleAction = (e: any) => { e.preventDefault(); - window.location.href = getSignInRedirectURL( - settings?.response.configs["signin.redirect-url"], - fromSignInHash, - RESET_PASSWORD - ); + if(ResetPasswordPossibleInvalid.includes(criticalError?.errorCode!!)) { + navigate(0) + } else { + window.location.href = getSignInRedirectURL( + settings?.response.configs["signin.redirect-url"], + fromSignInHash, + RESET_PASSWORD + ); + } + }; return ( @@ -51,7 +58,7 @@ export const ResetPasswordPopover = () => { <> - {["knowledgebase_mismatch"].includes(criticalError?.errorCode!!) ? t("invalid") : t("error")} + {ResetPasswordPossibleInvalid.includes(criticalError?.errorCode!!) ? t("invalid") : t("error")} @@ -63,7 +70,7 @@ export const ResetPasswordPopover = () => { onClick={handleAction} className="w-full bg-primary" > - {["knowledgebase_mismatch"].includes(criticalError?.errorCode!!) ? t("retry") : t("okay")} + {ResetPasswordPossibleInvalid.includes(criticalError?.errorCode!!) ? t("retry") : t("okay")} diff --git a/signup-ui/src/pages/SignUpPage/SignUpPage.tsx b/signup-ui/src/pages/SignUpPage/SignUpPage.tsx index b6412fa5..66de3f71 100644 --- a/signup-ui/src/pages/SignUpPage/SignUpPage.tsx +++ b/signup-ui/src/pages/SignUpPage/SignUpPage.tsx @@ -76,8 +76,8 @@ export const SignUpPage = ({ settings }: SignUpPageProps) => { () => [ // Step 1 - Phone Validation yup.object({ - phone: validateUsername(settings, t), - captchaToken: validateCaptchaToken(t), + phone: validateUsername(settings), + captchaToken: validateCaptchaToken(), }), // Step 2 - OTP Validation yup.object({ @@ -88,9 +88,9 @@ export const SignUpPage = ({ settings }: SignUpPageProps) => { // Step 4 - Account Setup Validation yup.object({ username: yup.string(), - fullNameInKhmer: validateFullName(settings, t), - password: validatePassword(settings, t), - confirmPassword: validateConfirmPassword("password", settings, t, true), + fullNameInKhmer: validateFullName(settings), + password: validatePassword(settings), + confirmPassword: validateConfirmPassword("password", settings, true), consent: yup.bool().oneOf([true], t("terms_and_conditions_validation")), }), // Step 5 - Register Status Validation diff --git a/signup-ui/src/pages/shared/validation.ts b/signup-ui/src/pages/shared/validation.ts index b6dc7242..ace34bce 100644 --- a/signup-ui/src/pages/shared/validation.ts +++ b/signup-ui/src/pages/shared/validation.ts @@ -3,31 +3,31 @@ import * as yup from "yup"; import { SettingsDto } from "~typings/types"; -export const validateUsername = (settings: SettingsDto, t: TFunction) => +export const validateUsername = (settings: SettingsDto) => yup .string() .trim() .matches(/^[^0].*$/, { - message: t("username_lead_zero_validation"), + message: "username_lead_zero_validation", excludeEmptyString: true, }) - .test("isUsernameValid", t("username_validation"), (value) => { + .test("isUsernameValid", "username_validation", (value) => { if (value === "") return true; return new RegExp(settings.response.configs["identifier.pattern"]).test( `${settings.response.configs["identifier.prefix"]}${value}` ); }); -export const validateCaptchaToken = (t: TFunction) => - yup.string().required(t("captcha_token_validation")); +export const validateCaptchaToken = () => + yup.string().required("captcha_token_validation"); -export const validateFullName = (settings: SettingsDto, t: TFunction) => +export const validateFullName = (settings: SettingsDto) => yup .string() .strict(true) - .trim(t("full_name_all_spaces_validation")) + .trim("full_name_all_spaces_validation") .matches(new RegExp(settings.response.configs["fullname.pattern"]), { - message: t("full_name_in_lng_validation"), + message: "full_name_in_lng_validation", excludeEmptyString: true, }); @@ -36,31 +36,30 @@ export const validateOtp = (settings: SettingsDto) => .string() .matches(new RegExp(`^\\d{${settings.response.configs["otp.length"]}}$`)); -export const validatePassword = (settings: SettingsDto, t: TFunction) => +export const validatePassword = (settings: SettingsDto) => yup .string() .trim() .matches(new RegExp(settings.response.configs["password.pattern"]), { - message: t("password_validation"), + message: "password_validation", excludeEmptyString: true, }); export const validateConfirmPassword = ( passwordRef: string, settings: SettingsDto, - t: TFunction, isRegister: boolean ) => yup .string() .trim() .matches(new RegExp(settings.response.configs["password.pattern"]), { - message: t("password_validation"), + message: "password_validation", excludeEmptyString: true, }) .oneOf( [yup.ref(passwordRef), ""], isRegister - ? t("register_password_validation_must_match") - : t("password_validation_must_match") + ? "register_password_validation_must_match" + : "password_validation_must_match" ); diff --git a/signup-ui/src/typings/types.ts b/signup-ui/src/typings/types.ts index bac84afc..e8530d9d 100644 --- a/signup-ui/src/typings/types.ts +++ b/signup-ui/src/typings/types.ts @@ -48,6 +48,14 @@ const RegisterStatusPossibleErrors = [ export type RegisterStatusErrors = (typeof RegisterStatusPossibleErrors)[number]; +export const ResetPasswordPossibleInvalid = [ + "knowledgebase_mismatch", + "identifier_not_found", + "invalid_kba_challenge", + "challenge_format_and_type_mismatch", + "kba_challenge_not_found" +]; + const ResetPasswordPossibleErrors = [ "invalid_transaction", "not_registered", @@ -56,6 +64,10 @@ const ResetPasswordPossibleErrors = [ "invalid_request", "reset_pwd_failed", "knowledgebase_mismatch", + "identifier_not_found", + "invalid_kba_challenge", + "challenge_format_and_type_mismatch", + "kba_challenge_not_found", ] as const; export type ResetPasswordErrors = (typeof ResetPasswordPossibleErrors)[number];