You've already forked FrameTour-BE
feat(puzzle): 实现智能自动填充引擎和安全增强
- 新增拼图元素自动填充引擎 PuzzleElementFillEngine - 支持基于规则的条件匹配和数据源解析 - 实现机位数量、机位ID等多维度条件策略 - 添加 DEVICE_IMAGE、USER_AVATAR 等数据源类型支持 - 增加景区隔离校验确保模板使用安全性 - 强化图片下载安全校验,防范 SSRF 攻击 - 支持本地文件路径解析和公网 URL 安全检查 - 完善静态值数据源策略支持 localPath 配置 - 优化生成流程中 faceId 和 scenicId 的校验逻辑 - 补充相关单元测试覆盖核心功能点
This commit is contained in:
@@ -2,18 +2,27 @@ package com.ycwl.basic.puzzle.element;
|
||||
|
||||
import com.ycwl.basic.puzzle.element.base.BaseElement;
|
||||
import com.ycwl.basic.puzzle.element.base.ElementFactory;
|
||||
import com.ycwl.basic.puzzle.element.enums.ElementType;
|
||||
import com.ycwl.basic.puzzle.element.impl.ImageElement;
|
||||
import com.ycwl.basic.puzzle.element.impl.TextElement;
|
||||
import com.ycwl.basic.puzzle.element.exception.ElementValidationException;
|
||||
import com.ycwl.basic.puzzle.element.renderer.RenderContext;
|
||||
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
|
||||
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
@@ -27,6 +36,23 @@ class ImageElementTest {
|
||||
private Graphics2D graphics;
|
||||
private RenderContext context;
|
||||
|
||||
@BeforeAll
|
||||
static void initRegistry() {
|
||||
ElementFactory.clearRegistry();
|
||||
ElementFactory.register(ElementType.TEXT, TextElement.class);
|
||||
ElementFactory.register(ElementType.IMAGE, ImageElement.class);
|
||||
}
|
||||
|
||||
static class TestableImageElement extends ImageElement {
|
||||
boolean isSafe(String url) {
|
||||
return isSafeRemoteUrl(url);
|
||||
}
|
||||
|
||||
BufferedImage load(String path) {
|
||||
return downloadImage(path);
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
BufferedImage canvas = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
|
||||
@@ -121,4 +147,31 @@ class ImageElementTest {
|
||||
assertTrue(schema.contains("imageFitMode"));
|
||||
assertTrue(schema.contains("borderRadius"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImageElement_SafeRemoteUrlChecks() {
|
||||
TestableImageElement element = new TestableImageElement();
|
||||
assertFalse(element.isSafe("http://127.0.0.1/admin.png"));
|
||||
assertFalse(element.isSafe("http://localhost/private.png"));
|
||||
assertFalse(element.isSafe("file:///etc/passwd"));
|
||||
assertTrue(element.isSafe("https://8.8.8.8/logo.png"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImageElement_LoadLocalImageSuccess() throws IOException {
|
||||
Path temp = Files.createTempFile("puzzle-image", ".png");
|
||||
try {
|
||||
BufferedImage bufferedImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
|
||||
ImageIO.write(bufferedImage, "png", temp.toFile());
|
||||
|
||||
TestableImageElement element = new TestableImageElement();
|
||||
BufferedImage loaded = element.load(temp.toString());
|
||||
|
||||
assertNotNull(loaded);
|
||||
assertEquals(10, loaded.getWidth());
|
||||
assertEquals(10, loaded.getHeight());
|
||||
} finally {
|
||||
Files.deleteIfExists(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user