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 #6335

Open
wants to merge 16 commits into
base: x
Choose a base branch
from
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',
Comment on lines +778 to +780
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

添加的生物识别相关词汇看起来不错!

这些新增的拼写检查跳过词很合理,与密码设置功能的更新相符。

建议考虑是否还需要添加其他相关术语,比如:

  • 'fingerprint'(指纹)
  • 'faceID'(面容ID)

];
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);
Comment on lines +307 to +308
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

打印原密码和新密码可能带来风险,建议删除或隐藏敏感输出。

-console.log('same__password', password);
-console.log('same__newPassword', newPassword);
+// 建议删除或通过安全日志替代,避免潜在敏感数据泄露
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log('same__password', password);
console.log('same__newPassword', newPassword);
// 建议删除或通过安全日志替代,避免潜在敏感数据泄露

Comment on lines +307 to +308
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

查看相同密码日志
仅打印到控制台,需要时可在生产环境移除调试信息,避免混淆或者意外泄露。

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;
Comment on lines +64 to +67
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

新增字段强化错误保护功能。
enablePasswordErrorProtectionpasswordErrorAttemptspasswordErrorProtectionTime为后续扩展埋下伏笔,用于限制错误输入尝试。

};
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