From b8573a5425358bde2269dc94f0b78fbb36ad66d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Fri, 22 May 2026 11:47:45 +0800 Subject: [PATCH] Tighten front database column type validation --- .../front/FrontProjectServiceImpl.java | 52 +++++++++++++------ .../front/FrontProjectServiceImplTest.java | 38 ++++++++++++++ 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/FrontProjectServiceImpl.java b/RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/FrontProjectServiceImpl.java index 4c27f24..d229021 100644 --- a/RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/FrontProjectServiceImpl.java +++ b/RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/FrontProjectServiceImpl.java @@ -1,11 +1,9 @@ package com.ruoyi.generator.service.front; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -31,12 +29,11 @@ public class FrontProjectServiceImpl implements IFrontProjectService { private static final Pattern SAFE_PROJECT_FILE_NAME = Pattern.compile("^[a-z][a-z0-9-]*[a-z0-9]$|^[a-z]$"); private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[a-z][a-z0-9_]{1,63}$"); - private static final Set ALLOWED_COLUMN_TYPES = new HashSet(Arrays.asList( - "tinyint", "smallint", "mediumint", "int", "integer", "bigint", - "float", "double", "decimal", "numeric", - "bit", "bool", "boolean", - "char", "varchar", "text", "tinytext", "mediumtext", "longtext", - "date", "time", "datetime", "timestamp", "json")); + private static final Pattern BIGINT_TYPE_PATTERN = Pattern.compile("^bigint(\\(20\\))?$"); + private static final Pattern INT_TYPE_PATTERN = Pattern.compile("^int(\\(11\\))?$"); + private static final Pattern VARCHAR_TYPE_PATTERN = Pattern.compile("^varchar\\((\\d{1,5})\\)$"); + private static final Pattern CHAR_TYPE_PATTERN = Pattern.compile("^char\\((\\d{1,3})\\)$"); + private static final Pattern DECIMAL_TYPE_PATTERN = Pattern.compile("^decimal\\((\\d{1,2}),(\\d{1,2})\\)$"); @Autowired private FrontProjectMapper frontProjectMapper; @@ -246,12 +243,37 @@ public class FrontProjectServiceImpl implements IFrontProjectService { return false; } - String normalizedType = columnType.trim().toLowerCase(Locale.ENGLISH) - .replaceAll("\\s+unsigned$", "") - .replaceAll("\\s+zerofill$", ""); - int bracketIndex = normalizedType.indexOf('('); - String baseType = bracketIndex >= 0 ? normalizedType.substring(0, bracketIndex) : normalizedType; - return ALLOWED_COLUMN_TYPES.contains(baseType); + String normalizedType = columnType.trim().toLowerCase(Locale.ENGLISH); + if ("datetime".equals(normalizedType) || "date".equals(normalizedType) + || "text".equals(normalizedType) || "longtext".equals(normalizedType)) + { + return true; + } + if (BIGINT_TYPE_PATTERN.matcher(normalizedType).matches() + || INT_TYPE_PATTERN.matcher(normalizedType).matches()) + { + return true; + } + Matcher varcharMatcher = VARCHAR_TYPE_PATTERN.matcher(normalizedType); + if (varcharMatcher.matches()) + { + int length = Integer.parseInt(varcharMatcher.group(1)); + return length >= 1 && length <= 65535; + } + Matcher charMatcher = CHAR_TYPE_PATTERN.matcher(normalizedType); + if (charMatcher.matches()) + { + int length = Integer.parseInt(charMatcher.group(1)); + return length >= 1 && length <= 255; + } + Matcher decimalMatcher = DECIMAL_TYPE_PATTERN.matcher(normalizedType); + if (decimalMatcher.matches()) + { + int precision = Integer.parseInt(decimalMatcher.group(1)); + int scale = Integer.parseInt(decimalMatcher.group(2)); + return precision >= 1 && precision <= 65 && scale >= 0 && scale <= 30 && scale <= precision; + } + return false; } private String joinCreateTableSql(List tables) diff --git a/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/FrontProjectServiceImplTest.java b/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/FrontProjectServiceImplTest.java index 0d38e0f..2e5f6d4 100644 --- a/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/FrontProjectServiceImplTest.java +++ b/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/FrontProjectServiceImplTest.java @@ -112,6 +112,44 @@ public class FrontProjectServiceImplTest verify(frontProjectTableMapper, never()).deleteTablesByProjectId(any(Long.class)); } + @Test + public void saveDatabaseRejectsColumnTypeWithSuffix() + { + when(frontProjectMapper.selectFrontProjectByUserAndId(7L, 10L)).thenReturn(project()); + + ServiceException exception = expectServiceException(new ThrowingRunnable() + { + @Override + public void run() + { + service.saveDatabase(7L, 10L, database(table("sys_user", column("id", "varchar(64) not null", "1")))); + } + }); + + assertEquals("字段类型不在允许范围内", exception.getMessage()); + verify(frontProjectColumnMapper, never()).deleteColumnsByProjectId(any(Long.class)); + verify(frontProjectTableMapper, never()).deleteTablesByProjectId(any(Long.class)); + } + + @Test + public void saveDatabaseRejectsJsonColumnType() + { + when(frontProjectMapper.selectFrontProjectByUserAndId(7L, 10L)).thenReturn(project()); + + ServiceException exception = expectServiceException(new ThrowingRunnable() + { + @Override + public void run() + { + service.saveDatabase(7L, 10L, database(table("sys_user", column("id", "json", "1")))); + } + }); + + assertEquals("字段类型不在允许范围内", exception.getMessage()); + verify(frontProjectColumnMapper, never()).deleteColumnsByProjectId(any(Long.class)); + verify(frontProjectTableMapper, never()).deleteTablesByProjectId(any(Long.class)); + } + @Test public void saveDatabasePersistsValidDraft() {