mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-21 11:43:56 +00:00
fix: password check (#4497)
* fix: password check * add doc * fix: password check
This commit is contained in:
20
docSite/content/zh-cn/docs/development/upgrading/495.md
Normal file
20
docSite/content/zh-cn/docs/development/upgrading/495.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: 'V4.9.5(进行中)'
|
||||
description: 'FastGPT V4.9.5 更新说明'
|
||||
icon: 'upgrade'
|
||||
draft: false
|
||||
toc: true
|
||||
weight: 795
|
||||
---
|
||||
|
||||
|
||||
## 🚀 新增内容
|
||||
|
||||
1. 团队成员权限细分,可分别控制是否可创建在根目录应用/知识库以及 API Key
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
1. password 检测规则错误
|
5
pnpm-lock.yaml
generated
5
pnpm-lock.yaml
generated
@@ -4,6 +4,11 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
patchedDependencies:
|
||||
mdast-util-gfm-autolink-literal@2.0.1:
|
||||
hash: f63d515781110436299ab612306211a9621c6dfaec1ce1a19e2f27454dc70251
|
||||
path: patches/mdast-util-gfm-autolink-literal@2.0.1.patch
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
|
@@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { updatePasswordByOld } from '@/web/support/user/api';
|
||||
import { PasswordRule } from '@/web/support/user/login/constants';
|
||||
import { checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
|
||||
type FormType = {
|
||||
@@ -70,9 +70,11 @@ const UpdatePswModal = ({ onClose }: { onClose: () => void }) => {
|
||||
placeholder={t('account_info:password_tip')}
|
||||
{...register('newPsw', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: PasswordRule,
|
||||
message: t('account_info:password_tip')
|
||||
validate: (val) => {
|
||||
if (!checkPasswordRule(val)) {
|
||||
return t('login:password_tip');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { Dispatch } from 'react';
|
||||
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { LoginPageTypeEnum, PasswordRule } from '@/web/support/user/login/constants';
|
||||
import { LoginPageTypeEnum, checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
import { postFindPassword } from '@/web/support/user/api';
|
||||
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
|
||||
import type { ResLogin } from '@/global/support/api/userRes.d';
|
||||
@@ -138,9 +138,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
placeholder={t('login:password_tip')}
|
||||
{...register('password', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: PasswordRule,
|
||||
message: t('login:password_tip')
|
||||
validate: (val) => {
|
||||
if (!checkPasswordRule(val)) {
|
||||
return t('login:password_tip');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { Dispatch } from 'react';
|
||||
import { FormControl, Box, Input, Button } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { LoginPageTypeEnum, PasswordRule } from '@/web/support/user/login/constants';
|
||||
import { LoginPageTypeEnum, checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
import { postRegister } from '@/web/support/user/api';
|
||||
import { useSendCode } from '@/web/support/user/hooks/useSendCode';
|
||||
import type { ResLogin } from '@/global/support/api/userRes';
|
||||
@@ -166,9 +166,11 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
placeholder={t('login:password_tip')}
|
||||
{...register('password', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: PasswordRule,
|
||||
message: t('login:password_tip')
|
||||
validate: (val) => {
|
||||
if (!checkPasswordRule(val)) {
|
||||
return t('login:password_tip');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
></Input>
|
||||
|
48
projects/app/src/pages/api/admin/initv495.ts
Normal file
48
projects/app/src/pages/api/admin/initv495.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { NextAPI } from '@/service/middleware/entry';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
|
||||
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
|
||||
import {
|
||||
TeamApikeyCreatePermissionVal,
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal
|
||||
} from '@fastgpt/global/support/permission/user/constant';
|
||||
import { retryFn } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
async function handler(req: NextApiRequest, _res: NextApiResponse) {
|
||||
await authCert({ req, authRoot: true });
|
||||
// 更新团队权限:
|
||||
// 目前所有有 TeamWritePermission 的,都需要添加三个新的权限。
|
||||
|
||||
const rps = await MongoResourcePermission.find({
|
||||
resourceType: 'team',
|
||||
teamId: { $exists: true },
|
||||
resourceId: null
|
||||
});
|
||||
|
||||
for await (const rp of rps) {
|
||||
const per = new TeamPermission({ per: rp.permission });
|
||||
console.log(per.hasWritePer, per.value);
|
||||
if (per.hasWritePer) {
|
||||
const newPer = per.addPer(
|
||||
TeamAppCreatePermissionVal,
|
||||
TeamDatasetCreatePermissionVal,
|
||||
TeamApikeyCreatePermissionVal
|
||||
);
|
||||
rp.permission = newPer.value;
|
||||
|
||||
try {
|
||||
await retryFn(async () => {
|
||||
await rp.save();
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('更新权限异常', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
export default NextAPI(handler);
|
@@ -5,5 +5,21 @@ export enum LoginPageTypeEnum {
|
||||
wechat = 'wechat'
|
||||
}
|
||||
|
||||
export const PasswordRule =
|
||||
/^(?:(?=.*\d)(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])|(?=.*\d)(?=.*[!@#$%^&*_])|(?=.*[a-z])(?=.*[A-Z])|(?=.*[a-z])(?=.*[!@#$%^&*_])|(?=.*[A-Z])(?=.*[!@#$%^&*_]))[\dA-Za-z!@#$%^&*_]{6,}$/;
|
||||
export const checkPasswordRule = (password: string) => {
|
||||
const patterns = [
|
||||
/\d/, // Contains digits
|
||||
/[a-z]/, // Contains lowercase letters
|
||||
/[A-Z]/, // Contains uppercase letters
|
||||
/[!@#$%^&*()_+=-]/ // Contains special characters
|
||||
];
|
||||
const validChars = /^[\dA-Za-z!@#$%^&*()_+=-]{6,100}$/;
|
||||
|
||||
// Check length and valid characters
|
||||
if (!validChars.test(password)) return false;
|
||||
|
||||
// Count how many patterns are satisfied
|
||||
const matchCount = patterns.filter((pattern) => pattern.test(password)).length;
|
||||
|
||||
// Must satisfy at least 2 patterns
|
||||
return matchCount >= 2;
|
||||
};
|
||||
|
35
test/cases/global/common/string/utils.test.ts
Normal file
35
test/cases/global/common/string/utils.test.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { checkPasswordRule } from '@/web/support/user/login/constants';
|
||||
|
||||
describe('PasswordRule', () => {
|
||||
it('should be a valid password', () => {
|
||||
// Small password
|
||||
expect(checkPasswordRule('123A')).toBe(false);
|
||||
expect(checkPasswordRule('@ga21')).toBe(false);
|
||||
|
||||
// Test single type characters
|
||||
expect(checkPasswordRule('123456')).toBe(false);
|
||||
expect(checkPasswordRule('abcdef')).toBe(false); // only lowercase
|
||||
expect(checkPasswordRule('ABCDEF')).toBe(false); // only uppercase
|
||||
expect(checkPasswordRule('!@#$%^')).toBe(false); // only special chars
|
||||
|
||||
// Test two types combination
|
||||
expect(checkPasswordRule('abc123')).toBe(true); // lowercase + numbers
|
||||
expect(checkPasswordRule('abcABC')).toBe(true); // lowercase + uppercase
|
||||
expect(checkPasswordRule('abc!@#')).toBe(true); // lowercase + special chars
|
||||
expect(checkPasswordRule('ABC!@#')).toBe(true); // uppercase + special chars
|
||||
expect(checkPasswordRule('ABC123')).toBe(true); // uppercase + numbers
|
||||
expect(checkPasswordRule('123!@#')).toBe(true); // numbers + special chars
|
||||
expect(checkPasswordRule('!@123fa')).toBe(true); // numbers + special chars
|
||||
expect(checkPasswordRule('+2222()222')).toBe(true); // special chars + numbers
|
||||
expect(checkPasswordRule('_2222()-+=22')).toBe(true); // special chars + numbers
|
||||
|
||||
// Test three types combination
|
||||
expect(checkPasswordRule('abcABC123')).toBe(true); // lower + upper + numbers
|
||||
expect(checkPasswordRule('abc123!@#')).toBe(true); // lower + numbers + special
|
||||
expect(checkPasswordRule('abc!@#123')).toBe(true); // lower + special + numbers
|
||||
|
||||
// Test all four types
|
||||
expect(checkPasswordRule('abcABC123!@#')).toBe(true); // all types
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user