Tighten front database column type validation

This commit is contained in:
王鹏
2026-05-22 11:47:45 +08:00
parent 3f2cdb8444
commit b8573a5425
2 changed files with 75 additions and 15 deletions

View File

@@ -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<String> ALLOWED_COLUMN_TYPES = new HashSet<String>(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<DatabaseTableDesign> tables)

View File

@@ -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()
{