Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/passcode ok-34139 #6335

Merged
merged 21 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -775,4 +775,7 @@ module.exports = [
'cacheable',
'benfen',
'bfc',
'biometric',
'biometrics',
'Biometric',
ezailWang marked this conversation as resolved.
Show resolved Hide resolved
];
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
16 changes: 15 additions & 1 deletion packages/components/src/forms/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ 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;
Expand All @@ -107,6 +115,7 @@ function Field({
name,
label,
optional,
display,
description,
rules,
children,
Expand Down Expand Up @@ -139,7 +148,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
69 changes: 54 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,33 @@ 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);

console.log('same__password', password);
console.log('same__newPassword', newPassword);
ezailWang marked this conversation as resolved.
Show resolved Hide resolved
ezailWang marked this conversation as resolved.
Show resolved Hide resolved
const realPassword = decodePassword({ password });
const realNewPassword = decodePassword({ password: newPassword });
if (realPassword === realNewPassword) {
Expand All @@ -296,20 +315,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 +358,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 +394,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 +428,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;
ezailWang marked this conversation as resolved.
Show resolved Hide resolved
};
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
Loading