Skip to content

Commit

Permalink
Fix/passcode (#6335)
Browse files Browse the repository at this point in the history
  • Loading branch information
ezailWang authored Dec 27, 2024
1 parent 650eeed commit 4c5acf5
Show file tree
Hide file tree
Showing 29 changed files with 1,201 additions and 333 deletions.
4 changes: 2 additions & 2 deletions apps/ext/src/ui/renderPassKeyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const usePassKeyOperations = () => {
passwordVerifyStatus: {
value: EPasswordVerifyStatus.ERROR,
message: intl.formatMessage({
id: ETranslations.auth_error_password_incorrect,
id: ETranslations.auth_error_passcode_incorrect,
}),
},
}));
Expand All @@ -90,7 +90,7 @@ const usePassKeyOperations = () => {
passwordVerifyStatus: {
value: EPasswordVerifyStatus.ERROR,
message: intl.formatMessage({
id: ETranslations.auth_error_password_incorrect,
id: ETranslations.auth_error_passcode_incorrect,
}),
},
}));
Expand Down
2 changes: 0 additions & 2 deletions apps/mobile/ios/OneKeyWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,6 @@
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/Sentry/Sentry.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
Expand All @@ -436,7 +435,6 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Sentry.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down
6 changes: 3 additions & 3 deletions apps/mobile/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,7 @@ SPEC CHECKSUMS:
Burnt: dde5dd245f124a4594098e3938ba71aae4ec83c3
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
CocoaLumberjack: 5c7e64cdb877770859bddec4d3d5a0d7c9299df9
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953
EXApplication: 137189a3f149b4e8e546884629392c3efc94cbd3
EXBarCodeScanner: d59fd943cebee3f913ebf4ffde0d05d344da8b78
EXConstants: 988aa430ca0f76b43cd46b66e7fae3287f9cc2fc
Expand All @@ -1713,7 +1713,7 @@ SPEC CHECKSUMS:
FBLazyVector: 9f533d5a4c75ca77c8ed774aced1a91a0701781e
FBReactNativeSpec: 2db5940ee4b58968274eec0a4f1c736fc4caefa3
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
hermes-engine: 39589e9c297d024e90fe68f6830ff86c4e01498a
ImageColors: 88be684570585c07ae2750bff34eb7b78bfc53b4
IQKeyboardManagerSwift: c7955c0bdbf7b2eb29bb7daaa44e3d90f55a9a85
Expand Down Expand Up @@ -1817,7 +1817,7 @@ SPEC CHECKSUMS:
SPIndicator: 93e0a4fb23de51294ac48e874c0f081a5e293e4f
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
Yoga: 6d01ccde54c9f8b92492beb05d468dbfed1d9881
Yoga: 07db09965bc46c4902e20d3ae6990d95e53af8a8
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5

PODFILE CHECKSUM: 5b7f20a90e19262f325cab10e37056b7f3cd0ffb
Expand Down
3 changes: 3 additions & 0 deletions development/spellCheckerSkipWords.js
Original file line number Diff line number Diff line change
Expand Up @@ -776,4 +776,7 @@ module.exports = [
'cacheable',
'benfen',
'bfc',
'biometric',
'biometrics',
'Biometric',
];
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"react-dom": "18.2.0",
"react-mobile-cropper": "^0.10.0",
"react-native": "0.73.7",
"react-native-confirmation-code-field": "^7.4.0",
"react-native-draggable-flatlist": "4.0.1",
"react-native-reanimated": "3.6.1",
"react-native-web": "0.18.12",
Expand Down
19 changes: 18 additions & 1 deletion packages/components/src/forms/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,27 @@ type IFieldProps = Omit<GetProps<typeof Controller>, 'render'> &
PropsWithChildren<{
testID?: string;
label?: string;
display?:
| 'inherit'
| 'none'
| 'inline'
| 'block'
| 'contents'
| 'flex'
| 'inline-flex';
description?: string | ReactNode;
horizontal?: boolean;
optional?: boolean;
labelAddon?: string | ReactElement;
errorMessageAlign?: 'left' | 'center' | 'right';
}>;

function Field({
name,
label,
optional,
display,
errorMessageAlign,
description,
rules,
children,
Expand Down Expand Up @@ -139,7 +150,12 @@ function Field({
control={control}
rules={rules}
render={({ field }) => (
<Fieldset p="$0" m="$0" borderWidth={0}>
<Fieldset
p="$0"
m="$0"
borderWidth={0}
{...(display ? { display } : {})}
>
<Stack
flexDirection={horizontal ? 'row' : 'column'}
jc={horizontal ? 'space-between' : undefined}
Expand Down Expand Up @@ -187,6 +203,7 @@ function Field({
<SizableText
color="$textCritical"
size="$bodyMd"
textAlign={errorMessageAlign}
key={error?.message}
testID={`${testID}-message`}
>
Expand Down
67 changes: 52 additions & 15 deletions packages/kit-bg/src/services/ServicePassword/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ import ServiceBase from '../ServiceBase';
import { checkExtUIOpen } from '../utils';

import { biologyAuthUtils } from './biologyAuthUtils';
import { EPasswordPromptType } from './types';
import {
EPasswordMode,
EPasswordPromptType,
PASSCODE_LENGTH,
PASSWORD_MAX_LENGTH,
PASSWORD_MIN_LENGTH,
} from './types';

import type { IPasswordRes } from './types';

Expand Down Expand Up @@ -273,20 +279,31 @@ export default class ServicePassword extends ServiceBase {
}

// validatePassword --------------------------------
validatePasswordValidRules(password: string): void {
validatePasswordValidRules(
password: string,
passwordMode: EPasswordMode,
): void {
ensureSensitiveTextEncoded(password);
const realPassword = decodePassword({ password });
// **** length matched
if (realPassword.length < 8 || realPassword.length > 128) {
if (
passwordMode === EPasswordMode.PASSWORD &&
(realPassword.length < PASSWORD_MIN_LENGTH ||
realPassword.length > PASSWORD_MAX_LENGTH)
) {
throw new OneKeyErrors.PasswordStrengthValidationFailed();
}
if (passwordMode === EPasswordMode.PASSCODE) {
if (realPassword.length !== PASSCODE_LENGTH) {
throw new OneKeyErrors.PasswordStrengthValidationFailed();
}
}
// **** other rules ....
}

validatePasswordSame(password: string, newPassword: string) {
ensureSensitiveTextEncoded(password);
ensureSensitiveTextEncoded(newPassword);

const realPassword = decodePassword({ password });
const realNewPassword = decodePassword({ password: newPassword });
if (realPassword === realNewPassword) {
Expand All @@ -296,20 +313,23 @@ export default class ServicePassword extends ServiceBase {

async validatePassword({
password,
passwordMode,
newPassword,
skipDBVerify,
}: {
password: string;
passwordMode: EPasswordMode;
newPassword?: string;
skipDBVerify?: boolean;
}): Promise<void> {
ensureSensitiveTextEncoded(password);
if (newPassword) {
ensureSensitiveTextEncoded(newPassword);
}
this.validatePasswordValidRules(password);
if (newPassword) {
this.validatePasswordValidRules(newPassword);
if (!newPassword) {
this.validatePasswordValidRules(password, passwordMode);
} else {
this.validatePasswordValidRules(newPassword, passwordMode);
this.validatePasswordSame(password, newPassword);
}
if (!skipDBVerify) {
Expand All @@ -336,20 +356,30 @@ export default class ServicePassword extends ServiceBase {
return checkPasswordSet;
}

async setPasswordSetStatus(isSet: boolean): Promise<void> {
await passwordPersistAtom.set((v) => ({ ...v, isPasswordSet: isSet }));
async setPasswordSetStatus(
isSet: boolean,
passMode?: EPasswordMode,
): Promise<void> {
await passwordPersistAtom.set((v) => ({
...v,
isPasswordSet: isSet,
...(passMode ? { passwordMode: passMode } : {}),
}));
}

// password actions --------------
@backgroundMethod()
async setPassword(password: string): Promise<string> {
async setPassword(
password: string,
passwordMode: EPasswordMode,
): Promise<string> {
ensureSensitiveTextEncoded(password);
await this.validatePassword({ password, skipDBVerify: true });
await this.validatePassword({ password, passwordMode, skipDBVerify: true });
try {
await this.unLockApp();
await this.saveBiologyAuthPassword(password);
await this.setCachedPassword(password);
await this.setPasswordSetStatus(true);
await this.setPasswordSetStatus(true, passwordMode);
await localDb.setPassword({ password });
return password;
} catch (e) {
Expand All @@ -362,16 +392,21 @@ export default class ServicePassword extends ServiceBase {
async updatePassword(
oldPassword: string,
newPassword: string,
passwordMode: EPasswordMode,
): Promise<string> {
ensureSensitiveTextEncoded(oldPassword);
ensureSensitiveTextEncoded(newPassword);

await this.validatePassword({ password: oldPassword, newPassword });
await this.validatePassword({
password: oldPassword,
newPassword,
passwordMode,
});
try {
await this.backgroundApi.serviceAddressBook.updateHash(newPassword);
await this.saveBiologyAuthPassword(newPassword);
await this.setCachedPassword(newPassword);
await this.setPasswordSetStatus(true);
await this.setPasswordSetStatus(true, passwordMode);
// update v5 db password
await localDb.updatePassword({ oldPassword, newPassword });
// update v4 db password
Expand All @@ -391,17 +426,19 @@ export default class ServicePassword extends ServiceBase {
@backgroundMethod()
async verifyPassword({
password,
passwordMode,
isBiologyAuth,
}: {
password: string;
passwordMode: EPasswordMode;
isBiologyAuth?: boolean;
}): Promise<string> {
let verifyingPassword = password;
if (isBiologyAuth) {
verifyingPassword = await this.getBiologyAuthPassword();
}
ensureSensitiveTextEncoded(verifyingPassword);
await this.validatePassword({ password: verifyingPassword });
await this.validatePassword({ password: verifyingPassword, passwordMode });
await this.setCachedPassword(verifyingPassword);
return verifyingPassword;
}
Expand Down
25 changes: 25 additions & 0 deletions packages/kit-bg/src/services/ServicePassword/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,28 @@ export enum EPasswordPromptType {
PASSWORD_SETUP = 'setup',
PASSWORD_VERIFY = 'verify',
}

export enum EPasswordMode {
PASSCODE = 'passcode',
PASSWORD = 'password',
}

export const PASSCODE_LENGTH = 6;
export const PASSCODE_PROTECTION_ATTEMPTS = 10;
export const PASSCODE_PROTECTION_ATTEMPTS_MESSAGE_SHOW_MAX = 5;
export const PASSCODE_PROTECTION_ATTEMPTS_PER_MINUTE_MAP: Record<
string,
number
> = {
'5': 2,
'6': 10,
'7': 30,
'8': 60,
'9': 180,
};

export const BIOLOGY_AUTH_ATTEMPTS_FACE = 1;
export const BIOLOGY_AUTH_ATTEMPTS_FINGERPRINT = 2;

export const PASSWORD_MIN_LENGTH = 8;
export const PASSWORD_MAX_LENGTH = 128;
18 changes: 18 additions & 0 deletions packages/kit-bg/src/states/jotai/atoms/password.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { isSupportWebAuth } from '@onekeyhq/shared/src/webAuth';
import { EPasswordVerifyStatus } from '@onekeyhq/shared/types/password';

import { biologyAuthUtils } from '../../../services/ServicePassword/biologyAuthUtils';
import { EPasswordMode } from '../../../services/ServicePassword/types';
import { EAtomNames } from '../atomNames';
import { globalAtom, globalAtomComputed } from '../utils';

Expand Down Expand Up @@ -60,12 +61,20 @@ export type IPasswordPersistAtom = {
webAuthCredentialId: string;
appLockDuration: number;
enableSystemIdleLock: boolean;
passwordMode: EPasswordMode;
enablePasswordErrorProtection: boolean;
passwordErrorAttempts: number;
passwordErrorProtectionTime: number;
};
export const passwordAtomInitialValue: IPasswordPersistAtom = {
isPasswordSet: false,
webAuthCredentialId: '',
appLockDuration: 240,
enableSystemIdleLock: true,
passwordMode: EPasswordMode.PASSWORD,
enablePasswordErrorProtection: false,
passwordErrorAttempts: 0,
passwordErrorProtectionTime: 0,
};
export const { target: passwordPersistAtom, use: usePasswordPersistAtom } =
globalAtom<IPasswordPersistAtom>({
Expand All @@ -74,6 +83,15 @@ export const { target: passwordPersistAtom, use: usePasswordPersistAtom } =
initialValue: passwordAtomInitialValue,
});

export const { target: passwordModeAtom, use: usePasswordModeAtom } =
globalAtomComputed<EPasswordMode>((get) => {
const { passwordMode, isPasswordSet } = get(passwordPersistAtom.atom());
if (platformEnv.isNative && !isPasswordSet) {
return EPasswordMode.PASSCODE;
}
return passwordMode;
});

export const { target: systemIdleLockSupport, use: useSystemIdleLockSupport } =
globalAtomComputed<Promise<boolean | undefined>>(async (get) => {
const platformSupport = platformEnv.isExtension || platformEnv.isDesktop;
Expand Down
Loading

0 comments on commit 4c5acf5

Please sign in to comment.