(improvement)(login) encrypt password (#1081) (#1116)

This commit is contained in:
zhaodongsheng
2024-06-09 08:16:45 +08:00
committed by GitHub
parent dcb7f21241
commit 5bc88b78a9
15 changed files with 289 additions and 95 deletions

View File

@@ -56,7 +56,7 @@ The high-level architecture and main process flow is as follows:
## Quick Demo ## Quick Demo
### Online playground ### Online playground
Visit http://117.72.46.148:9080 with username/password: admin/admin. Please do not modify system configurations. We will restart to reset configurations regularly every weekend. Visit http://117.72.46.148:9080 to register and experience as a new user. Please do not modify system configurations. We will restart to reset configurations regularly every weekend.
## Local build ## Local build
SuperSonic comes with sample semantic models as well as chat conversations that can be used as a starting point. Please follow the steps: SuperSonic comes with sample semantic models as well as chat conversations that can be used as a starting point. Please follow the steps:

View File

@@ -53,7 +53,7 @@ SuperSonic的整体架构和主流程如下图所示
## 快速体验 ## 快速体验
### 线上环境体验 ### 线上环境体验
访问http://117.72.46.148:9080 用户名/密码:admin/admin. 请勿修改系统配置。我们每周末定期重启重置配置。 访问http://117.72.46.148:9080 注册新用户体验. 请勿修改系统配置。我们每周末定期重启重置配置。
### 本地构建 ### 本地构建

View File

@@ -9,6 +9,7 @@ import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
import com.tencent.supersonic.auth.api.authentication.request.UserReq; import com.tencent.supersonic.auth.api.authentication.request.UserReq;
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO; import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
import com.tencent.supersonic.auth.authentication.persistence.repository.UserRepository; import com.tencent.supersonic.auth.authentication.persistence.repository.UserRepository;
import com.tencent.supersonic.auth.authentication.utils.AESEncryptionUtil;
import com.tencent.supersonic.auth.authentication.utils.UserTokenUtils; import com.tencent.supersonic.auth.authentication.utils.UserTokenUtils;
import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.ContextUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@@ -72,6 +73,14 @@ public class DefaultUserAdaptor implements UserAdaptor {
} }
UserDO userDO = new UserDO(); UserDO userDO = new UserDO();
BeanUtils.copyProperties(userReq, userDO); BeanUtils.copyProperties(userReq, userDO);
try {
byte[] salt = AESEncryptionUtil.generateSalt(userDO.getName());
userDO.setSalt(AESEncryptionUtil.getStringFromBytes(salt));
System.out.println("salt: " + userDO.getSalt());
userDO.setPassword(AESEncryptionUtil.encrypt(userReq.getPassword(), salt));
} catch (Exception e) {
throw new RuntimeException("password encrypt error, please try again");
}
userRepository.addUser(userDO); userRepository.addUser(userDO);
} }
@@ -82,12 +91,24 @@ public class DefaultUserAdaptor implements UserAdaptor {
if (userDO == null) { if (userDO == null) {
throw new RuntimeException("user not exist,please register"); throw new RuntimeException("user not exist,please register");
} }
if (userDO.getPassword().equals(userReq.getPassword())) {
UserWithPassword user = UserWithPassword.get(userDO.getId(), userDO.getName(), userDO.getDisplayName(), try {
userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin()); String password = AESEncryptionUtil.encrypt(userReq.getPassword(),
return userTokenUtils.generateToken(user); AESEncryptionUtil.getBytesFromString(userDO.getSalt()));
System.out.println("userReq.getPassword(): " + userReq.getPassword());
System.out.println("password: " + password);
System.out.println("userDO.getPassword(): " + userDO.getPassword());
if (userDO.getPassword().equals(password)) {
UserWithPassword user = UserWithPassword.get(userDO.getId(), userDO.getName(), userDO.getDisplayName(),
userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin());
return userTokenUtils.generateToken(user);
} else {
throw new RuntimeException("password not correct, please try again");
}
} catch (Exception e) {
throw new RuntimeException("password encrypt error, please try again");
} }
throw new RuntimeException("password not correct, please try again");
} }
@Override @Override

View File

@@ -16,6 +16,8 @@ public class UserDO {
*/ */
private String password; private String password;
private String salt;
/** /**
* *
*/ */
@@ -79,6 +81,14 @@ public class UserDO {
this.password = password == null ? null : password.trim(); this.password = password == null ? null : password.trim();
} }
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt == null ? null : salt.trim();
}
/** /**
* *
* @return display_name * @return display_name

View File

@@ -0,0 +1,59 @@
package com.tencent.supersonic.auth.authentication.utils;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.MessageDigest;
import java.security.spec.KeySpec;
import java.util.Base64;
public class AESEncryptionUtil {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String ENCODE = "UTF-8";
private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA256";
private static final int ITERATIONS = 65536;
private static final int KEY_LENGTH = 256;
public static byte[] generateSalt(String username) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(username.getBytes(ENCODE));
byte[] hash = md.digest();
// 通常只需要使用盐的一部分作为盐值例如16字节
byte[] salt = new byte[16];
System.arraycopy(hash, 0, salt, 0, salt.length);
return salt;
}
public static String encrypt(String password, byte[] salt) throws Exception {
// TODO 固定IV确保每次加密时使用相同的IV,该值应该安全保管
byte[] iv = "supersonic@bicom".getBytes(ENCODE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SECRET_KEY_ALGORITHM);
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(password.getBytes(ENCODE));
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
return Base64.getEncoder().encodeToString(combined);
}
public static String getStringFromBytes(byte[] salt) {
return Base64.getEncoder().encodeToString(salt);
}
public static byte[] getBytesFromString(String encodeSalt) {
return Base64.getDecoder().decode(encodeSalt);
}
}

View File

@@ -5,6 +5,7 @@
<result column="id" jdbcType="BIGINT" property="id" /> <result column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" /> <result column="name" jdbcType="VARCHAR" property="name" />
<result column="password" jdbcType="VARCHAR" property="password" /> <result column="password" jdbcType="VARCHAR" property="password" />
<result column="salt" jdbcType="VARCHAR" property="salt" />
<result column="display_name" jdbcType="VARCHAR" property="displayName" /> <result column="display_name" jdbcType="VARCHAR" property="displayName" />
<result column="email" jdbcType="VARCHAR" property="email" /> <result column="email" jdbcType="VARCHAR" property="email" />
<result column="is_admin" jdbcType="INTEGER" property="isAdmin" /> <result column="is_admin" jdbcType="INTEGER" property="isAdmin" />
@@ -39,7 +40,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, name, password, display_name, email, is_admin id, name, password, salt, display_name, email, is_admin
</sql> </sql>
<select id="selectByExample" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample" resultMap="BaseResultMap">
select select
@@ -59,10 +60,10 @@
</if> </if>
</select> </select>
<insert id="insert" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO"> <insert id="insert" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
insert into s2_user (id, name, password, insert into s2_user (id, name, password, salt,
display_name, email, is_admin display_name, email, is_admin
) )
values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR},
#{displayName,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{isAdmin,jdbcType=INTEGER} #{displayName,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{isAdmin,jdbcType=INTEGER}
) )
</insert> </insert>
@@ -78,6 +79,9 @@
<if test="password != null"> <if test="password != null">
password, password,
</if> </if>
<if test="password != null">
salt,
</if>
<if test="displayName != null"> <if test="displayName != null">
display_name, display_name,
</if> </if>
@@ -98,6 +102,9 @@
<if test="password != null"> <if test="password != null">
#{password,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},
</if> </if>
<if test="salt != null">
#{salt,jdbcType=VARCHAR},
</if>
<if test="displayName != null"> <if test="displayName != null">
#{displayName,jdbcType=VARCHAR}, #{displayName,jdbcType=VARCHAR},
</if> </if>

View File

@@ -1,9 +1,9 @@
-- sample user -- sample user
MERGE INTO s2_user (id, `name`, password, display_name, email, is_admin) values (1, 'admin','admin','admin','admin@xx.com', 1); MERGE INTO s2_user (id, `name`, password, salt, display_name, email, is_admin) values (1, 'admin11','c3VwZXJzb25pY0BiaWNvbQIY4hJ2TJ0bM4aJLIAEreUBTMlveZUDOTINOon+hs59pSoijg6AoB6m3khO/6lX/g==','jGl25bVBBBW96Qi9Te4V3w==','admin11','admin@xx.com', 1);
MERGE INTO s2_user (id, `name`, password, display_name, email) values (2, 'jack','123456','jack','jack@xx.com'); MERGE INTO s2_user (id, `name`, password, salt, display_name, email) values (2, 'jack','123456','123456','jack','jack@xx.com');
MERGE INTO s2_user (id, `name`, password, display_name, email) values (3, 'tom','123456','tom','tom@xx.com'); MERGE INTO s2_user (id, `name`, password, salt, display_name, email) values (3, 'tom','123456','123456','tom','tom@xx.com');
MERGE INTO s2_user (id, `name`, password, display_name, email, is_admin) values (4, 'lucy','123456','lucy','lucy@xx.com', 1); MERGE INTO s2_user (id, `name`, password, salt, display_name, email, is_admin) values (4, 'lucy','123456','123456','lucy','lucy@xx.com', 1);
MERGE INTO s2_user (id, `name`, password, display_name, email) values (5, 'alice','123456','alice','alice@xx.com'); MERGE INTO s2_user (id, `name`, password, salt, display_name, email) values (5, 'alice','123456','123456','alice','alice@xx.com');
MERGE INTO s2_available_date_info(`id`,`item_id` ,`type` ,`date_format` ,`start_date` ,`end_date` ,`unavailable_date` ,`created_at` ,`created_by` ,`updated_at` ,`updated_by` ) MERGE INTO s2_available_date_info(`id`,`item_id` ,`type` ,`date_format` ,`start_date` ,`end_date` ,`unavailable_date` ,`created_at` ,`created_by` ,`updated_at` ,`updated_by` )
values (1 , 1, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin'); values (1 , 1, 'dimension', 'yyyy-MM-dd', DATEADD('DAY', -28, CURRENT_DATE()), DATEADD('DAY', -1, CURRENT_DATE()), '[]', '2023-06-01', 'admin', '2023-06-01', 'admin');

View File

@@ -1,6 +1,6 @@
-- sample user -- sample user
insert into s2_user (id, `name`, password, display_name, email, is_admin) values (1, 'admin','admin','admin','admin@xx.com', 1); insert into s2_user (id, `name`, password, salt, display_name, email, is_admin) values (1, 'admin','admin','admin','admin@xx.com', 1);
insert into s2_user (id, `name`, password, display_name, email, is_admin) values (4, 'lucy','123456','lucy','lucy@xx.com', 1); insert into s2_user (id, `name`, password, salt, display_name, email, is_admin) values (4, 'lucy','123456','lucy','lucy@xx.com', 1);
INSERT INTO s2_available_date_info (`item_id`, `type`, `date_format`, `start_date`, `end_date`, `unavailable_date`, `created_at`, `created_by`, `updated_at`, `updated_by`) INSERT INTO s2_available_date_info (`item_id`, `type`, `date_format`, `start_date`, `end_date`, `unavailable_date`, `created_at`, `created_by`, `updated_at`, `updated_by`)

View File

@@ -88,7 +88,8 @@ create table IF NOT EXISTS s2_user
id INT AUTO_INCREMENT, id INT AUTO_INCREMENT,
name varchar(100) not null, name varchar(100) not null,
display_name varchar(100) null, display_name varchar(100) null,
password varchar(100) null, password varchar(256) null,
salt varchar(256) NULL,
email varchar(100) null, email varchar(100) null,
is_admin INT null, is_admin INT null,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)

View File

@@ -426,7 +426,8 @@ create table s2_user
id int(11) NOT NULL AUTO_INCREMENT, id int(11) NOT NULL AUTO_INCREMENT,
name varchar(100) not null, name varchar(100) not null,
display_name varchar(100) null, display_name varchar(100) null,
password varchar(100) null, password varchar(256) null,
salt varchar(256) DEFAULT NULL COMMENT 'md5密码盐',
email varchar(100) null, email varchar(100) null,
is_admin int(11) null, is_admin int(11) null,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)

View File

@@ -0,0 +1,35 @@
package com.tencent.supersonic.util;
import com.tencent.supersonic.auth.authentication.utils.AESEncryptionUtil;
public class AESEncryptionUtilTest {
public static boolean areByteArraysEqual(byte[] array1, byte[] array2) {
if (array1.length != array2.length) {
return false;
}
for (int i = 0; i < array1.length; i++) {
if (array1[i] != array2[i]) {
return false;
}
}
return true;
}
public static void main(String[] args) throws Exception {
byte[] salt = AESEncryptionUtil.generateSalt("zhangsan1234");
System.out.println("salt: " + salt);
String encodeSalt = AESEncryptionUtil.getStringFromBytes(salt);
System.out.println("encodeSalt: " + encodeSalt);
byte[] decodeSalt = AESEncryptionUtil.getBytesFromString(encodeSalt);
System.out.println("decodeSalt: " + decodeSalt);
System.out.println("areByteArraysEqual: " + areByteArraysEqual(salt, decodeSalt));
String password = AESEncryptionUtil.encrypt("zhangsan1234", salt);
System.out.println("password: " + password);
String password2 = AESEncryptionUtil.encrypt("zhangsan1234", decodeSalt);
System.out.println("password2: " + password2);
}
}

View File

@@ -74,7 +74,7 @@
"compression-webpack-plugin": "^11.0.0", "compression-webpack-plugin": "^11.0.0",
"copy-to-clipboard": "^3.3.1", "copy-to-clipboard": "^3.3.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"crypto-js": "^4.0.0", "crypto-js": "^4.2.0",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"echarts": "^5.0.2", "echarts": "^5.0.2",
"echarts-for-react": "^3.0.1", "echarts-for-react": "^3.0.1",

View File

@@ -13,6 +13,7 @@ import { postUserLogin, userRegister } from './services';
import { AUTH_TOKEN_KEY } from '@/common/constants'; import { AUTH_TOKEN_KEY } from '@/common/constants';
import { queryCurrentUser } from '@/services/user'; import { queryCurrentUser } from '@/services/user';
import { history, useModel } from 'umi'; import { history, useModel } from 'umi';
import {encryptPassword} from "@/utils/utils";
const { Item } = Form; const { Item } = Form;
const LoginPage: React.FC = () => { const LoginPage: React.FC = () => {
@@ -43,21 +44,24 @@ const LoginPage: React.FC = () => {
message.success(msg); message.success(msg);
}; };
// 处理登录按钮响应 // 处理登录按钮响应
const handleLogin = async () => { const handleLogin = async () => {
const { validateFields } = form; const { validateFields } = form;
const content = await validateFields(); const content = await validateFields();
await loginDone(content); await loginDone({...content, password: encryptPassword(content.password)});
}; };
// 处理注册弹窗确定按钮 // 处理注册弹窗确定按钮
const handleRegister = async (values: RegisterFormDetail) => { const handleRegister = async (values: RegisterFormDetail) => {
const { code } = await userRegister({ ...values }); const enCodeValues = { ...values, password: encryptPassword(values.password) };
const { code } = await userRegister(enCodeValues);
if (code === 200) { if (code === 200) {
message.success('注册成功'); message.success('注册成功');
setCreateModalVisible(false); setCreateModalVisible(false);
// 注册完自动帮用户登录 // 注册完自动帮用户登录
await loginDone(values); await loginDone(enCodeValues);
} }
}; };
@@ -103,7 +107,7 @@ const LoginPage: React.FC = () => {
<Input <Input
size="large" size="large"
type="password" type="password"
placeholder="密码: admin" placeholder="密码: admin123"
onPressEnter={handleLogin} onPressEnter={handleLogin}
prefix={<LockOutlined />} prefix={<LockOutlined />}
/> />

View File

@@ -3,6 +3,7 @@ import { message } from 'antd';
import numeral from 'numeral'; import numeral from 'numeral';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import { isString } from 'lodash'; import { isString } from 'lodash';
import CryptoJS from 'crypto-js';
/* eslint no-useless-escape:0 */ /* eslint no-useless-escape:0 */
const reg = const reg =
@@ -470,3 +471,15 @@ export const objToArray = (_obj: ObjToArrayParams, keyType: string = 'string') =
}; };
}); });
}; };
export function encryptPassword(password: string, username: string) {
if (!password) {
return password;
}
// TODO This key should be stored in a secure place
const key = CryptoJS.enc.Utf8.parse('supersonic@2024');
const srcs = CryptoJS.enc.Utf8.parse(password);
const encrypted = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7});
return encrypted.toString();
};

185
webapp/pnpm-lock.yaml generated
View File

@@ -1,9 +1,5 @@
lockfileVersion: '6.0' lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers: importers:
packages/chat-sdk: packages/chat-sdk:
@@ -364,7 +360,7 @@ importers:
specifier: ^7.0.3 specifier: ^7.0.3
version: 7.0.3 version: 7.0.3
crypto-js: crypto-js:
specifier: ^4.0.0 specifier: ^4.2.0
version: 4.2.0 version: 4.2.0
dayjs: dayjs:
specifier: ^1.11.10 specifier: ^1.11.10
@@ -582,7 +578,7 @@ packages:
babel-plugin-import: 1.13.8 babel-plugin-import: 1.13.8
babel-runtime-jsx-plus: 0.1.5 babel-runtime-jsx-plus: 0.1.5
classnames: 2.5.1 classnames: 2.5.1
dva-core: 2.0.4(redux@4.2.1) dva-core: 2.0.4(redux@3.7.2)
dva-immer: 1.0.2(dva@2.5.0-beta.2) dva-immer: 1.0.2(dva@2.5.0-beta.2)
dva-loading: 3.0.25(dva-core@2.0.4) dva-loading: 3.0.25(dva-core@2.0.4)
history: 5.3.0 history: 5.3.0
@@ -5549,7 +5545,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.24.5 '@babel/core': 7.24.5
postcss: 8.4.38 postcss: 8.4.38
postcss-syntax: 0.36.2(postcss@8.4.38) postcss-syntax: 0.36.2(postcss-html@0.36.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@7.0.39)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -7185,6 +7181,18 @@ packages:
- react-router - react-router
dev: true dev: true
/@umijs/bundler-utils@3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0):
resolution: {integrity: sha512-irJUU/eWa2GG6JCkz172lMi+jiq7ZXatE2N7Tq/lokZUYu9R9BRaRN7dphgBlAUfOP3aBtjx51/5yZdYAeW0yQ==}
dependencies:
'@umijs/babel-preset-umi': 3.5.41
'@umijs/types': 3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0)
'@umijs/utils': 3.5.41
transitivePeerDependencies:
- react
- react-dom
- react-router
dev: true
/@umijs/bundler-utils@4.2.5: /@umijs/bundler-utils@4.2.5:
resolution: {integrity: sha512-Hj8Uda4E/Bf9aIWLfMiixxjFRRXaVDQDU1MbUf7HhDtpgmfeQfIfWhzWRat9B8TfPLDA4KI3yW1EPdlNHGBiSA==} resolution: {integrity: sha512-Hj8Uda4E/Bf9aIWLfMiixxjFRRXaVDQDU1MbUf7HhDtpgmfeQfIfWhzWRat9B8TfPLDA4KI3yW1EPdlNHGBiSA==}
dependencies: dependencies:
@@ -7248,6 +7256,31 @@ packages:
- react-router - react-router
dev: true dev: true
/@umijs/bundler-webpack@3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0):
resolution: {integrity: sha512-n4HIrDUE3QfN5xSTWJlRz5wzsnWggzRJhEDJZ6l23BWiwWasFW6QMGCnFWLwO93ei273LovylD5vZhI221tBtQ==}
hasBin: true
dependencies:
'@umijs/bundler-utils': 3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0)
'@umijs/case-sensitive-paths-webpack-plugin': 1.0.1
'@umijs/deps': 3.5.41
'@umijs/types': 3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0)
'@umijs/utils': 3.5.41
jest-worker: 26.6.2
node-libs-browser: 2.2.1
normalize-url: 1.9.1
postcss: 7.0.32
postcss-flexbugs-fixes: 4.2.1
postcss-loader: 3.0.0
postcss-preset-env: 6.7.0
postcss-safe-parser: 4.0.2
terser: 5.14.2
webpack-chain: 6.5.1
transitivePeerDependencies:
- react
- react-dom
- react-router
dev: true
/@umijs/bundler-webpack@4.2.5(typescript@4.9.5)(webpack@5.91.0): /@umijs/bundler-webpack@4.2.5(typescript@4.9.5)(webpack@5.91.0):
resolution: {integrity: sha512-kABzFUTbkgccf2XwMiKEEVyfBuvZZSnFFU7E1uu2OQg3x7rv5dnF9yrMGwvul4I0KClPZAabd5eaf7WuKYyBAA==} resolution: {integrity: sha512-kABzFUTbkgccf2XwMiKEEVyfBuvZZSnFFU7E1uu2OQg3x7rv5dnF9yrMGwvul4I0KClPZAabd5eaf7WuKYyBAA==}
hasBin: true hasBin: true
@@ -7522,7 +7555,7 @@ packages:
eslint-plugin-react: 7.33.2(eslint@8.35.0) eslint-plugin-react: 7.33.2(eslint@8.35.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.35.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.35.0)
postcss: 8.4.38 postcss: 8.4.38
postcss-syntax: 0.36.2(postcss@8.4.38) postcss-syntax: 0.36.2(postcss-html@0.36.0)(postcss-less@3.1.4)(postcss-scss@2.1.1)(postcss@7.0.39)
stylelint-config-standard: 25.0.0(stylelint@14.8.2) stylelint-config-standard: 25.0.0(stylelint@14.8.2)
transitivePeerDependencies: transitivePeerDependencies:
- eslint - eslint
@@ -7692,7 +7725,7 @@ packages:
umi: 3.x umi: 3.x
dependencies: dependencies:
fast-deep-equal: 3.1.1 fast-deep-equal: 3.1.1
umi: 3.5.41(react-router@5.2.0) umi: 3.5.41(react-router@6.23.1)
dev: true dev: true
/@umijs/plugin-run@4.2.5: /@umijs/plugin-run@4.2.5:
@@ -7824,7 +7857,7 @@ packages:
mime: 1.4.1 mime: 1.4.1
react: 16.14.0 react: 16.14.0
react-refresh: 0.10.0 react-refresh: 0.10.0
react-router: 5.2.0(react@18.3.1) react-router: 5.2.0(react@16.14.0)
react-router-config: 5.1.1(react-router@5.2.0)(react@16.14.0) react-router-config: 5.1.1(react-router@5.2.0)(react@16.14.0)
react-router-dom: 5.2.0(react@16.14.0) react-router-dom: 5.2.0(react@16.14.0)
regenerator-runtime: 0.13.5 regenerator-runtime: 0.13.5
@@ -7962,6 +7995,23 @@ packages:
- react-router - react-router
dev: true dev: true
/@umijs/renderer-react@3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0):
resolution: {integrity: sha512-DmExaziU84uFXv09gYXpFk/tHB+mjINUD8YmYULjbQ+QQA9so2zkxNSv9gYy5hXNepheUMd+uriV/qUB6HNBVg==}
peerDependencies:
react: 16.x || 17.x
react-dom: 16.x || 17.x
dependencies:
'@types/react': 16.14.60
'@types/react-dom': 16.9.24
'@types/react-router-config': 5.0.2
'@umijs/runtime': 3.5.41(react@16.14.0)
react: 16.14.0
react-dom: 16.14.0(react@16.14.0)
react-router-config: 5.1.1(react-router@6.23.1)(react@16.14.0)
transitivePeerDependencies:
- react-router
dev: true
/@umijs/renderer-react@4.2.5(react-dom@18.1.0)(react@18.1.0): /@umijs/renderer-react@4.2.5(react-dom@18.1.0)(react@18.1.0):
resolution: {integrity: sha512-WuV2ye/A9NY5eHQ9VH6pD1MEgeuBbn18AU9dpJku5gaQ0kigPIMfMLVuon1Cvwc2XA9ab+5HcpwsJiAqrde3EQ==} resolution: {integrity: sha512-WuV2ye/A9NY5eHQ9VH6pD1MEgeuBbn18AU9dpJku5gaQ0kigPIMfMLVuon1Cvwc2XA9ab+5HcpwsJiAqrde3EQ==}
peerDependencies: peerDependencies:
@@ -8001,7 +8051,7 @@ packages:
express: 4.19.2 express: 4.19.2
lodash: 4.17.21 lodash: 4.17.21
prettier: 2.8.8 prettier: 2.8.8
umi: 3.5.41(react-router@5.2.0) umi: 3.5.41(react-router@6.23.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -8084,6 +8134,22 @@ packages:
- react-router - react-router
dev: true dev: true
/@umijs/types@3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0):
resolution: {integrity: sha512-pxvLiQ99EL8Yu98F/ZMojG9ukDptC315cnxSnRYOdS34F57oiIgW0Zoi0TrKlA0pVIQxC2MXzyQwy+HfDmB23Q==}
dependencies:
'@umijs/babel-preset-umi': 3.5.41
'@umijs/core': 3.5.41
'@umijs/deps': 3.5.41
'@umijs/renderer-react': 3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0)
'@umijs/server': 3.5.41
'@umijs/utils': 3.5.41
webpack-chain: 6.5.1
transitivePeerDependencies:
- react
- react-dom
- react-router
dev: true
/@umijs/ui@3.0.1: /@umijs/ui@3.0.1:
resolution: {integrity: sha512-zcz37AJH0xt/6XVVbyO/hmsK9Hq4vH23HZ4KYVi5A8rbM9KeJkJigTS7ELOdArawZhVNGe+h3a5Oixs4a2QsWw==} resolution: {integrity: sha512-zcz37AJH0xt/6XVVbyO/hmsK9Hq4vH23HZ4KYVi5A8rbM9KeJkJigTS7ELOdArawZhVNGe+h3a5Oixs4a2QsWw==}
dev: true dev: true
@@ -10340,6 +10406,7 @@ packages:
/core-js@3.6.5: /core-js@3.6.5:
resolution: {integrity: sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==} resolution: {integrity: sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==}
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
requiresBuild: true requiresBuild: true
dev: true dev: true
@@ -11676,6 +11743,21 @@ packages:
warning: 3.0.0 warning: 3.0.0
dev: true dev: true
/dva-core@2.0.4(redux@3.7.2):
resolution: {integrity: sha512-Zh39llFyItu9HKXKfCZVf9UFtDTcypdAjGBew1S+wK8BGVzFpm1GPTdd6uIMeg7O6STtCvt2Qv+RwUut1GFynA==}
peerDependencies:
redux: 4.x
dependencies:
'@babel/runtime': 7.24.5
flatten: 1.0.3
global: 4.4.0
invariant: 2.2.4
is-plain-object: 2.0.4
redux: 3.7.2
redux-saga: 0.16.2
warning: 3.0.0
dev: true
/dva-core@2.0.4(redux@4.2.1): /dva-core@2.0.4(redux@4.2.1):
resolution: {integrity: sha512-Zh39llFyItu9HKXKfCZVf9UFtDTcypdAjGBew1S+wK8BGVzFpm1GPTdd6uIMeg7O6STtCvt2Qv+RwUut1GFynA==} resolution: {integrity: sha512-Zh39llFyItu9HKXKfCZVf9UFtDTcypdAjGBew1S+wK8BGVzFpm1GPTdd6uIMeg7O6STtCvt2Qv+RwUut1GFynA==}
peerDependencies: peerDependencies:
@@ -17686,19 +17768,6 @@ packages:
tiny-warning: 1.0.3 tiny-warning: 1.0.3
dev: true dev: true
/mini-create-react-context@0.4.1(prop-types@15.8.1)(react@18.3.1):
resolution: {integrity: sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
peerDependencies:
prop-types: ^15.0.0
react: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
dependencies:
'@babel/runtime': 7.24.5
prop-types: 15.8.1
react: 18.3.1
tiny-warning: 1.0.3
dev: true
/mini-css-extract-plugin@2.9.0(webpack@5.91.0): /mini-css-extract-plugin@2.9.0(webpack@5.91.0):
resolution: {integrity: sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==} resolution: {integrity: sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==}
engines: {node: '>= 12.13.0'} engines: {node: '>= 12.13.0'}
@@ -18096,7 +18165,7 @@ packages:
dev: true dev: true
/normalize-url@1.9.1: /normalize-url@1.9.1:
resolution: {integrity: sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=} resolution: {integrity: sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==}
engines: {node: '>=4'} engines: {node: '>=4'}
dependencies: dependencies:
object-assign: 4.1.1 object-assign: 4.1.1
@@ -20412,30 +20481,6 @@ packages:
postcss-scss: 2.1.1 postcss-scss: 2.1.1
dev: true dev: true
/postcss-syntax@0.36.2(postcss@8.4.38):
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
peerDependencies:
postcss: '>=5.0.0'
postcss-html: '*'
postcss-jsx: '*'
postcss-less: '*'
postcss-markdown: '*'
postcss-scss: '*'
peerDependenciesMeta:
postcss-html:
optional: true
postcss-jsx:
optional: true
postcss-less:
optional: true
postcss-markdown:
optional: true
postcss-scss:
optional: true
dependencies:
postcss: 8.4.38
dev: true
/postcss-unique-selectors@5.1.1(postcss@8.4.38): /postcss-unique-selectors@5.1.1(postcss@8.4.38):
resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==}
engines: {node: ^10 || ^12 || >=14.0} engines: {node: ^10 || ^12 || >=14.0}
@@ -22869,7 +22914,18 @@ packages:
dependencies: dependencies:
'@babel/runtime': 7.24.5 '@babel/runtime': 7.24.5
react: 16.14.0 react: 16.14.0
react-router: 5.2.0(react@18.3.1) react-router: 5.2.0(react@16.14.0)
dev: true
/react-router-config@5.1.1(react-router@6.23.1)(react@16.14.0):
resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==}
peerDependencies:
react: '>=15'
react-router: '>=5'
dependencies:
'@babel/runtime': 7.24.5
react: 16.14.0
react-router: 6.23.1(react@18.3.1)
dev: true dev: true
/react-router-dom@4.3.1(react@18.3.1): /react-router-dom@4.3.1(react@18.3.1):
@@ -22983,24 +23039,6 @@ packages:
tiny-warning: 1.0.3 tiny-warning: 1.0.3
dev: true dev: true
/react-router@5.2.0(react@18.3.1):
resolution: {integrity: sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==}
peerDependencies:
react: '>=15'
dependencies:
'@babel/runtime': 7.24.5
history: 4.10.1
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
mini-create-react-context: 0.4.1(prop-types@15.8.1)(react@18.3.1)
path-to-regexp: 1.8.0
prop-types: 15.8.1
react: 18.3.1
react-is: 16.13.1
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
dev: true
/react-router@6.23.1(react@18.3.1): /react-router@6.23.1(react@18.3.1):
resolution: {integrity: sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==} resolution: {integrity: sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@@ -26344,16 +26382,16 @@ packages:
slash2: 2.0.0 slash2: 2.0.0
dev: true dev: true
/umi@3.5.41(react-router@5.2.0): /umi@3.5.41(react-router@6.23.1):
resolution: {integrity: sha512-sjgfFGC3E5jG5Cn8pXdwODDgPW1hnlkn24f7+onNnNdq77syuc4s3R5z7BKQHbjiWtVVIV1VOFMYE9JsJYnOPQ==} resolution: {integrity: sha512-sjgfFGC3E5jG5Cn8pXdwODDgPW1hnlkn24f7+onNnNdq77syuc4s3R5z7BKQHbjiWtVVIV1VOFMYE9JsJYnOPQ==}
hasBin: true hasBin: true
dependencies: dependencies:
'@umijs/bundler-webpack': 3.5.41(react-dom@16.14.0)(react-router@5.2.0)(react@16.14.0) '@umijs/bundler-webpack': 3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0)
'@umijs/core': 3.5.41 '@umijs/core': 3.5.41
'@umijs/deps': 3.5.41 '@umijs/deps': 3.5.41
'@umijs/preset-built-in': 3.5.41(react-dom@16.14.0)(react@16.14.0) '@umijs/preset-built-in': 3.5.41(react-dom@16.14.0)(react@16.14.0)
'@umijs/runtime': 3.5.41(react@16.14.0) '@umijs/runtime': 3.5.41(react@16.14.0)
'@umijs/types': 3.5.41(react-dom@16.14.0)(react-router@5.2.0)(react@16.14.0) '@umijs/types': 3.5.41(react-dom@16.14.0)(react-router@6.23.1)(react@16.14.0)
'@umijs/utils': 3.5.41 '@umijs/utils': 3.5.41
react: 16.14.0 react: 16.14.0
react-dom: 16.14.0(react@16.14.0) react-dom: 16.14.0(react@16.14.0)
@@ -26990,6 +27028,7 @@ packages:
/webpack-chain@6.5.1: /webpack-chain@6.5.1:
resolution: {integrity: sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==} resolution: {integrity: sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==}
engines: {node: '>=8'} engines: {node: '>=8'}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
dependencies: dependencies:
deepmerge: 1.5.2 deepmerge: 1.5.2
javascript-stringify: 2.1.0 javascript-stringify: 2.1.0
@@ -27682,3 +27721,7 @@ packages:
/zwitch@2.0.4: /zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: false dev: false
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false